diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Sat Jun  8 22:31:36 2002
+++ b/CREDITS	Sat Jun  8 22:31:36 2002
@@ -2779,6 +2779,10 @@
 E: x@xman.org
 D: Tulip net driver hacker
 
+N: Mark Smith
+E: mark.smith@comdev.cc
+D: Multicast support in bonding driver
+
 N: Miquel van Smoorenburg
 E: miquels@cistron.nl
 D: Kernel and net hacker. Sysvinit, minicom. doing Debian stuff.
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile	Sat Jun  8 22:31:37 2002
+++ b/Documentation/DocBook/Makefile	Sat Jun  8 22:31:37 2002
@@ -161,18 +161,20 @@
 OUT	:=	$(patsubst %.sgml, %.out, $(BOOKS))
 
 clean:
-	rm -f core *~
-	rm -f $(BOOKS)
-	rm -f $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
-	rm -f $(PNG-parportbook) $(EPS-parportbook)
-	rm -f $(C-procfs-example)
+	@echo 'Cleaning up (DocBook)'
+	@rm -f core *~
+	@rm -f $(BOOKS)
+	@rm -f $(DVI) $(AUX) $(TEX) $(LOG) $(OUT)
+	@rm -f $(PNG-parportbook) $(EPS-parportbook)
+	@rm -f $(C-procfs-example)
 
-mrproper: clean
-	rm -f $(PS) $(PDF)
-	rm -f -r $(HTML)
-	rm -f .depend
-	rm -f $(TOPDIR)/scripts/mkdep-docbook
-	rm -rf DBTOHTML_OUTPUT*
+mrproper:
+	@echo 'Making mrproper (DocBook)'
+	@rm -f $(PS) $(PDF)
+	@rm -f -r $(HTML)
+	@rm -f .depend
+	@rm -f $(TOPDIR)/scripts/mkdep-docbook
+	@rm -rf DBTOHTML_OUTPUT*
 
 %.ps : %.sgml
 	@(which db2ps > /dev/null 2>&1) || \
diff -Nru a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
--- a/Documentation/filesystems/Locking	Sat Jun  8 22:31:37 2002
+++ b/Documentation/filesystems/Locking	Sat Jun  8 22:31:37 2002
@@ -88,6 +88,7 @@
 	void (*read_inode) (struct inode *);
 	void (*write_inode) (struct inode *, int);
 	void (*put_inode) (struct inode *);
+	void (*drop_inode) (struct inode *);
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
@@ -102,6 +103,7 @@
 read_inode:	yes				(see below)
 write_inode:	no	
 put_inode:	no	
+drop_inode:	no				!!!inode_lock!!!
 delete_inode:	no	
 clear_inode:	no	
 put_super:	yes	yes	maybe		(see below)
diff -Nru a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
--- a/Documentation/filesystems/ntfs.txt	Sat Jun  8 22:31:49 2002
+++ b/Documentation/filesystems/ntfs.txt	Sat Jun  8 22:31:49 2002
@@ -73,52 +73,27 @@
 			Otherwise the default behaviour is to abort mount if
 			any unknown options are found.
 
-posix=<bool>		Deprecated option. Still supported but please use
-			show_inodes=posix in the future. See description for
-			show_inodes=opt.
-
-show_sys_files=<bool>	Deprecated option. Still supported but please use
-			show_inodes=system in the future. See description for
-			show_inodes=opt.
-
-show_inodes=opt		Allows choice of which types of inode names readdir()
-			returns, i.e. this affects what "ls" shows. Following
-			values can be used for "opt":
-			   system: show system files
-			   win32:  long file names (includes POSIX) [DEFAULT]
-			   long:   same as win32
-			   dos:    short file names only (excludes POSIX)
-			   short:  same as dos
-			   posix:  same as both win32 and dos
-			   all:    all file names
-			Note that the options are additive, i.e. specifying:
-			   show_inodes=system,show_inodes=win32,show_inodes=dos
-			is the same as specifying:
-			   show_inodes=all
-			Note that the "posix" and "all" options will show all
-			directory names, BUT the link count on each directory
-			inode entry is set to 1, due to Linux not supporting
-			directory hard links. This may well confuse some
-			user space applications, since the directory names will
-			have the same inode numbers. Thus it is NOT advisable
-			to use the "posix" and "all" options. We provide them
-			only for completeness sake.
-			Further, note that the "system" option will not show
-			"$MFT" due to bugs/mis-features in glibc. Even though
-			it does not show, you can specifically "ls" it:
-				ls -l \$MFT
-			And of course you can stat it, too.
-			Further, note that irrespective of what show_inodes
-			option(s) you use, all files are accessible when you
-			specify the correct name, even though they may not be
-			shown in a normal "ls", i.e. you can always access the
-			system files and both the short and long file names of
-			files and directories.
-			Finally, note that win32 and dos file names are not
-			case sensitive and can be accessed using any
-			combination of lower and upper case, while POSIX file
-			names are case sensitive and they can only be accessed
-			given the correct case.
+show_sys_files=<BOOL>	If show_sys_files is specified, show the system files
+			in directory listings. Otherwise the default behaviour
+			is to hide the system files.
+			Note that even when show_sys_files is specified, "$MFT"
+			will not be visible due to bugs/mis-features in glibc.
+			Further, note that irrespective of show_sys_files, all
+			files are accessible by name, i.e. you can always do
+			"ls -l \$UpCase" for example to specifically show the
+			system file containing the Unicode upcase table.
+
+case_sensitive=<BOOL>	If case_sensitive is specified, treat all file names as
+			case sensitive and create file names in the POSIX
+			namespace. Otherwise the default behaviour is to treat
+			file names as case insensitive and to create file names
+			in the WIN32/LONG name space. Note, the Linux NTFS
+			driver will never create short file names and will
+			remove them on rename/delete of the corresponding long
+			file name.
+			Note that files remain accessible via their short file
+			name, if it exists. If case_sensitive, you will need to
+			provide the correct case of the short file name.
 
 errors=opt		What to do when critical file system errors are found.
 			Following values can be used for "opt":
@@ -174,12 +149,22 @@
   (from 9:43 minutes on average down to 7:53). The time spent in user space
   was unchanged but the time spent in the kernel was decreased by a factor of
   2.5 (from 85 CPU seconds down to 33).
+- The driver does not support short file names in general. For backwards
+  compatibility, we implement access to files using their short file names if
+  they exist. The driver will not create short file names however, and a rename
+  will discard any existing short file name.
 
 
 Known bugs and (mis-)features
 =============================
 
-- None
+- The link count on each directory inode entry is set to 1, due to Linux not
+  supporting directory hard links. This may well confuse some user space
+  applications, since the directory names will have the same inode numbers.
+  This also speeds up ntfs_read_inode() immensely. And we haven't found any
+  problems with this approach so far. If you find a problem with this, please
+  let us know.
+
 
 Please send bug reports/comments/feedback/abuse to the Linux-NTFS development
 list at sourceforge: linux-ntfs-dev@lists.sourceforge.net
@@ -260,8 +245,20 @@
 ChangeLog
 =========
 
-Note that a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
+Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
 
+2.0.8:
+	- Remove now obsolete show_inodes and posix mount option(s).
+	- Restore show_sys_files mount option.
+	- Add new mount option case_sensitive, to determine if the driver
+	  treats file names as case sensitive or not.
+	- Mostly drop support for short file names (for backwards compatibility
+	  we only support accessing files via their short file name if one
+	  exists).
+	- Fix dcache aliasing issues wrt short/long file names.
+	- Cleanups and minor fixes.
+2.0.7:
+	- Just cleanups.
 2.0.6:
 	- Major bugfix to make compatible with other kernel changes. This fixes
 	  the hangs/oopses on umount.
diff -Nru a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
--- a/Documentation/filesystems/vfs.txt	Sat Jun  8 22:31:36 2002
+++ b/Documentation/filesystems/vfs.txt	Sat Jun  8 22:31:36 2002
@@ -178,6 +178,7 @@
 	void (*read_inode) (struct inode *);
 	void (*write_inode) (struct inode *, int);
 	void (*put_inode) (struct inode *);
+	void (*drop_inode) (struct inode *);
 	void (*delete_inode) (struct inode *);
 	int (*notify_change) (struct dentry *, struct iattr *);
 	void (*put_super) (struct super_block *);
@@ -203,6 +204,19 @@
 
   put_inode: called when the VFS inode is removed from the inode
 	cache. This method is optional
+
+  drop_inode: called when the last access to the inode is dropped,
+	with the inode_lock spinlock held.
+
+	This method should be either NULL (normal unix filesystem
+	semantics) or "generic_delete_inode" (for filesystems that do not
+	want to cache inodes - causing "delete_inode" to always be
+	called regardless of the value of i_nlink)
+
+	The "generic_delete_inode()" behaviour is equivalent to the
+	old practice of using "force_delete" in the put_inode() case,
+	but does not have the races that the "force_delete()" approach
+	had. 
 
   delete_inode: called when the VFS wants to delete an inode
 
diff -Nru a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax
--- a/Documentation/isdn/README.HiSax	Sat Jun  8 22:31:36 2002
+++ b/Documentation/isdn/README.HiSax	Sat Jun  8 22:31:36 2002
@@ -41,9 +41,10 @@
 ELSA Quickstep 3000PCI
 ELSA PCMCIA
 ITK ix1-micro Rev.2
-Eicon.Diehl Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
-Eicon.Diehl Diva 2.01 ISA and PCI
-Eicon.Diehl Diva Piccola
+Eicon Diva 2.0 ISA and PCI (S0 and U interface, no PRO version)
+Eicon Diva 2.01 ISA and PCI
+Eicon Diva 2.02 PCI
+Eicon Diva Piccola
 ASUSCOM NETWORK INC. ISDNLink 128K PC adapter (order code I-IN100-ST-D)
 Dynalink IS64PH (OEM version of ASUSCOM NETWORK INC. ISDNLink 128K adapter)
 PCBIT-DP (OEM version of ASUSCOM NETWORK INC. ISDNLink)
@@ -52,6 +53,7 @@
 Sedlbauer Speed Star/Speed Star2 (PCMCIA)
 Sedlbauer ISDN-Controller PC/104
 USR Sportster internal TA (compatible Stollmann tina-pp V3)
+USR internal TA PCI
 ith Kommunikationstechnik GmbH MIC 16 ISA card
 Traverse Technologie NETjet PCI S0 card and NETspider U card
 Ovislink ISDN sc100-p card (NETjet driver)
@@ -66,13 +68,14 @@
 HFC-PCI based cards
 Winbond W6692 based cards
 HFC-S+, HFC-SP/PCMCIA cards
+formula-n enternow
+Gerdes Power ISDN
 
 Note: PCF, PCF-Pro: up to now, only the ISDN part is supported
       PCC-8: not tested yet
       Eicon.Diehl Diva U interface not tested
 
 If you know other passive cards with the Siemens chipset, please let me know.
-To use the PNP cards you need the isapnptools.
 You can combine any card, if there is no conflict between the resources
 (io, mem, irq).
 
@@ -88,8 +91,15 @@
 modules. It is included in the normal "make [menu]config" target at the
 kernel. Don't forget it, especially to select the right D-channel protocol.
 
-Please note: All PnP cards need to be configured with isapnp and will work
-only with the HiSax driver used as a module.
+Please note: In older versions of the HiSax driver, all PnP cards
+needed to be configured with isapnp and worked only with the HiSax
+driver used as a module.
+
+In the current version, HiSax will automatically use the in-kernel
+ISAPnP support, provided you selected it during kernel configuration
+(CONFIG_ISAPNP), if you don't give the io=, irq= command line parameters.
+
+The affected card types are: 4,7,12,14,19,27-30
 
 a) when built as a module
 -------------------------
@@ -190,6 +200,8 @@
    37	HFC 2BDS0 S+, SP         irq,io 
    38	NETspider U PCI card     none
    39	HFC 2BDS0 SP/PCMCIA      irq,io (set with cardmgr)
+   40   hotplug interface
+   41   Formula-n enter:now PCI  none
 
 At the moment IRQ sharing is only possible with PCI cards. Please make sure
 that your IRQ is free and enabled for ISA use.
@@ -215,6 +227,13 @@
                    (IO 1 (BASE 0x0180))
    modprobe hisax type=4 protocol=2 irq=10 io0=0x580 io1=0x180
 
+   In the current version of HiSax, you can instead simply use
+
+   modprobe hisax type=4 protocol=2
+
+   if you configured your kernel for ISAPnP. Don't run isapnp in
+   this case!
+
 6. Teles 16.3, Euro ISDN, I/O base 280 hex, IRQ 12 and
    Teles 16.0, 1TR6, IRQ 5, Memory d0000 hex
    modprobe hisax type=3,1 protocol=2,1 io=0x280 mem=0,0xd0000
@@ -295,7 +314,9 @@
    36	W6692 based PCI cards   none
    37	HFC 2BDS0 S+,SP/PCMCIA  ONLY WORKS AS A MODULE !
    38	NETspider U PCI card    none
-
+   39	HFC 2BDS0 SP/PCMCIA     ONLY WORKS AS A MODULE !
+   40   hotplug interface	ONLY WORKS AS A MODULE !
+   41   Formula-n enter:now PCI none
 
 Running the driver
 ------------------
diff -Nru a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
--- a/Documentation/s390/CommonIO	Sat Jun  8 22:31:52 2002
+++ b/Documentation/s390/CommonIO	Sat Jun  8 22:31:52 2002
@@ -21,7 +21,8 @@
   Default is on.
 
 
-* cio_ignore = <range of device numbers>, <range of device numbers>, ...
+* cio_ignore = <device number> | <range of device numbers>, 
+	       <device number> | <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 
@@ -41,45 +42,27 @@
   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).
+  This entry shows information on a per-subchannel basis.
+
+  The data is ordered in the following way:
+
+  - device number 
+  - subchannel number 
+  - device type/model (if applicable; if not, this is empty) and control unit 
+    type/model
+  - whether the device is in use (i. e. a device driver has requested ownership 
+    and registered an interrupt handler)
+  - path installed mask (PIM), as reflected by last store subchannel
+  - path available mask (PAM), as reflected by last store subchannel
+  - path operational mask (POM), as reflected by last store subchannel
+  - the channel path IDs (CHPIDs)
+
+  All fields are separated by spaces, the chpids are in blocks of four chpids.
 
 * /proc/cio_ignore
 
@@ -137,3 +120,26 @@
 
   This entry counts how many times s390_process_IRQ has been called for each 
   CPU. This info is in /proc/interrupts on other architectures.
+
+* /proc/chpids
+
+  This entry will only show up if you specified CONFIG_CHSC=y during kernel
+  config.
+
+  This entry serves a dual purpose:
+ 
+  - show which chpids are currently known to Linux and their status (online,
+    logically offline),
+
+  - toggling known chpids logically online/offline.
+
+  To toggle a known chpid logically offline, do an
+	echo off <chpid> > /proc/chpids
+  <chpid> is interpreted as hex, even if you omit the '0x'.
+  The chpid will be treated by Linux as if it were not online, which can mean 
+  some devices will become unavailable.
+
+  You can toggle a logically offline chpid online again by
+	echo on <chpid> > /proc/chpids
+  If devices became unavailable by toggling the chpid logically offline, they 
+  will become available again after you toggle the chpid online again.
diff -Nru a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
--- a/Documentation/s390/Debugging390.txt	Sat Jun  8 22:31:36 2002
+++ b/Documentation/s390/Debugging390.txt	Sat Jun  8 22:31:36 2002
@@ -237,9 +237,10 @@
 
 
 On 390 our limitations & strengths make us slightly different.
-For backward compatibility we are only allowed use 31 bits (2GB)
-of our 32 bit addresses,however, we use entirely separate address 
-spaces for the user & kernel.
+For backward compatibility ( because of the psw address hi bit which
+indicates whether we are in 31 or 24 bit mode ) we are only allowed 
+use 31 bits (2GB) 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 on s/390, & more
 with the Extended memory managment swap device & 
@@ -1474,6 +1475,12 @@
 D 00014CB4.20
 V00014CB4  2F646576 2F636F6E 736F6C65 00001BF5
 V00014CC4  FC00014C B4001001 E0001000 B8070707
+
+Alternatively you can do the more elegant
+D 0.20;BASE2
+BASE2 telling VM to use GPR2 as the base register.
+
+
 Now copy the text till the first 00 hex ( which is the end of the string
 to an xterm & do hex2ascii on it.
 hex2ascii 2F646576 2F636F6E 736F6C65 00 
@@ -2123,6 +2130,12 @@
 now do
 p/x (*(**$sp+56))&0x7fffffff
 & so on.
+
+Another good trick to look at addresses on the stack if you've somehow lost 
+the backchain is.
+x/500xa $sp
+This displays anything the name of any known functions above the stack pointer
+for 500 bytes.
 
 Disassembling instructions without debug info
 ---------------------------------------------
diff -Nru a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
--- a/Documentation/s390/cds.txt	Sat Jun  8 22:31:36 2002
+++ b/Documentation/s390/cds.txt	Sat Jun  8 22:31:36 2002
@@ -5,12 +5,14 @@
 
 Author : Ingo Adlung
 
-Copyright, IBM Corp. 1999
+Copyright, IBM Corp. 1999-2002
+
+ChangeLog: 02/01/2002   Cornelia Huck    brought up-to-date
 
 Introduction
 
 This document describes the common device support routines for Linux/390.
-Different than other hardware architectures, ESA/390 hasdefined a unified
+Different than other hardware architectures, ESA/390 has defined a unified
 I/O access method. This gives relief to the device drivers as they don't
 have to deal with different bus types, polling versus interrupt
 processing, shared versus non-shared interrupt processing, DMA versus port
@@ -26,14 +28,11 @@
 
 In order to build common device support for ESA/390 I/O interfaces, a
 functional layer was introduced that provides generic I/O access methods to
-the hardware. The following figure shows the usage of the common device support
-of Linux/390 using a TbCP/IP driven device access an example. Similar figures
-could be drawn for other access methods, e.g. file system access to disk
-devices.
-
-The common device support layer shown above comprises the I/O support routines
-defined below. Some of them implement common Linux device driver interfaces,
-while some of them are ESA/390 platform specific.
+the hardware. 
+
+The common device support layer comprises the I/O support routines defined 
+below. Some of them implement common Linux device driver interfaces, while 
+some of them are ESA/390 platform specific.
 
 get_dev_info_by_irq() / get_dev_info_by_devno()	
    allow a device driver to determine the devices attached (visible) to the
@@ -44,10 +43,17 @@
 
 read_dev_chars()	
    read device characteristics
+   
+read_conf_data()
+   read configuration data.
 
 request_irq()	
    obtain ownership for a specific device.
 
+s390_request_irq_special()
+   obtain ownership for a specific device. Similar to request_irq(), but
+   allows for device not operational notification too.
+
 free_irq()	
    release ownership for a specific device.
 
@@ -60,6 +66,9 @@
 do_IO()	
    initiate an I/O request.
 
+resume_IO()
+   resume channel program execution.
+
 halt_IO()	
    terminate the current I/O request processed on the device.
 
@@ -70,12 +79,14 @@
    interrupt handler according to the rules (flags) defined during I/O request
    initiation with do_IO().
 
-The next chapters describe the functions, other than do_IRQ() in more details.
+The next chapters describe the functions other than do_IRQ() in more details.
 The do_IRQ() interface is not described, as it is called from the Linux/390
 first level interrupt handler only and does not comprise a device driver
 callable interface. Instead, the functional description of do_IO() also
 describes the input to the device specific interrupt handler.
 
+Note: All explanations apply also to the 64 bit architecture s390x.
+
 
 Common Device Support (CDS) for Linux/390 Device Drivers
 
@@ -90,7 +101,7 @@
 of them can be found on other Linux platforms implementations too.
 Miscellaneous function prototypes, data declarations, and macro definitions
 can be found in the architecture specific C header file
-linux/arch/s390/kernel/irq.h.
+linux/include/asm-s390/irq.h.
 
 Overview of CDS interface concepts
 
@@ -106,7 +117,7 @@
 single device is uniquely identified to the system by a so called subchannel,
 where the ESA/390 architecture allows for 64k devices be attached.
 
-Linux, however was first built on the Intel PC architecture, with its two
+Linux, however, was first built on the Intel PC architecture, with its two
 cascaded 8259 programmable interrupt controllers (PICs), that allow for a
 maximum of 15 different interrupt lines. All devices attached to such a system
 share those 15 interrupt levels. Devices attached to the ISA bus system must
@@ -117,7 +128,7 @@
 has to call every single device driver registered on this IRQ in order to
 determine the device driver owning the device that raised the interrupt.
 
-In order to not introduce a new I/O concept to the common Linux code,
+In order not to introduce a new I/O concept to the common Linux code,
 Linux/390 preserves the IRQ concept and semantically maps the ESA/390
 subchannels to Linux as IRQs. This allows Linux/390 to support up to 64k
 different IRQs, uniquely representig a single device each.
@@ -126,7 +137,7 @@
 of those devices is uniquely defined by a so called subchannel by the ESA/390
 channel subsystem. While the subchannel numbers are system generated, each
 subchannel also takes a user defined attribute, the so called device number.
-Both, subchannel number and device number can not exceed 65535. The
+Both subchannel number and device number can not exceed 65535. The
 init_IRQ() routine gathers the information about control unit type and device
 types that imply specific I/O commands (channel command words - CCWs) in
 order to operate the device. Device drivers can retrieve this set of hardware
@@ -141,7 +152,7 @@
 When a device driver has recognized a device it wants to claim ownership for,
 it calls request_irq() with the device's subchannel id serving as pseudo irq
 line. One of the required parameters it has to specify is dev_id, defining a
-device status block, the CDS layer will use to notify the device driver's
+device status block which the CDS layer will use to notify the device driver's
 interrupt handler about interrupt information observed. It depends on the
 device driver to properly handle those interrupts.
 
@@ -169,6 +180,41 @@
 
 
 
+get_irq_first() / get_irq_next() - Retrieve Information about available IRQs 
+
+A device driver can use those interface routines to retrieve information for 
+those IRQs only that have valid device information available. As 
+Linux for S/390 supports a maximum of 65535 subchannels (devices), it might 
+be a waste of CPU to scan for the max number of  devices while a fraction is 
+available/usable only. get_irq_first() will retrieve the first usable IRQ. 
+Using this as input get_irq_next() will retrieve the next IRQ available, etc..
+
+int get_irq_first( void );
+int get_irq_next( int irq );
+
+irq - defines the subchannel to start scanning with. This must be
+      a valid subchannel or an error is returned. 
+
+The get_irq_first() / get_irq_next() functions return:
+
+non-negative value - next available IRQ
+          -ENODEV  - no more IRQs available
+
+Example : 
+
+ irq = get_irq_first();
+ while ( irq != -ENODEV) 
+ {
+  get_dev_info_by_irq( irq, &dinfo);
+  if (    dinfo.devno == devno_to_look_for 
+       || dinfo.sid_data.cu_type == cu_type_to_look_for )
+  {
+   do_some_action( irq, &dinfo ); 
+  } /* endif */
+    
+  irq = get_irq_next(irq);
+ }
+
 get_dev_info_by_irq() / get_dev_info_by_devno() - Retrieve Device Information
 
 During system startup - init_IRQ() processing - the generic I/O device support
@@ -176,24 +222,26 @@
 SenseID information. For those devices supporting the command it also obtains
 extended SenseID information.
 
-int get_dev_info_by_irq( int         irq,
-                         dev_info_t *devinfo);
+int get_dev_info_by_irq( int             irq,
+                         s390_dev_info_t *pdi);
 
-int get_dev_info_by_devno( unsigned int  irq,
-                           dev_info_t   *devinfo);
+int get_dev_info_by_devno( __u16           devno,
+                           s390_dev_info_t *pdi);
 
-irq     - defines the subchannel, status information is to be
+irq     - defines the subchannel status information is to be
           returned for.
 devno   - device number.
-devinfo - pointer to a user buffer of type dev_info_t that should
+pdi     - pointer to a user buffer of type s390_dev_info_t that should
           be filled with device specific information.
 
 typedef struct {
-     unsigned int devno;     /* device number */
-     unsigned int status;    /* device status */
-     senseid_t    sid_data;  /* senseID data  */
-} dev_info_t;
+     int          irq;                  /* irq, aka. subchannel */
+     __u16        devno;                /* device number */
+     unsigned int status;               /* device status */
+     senseid_t    sid_data;             /* senseID data */
+} s390_dev_info_t;			
 
+irq       - subchannel.
 devno     - device number as configured in the IOCDS.
 status    - device status
 sid_data  - data obtained by a SenseID call
@@ -205,31 +253,33 @@
                    buffer content.
 
 //
-// SenseID response buffer layout
+// sense-id response buffer layout
 //
 typedef struct {
   /* common part */
-      unsigned char  reserved;     /* always 0x'FF' */
-      unsigned short cu_type;      /* control unit type */
-      unsigned char  cu_model;     /* control unit model */
-      unsigned short dev_type;     /* device type */
-      unsigned char  dev_model;    /* device model */
-      unsigned char  unused;       /* padding byte */
+      __u8           reserved;     /* always 0x'FF' */
+      __u16          cu_type;      /* control unit type */
+      __u8           cu_model;     /* control unit model */
+      __u16          dev_type;     /* device type */
+      __u8           dev_model;    /* device model */
+      __u8           unused;       /* padding byte */
   /* extended part */
-      ciw_t    ciw[62];            /* variable # of CIWs */
-} senseid_t;
+      ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
+}  __attribute__ ((packed,aligned(4))) senseid_t;
+
+MAX_CIWS is currently defined as 8.
 
 The ESA/390 I/O architecture defines certain device specific I/O functions.
 The device returns the device specific command code together with the SenseID
 data in so called Command Information Words (CIW) :
 
 typedef struct _ciw {
-   unsigned int et       :  2;    // entry type
-   unsigned int reserved :  2;    // reserved
-   unsigned int ct       :  4;    // command type
-   unsigned int cmd      :  8;    // command
-   unsigned int count    : 16;    // count
-} ciw_t;
+   __u32        et       :  2; // entry type
+   __u32        reserved :  2; // reserved
+   __u32        ct       :  4; // command type
+   __u32        cmd      :  8; // command
+   __u32        count    : 16; // count
+} __attribute__ ((packed)) ciw_t;
 
 Possible CIW entry types are :
 
@@ -252,7 +302,7 @@
 calling     get_dev_info() until it returns -ENODEV as there aren't any more
 available devices.
 
-If a device driver wants to request ownership for a specific device it must
+If a device driver wants to request ownership for a specific device, it must
 call request_irq() prior to be able to issue any I/O request for it, including
 above mentioned   device dependent commands.
 
@@ -269,7 +319,7 @@
 numbers configured in the IOCDS. The following routines serve the purpose to
 convert irq values into device numbers and vice versa.
 
-int get_irq_by_devno( unsigned int devno );
+int get_irq_by_devno( __u16 devno );
 
 unsigned int get_devno_by_irq( int irq );
 
@@ -336,6 +386,41 @@
 he specifies, or the buffer he wants to be allocated.
 
 
+read_conf_data() - Read Configuration Data
+
+Retrieve the device dependent configuration data. Please have a look at your 
+device dependent I/O commands for the device specific layout of the node 
+descriptor elements. 
+
+The function is meant to be called without an irq handler be in place. However,
+the irq for the requested device must not be locked or this will cause a 
+deadlock situation ! 
+
+The function may be called enabled or disabled.
+
+int read_conf_data( int irq, void **buffer, int *length, __u8 lpm);
+
+irq    - Specifies the subchannel the configuration data is to be
+         retrieved for.
+buffer - Pointer to a buffer pointer. The read_conf_data() routine
+         will allocate a buffer and initialize the buffer pointer
+         accordingly. It's the device driver's responsability to
+         release the kernel memory if no longer needed. 
+length - Length of the buffer allocated and retrieved.
+lpm    - Logical path mask to be used for retrieving the data. If
+         zero the data is retrieved on the next path available.
+
+The read_conf_data() function returns :
+          0 - Successful completion
+-ENODEV     - irq doesn't specify a valid subchannel number
+-EINVAL     - An invalid parameter was detected
+-EIO        - An irrecoverable I/O error occured or the device is
+              not operational.
+-ENOMEM     - The read_conf_data() routine couldn't obtain storage.
+-EOPNOTSUPP - The device doesn't support the read configuration 
+              data command.
+
+
 request_irq() - Request Device Ownership
 
 As previously discussed a device driver will scan for the devices its supports
@@ -343,6 +428,9 @@
 request_irq() to request ownership for it. This call causes the subchannel to
 be enabled for interrupts if it was found operational.
 
+Note: This function is obsolete and provided for compatibility purposes only. 
+Device drivers should use s390_request_irq_special() instead. 
+
 int request_irq( unsigned int   irq,
                  int          (*handler)( int,
                                           void *,
@@ -354,27 +442,28 @@
 irq      : specifies the subchannel the ownership is requested for
 handler  : specifies the device driver's interrupt handler to be
            called for interrupt processing
-irqflags : IRQ flags, must be 0 (zero) or SA_SAMPLE_RANDOM
+irqflags : IRQ flags, currently ignored
 devname  : device name
 dev_id   : required pointer to a device specific buffer of type
            devstat_t
 
 typedef struct {
-     unsigned int  devno;   /* device number from irb */
-     unsigned int  intparm; /* interrupt parameter */
-     unsigned char cstat;   /* channel status - accumulated */
-     unsigned char dstat;   /* device status - accumulated */
-     unsigned char lpum;    /* last path used mask from irb */
-     unsigned char unused;  /* not used - reserved */
-     unsigned int  flag;    /* flag : see below */
-     unsigned long cpa;     /* CCW addr from irb at prim. status */
-     unsigned int  rescnt;  /* count from irb at primary status */
-     unsigned int  scnt;    /* sense count, if available */
+     __u16         devno;    /* device number, aka. "cuu" from irb */
+     unsigned long intparm;  /* interrupt parameter */
+     __u8          cstat;    /* channel status - accumulated */
+     __u8          dstat;    /* device status - accumulated */
+     __u8          lpum;     /* last path used mask from irb */
+     __u8          unused;   /* not used - reserved */
+     unsigned int  flag;     /* flag : see below */
+     __u32         cpa;      /* CCW address from irb at primary status */
+     __u32         rescnt;   /* res. count from irb at primary status */
+     __u32         scnt;     /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
      union {
-        irb_t   irb;        /* interruption response block */
-        sense_t sense;      /* sense information */
-        } ii;               /* interrupt information */
-  } devstat_t;
+        irb_t   irb;         /* interruption response block */
+        sense_t sense;       /* sense information */
+     } ii;                /* interrupt information */
+} devstat_t;
+
 
 During request_irq() processing, the devstat_t layout does not matter as it
 won't be used during request_irq() processing. See do_IO() for a functional
@@ -396,9 +485,9 @@
 layer, and the device specific driver. The value passed to request_irq()
 must therefore point to a valid devstat_t type buffer area the device driver
 must preserve for later usage. I.e. it must not be released prior to a call
-to free_irq()
+to free_irq().
 
-The only value parameter irqflags supports is SA_SAMPLE_RANDOM if appropriate.
+Irqflags are currently ignored by the cds layer.
 The Linux/390 kernel does neither know about "fast" interrupt handlers, nor
 does it allow for interrupt sharing. Remember, the term interrupt level (irq),
 device, and subchannel are used interchangeably in Linux/390.
@@ -416,6 +505,126 @@
 therefore not rely on this parameter on function entry.
 
 
+s390_request_irq_special() - Request Device Ownership 
+
+As previously discussed a device driver will scan for the devices its supports 
+by calling get_dev_info(). Once it has found a device it will call 
+request_irq() to request ownership.
+
+Note:  This function replaces request_irq() described previously.
+
+int s390_request_irq_special( 
+                     int                      irq,
+                     io_handler_func_t        io_handler,
+                     not_oper_handler_func_t  not_oper_handler,
+                     unsigned long            irqflags,
+                     const char              *devname,
+                     void                    *dev_id);
+
+irq              : specifies the subchannel the ownership is
+                    requested for
+io_handler       : specifies the device driver's interrupt handler
+                    to be called for interrupt processing
+not_oper_handler : specifies a device driver "not operational" handler
+irqflags         : IRQ flags, currently ignored
+devname          : device name
+dev_id           : required pointer to a device specific buffer of
+                    type devstat_t
+
+
+typedef struct {
+     __u16         devno;    /* device number, aka. "cuu" from irb */
+     unsigned long intparm;  /* interrupt parameter */
+     __u8          cstat;    /* channel status - accumulated */
+     __u8          dstat;    /* device status - accumulated */
+     __u8          lpum;     /* last path used mask from irb */
+     __u8          unused;   /* not used - reserved */
+     unsigned int  flag;     /* flag : see below */
+     __u32         cpa;      /* CCW address from irb at primary status */
+     __u32         rescnt;   /* res. count from irb at primary status */
+     __u32         scnt;     /* sense count, if DEVSTAT_FLAG_SENSE_AVAIL */
+     union {
+        irb_t   irb;         /* interruption response block */
+        sense_t sense;       /* sense information */
+     } ii;                   /* interrupt information */
+} devstat_t;
+
+During request_irq() processing, the devstat_t layout does not matter as it 
+won't be used during request_irq() processing. See do_IO() for a functional 
+description of its usage.
+
+typedef  void (* io_handler_func_t) ( int             irq,
+                                      void           *devstat,
+                                      struct pt_regs *rgs);
+
+irq     : IRQ the interrupt handler is called for
+devstat : device status block
+rgs     : obsolete
+
+typedef (void)(* not_oper_handler_func_t)( int irq, 
+                                           int status );
+
+irq    : IRQ the not operational status has been encountered for
+status : device status
+         DEVSTAT_NOT_OPER    - device is not operational
+         DEVSTAT_REVALIDATE  - revalidate device number
+         DEVSTAT_DEVICE_GONE - no such device (irq)  
+
+Note: Revalidate indicates that running under VM the device number has been 
+modified by means of a DEFINE xxxx [as] yyyy command. Therewith device number 
+xxxx was altered to yyyy. It's the device drivers responsibility to decide 
+whether device ownership can be retained.
+
+Gone indicates that the device was detached under VM, or the device number 
+became invalid (native, LPAR). In order to prevent further I/O the IRQ was 
+implicitly freed on behalf of the device driver. The driver must not call 
+free_irq itself.
+
+Not Oper indicates the device became not operational. It's the device driver's 
+responsibility whether it wants to maintain ownership for the IRQ, or not. 
+
+The s390_request_irq_special() function returns :
+      0 - successful completion
+-EINVAL - an invalid parameter was detected
+-EBUSY  - device (subchannel) already owned 
+-ENODEV - the device is not-operational
+-ENOMEM - not enough kernel memory to process request
+
+Usage Notes :
+ 
+While Linux for Intel defines dev_id as a unique identifier for shared 
+interrupt lines, it has a totally different purpose on Linux for S/390. Here 
+it serves as a shared interrupt status area between the generic device support 
+layer and the device specific driver. The value passed to request_irq() must 
+therefore point to a valid devstat_t type buffer area the device driver must 
+preserve for later usage. I.e. it must not be released prior to a call to 
+free_irq().
+ 
+Currently, the value of irqflags is ignored. The Linux for S/390 kernel does 
+neither know about "fast" interrupt handlers, nor does it allow for interrupt 
+sharing. Remember, the term interrupt level (irq), device, and subchannel are 
+used interchangeably in Linux for S/390.
+ 
+Other than request_irq(), this function does allow for a not operational 
+handler to be defined. This handler is called when a device either became not 
+operational, the last path to a device became not operational, or the device 
+was detached from the system. A detach could be a "detach" under VM or that 
+the device became unassigned by the Support Element (SE) or Hardware Management 
+Console (HMC). 
+ 
+If s390_request_irq_special() was called in enabled state, or if multiple CPUs 
+are present, the device may present an interrupt to the specified handler prior 
+to request_irq() return to the caller already ! This includes the possibility 
+of unsolicited interrupts or a pending interrupt status from an earlier 
+solicited I/O request. The device driver must be able to handle this situation 
+properly or the device may become unoperational otherwise !
+
+Although the interrupt handler is defined to be called with a pointer to a 
+struct pt_regs buffer area, this is not implemented by the Linux for S/390 
+platform specific common I/O support layer. The device driver's interrupt 
+handler must therefore not rely on this parameter on function entry.
+
+
 free_irq() - Release Device Ownership
 
 A device driver may call free_irq() to release ownership of a previously
@@ -523,19 +732,19 @@
 
 int do_IO( int            irq,
            ccw1_t        *cpa,
-           unsigned long  intparm,
+           unsigned long  user_intparm,
            unsigned int   lpm,
            unsigned long  flag);
 
-irq     : irq (subchannel) the I/O request is destined for
-cpa     : logical start address of channel program
-intparm : user specific interrupt information; will be presented
-          back to the device driver's interrupt handler. Allows a
-          device driver to associate the interrupt with a
-          particular I/O request.
-lpm     : defines the channel path to be used for a specific I/O
-          request. Valid with flag value DOIO_VALID_LPM only.
-flag    : defines the action to e parformed for I/O processing
+irq          : irq (subchannel) the I/O request is destined for
+cpa          : logical start address of channel program
+user_intparm : user specific interrupt information; will be presented
+	       back to the device driver's interrupt handler. Allows a
+               device driver to associate the interrupt with a
+               particular I/O request.
+lpm          : defines the channel path to be used for a specific I/O
+               request. Valid with flag value DOIO_VALID_LPM only.
+flag         : defines the action to e parformed for I/O processing
 
 Possible flag values are :
 
@@ -543,16 +752,25 @@
 DOIO_VALID_LPM           - LPM input parameter is valid (see usage
                            notes below for details)
 DOIO_WAIT_FOR_INTERRUPT  - wait synchronously for final status
+DOIO_TIMEOUT             - perform a loop while waiting for final status
+			   and fail after a timeout
 DOIO_REPORT_ALL          - report all interrupt conditions
+DOIO_ALLOW_SUSPEND       - channel program may become suspended
+DOIO_DENY_PREFETCH       - don't allow for CCW prefetch; usually
+                           this implies the channel program might
+                           become modified 
+DOIO_CANCEL_ON_TIMEOUT   - do a cancel_IO if there is a timeout waiting
+			   for the channel program to finish (see usage
+                           notes below for details)
 
 The cpa parameter points to the first format 1 CCW of a channel program :
 
 typedef struct {
-   char            cmd_code; /* command code */
-   char            flags;    /* flags, like IDA addressing, etc. */
-   unsigned short  count;    /* byte count */
-   void           *cda;      /* data address */
-} ccw1_t __attribute__ ((aligned(8)));
+      __u8  cmd_code;/* command code */
+      __u8  flags;   /* flags, like IDA adressing, etc. */
+      __u16 count;   /* byte count */
+      __u32 cda;     /* data address */
+} __attribute__ ((packed,aligned(8))) ccw1_t;
 
 with the following CCW flags values defined :
 
@@ -605,6 +823,9 @@
                            successfully be started previously.
 DEVSTAT_FINAL_STATUS     - This is a final interrupt status for the
                            I/O requst identified by intparm.
+DEVSTAT_PCI              - A PCI was received. 
+DEVSTAT_SUSPENDED        - A "suspended" intermediate status was
+                           received.  
 
 If device status DEVSTAT_FLAG_SENSE_AVAIL is indicated in field dev_id->flag,
 field dev_id->scnt describes the numer of device specific sense bytes
@@ -612,9 +833,9 @@
 driver itself is required.
 
 typedef struct {
-   unsigned char res[32];       /* reserved   */
-   unsigned char data[32];      /* sense data */
-} sense_t;
+      __u8          res[32];   /* reserved   */
+      __u8          data[32];  /* sense data */
+   } __attribute__ ((packed)) sense_t;
 
 The device interrupt handler can use the following definitions to investigate
 the primary unit check source coded in sense byte 0 :
@@ -625,6 +846,7 @@
 SNS0_EQUIPMENT_CHECK    0x10
 SNS0_DATA_CHECK         0x08
 SNS0_OVERRUN            0x04
+SNS0_INCOMPL_DOMAIN     0x01
 
 Depending on the device status, multiple of those values may be set together.
 Please refer to the device specific documentation for details.
@@ -661,12 +883,10 @@
 
 Usage Notes :
 
-Prior to call do_IO() the device driver must
-
-assure disabled state, i.e. the I/O mask value in the PSW must be disabled.
-This can be accomplished by calling __save_flags( flags). The current PSW
-flags are preserved and can be restored by __restore_flags( flags) at a
-later time.
+Prior to call do_IO() the device driver must assure disabled state, i.e. the 
+I/O mask value in the PSW must be disabled. This can be accomplished by calling 
+__save_flags( flags). The current PSW flags are preserved and can be restored 
+by __restore_flags( flags) at a later time.
 
 If the device driver violates this rule while running in a uni-processor
 environment an interrupt might be presented prior to the do_IO() routine
@@ -674,7 +894,7 @@
 deadlock situation as the interrupt handler will try to obtain the irq
 lock the device driver still owns (see below) !
 
-the driver must assure to hold the device specific lock. This can be
+The driver must assure to hold the device specific lock. This can be
 accomplished by
 
 (i)  s390irq_spin_lock( irq), or
@@ -705,6 +925,10 @@
 is therewith primarily meant to be used during device driver initialization
 for ease of device setup.
 
+If the device driver is using the DOIO_TIMEOUT parameter, it is a good idea
+also to specify DOIO_CANCEL_ON_TIMEOUT. Otherwise, the failing channel program
+may prevent the execution of any other channel program at the subchannel.
+
 The lpm input parameter might be used for multipath devices shared among
 multiple systems as the Linux/390 CDS isn't grouping channel paths. Therefore
 its use might be required if multiple access paths to a device are available
@@ -757,6 +981,34 @@
 and dev_id->dstat that represent the accumulated subchannel and device status
 information gathered since do_IO() request initiation.
 
+Channel programs that intend to set the suspend flag on a channel command word 
+(CCW)  must start the I/O operation with the DOIO_ALLOW_SUSPEND option or the 
+suspend flag will cause a channel program check. At the time the channel program 
+becomes suspended an intermediate interrupt will be generated by the channel 
+subsystem.
+
+resume_IO() - Resume Channel Program Execution 
+
+If a device driver chooses to suspend the current channel program execution by 
+setting the CCW suspend flag on a particular CCW, the channel program execution 
+is suspended. In order to resume channel program execution the CIO layer 
+provides the resume_IO() routine. 
+
+int resume_IO( int irq);
+
+irq     : irq (subchannel) the halt operation is requested for
+
+The resume_IO() function returns:
+
+        0  - suspended channel program is resumed
+-EBUSY     - status pending
+-ENODEV    - invalid or not-operational subchannel 
+-EINVAL    - resume function not applicable  
+-ENOTCONN  - there is no I/O request pending for completion 
+
+Usage Notes:
+Please have a look at the do_IO()  usage notes for more details on suspended 
+channel programs.
 
 halt_IO() - Halt I/O Request Processing
 
@@ -765,9 +1017,9 @@
 a halt subchannel (HSCH) I/O command. For those purposes the halt_IO() command
 is provided.
 
-int halt_IO( int          irq,     /* subchannel number */
-             int          intparm, /* dummy intparm */
-             unsigned int flag);   /* operation mode */
+int halt_IO( int           irq,     /* subchannel number */
+             unsigned long intparm, /* dummy intparm */
+             unsigned long flag);   /* operation mode */
 
 irq     : irq (subchannel) the halt operation is requested for
 intparm : interruption parameter; value is only used if no I/O
@@ -867,7 +1119,7 @@
 reset_cons_dev - Reset Console Device
 
 This routine allows for resetting the console device specification. See
-set_cons_dev() for details.
+wait_cons_dev() for details.
 
 int reset_cons_dev( int irq);
 
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Sat Jun  8 22:31:35 2002
+++ b/MAINTAINERS	Sat Jun  8 22:31:35 2002
@@ -1388,6 +1388,14 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+SCHEDULER
+P:	Ingo Molnar
+M:	mingo@elte.hu
+P:	Robert Love
+M:	rml@tech9.net
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 SCSI CDROM DRIVER
 P:	Jens Axboe
 M:	axboe@suse.de
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sat Jun  8 22:31:36 2002
+++ b/Makefile	Sat Jun  8 22:31:36 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 20
+SUBLEVEL = 21
 EXTRAVERSION =
 
 # We are using a recursive build, so we need to do a little thinking
@@ -37,6 +37,56 @@
 
 CROSS_COMPILE 	=
 
+# 	That's our default target when none is given on the command line
+
+all:	vmlinux
+
+#	Print entire command lines instead of short version
+#	For now, leave the default
+
+ifndef KBUILD_VERBOSE
+  KBUILD_VERBOSE = 1
+endif
+
+# 	Decide whether to build built-in, modular, or both
+
+KBUILD_MODULES := 1
+KBUILD_BUILTIN := 1
+
+export KBUILD_MODULES KBUILD_BUILTIN
+
+# Beautify output
+# ---------------------------------------------------------------------------
+#
+# Normally, we echo the whole command before executing it. By making
+# that echo $($(quiet)$(cmd)), we now have the possibility to set
+# $(quiet) to choose other forms of output instead, e.g.
+#
+#         quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@
+#         cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
+#
+# If $(quiet) is empty, the whole command will be printed.
+# If it is set to "quiet_", only the short version will be printed. 
+# If it is set to "silent_", nothing wil be printed at all, since
+# the variable $(silent_cmd_cc_o_c) doesn't exist.
+
+#	If the user wants quiet mode, echo short versions of the commands 
+#	only and suppress the 'Entering/Leaving directory' messages
+
+ifneq ($(KBUILD_VERBOSE),1)
+  quiet=quiet_
+  MAKEFLAGS += --no-print-directory
+endif
+
+#	If the user is running make -s (silent mode), suppress echoing of
+#	commands
+
+ifneq ($(findstring s,$(MAKEFLAGS)),)
+  quiet=silent_
+endif
+
+export quiet
+
 #
 # Include the make variables (CC, etc...)
 #
@@ -56,33 +106,46 @@
 PERL		= perl
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
-AFLAGS_MODULE   =
+AFLAGS_MODULE   = $(MODFLAGS)
 CFLAGS_KERNEL	=
 AFLAGS_KERNEL	=
 EXPORT_FLAGS    =
+NOSTDINC_FLAGS  = -nostdinc -iwithprefix include
 
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
 	CONFIG_SHELL TOPDIR HPATH HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
 	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE MAKEFILES GENKSYMS PERL
 
-export CPPFLAGS EXPORT_FLAGS
+export CPPFLAGS EXPORT_FLAGS NOSTDINC_FLAGS
 export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
 export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE
 
-all:	do-it-all
+noconfig_targets := xconfig menuconfig config oldconfig randconfig \
+		    defconfig allyesconfig allnoconfig allmodconfig \
+		    clean mrproper distclean
 
-#
-# Make "config" the default target if there is no configuration file or
-# "depend" the target if there is no top-level dependency information.
-#
+ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
 
-ifeq (.config,$(wildcard .config))
-include .config
-do-it-all:	vmlinux
-else
-CONFIGURATION = config
-do-it-all:	config
-endif
+# Here goes the main Makefile
+# ===========================================================================
+#
+# If the user gave a *config target, it'll be handled in another
+# section below, since in this case we cannot include .config
+# Same goes for other targets like clean/mrproper etc, which
+# don't need .config, either
+
+#	In this section, we need .config
+
+-include .config
+
+#	If .config doesn't exist - tough luck
+
+.config:
+	@echo '***'
+	@echo '*** You have not yet configured your kernel!'
+	@echo '*** Please run "make xconfig/menuconfig/config/oldconfig"'
+	@echo '***'
+	@exit 1
 
 #
 # INSTALL_PATH specifies where to place the updated kernel and system map
@@ -114,18 +177,14 @@
 EXPORT_FLAGS := -DEXPORT_SYMTAB
 endif
 
-INIT		=init/init.o
-CORE_FILES	=kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
-NETWORKS	=net/network.o
-
-LIBS		=$(TOPDIR)/lib/lib.a
-SUBDIRS		=init kernel lib drivers mm fs net ipc sound
-
-DRIVERS-y 	= drivers/built-in.o
-DRIVERS-$(CONFIG_SOUND) += sound/sound.o
-
-DRIVERS := $(DRIVERS-y)
-
+# Link components for vmlinux
+# ---------------------------------------------------------------------------
+SUBDIRS		:= init kernel mm fs ipc lib drivers sound net
+INIT		:= init/init.o
+CORE_FILES	:= kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
+LIBS		:= lib/lib.a
+DRIVERS		:= drivers/built-in.o sound/sound.o
+NETWORKS	:= net/network.o
 
 include arch/$(ARCH)/Makefile
 
@@ -149,6 +208,7 @@
 
 vmlinux-objs := $(HEAD) $(INIT) $(CORE_FILES) $(LIBS) $(DRIVERS) $(NETWORKS)
 
+quiet_cmd_link_vmlinux = LD     $@
 cmd_link_vmlinux = $(LD) $(LINKFLAGS) $(HEAD) $(INIT) \
 		--start-group \
 		$(CORE_FILES) \
@@ -166,13 +226,13 @@
 	. scripts/mkversion > .tmpversion
 	mv -f .tmpversion .version
 	$(MAKE) -C init
-	echo $(cmd_link_vmlinux)
+	$(call cmd,cmd_link_vmlinux)
 	$(cmd_link_vmlinux)
 	echo 'cmd_$@ := $(cmd_link_vmlinux)' > $(@D)/.$(@F).cmd
 	$(NM) vmlinux | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
 endef
 
-vmlinux: $(CONFIGURATION) $(vmlinux-objs) FORCE
+vmlinux: $(vmlinux-objs) FORCE
 	$(call if_changed_rule,link_vmlinux)
 
 #	The actual objects are generated when descending, 
@@ -183,15 +243,14 @@
 # 	Handle descending into subdirectories listed in $(SUBDIRS)
 
 .PHONY: $(SUBDIRS)
-$(SUBDIRS): prepare
+$(SUBDIRS): .hdepend prepare include/config/MARKER
 	@$(MAKE) -C $@
 
-#	Things we need done before we even start the actual build.
-#	The dependency on .hdepend will in turn take care of
-#	include/asm, include/linux/version etc.
+#	Things we need done before we descend to build or make
+#	module versions are listed in "prepare"
 
 .PHONY: prepare
-prepare: .hdepend include/config/MARKER
+prepare: include/linux/version.h include/asm
 
 # Single targets
 # ---------------------------------------------------------------------------
@@ -202,6 +261,8 @@
 	@$(MAKE) -C $(@D) $(@F)
 %.o: %.c FORCE
 	@$(MAKE) -C $(@D) $(@F)
+%.lst: %.c FORCE
+	@$(MAKE) -C $(@D) $(@F)
 %.s: %.S FORCE
 	@$(MAKE) -C $(@D) $(@F)
 %.o: %.S FORCE
@@ -214,14 +275,23 @@
 include/asm:
 	@echo 'Making asm->asm-$(ARCH) symlink'
 	@ln -s asm-$(ARCH) $@
-	@echo 'Making directory include/linux/modules'
-	@mkdir include/linux/modules
 
 # 	Split autoconf.h into include/linux/config/*
 
 include/config/MARKER: scripts/split-include include/linux/autoconf.h
-	scripts/split-include include/linux/autoconf.h include/config
-	@ touch include/config/MARKER
+	@echo 'Splitting include/linux/autoconf.h -> include/config'
+	@scripts/split-include include/linux/autoconf.h include/config
+	@touch $@
+
+# 	if .config is newer than include/linux/autoconf.h, someone tinkered
+# 	with it and forgot to run make oldconfig
+
+include/linux/autoconf.h: .config
+	@echo '***'
+	@echo '*** You changed .config w/o running make *config?'
+	@echo '*** Please run "make oldconfig"'
+	@echo '***'
+	@exit 1
 
 # Generate some files
 # ---------------------------------------------------------------------------
@@ -229,64 +299,77 @@
 #	version.h changes when $(KERNELRELEASE) etc change, as defined in
 #	this Makefile
 
+uts_len := 64
+
 include/linux/version.h: Makefile
-	@echo Generating $@
-	@. scripts/mkversion_h $@ $(KERNELRELEASE) $(VERSION) $(PATCHLEVEL) $(SUBLEVEL)
+	@if expr length "$(KERNELRELEASE)" \> $(uts_len) >/dev/null ; then \
+	  echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \
+	  exit 1; \
+	fi;
+	@echo -n 'Generating $@'
+	@(echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \
+	  echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)`; \
+	 echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'; \
+	) > $@.tmp
+	@$(update-if-changed)
 
 # Helpers built in scripts/
 # ---------------------------------------------------------------------------
 
-scripts/mkdep scripts/split-include : FORCE
+scripts/fixdep scripts/split-include : scripts ;
+
+.PHONY: scripts
+scripts:
 	@$(MAKE) -C scripts
 
-# Generate dependencies
+# Generate module versions
 # ---------------------------------------------------------------------------
 
-# 	In the same pass, generate module versions, that's why it's
-#	all mixed up here.
+# 	The targets are still named depend / dep for traditional
+#	reasons, but the only thing we do here is generating
+#	the module version checksums.
+#	FIXME: For now, we are also calling "archdep" from here,
+#	which should be replaced by a more sensible solution.
 
 .PHONY: depend dep $(patsubst %,_sfdep_%,$(SUBDIRS))
 
 depend dep: .hdepend
 
-#	.hdepend is missing prerequisites - in fact dependencies need
-#	to be redone basically each time anything changed - since
-#	that's too expensive, we traditionally rely on the user to
-#	run "make dep" manually whenever necessary. In this case,
-#	we make "FORCE" a prequisite, to force redoing the
-#	dependencies. Yeah, that's ugly, and it'll go away soon.
-
-.hdepend: scripts/mkdep include/linux/version.h include/asm \
-	  $(if $(filter dep depend,$(MAKECMDGOALS)),FORCE)
-	scripts/mkdep -- `find $(FINDHPATH) -name SCCS -prune -o -follow -name \*.h ! -name modversions.h -print` > $@
-	@$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS))
+#	.hdepend is our (misnomed) marker for whether we've run
+#	generated module versions and made archdep
+
+.hdepend: $(if $(filter dep depend,$(MAKECMDGOALS)),FORCE)
+	@$(MAKE) archdep include/linux/modversions.h
+	@touch $@
+
 ifdef CONFIG_MODVERSIONS
-	@$(MAKE) include/linux/modversions.h
-endif
-	@$(MAKE) archdep
+
+# 	Update modversions.h, but only if it would change.
+
+include/linux/modversions.h: scripts/fixdep prepare FORCE
+	@rm -rf .tmp_export-objs
+	@$(MAKE) $(patsubst %,_sfdep_%,$(SUBDIRS))
+	@echo -n 'Generating $@'
+	@( echo "#ifndef _LINUX_MODVERSIONS_H";\
+	   echo "#define _LINUX_MODVERSIONS_H"; \
+	   echo "#include <linux/modsetver.h>"; \
+	   for f in `cd .tmp_export-objs; find modules -name \*.ver -print`; do \
+	     echo "#include <linux/$${f}>"; \
+	   done; \
+	   echo "#endif"; \
+	) > $@.tmp; \
+	$(update-if-changed)
 
 $(patsubst %,_sfdep_%,$(SUBDIRS)): FORCE
 	@$(MAKE) -C $(patsubst _sfdep_%, %, $@) fastdep
 
-# 	Update modversions.h, but only if it would change.
+else # !CONFIG_MODVERSIONS
 
-include/linux/modversions.h: FORCE
-	@(echo "#ifndef _LINUX_MODVERSIONS_H";\
-	  echo "#define _LINUX_MODVERSIONS_H"; \
-	  echo "#include <linux/modsetver.h>"; \
-	  cd $(TOPDIR)/include/linux/modules; \
-	  for f in *.ver; do \
-	    if [ -f $$f ]; then echo "#include <linux/modules/$${f}>"; fi; \
-	  done; \
-	  echo "#endif"; \
-	) > $@.tmp
-	@if [ -r $@ ] && cmp -s $@ $@.tmp; then \
-		echo $@ was not updated; \
-		rm -f $@.tmp; \
-	else \
-		echo $@ was updated; \
-		mv -f $@.tmp $@; \
-	fi
+.PHONY: include/linux/modversions.h
+
+include/linux/modversions.h:
+
+endif # CONFIG_MODVERSIONS
 
 # ---------------------------------------------------------------------------
 # Modules
@@ -300,11 +383,8 @@
 endif
 
 .PHONY: modules
-modules: $(patsubst %, _mod_%, $(SUBDIRS))
-
-.PHONY: $(patsubst %, _mod_%, $(SUBDIRS))
-$(patsubst %, _mod_%, $(SUBDIRS)) : include/linux/version.h include/config/MARKER
-	@$(MAKE) -C $(patsubst _mod_%, %, $@) modules
+modules:
+	@$(MAKE) KBUILD_BUILTIN= $(SUBDIRS)
 
 #	Install modules
 
@@ -369,7 +449,7 @@
 TAGS: FORCE
 	{ find include/asm-${ARCH} -name '*.h' -print ; \
 	find include -type d \( -name "asm-*" -o -name config \) -prune -o -name '*.h' -print ; \
-	find $(SUBDIRS) init -name '*.[ch]' ; } | grep -v SCCS | etags -
+	find $(SUBDIRS) init arch/${ARCH} -name '*.[chS]' ; } | grep -v SCCS | etags -
 
 # 	Exuberant ctags works better with -I
 tags: FORCE
@@ -412,28 +492,82 @@
 	rpm -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
 	rm $(TOPDIR)/../$(KERNELPATH).tar.gz
 
+else # ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
+
 # Targets which don't need .config
 # ===========================================================================
+#
+# These targets basically have their own Makefile - not quite, but at
+# least its own exclusive section in the same Makefile. The reason for
+# this is the following:
+# To know the configuration, the main Makefile has to include
+# .config. That's a obviously a problem when .config doesn't exist
+# yet, but that could be kludged around with only including it if it
+# exists.
+# However, the larger problem is: If you run make *config, make will
+# include the old .config, then execute your *config. It will then
+# notice that a piece it included (.config) did change and restart from
+# scratch. Which will cause execution of *config again. You get the
+# picture.
+# If we don't explicitly let the Makefile know that .config is changed
+# by *config (the old way), it won't reread .config after *config,
+# thus working with possibly stale values - we don't that either.
+#
+# So we divide things: This part here is for making *config targets,
+# and other targets which should work when no .config exists yet.
+# The main part above takes care of the rest after a .config exists.
 
 # Kernel configuration
 # ---------------------------------------------------------------------------
 
-.PHONY: oldconfig xconfig menuconfig config
-
-oldconfig:
-	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+.PHONY: oldconfig xconfig menuconfig config \
+	make_with_config
 
 xconfig:
 	@$(MAKE) -C scripts kconfig.tk
 	wish -f scripts/kconfig.tk
 
 menuconfig:
-	@$(MAKE) -C scripts/lxdialog all
+	@$(MAKE) -C scripts lxdialog
 	$(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
 
 config:
 	$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
 
+oldconfig:
+	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+
+randconfig:
+	$(CONFIG_SHELL) scripts/Configure -r arch/$(ARCH)/config.in
+
+allyesconfig:
+	$(CONFIG_SHELL) scripts/Configure -y arch/$(ARCH)/config.in
+
+allnoconfig:
+	$(CONFIG_SHELL) scripts/Configure -n arch/$(ARCH)/config.in
+
+allmodconfig:
+	$(CONFIG_SHELL) scripts/Configure -m arch/$(ARCH)/config.in
+
+defconfig:
+	yes '' | $(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
+
+#	How we generate .config depends on which *config the
+#	user chose when calling make
+
+.config: $(filter oldconfig xconfig menuconfig config,$(MAKECMDGOALS)) ;
+
+#	If the user gave commands from both the need / need not
+#	.config sections, we need to call make again after
+#	.config is generated, now to take care of the remaining
+#	targets we know nothing about in this section
+
+remaining_targets := $(filter-out $(noconfig_targets),$(MAKECMDGOALS))
+
+$(remaining_targets) : make_with_config
+
+make_with_config: .config
+	@$(MAKE) $(remaining_targets)
 
 # Cleaning up
 # ---------------------------------------------------------------------------
@@ -461,10 +595,6 @@
 	net/khttpd/times.h \
 	submenu*
 
-# 	directories removed with 'make clean'
-CLEAN_DIRS += \
-	modules
-
 # 	files removed with 'make mrproper'
 MRPROPER_FILES += \
 	include/linux/autoconf.h include/linux/version.h \
@@ -483,34 +613,43 @@
 	scripts/lxdialog/*.o scripts/lxdialog/lxdialog \
 	.menuconfig.log \
 	include/asm \
-	.hdepend scripts/mkdep scripts/split-include scripts/docproc \
-	$(TOPDIR)/include/linux/modversions.h \
-	kernel.spec
+	.hdepend scripts/split-include scripts/docproc \
+	scripts/fixdep $(TOPDIR)/include/linux/modversions.h \
+	tags TAGS kernel.spec \
 
 # 	directories removed with 'make mrproper'
 MRPROPER_DIRS += \
 	include/config \
 	$(TOPDIR)/include/linux/modules
 
+#	That's our way to know about arch specific cleanup.
+
+include arch/$(ARCH)/Makefile
 
 clean:	archclean
-	find . \( -name '*.[oas]' -o -name core -o -name '.*.cmd' \) -type f -print \
+	@echo 'Cleaning up'
+	@find . \( -name \*.[oas] -o -name core -o -name .\*.cmd -o \
+		   -name .\*.tmp -o -name .\*.d \) -type f -print \
 		| grep -v lxdialog/ | xargs rm -f
-	rm -f $(CLEAN_FILES)
-	rm -rf $(CLEAN_DIRS)
+	@rm -rf $(CLEAN_FILES)
 	@$(MAKE) -C Documentation/DocBook clean
 
 mrproper: clean archmrproper
-	find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
-	rm -f $(MRPROPER_FILES)
-	rm -rf $(MRPROPER_DIRS)
+	@echo 'Making mrproper'
+	@find . \( -size 0 -o -name .depend \) -type f -print | xargs rm -f
+	@rm -f $(MRPROPER_FILES)
+	@rm -rf $(MRPROPER_DIRS)
 	@$(MAKE) -C Documentation/DocBook mrproper
 
 distclean: mrproper
-	rm -f core `find . \( -not -type d \) -and \
-		\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+	@echo 'Making distclean'
+	@find . \( -not -type d \) -and \
+	 	\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
 		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-		-o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f -print` TAGS tags
+	 	-o -name '.*.rej' -o -name '.SUMS' -o -size 0 \) -type f \
+		-print | xargs rm -f
+
+endif # ifeq ($(filter $(noconfig_targets),$(MAKECMDGOALS)),)
 
 # FIXME Should go into a make.lib or something 
 # ===========================================================================
@@ -530,5 +669,20 @@
 		               $(filter-out $(cmd_$(1)),$(cmd_$(@F)))\
 			       $(filter-out $(cmd_$(@F)),$(cmd_$(1)))),\
 	               @$(rule_$(1)))
+
+# If quiet is set, only print short version of rule
+
+cmd = @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1))
+
+define update-if-changed
+	if [ -r $@ ] && cmp -s $@ $@.tmp; then \
+		echo ' (unchanged)'; \
+		rm -f $@.tmp; \
+	else \
+		echo ' (updated)'; \
+		mv -f $@.tmp $@; \
+	fi
+endef
+
 
 FORCE:
diff -Nru a/Rules.make b/Rules.make
--- a/Rules.make	Sat Jun  8 22:31:37 2002
+++ b/Rules.make	Sat Jun  8 22:31:37 2002
@@ -52,9 +52,8 @@
 # add it to $(subdir-m)
 
 both-m          := $(filter $(mod-subdirs), $(subdir-y))
-SUB_DIRS	:= $(subdir-y) $(if $(BUILD_MODULES),$(subdir-m))
-MOD_SUB_DIRS	:= $(sort $(subdir-m) $(both-m))
-ALL_SUB_DIRS	:= $(sort $(subdir-y) $(subdir-m) $(subdir-n) $(subdir-))
+subdir-ym	:= $(sort $(subdir-y) $(subdir-m))
+subdir-ymn	:= $(sort $(subdir-ym) $(subdir-n) $(subdir-))
 
 # export.o is never a composite object, since $(export-objs) has a
 # fixed meaning (== objects which EXPORT_SYMBOL())
@@ -86,51 +85,67 @@
 real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m))) $(EXTRA_TARGETS)
 real-objs-m := $(foreach m, $(obj-m), $(if $($(m:.o=-objs)),$($(m:.o=-objs)),$(m)))
 
-# ==========================================================================
-#
 # Get things started.
-#
-first_rule: vmlinux $(if $(BUILD_MODULES),$(obj-m))
+# ==========================================================================
 
-#
-# Common rules
-#
+ifndef O_TARGET
+ifndef L_TARGET
+O_TARGET := built-in.o
+endif
+endif
+
+#	The echo suppresses the "Nothing to be done for first_rule"
+first_rule: $(if $(KBUILD_BUILTIN),$(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS)) \
+	    $(if $(KBUILD_MODULES),$(obj-m)) \
+	    sub_dirs
+	@echo -n
 
 # Compile C sources (.c)
 # ---------------------------------------------------------------------------
 
-# FIXME: if we don't know if built-in or modular, assume built-in.
+# If we don't know if built-in or modular, assume built-in.
 # Only happens in Makefiles which override the default first_rule:
 modkern_cflags := $(CFLAGS_KERNEL)
 
-$(real-objs-y)      : modkern_cflags := $(CFLAGS_KERNEL)
-$(real-objs-y:.o=.i): modkern_cflags := $(CFLAGS_KERNEL)
-$(real-objs-y:.o=.s): modkern_cflags := $(CFLAGS_KERNEL)
-
-$(real-objs-m)      : modkern_cflags := $(CFLAGS_MODULE)
-$(real-objs-m:.o=.i): modkern_cflags := $(CFLAGS_MODULE)
-$(real-objs-m:.o=.s): modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-y)        : modkern_cflags := $(CFLAGS_KERNEL)
+$(real-objs-y:.o=.i)  : modkern_cflags := $(CFLAGS_KERNEL)
+$(real-objs-y:.o=.s)  : modkern_cflags := $(CFLAGS_KERNEL)
+$(real-objs-y:.o=.lst): modkern_cflags := $(CFLAGS_KERNEL)
+
+$(real-objs-m)        : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.i)  : modkern_cflags := $(CFLAGS_MODULE)
+$(real-objs-m:.o=.lst): modkern_cflags := $(CFLAGS_MODULE)
+
+$(export-objs)        : export_flags   := $(EXPORT_FLAGS)
+$(export-objs:.o=.i)  : export_flags   := $(EXPORT_FLAGS)
+$(export-objs:.o=.s)  : export_flags   := $(EXPORT_FLAGS)
+$(export-objs:.o=.lst): export_flags   := $(EXPORT_FLAGS)
 
-$(export-objs)      : export_flags   := $(EXPORT_FLAGS)
-$(export-objs:.o=.i): export_flags   := $(EXPORT_FLAGS)
-$(export-objs:.o=.s): export_flags   := $(EXPORT_FLAGS)
+c_flags = $(CFLAGS) $(NOSTDINC_FLAGS) $(modkern_cflags) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(export_flags) 
 
-c_flags = $(CFLAGS) $(modkern_cflags) $(EXTRA_CFLAGS) $(CFLAGS_$(*F).o) -DKBUILD_BASENAME=$(subst $(comma),_,$(subst -,_,$(*F))) $(export_flags)
-
-cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< 
+quiet_cmd_cc_s_c = CC     $(RELDIR)/$@
+cmd_cc_s_c       = $(CC) $(c_flags) -S -o $@ $< 
 
 %.s: %.c FORCE
-	$(call if_changed,cmd_cc_s_c)
+	$(call cmd,cmd_cc_s_c)
 
-cmd_cc_i_c = $(CPP) $(c_flags)   -o $@ $<
+quiet_cmd_cc_i_c = CPP    $(RELDIR)/$@
+cmd_cc_i_c       = $(CPP) $(c_flags)   -o $@ $<
 
 %.i: %.c FORCE
-	$(call if_changed,cmd_cc_i_c)
+	$(call cmd,cmd_cc_i_c)
 
-cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
+quiet_cmd_cc_o_c = CC     $(RELDIR)/$@
+cmd_cc_o_c       = $(CC) -Wp,-MD,.$(subst /,_,$@).d $(c_flags) -c -o $@ $<
 
 %.o: %.c FORCE
-	$(call if_changed,cmd_cc_o_c)
+	$(call if_changed_dep,cc_o_c)
+
+quiet_cmd_cc_lst_c = Generating $(RELDIR)/$@
+cmd_cc_lst_c     = $(CC) $(c_flags) -g -c -o $*.o $< && $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP) > $@
+
+%.lst: %.c FORCE
+	$(call cmd,cmd_cc_lst_c)
 
 # Compile assembler sources (.S)
 # ---------------------------------------------------------------------------
@@ -144,39 +159,26 @@
 $(real-objs-m)      : modkern_aflags := $(AFLAGS_MODULE)
 $(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE)
 
-a_flags = $(AFLAGS) $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
+a_flags = $(AFLAGS) $(NOSTDINC_FLAGS) $(modkern_aflags) $(EXTRA_AFLAGS) $(AFLAGS_$(*F).o)
 
-cmd_as_s_S = $(CPP) $(a_flags)   -o $@ $< 
+quiet_cmd_as_s_S = CPP    $(RELDIR)/$@
+cmd_as_s_S       = $(CPP) $(a_flags)   -o $@ $< 
 
 %.s: %.S FORCE
-	$(call if_changed,cmd_as_s_S)
+	$(call cmd,cmd_as_s_S)
 
-cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $<
+quiet_cmd_as_o_S = AS     $(RELDIR)/$@
+cmd_as_o_S       = $(CC) -Wp,-MD,.$(subst /,_,$@).d $(a_flags) -c -o $@ $<
 
 %.o: %.S FORCE
-	$(call if_changed,cmd_as_o_S)
-
-# FIXME
-
-%.lst: %.c
-	$(CC) $(c_flags) -g -c -o $*.o $<
-	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
-
+	$(call if_changed_dep,as_o_S)
 
 # If a Makefile does define neither O_TARGET nor L_TARGET,
 # use a standard O_TARGET named "built-in.o"
 
-ifndef O_TARGET
-ifndef L_TARGET
-O_TARGET := built-in.o
-endif
-endif
-
 # Build the compiled-in targets
 # ---------------------------------------------------------------------------
 
-vmlinux: $(O_TARGET) $(L_TARGET) $(EXTRA_TARGETS) sub_dirs
-
 # To build objects in subdirs, we need to descend into the directories
 $(sort $(subdir-obj-y)): sub_dirs ;
 
@@ -184,6 +186,7 @@
 # Rule to compile a set of .o files into one .o file
 #
 ifdef O_TARGET
+quiet_cmd_link_o_target = LD     $(RELDIR)/$@
 # If the list of objects to link is empty, just create an empty O_TARGET
 cmd_link_o_target = $(if $(strip $(obj-y)),\
 		      $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $(obj-y), $^),\
@@ -197,6 +200,7 @@
 # Rule to compile a set of .o files into one .a file
 #
 ifdef L_TARGET
+quiet_cmd_link_l_target = AR     $(RELDIR)/$@
 cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y)
 
 $(L_TARGET): $(obj-y) FORCE
@@ -207,7 +211,7 @@
 # Rule to link composite objects
 #
 
-
+quiet_cmd_link_multi = LD     $(RELDIR)/$@
 cmd_link_multi = $(LD) $(EXTRA_LDFLAGS) -r -o $@ $(filter $($(basename $@)-objs),$^)
 
 # We would rather have a list of rules like
@@ -220,62 +224,83 @@
 $(multi-used-m) : %.o: $(multi-objs-m) FORCE
 	$(call if_changed,cmd_link_multi)
 
-#
-# This make dependencies quickly
-#
-fastdep: FORCE
-	$(TOPDIR)/scripts/mkdep $(CFLAGS) $(EXTRA_CFLAGS) -- $(wildcard *.[chS]) > .depend
-ifdef ALL_SUB_DIRS
-	$(MAKE) $(patsubst %,_sfdep_%,$(ALL_SUB_DIRS)) _FASTDEP_ALL_SUB_DIRS="$(ALL_SUB_DIRS)"
-endif
+# Compile programs on the host
+# ===========================================================================
+
+host-progs-single     := $(foreach m,$(host-progs),$(if $($(m)-objs),,$(m)))
+host-progs-multi      := $(foreach m,$(host-progs),$(if $($(m)-objs),$(m)))
+host-progs-multi-objs := $(foreach m,$(host-progs-multi),$($(m)-objs))
+
+quiet_cmd_host_cc__c  = HOSTCC $(RELDIR)/$@
+cmd_host_cc__c        = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -o $@ $<
+
+$(host-progs-single): %: %.c FORCE
+	$(call if_changed_dep,host_cc__c)
+
+quiet_cmd_host_cc_o_c = HOSTCC $(RELDIR)/$@
+cmd_host_cc_o_c       = $(HOSTCC) -Wp,-MD,.$(subst /,_,$@).d \
+			$(HOSTCFLAGS) $(HOST_EXTRACFLAGS) -c -o $@ $<
+
+$(host-progs-multi-objs): %.o: %.c FORCE
+	$(call if_changed_dep,host_cc_o_c)
+
+quiet_cmd_host_cc__o  = HOSTLD $(RELDIR)/$@
+cmd_host_cc__o        = $(HOSTCC) $(HOSTLDFLAGS) -o $@ $($@-objs) \
+			$(HOST_LOADLIBES)
+
+$(host-progs-multi): %: $(host-progs-multi-objs) FORCE
+	$(call if_changed,cmd_host_cc__o)
+
 
-ifdef _FASTDEP_ALL_SUB_DIRS
-$(patsubst %,_sfdep_%,$(_FASTDEP_ALL_SUB_DIRS)):
+# Descending when making module versions
+# ---------------------------------------------------------------------------
+
+fastdep-list := $(addprefix _sfdep_,$(subdir-ymn))
+
+.PHONY: fastdep $(fastdep-list)
+
+fastdep: $(fastdep-list)
+
+$(fastdep-list):
 	@$(MAKE) -C $(patsubst _sfdep_%,%,$@) fastdep
-endif
 
+# Descending when building
+# ---------------------------------------------------------------------------
 
-#
-# A rule to make subdirectories
-#
-subdir-list = $(sort $(patsubst %,_subdir_%,$(SUB_DIRS)))
-sub_dirs: FORCE $(subdir-list)
+subdir-list := $(addprefix _subdir_,$(subdir-ym))
+
+.PHONY: sub_dirs $(subdir-list)
 
-ifdef SUB_DIRS
-$(subdir-list) : FORCE
+sub_dirs: $(subdir-list)
+
+$(subdir-list):
 	@$(MAKE) -C $(patsubst _subdir_%,%,$@)
-endif
 
-#
-# A rule to make modules
-#
-ifneq "$(strip $(MOD_SUB_DIRS))" ""
-.PHONY: $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
-$(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS)) : FORCE
-	@$(MAKE) -C $(patsubst _modsubdir_%,%,$@) modules
+# Descending and installing modules
+# ---------------------------------------------------------------------------
 
-.PHONY: $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
-$(patsubst %,_modinst_%,$(MOD_SUB_DIRS)) : FORCE
-	@$(MAKE) -C $(patsubst _modinst_%,%,$@) modules_install
-endif
+modinst-list := $(addprefix _modinst_,$(subdir-ym))
 
-.PHONY: modules
-modules: $(obj-m) FORCE $(patsubst %,_modsubdir_%,$(MOD_SUB_DIRS))
+.PHONY: modules_install _modinst_ $(modinst-list)
 
-.PHONY: _modinst__
-_modinst__: FORCE
-ifneq "$(strip $(obj-m))" ""
-	mkdir -p $(MODLIB)/kernel/$(RELDIR)
-	cp $(obj-m) $(MODLIB)/kernel/$(RELDIR)
+modules_install: $(modinst-list)
+ifneq ($(obj-m),)
+	@echo Installing modules in $(MODLIB)/kernel/$(RELDIR)
+	@mkdir -p $(MODLIB)/kernel/$(RELDIR)
+	@cp $(obj-m) $(MODLIB)/kernel/$(RELDIR)
+else
+	@echo -n
 endif
 
-.PHONY: modules_install
-modules_install: _modinst__ $(patsubst %,_modinst_%,$(MOD_SUB_DIRS))
-
+$(modinst-list):
+	@$(MAKE) -C $(patsubst _modinst_%,%,$@) modules_install
 
 # Add FORCE to the prequisites of a target to force it to be always rebuilt.
 # ---------------------------------------------------------------------------
+
 .PHONY: FORCE
+
 FORCE:
 
 #
@@ -289,13 +314,11 @@
 # Separate the object into "normal" objects and "exporting" objects
 # Exporting objects are: all objects that define symbol tables
 #
-ifdef CONFIG_MODULES
 
 ifdef CONFIG_MODVERSIONS
 ifneq "$(strip $(export-objs))" ""
 
-MODINCL := $(TOPDIR)/include/linux/modules
-MODPREFIX := $(subst /,-,$(RELDIR))__
+MODVERDIR := $(TOPDIR)/include/linux/modules/$(RELDIR)
 
 #
 # Added the SMP separator to stop module accidents between uniprocessor
@@ -311,47 +334,32 @@
 # We don't track dependencies for .ver files, so we FORCE to check
 # them always (i.e. always at "make dep" time).
 
+quiet_cmd_create_ver = Creating include/linux/modules/$(RELDIR)/$*.ver
 cmd_create_ver = $(CC) $(CFLAGS) $(EXTRA_CFLAGS) -E -D__GENKSYMS__ $< | \
 		 $(GENKSYMS) $(genksyms_smp_prefix) -k $(VERSION).$(PATCHLEVEL).$(SUBLEVEL) > $@.tmp
 
-$(MODINCL)/$(MODPREFIX)%.ver: %.c FORCE
-	@echo $(cmd_create_ver)
-	@$(cmd_create_ver)
+$(MODVERDIR)/%.ver: %.c FORCE
+	@mkdir -p $(dir $@)
+	@$(call cmd,cmd_create_ver)
 	@if [ -r $@ ] && cmp -s $@ $@.tmp; then \
-	  echo $@ is unchanged; rm -f $@.tmp; \
+	  rm -f $@.tmp; \
 	else \
-	  echo mv $@.tmp $@; mv -f $@.tmp $@; \
+	  touch $(TOPDIR)/include/linux/modversions.h; \
+	  mv -f $@.tmp $@; \
 	fi
 
 # updates .ver files but not modversions.h
-fastdep: $(addprefix $(MODINCL)/$(MODPREFIX),$(export-objs:.o=.ver))
-
-endif # export-objs 
+fastdep: $(addprefix $(MODVERDIR)/,$(export-objs:.o=.ver))
+ifneq ($(export-objs),)
+	@mkdir -p $(TOPDIR)/.tmp_export-objs/modules/$(RELDIR)
+	@touch $(addprefix $(TOPDIR)/.tmp_export-objs/modules/$(RELDIR)/,$(export-objs:.o=.ver))
+endif
 
-# make dep cannot correctly figure out the dependency on the generated
-# modversions.h, so we list them here:
-# o files which export symbols and are compiled into the kernel include
-#   it (to generate a correct symbol table)
-# o all modules get compiled with -include modversions.h
 
-$(filter $(export-objs),$(real-objs-y)): $(TOPDIR)/include/linux/modversions.h
-$(real-objs-m): $(TOPDIR)/include/linux/modversions.h
+endif # export-objs 
 
 endif # CONFIG_MODVERSIONS
 
-endif # CONFIG_MODULES
-
-#
-# include dependency files if they exist
-#
-ifneq ($(wildcard .depend),)
-include .depend
-endif
-
-ifneq ($(wildcard $(TOPDIR)/.hdepend),)
-include $(TOPDIR)/.hdepend
-endif
-
 # ---------------------------------------------------------------------------
 # Check if command line has changed
 
@@ -383,7 +391,7 @@
 #   which is saved in .<target>.o, to the current command line using
 #   the two filter-out commands)
 
-# read all saved command lines
+# read all saved command lines and dependencies
 
 cmd_files := $(wildcard .*.cmd)
 ifneq ($(cmd_files),)
@@ -395,4 +403,22 @@
 if_changed = $(if $(strip $? \
 		          $(filter-out $($(1)),$(cmd_$(@F)))\
 			  $(filter-out $(cmd_$(@F)),$($(1)))),\
-	       @echo '$($(1))' && $($(1)) && echo 'cmd_$@ := $($(1))' > $(@D)/.$(@F).cmd)
+	       @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1)) && echo 'cmd_$@ := $($(1))' > $(@D)/.$(@F).cmd)
+
+
+# execute the command and also postprocess generated .d dependencies
+# file
+
+if_changed_dep = $(if $(strip $? \
+		          $(filter-out $(cmd_$(1)),$(cmd_$@))\
+			  $(filter-out $(cmd_$@),$(cmd_$(1)))),\
+	@set -e; \
+	$(if $($(quiet)cmd_$(1)),echo '  $($(quiet)cmd_$(1))';) \
+	$(cmd_$(1)); \
+	$(TOPDIR)/scripts/fixdep $(subst /,_,$@) $(TOPDIR) '$(cmd_$(1))' > .$(subst /,_,$@).tmp; \
+	rm -f .$(subst /,_,$@).d; \
+	mv -f .$(subst /,_,$@).tmp .$(subst /,_,$@).cmd )
+
+# If quiet is set, only print short version of command
+
+cmd = @$(if $($(quiet)$(1)),echo '  $($(quiet)$(1))' &&) $($(1))
diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c	Sat Jun  8 22:31:35 2002
+++ b/arch/alpha/kernel/osf_sys.c	Sat Jun  8 22:31:35 2002
@@ -116,15 +116,17 @@
 	if (reclen > buf->count)
 		return -EINVAL;
 	if (buf->basep) {
-		put_user(offset, buf->basep);
+		if (put_user(offset, buf->basep))
+			return -EFAULT;
 		buf->basep = NULL;
 	}
 	dirent = buf->dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(namlen, &dirent->d_namlen);
 	put_user(reclen, &dirent->d_reclen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
+	if (copy_to_user(dirent->d_name, name, namlen) ||
+	    put_user(0, dirent->d_name + namlen))
+		return -EFAULT;
 	((char *) dirent) += reclen;
 	buf->dirent = dirent;
 	buf->count -= reclen;
@@ -629,18 +631,16 @@
 			error = args->fset.nbytes;
 		break;
 	case PL_GET:
-		get_user(min_buf_size_ptr, &args->get.min_buf_size);
-		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
-				    sizeof(*min_buf_size_ptr));
-		if (!error)
-			put_user(0, min_buf_size_ptr);
+		error = get_user(min_buf_size_ptr, &args->get.min_buf_size);
+		if (error)
+			break;
+		error = put_user(0, min_buf_size_ptr);
 		break;
 	case PL_FGET:
-		get_user(min_buf_size_ptr, &args->fget.min_buf_size);
-		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
-				    sizeof(*min_buf_size_ptr));
-		if (!error)
-			put_user(0, min_buf_size_ptr);
+		error = get_user(min_buf_size_ptr, &args->fget.min_buf_size);
+		if (error)
+			break;
+		error = put_user(0, min_buf_size_ptr);
 		break;
 	case PL_DEL:
 	case PL_FDEL:
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
--- a/arch/alpha/kernel/signal.c	Sat Jun  8 22:31:37 2002
+++ b/arch/alpha/kernel/signal.c	Sat Jun  8 22:31:37 2002
@@ -253,9 +253,8 @@
 		   struct switch_stack *sw)
 {
 	unsigned long usp;
-	long i, err = 0;
+	long i, err = __get_user(regs->pc, &sc->sc_pc);
 
-	err |= __get_user(regs->pc, &sc->sc_pc);
 	sw->r26 = (unsigned long) ret_from_sys_call;
 
 	err |= __get_user(regs->r0, sc->sc_regs+0);
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/Makefile	Sat Jun  8 22:31:37 2002
@@ -201,15 +201,30 @@
 $(patsubst %,_dir_%, $(SUBDIRS)): maketools
 $(patsubst %,_modsubdir_%,$(MOD_DIRS)): maketools
 
-symlinks: archsymlinks
+#	Update machine arch and proc symlinks if something which affects
+#	them changed.  We use .arch and .proc to indicate when they were
+#	updated last, otherwise make uses the target directory mtime.
+
+include/asm-arm/.arch: $(wildcard include/config/arch/*.h)
+	@echo 'Making asm-arm/arch -> asm-arm/arch-$(INCDIR) symlink'
+	@rm -f include/asm-arm/arch
+	@ln -sf arch-$(INCDIR) include/asm-arm/arch
+	@touch $@
+
+include/asm-arm/.proc: $(wildcard include/config/cpu/32.h) $(wildcard include/config/cpu/26.h)
+	@echo 'Making asm-arm/proc -> asm-arm/proc-$(PROCESSOR) symlink'
+	@rm -f include/asm-arm/proc
+	@ln -sf proc-$(PROCESSOR) include/asm-arm/proc
+	@touch $@
 
-archsymlinks:
-	$(RM) include/asm-arm/arch include/asm-arm/proc
-	(cd include/asm-arm; ln -sf arch-$(INCDIR) arch; ln -sf proc-$(PROCESSOR) proc)
+.hdepend: include/asm-arm/.arch include/asm-arm/.proc
 
 vmlinux: arch/arm/vmlinux.lds
 
-arch/arm/vmlinux.lds: $(LDSCRIPT) FORCE
+arch/arm/vmlinux.lds: arch/arm/Makefile $(LDSCRIPT) \
+	$(wildcard include/config/cpu/32.h) \
+	$(wildcard include/config/cpu/26.h) \
+	$(wildcard include/config/arch/*.h)
 	@sed 's/TEXTADDR/$(TEXTADDR)/;s/DATAADDR/$(DATAADDR)/' $(LDSCRIPT) >$@
 
 bzImage zImage zinstall Image bootpImage install: vmlinux
@@ -220,38 +235,25 @@
 
 MRPROPER_FILES	+= \
 	arch/arm/tools/constants.h* \
-	include/asm-arm/arch \
-	include/asm-arm/proc \
+	include/asm-arm/arch include/asm-arm/.arch \
+	include/asm-arm/proc include/asm-arm/.proc \
 	include/asm-arm/constants.h* \
 	include/asm-arm/mach-types.h
 
 # We use MRPROPER_FILES and CLEAN_FILES now
-archmrproper:
+archmrproper: FORCE
 	@/bin/true
 
-archclean:
+archclean: FORCE
 	@$(MAKEBOOT) clean
 
-archdep: scripts/mkdep archsymlinks
+archdep: FORCE
 	@$(MAKETOOLS) dep
 	@$(MAKEBOOT) dep
 
 # we need version.h
-maketools: checkbin include/linux/version.h
+maketools: include/linux/version.h FORCE
 	@$(MAKETOOLS) all
-
-# Ensure this is ld "2.9.4" or later
-NEW_LINKER	:= $(shell $(LD) --gc-sections --version >/dev/null 2>&1; echo $$?)
-
-ifneq ($(NEW_LINKER),0)
-checkbin:
-	@echo '*** ${VERSION}.${PATCHLEVEL} kernels no longer build correctly with old versions of binutils.'
-	@echo '*** Please upgrade your binutils to 2.9.5.'
-	@false
-else
-checkbin:
-	@true
-endif
 
 # My testing targets (that short circuit a few dependencies)
 zImg:;	@$(MAKEBOOT) zImage
diff -Nru a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile
--- a/arch/arm/boot/Makefile	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/boot/Makefile	Sat Jun  8 22:31:36 2002
@@ -114,12 +114,12 @@
 
 export	SYSTEM ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS
 
-Image:	$(CONFIGURE) $(SYSTEM)
+Image:	$(SYSTEM)
 	$(OBJCOPY) -O binary -R .note -R .comment -S $(SYSTEM) $@
 
 bzImage: zImage
 
-zImage:	$(CONFIGURE) compressed/vmlinux
+zImage:	compressed/vmlinux
 	$(OBJCOPY) -O binary -R .note -R .comment -S compressed/vmlinux $@
 
 bootpImage: bootp/bootp
@@ -135,10 +135,10 @@
 	@test "$(INITRD_PHYS)" != "" || (echo This architecture does not support INITRD; exit -1)
 	@test "$(INITRD)" != "" || (echo You must specify INITRD; exit -1)
 
-install: $(CONFIGURE) Image
+install: Image
 	sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-zinstall: $(CONFIGURE) zImage
+zinstall: zImage
 	sh ./install.sh $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
 clean:
diff -Nru a/arch/arm/mach-adifcc/mm.c b/arch/arm/mach-adifcc/mm.c
--- a/arch/arm/mach-adifcc/mm.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-adifcc/mm.c	Sat Jun  8 22:31:36 2002
@@ -1,7 +1,7 @@
 /*
  *  linux/arch/arm/mach-xscale/mm.c
  */
-
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 
@@ -14,11 +14,10 @@
 
 static struct map_desc adifcc_io_desc[] __initdata = {
  /* on-board devices */
- { 0xff400000,   0x00400000,   0x00300000,   DOMAIN_IO, 0, 1, 0, 0},
- LAST_DESC
+ { 0xff400000,   0x00400000,   0x00300000,   MT_DEVICE }
 };
 
 void __init adifcc_map_io(void)
 {
-	iotable_init(adifcc_io_desc);
+	iotable_init(adifcc_io_desc, ARRAY_SIZE(adifcc_io_desc));
 }
diff -Nru a/arch/arm/mach-anakin/mm.c b/arch/arm/mach-anakin/mm.c
--- a/arch/arm/mach-anakin/mm.c	Sat Jun  8 22:31:52 2002
+++ b/arch/arm/mach-anakin/mm.c	Sat Jun  8 22:31:52 2002
@@ -10,8 +10,7 @@
  *  Changelog:
  *   09-Apr-2001 W/TTC	Created
  */
-
-#include <linux/mm.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/io.h>
@@ -19,14 +18,13 @@
 #include <asm/mach/map.h>
 
 static struct map_desc anakin_io_desc[] __initdata = {
-	{ IO_BASE,    IO_START,    IO_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
-	{ FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-	{ VGA_BASE,   VGA_START,   VGA_SIZE,   DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+	{ IO_BASE,    IO_START,    IO_SIZE,    MT_DEVICE },
+	{ FLASH_BASE, FLASH_START, FLASH_SIZE, MT_DEVICE },
+	{ VGA_BASE,   VGA_START,   VGA_SIZE,   MT_DEVICE }
 };
 
 void __init
 anakin_map_io(void)
 {
-	iotable_init(anakin_io_desc);
+	iotable_init(anakin_io_desc, ARRAY_SIZE(anakin_io_desc));
 }
diff -Nru a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
--- a/arch/arm/mach-clps711x/autcpu12.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-clps711x/autcpu12.c	Sat Jun  8 22:31:36 2002
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -48,18 +49,16 @@
 */
 
 static struct map_desc autcpu12_io_desc[] __initdata = {
- /* virtual, physical, length, domain, r, w, c, b */
+ /* virtual, physical, length, type */
  /* memory-mapped extra io and CS8900A Ethernet chip */
  /* ethernet chip */
- 	{ AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 },
-	
- 	LAST_DESC
+ 	{ AUTCPU12_VIRT_CS8900A, AUTCPU12_PHYS_CS8900A, SZ_1M, MT_DEVICE }
 };
 
 void __init autcpu12_map_io(void)
 {
         clps711x_map_io();
-        iotable_init(autcpu12_io_desc);
+        iotable_init(autcpu12_io_desc, ARRAY_SIZE(autcpu12_io_desc));
 }
 
 MACHINE_START(AUTCPU12, "autronix autcpu12")
diff -Nru a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c
--- a/arch/arm/mach-clps711x/cdb89712.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-clps711x/cdb89712.c	Sat Jun  8 22:31:35 2002
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -40,14 +41,13 @@
  * ethernet driver, perhaps.
  */
 static struct map_desc cdb89712_io_desc[] __initdata = {
-	{ ETHER_BASE, ETHER_START, ETHER_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+	{ ETHER_BASE, ETHER_START, ETHER_SIZE, MT_DEVICE }
 };
 
 static void __init cdb89712_map_io(void)
 {
 	clps711x_map_io();
-	iotable_init(cdb89712_io_desc);
+	iotable_init(cdb89712_io_desc, ARRAY_SIZE(cdb89712_io_desc));
 }
 
 MACHINE_START(CDB89712, "Cirrus-CDB89712")
diff -Nru a/arch/arm/mach-clps711x/edb7211-mm.c b/arch/arm/mach-clps711x/edb7211-mm.c
--- a/arch/arm/mach-clps711x/edb7211-mm.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-clps711x/edb7211-mm.c	Sat Jun  8 22:31:37 2002
@@ -19,13 +19,12 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
-#include <asm/pgtable.h>
 #include <asm/page.h>
+#include <asm/pgtable.h>
 #include <asm/sizes.h>
  
 #include <asm/mach/map.h>
@@ -52,22 +51,20 @@
  *     happens).
  */
 static struct map_desc edb7211_io_desc[] __initdata = {
- /* virtual, physical, length, domain, r, w, c, b */
+ /* virtual, physical, length, type */
 
  /* memory-mapped extra keyboard row and CS8900A Ethernet chip */
- { EP7211_VIRT_EXTKBD,  EP7211_PHYS_EXTKBD,  SZ_1M, DOMAIN_IO, 0, 1, 0, 0 }, 
- { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, SZ_1M, DOMAIN_IO, 0, 1, 0, 0 },
+ { EP7211_VIRT_EXTKBD,  EP7211_PHYS_EXTKBD,  SZ_1M, MT_DEVICE }, 
+ { EP7211_VIRT_CS8900A, EP7211_PHYS_CS8900A, SZ_1M, MT_DEVICE },
 
  /* flash banks */
- { EP7211_VIRT_FLASH1,  EP7211_PHYS_FLASH1,  SZ_8M, DOMAIN_KERNEL, 0, 1, 0, 0 },
- { EP7211_VIRT_FLASH2,  EP7211_PHYS_FLASH2,  SZ_8M, DOMAIN_KERNEL, 0, 1, 0, 0 },
-
- LAST_DESC
+ { EP7211_VIRT_FLASH1,  EP7211_PHYS_FLASH1,  SZ_8M, MT_DEVICE },
+ { EP7211_VIRT_FLASH2,  EP7211_PHYS_FLASH2,  SZ_8M, MT_DEVICE }
 };
 
 void __init edb7211_map_io(void)
 {
         clps711x_map_io();
-        iotable_init(edb7211_io_desc);
+        iotable_init(edb7211_io_desc, ARRAY_SIZE(edb7211_io_desc));
 }
 
diff -Nru a/arch/arm/mach-clps711x/mm.c b/arch/arm/mach-clps711x/mm.c
--- a/arch/arm/mach-clps711x/mm.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-clps711x/mm.c	Sat Jun  8 22:31:37 2002
@@ -19,6 +19,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -31,40 +32,14 @@
 #include <asm/mach/map.h>
 #include <asm/hardware/clps7111.h>
 
-#if 0 //def CONFIG_DISCONTIGMEM
-  
-/*
- * The assumption of maximum 4 discontiguous memory banks is present
- * in several places in the ARM kernel, including the parameter block
- * (this affects boot loaders, too).  Banks do not necessarily
- * correspond 1:1 with NUMA nodes, although they usually will,
- * especially if they are widely discontiguous.
- *
- *  - note that the parameter block is depreciated for new implementations
- *  - also note that discontig_node_data is actually used
- *    -- rmk 
- */
-
-static bootmem_data_t node_bootmem_data[4];
-
-pg_data_t clps711x_node_data[4] = {
-        { bdata: &node_bootmem_data[0] },
-        { bdata: &node_bootmem_data[1] },
-        { bdata: &node_bootmem_data[2] },
-        { bdata: &node_bootmem_data[3] },
-};
-
-#endif
-
 /*
  * This maps the generic CLPS711x registers
  */
 static struct map_desc clps711x_io_desc[] __initdata = {
- { CLPS7111_VIRT_BASE,	CLPS7111_PHYS_BASE,	1048576, DOMAIN_IO, 0, 1 },
- LAST_DESC
+ { CLPS7111_VIRT_BASE,	CLPS7111_PHYS_BASE,	1048576, MT_DEVICE }
 };
 
 void __init clps711x_map_io(void)
 {
-	iotable_init(clps711x_io_desc);
+	iotable_init(clps711x_io_desc, ARRAY_SIZE(clps711x_io_desc));
 }
diff -Nru a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
--- a/arch/arm/mach-clps711x/p720t.c	Sat Jun  8 22:31:43 2002
+++ b/arch/arm/mach-clps711x/p720t.c	Sat Jun  8 22:31:43 2002
@@ -18,6 +18,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -43,9 +44,8 @@
  * We map both here.
  */
 static struct map_desc p720t_io_desc[] __initdata = {
-	{ SYSPLD_VIRT_BASE,	SYSPLD_PHYS_BASE, 1048576, DOMAIN_IO, 0, 1 },
-	{ 0xfe400000,		0x10400000,	  1048576, DOMAIN_IO, 0, 1 },
-	LAST_DESC
+	{ SYSPLD_VIRT_BASE,	SYSPLD_PHYS_BASE, 1048576, MT_DEVICE },
+	{ 0xfe400000,		0x10400000,	  1048576, MT_DEVICE }
 };
 
 static void __init
@@ -77,7 +77,7 @@
 static void __init p720t_map_io(void)
 {
 	clps711x_map_io();
-	iotable_init(p720t_io_desc);
+	iotable_init(p720t_io_desc, ARRAY_SIZE(p720t_io_desc));
 }
 
 MACHINE_START(P720T, "ARM-Prospector720T")
diff -Nru a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
--- a/arch/arm/mach-clps7500/core.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-clps7500/core.c	Sat Jun  8 22:31:35 2002
@@ -1,11 +1,12 @@
 /*
- *  linux/arch/arm/mm/mm-cl7500.c
+ *  linux/arch/arm/mach-clps7500/core.c
  *
  *  Copyright (C) 1998 Russell King
  *  Copyright (C) 1999 Nexus Electronics Ltd
  *
  * Extra MM routines for CL7500 architecture
  */
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/init.h>
 
@@ -215,16 +216,15 @@
 }
 
 static struct map_desc cl7500_io_desc[] __initdata = {
-	{ IO_BASE,	IO_START,	IO_SIZE	 , DOMAIN_IO, 0, 1 },	/* IO space	*/
-	{ ISA_BASE,	ISA_START,	ISA_SIZE , DOMAIN_IO, 0, 1 },	/* ISA space	*/
-	{ FLASH_BASE,	FLASH_START,	FLASH_SIZE, DOMAIN_IO, 0, 1 },	/* Flash	*/
-	{ LED_BASE,	LED_START,	LED_SIZE , DOMAIN_IO, 0, 1 },	/* LED		*/
-	LAST_DESC
+	{ IO_BASE,	IO_START,	IO_SIZE,    MT_DEVICE },	/* IO space	*/
+	{ ISA_BASE,	ISA_START,	ISA_SIZE,   MT_DEVICE },	/* ISA space	*/
+	{ FLASH_BASE,	FLASH_START,	FLASH_SIZE, MT_DEVICE },	/* Flash	*/
+	{ LED_BASE,	LED_START,	LED_SIZE,   MT_DEVICE } 	/* LED		*/
 };
 
 static void __init clps7500_map_io(void)
 {
-	iotable_init(cl7500_io_desc);
+	iotable_init(cl7500_io_desc, ARRAY_SIZE(cl7500_io_desc));
 }
 
 MACHINE_START(CLPS7500, "CL-PS7500")
diff -Nru a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
--- a/arch/arm/mach-ebsa110/core.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-ebsa110/core.c	Sat Jun  8 22:31:36 2002
@@ -9,6 +9,7 @@
  *
  *  Extra MM routines for the EBSA-110 architecture
  */
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 
@@ -71,22 +72,21 @@
 	/*
 	 * sparse external-decode ISAIO space
 	 */
-	{ IRQ_STAT,    TRICK4_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_STAT/IRQ_MCLR */
-	{ IRQ_MASK,    TRICK3_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* IRQ_MASK/IRQ_MSET */
-	{ SOFT_BASE,   TRICK1_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* SOFT_BASE */
-	{ PIT_BASE,    TRICK0_PHYS, PGDIR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 }, /* PIT_BASE */
+	{ IRQ_STAT,    TRICK4_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* IRQ_STAT/IRQ_MCLR */
+	{ IRQ_MASK,    TRICK3_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* IRQ_MASK/IRQ_MSET */
+	{ SOFT_BASE,   TRICK1_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* SOFT_BASE */
+	{ PIT_BASE,    TRICK0_PHYS, PGDIR_SIZE,  MT_DEVICE }, /* PIT_BASE */
 
 	/*
 	 * self-decode ISAIO space
 	 */
-	{ ISAIO_BASE,  ISAIO_PHYS,  ISAIO_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
-	{ ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+	{ ISAIO_BASE,  ISAIO_PHYS,  ISAIO_SIZE,  MT_DEVICE },
+	{ ISAMEM_BASE, ISAMEM_PHYS, ISAMEM_SIZE, MT_DEVICE }
 };
 
 static void __init ebsa110_map_io(void)
 {
-	iotable_init(ebsa110_io_desc);
+	iotable_init(ebsa110_io_desc, ARRAY_SIZE(ebsa110_io_desc));
 }
 
 MACHINE_START(EBSA110, "EBSA110")
diff -Nru a/arch/arm/mach-epxa10db/mm.c b/arch/arm/mach-epxa10db/mm.c
--- a/arch/arm/mach-epxa10db/mm.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mach-epxa10db/mm.c	Sat Jun  8 22:31:51 2002
@@ -19,14 +19,11 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
 #include <asm/sizes.h>
  
 #include <asm/mach/map.h>
@@ -34,16 +31,15 @@
 /* Page table mapping for I/O region */
  
 static struct map_desc epxa10db_io_desc[] __initdata = {
- { IO_ADDRESS(EXC_REGISTERS_BASE),   EXC_REGISTERS_BASE,   SZ_16K     , DOMAIN_IO, 0, 1}, 
-{IO_ADDRESS(EXC_PLD_BLOCK0_BASE),   EXC_PLD_BLOCK0_BASE,   SZ_16K     , DOMAIN_IO, 0, 1}, 
-{IO_ADDRESS(EXC_PLD_BLOCK1_BASE),   EXC_PLD_BLOCK1_BASE,   SZ_16K     , DOMAIN_IO, 0, 1}, 
-{IO_ADDRESS(EXC_PLD_BLOCK2_BASE),   EXC_PLD_BLOCK2_BASE,   SZ_16K     , DOMAIN_IO, 0, 1}, 
-{IO_ADDRESS(EXC_PLD_BLOCK3_BASE),   EXC_PLD_BLOCK3_BASE,   SZ_16K     , DOMAIN_IO, 0, 1}, 
-{ FLASH_VADDR(EXC_EBI_BLOCK0_BASE),   EXC_EBI_BLOCK0_BASE,   SZ_16M     , DOMAIN_IO, 0, 1},
- LAST_DESC
+ { IO_ADDRESS(EXC_REGISTERS_BASE),   EXC_REGISTERS_BASE,    SZ_16K, MT_DEVICE }, 
+ { IO_ADDRESS(EXC_PLD_BLOCK0_BASE),  EXC_PLD_BLOCK0_BASE,   SZ_16K, MT_DEVICE }, 
+ { IO_ADDRESS(EXC_PLD_BLOCK1_BASE),  EXC_PLD_BLOCK1_BASE,   SZ_16K, MT_DEVICE }, 
+ { IO_ADDRESS(EXC_PLD_BLOCK2_BASE),  EXC_PLD_BLOCK2_BASE,   SZ_16K, MT_DEVICE }, 
+ { IO_ADDRESS(EXC_PLD_BLOCK3_BASE),  EXC_PLD_BLOCK3_BASE,   SZ_16K, MT_DEVICE }, 
+ { FLASH_VADDR(EXC_EBI_BLOCK0_BASE), EXC_EBI_BLOCK0_BASE,   SZ_16M, MT_DEVICE }
 };
 
 void __init epxa10db_map_io(void)
 {
-	iotable_init(epxa10db_io_desc);
+	iotable_init(epxa10db_io_desc, ARRAY_SIZE(epxa10db_io_desc));
 }
diff -Nru a/arch/arm/mach-footbridge/mm.c b/arch/arm/mach-footbridge/mm.c
--- a/arch/arm/mach-footbridge/mm.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mach-footbridge/mm.c	Sat Jun  8 22:31:51 2002
@@ -10,6 +10,7 @@
  *  Extra MM routines for the EBSA285 architecture
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -28,9 +29,8 @@
  * it means that we have extra bullet protection on our feet.
  */
 static struct map_desc fb_common_io_desc[] __initdata = {
- { ARMCSR_BASE,	 DC21285_ARMCSR_BASE,	    ARMCSR_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
- { XBUS_BASE,    0x40000000,		    XBUS_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
- LAST_DESC
+ { ARMCSR_BASE,	 DC21285_ARMCSR_BASE,	    ARMCSR_SIZE,  MT_DEVICE },
+ { XBUS_BASE,    0x40000000,		    XBUS_SIZE,    MT_DEVICE }
 };
 
 /*
@@ -39,13 +39,12 @@
  */
 static struct map_desc ebsa285_host_io_desc[] __initdata = {
 #if defined(CONFIG_ARCH_FOOTBRIDGE) && defined(CONFIG_FOOTBRIDGE_HOST)
- { PCIMEM_BASE,  DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
- { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCIIACK_BASE, DC21285_PCI_IACK,	    PCIIACK_SIZE, DOMAIN_IO, 0, 1, 0, 0 },
- { PCIO_BASE,    DC21285_PCI_IO,	    PCIO_SIZE,	  DOMAIN_IO, 0, 1, 0, 0 },
+ { PCIMEM_BASE,  DC21285_PCI_MEM,	    PCIMEM_SIZE,  MT_DEVICE },
+ { PCICFG0_BASE, DC21285_PCI_TYPE_0_CONFIG, PCICFG0_SIZE, MT_DEVICE },
+ { PCICFG1_BASE, DC21285_PCI_TYPE_1_CONFIG, PCICFG1_SIZE, MT_DEVICE },
+ { PCIIACK_BASE, DC21285_PCI_IACK,	    PCIIACK_SIZE, MT_DEVICE },
+ { PCIO_BASE,    DC21285_PCI_IO,	    PCIO_SIZE,	  MT_DEVICE }
 #endif
- LAST_DESC
 };
 
 /*
@@ -53,33 +52,27 @@
  */
 static struct map_desc co285_io_desc[] __initdata = {
 #ifdef CONFIG_ARCH_CO285
- { PCIO_BASE,	 DC21285_PCI_IO,	    PCIO_SIZE,    DOMAIN_IO, 0, 1, 0, 0 },
- { PCIMEM_BASE,	 DC21285_PCI_MEM,	    PCIMEM_SIZE,  DOMAIN_IO, 0, 1, 0, 0 },
+ { PCIO_BASE,	 DC21285_PCI_IO,	    PCIO_SIZE,    MT_DEVICE },
+ { PCIMEM_BASE,	 DC21285_PCI_MEM,	    PCIMEM_SIZE,  MT_DEVICE }
 #endif
- LAST_DESC
 };
 
 void __init footbridge_map_io(void)
 {
-	struct map_desc *desc = NULL;
-
 	/*
 	 * Set up the common mapping first; we need this to
 	 * determine whether we're in host mode or not.
 	 */
-	iotable_init(fb_common_io_desc);
+	iotable_init(fb_common_io_desc, ARRAY_SIZE(fb_common_io_desc));
 
 	/*
 	 * Now, work out what we've got to map in addition on this
 	 * platform.
 	 */
 	if (machine_is_co285())
-		desc = co285_io_desc;
-	else if (footbridge_cfn_mode())
-		desc = ebsa285_host_io_desc;
-
-	if (desc)
-		iotable_init(desc);
+		iotable_init(co285_io_desc, ARRAY_SIZE(co285_io_desc));
+	if (footbridge_cfn_mode())
+		iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
 }
 
 #ifdef CONFIG_FOOTBRIDGE_ADDIN
diff -Nru a/arch/arm/mach-ftvpci/core.c b/arch/arm/mach-ftvpci/core.c
--- a/arch/arm/mach-ftvpci/core.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-ftvpci/core.c	Sat Jun  8 22:31:37 2002
@@ -8,6 +8,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -76,17 +77,16 @@
 }
 
 static struct map_desc ftvpci_io_desc[] __initdata = {
- 	{ INTCONT_BASE,	INTCONT_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ PLX_BASE,	PLX_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ PCIO_BASE,	PLX_IO_START,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
- 	{ DUART_BASE,	DUART_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
-	{ STATUS_BASE,	STATUS_START,	0x00001000, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+ 	{ INTCONT_BASE,	INTCONT_START,	0x00001000, MT_DEVICE },
+ 	{ PLX_BASE,	PLX_START,	0x00001000, MT_DEVICE },
+ 	{ PCIO_BASE,	PLX_IO_START,	0x00100000, MT_DEVICE },
+ 	{ DUART_BASE,	DUART_START,	0x00001000, MT_DEVICE },
+	{ STATUS_BASE,	STATUS_START,	0x00001000, MT_DEVICE }
 };
 
 static void __init ftvpci_map_io(void)
 {
-	iotable_init(ftvpci_io_desc);
+	iotable_init(ftvpci_io_desc, ARRAY_SIZE(ftvpci_io_desc));
 }
 
 MACHINE_START(NEXUSPCI, "FTV/PCI")
diff -Nru a/arch/arm/mach-integrator/mm.c b/arch/arm/mach-integrator/mm.c
--- a/arch/arm/mach-integrator/mm.c	Sat Jun  8 22:31:49 2002
+++ b/arch/arm/mach-integrator/mm.c	Sat Jun  8 22:31:49 2002
@@ -20,14 +20,11 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
  
 #include <asm/mach/map.h>
 
@@ -53,26 +50,25 @@
  */
  
 static struct map_desc integrator_io_desc[] __initdata = {
- { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_KBD_BASE),   INTEGRATOR_KBD_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K     , DOMAIN_IO, 0, 1},
- { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K     , DOMAIN_IO, 0, 1},
- { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M    , DOMAIN_IO, 0, 1},
- { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M    , DOMAIN_IO, 0, 1},
- { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_64K   , DOMAIN_IO, 0, 1},
- { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K    , DOMAIN_IO, 0, 1},
- LAST_DESC
+ { IO_ADDRESS(INTEGRATOR_HDR_BASE),   INTEGRATOR_HDR_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_SC_BASE),    INTEGRATOR_SC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_EBI_BASE),   INTEGRATOR_EBI_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_CT_BASE),    INTEGRATOR_CT_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_IC_BASE),    INTEGRATOR_IC_BASE,    SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_KBD_BASE),   INTEGRATOR_KBD_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
+ { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
+ { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M, MT_DEVICE },
+ { PCI_CONFIG_VADDR,                  PHYS_PCI_CONFIG_BASE,  SZ_16M, MT_DEVICE },
+ { PCI_V3_VADDR,                      PHYS_PCI_V3_BASE,      SZ_64K, MT_DEVICE },
+ { PCI_IO_VADDR,                      PHYS_PCI_IO_BASE,      SZ_64K, MT_DEVICE }
 };
 
 void __init integrator_map_io(void)
 {
-	iotable_init(integrator_io_desc);
+	iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc));
 }
diff -Nru a/arch/arm/mach-iop310/mm.c b/arch/arm/mach-iop310/mm.c
--- a/arch/arm/mach-iop310/mm.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-iop310/mm.c	Sat Jun  8 22:31:36 2002
@@ -14,6 +14,7 @@
  *
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/init.h>
 
@@ -32,17 +33,16 @@
  * Standard IO mapping for all IOP310 based systems
  */
 static struct map_desc iop80310_std_desc[] __initdata = {
- /* virtual     physical      length      domain     r  w  c  b */
+ /* virtual     physical      length       type */
  // IOP310 Memory Mapped Registers
- { 0xe8001000,  0x00001000,   0x00001000,  DOMAIN_IO, 0, 1, 0, 0 },
+ { 0xe8001000,  0x00001000,   0x00001000,  MT_DEVICE },
  // PCI I/O Space
- { 0xfe000000,  0x90000000,   0x00020000,  DOMAIN_IO, 0, 1, 0, 0 },
- LAST_DESC
+ { 0xfe000000,  0x90000000,   0x00020000,  MT_DEVICE }
 };
 
 void __init iop310_map_io(void)
 {
-	iotable_init(iop80310_std_desc);
+	iotable_init(iop80310_std_desc, ARRAY_SIZE(iop80310_std_desc));
 }
 
 /*
@@ -50,10 +50,9 @@
  */
 #ifdef CONFIG_ARCH_IQ80310
 static struct map_desc iq80310_io_desc[] __initdata = {
- /* virtual     physical      length        domain     r  w  c  b */
+ /* virtual     physical      length        type */
  // IQ80310 On-Board Devices
- { 0xfe800000,  0xfe800000,   0x00100000,   DOMAIN_IO, 0, 1, 0, 0 },
- LAST_DESC
+ { 0xfe800000,  0xfe800000,   0x00100000,   MT_DEVICE }
 };
 
 void __init iq80310_map_io(void)
@@ -65,7 +64,7 @@
 
 	iop310_map_io();
 
-	iotable_init(iq80310_io_desc);
+	iotable_init(iq80310_io_desc, ARRAY_SIZE(iq80310_io_desc));
 }
 #endif // CONFIG_ARCH_IQ80310
 
diff -Nru a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c
--- a/arch/arm/mach-l7200/core.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-l7200/core.c	Sat Jun  8 22:31:36 2002
@@ -6,6 +6,7 @@
  *  Extra MM routines for L7200 architecture
  */
 #include <linux/config.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
@@ -69,17 +70,16 @@
 }
 
 static struct map_desc l7200_io_desc[] __initdata = {
-	{ IO_BASE,	IO_START,	IO_SIZE,	DOMAIN_IO, 0, 1 ,0 ,0},
-	{ IO_BASE_2,	IO_START_2,	IO_SIZE_2,	DOMAIN_IO, 0, 1 ,0 ,0},
-	{ AUX_BASE,     AUX_START,      AUX_SIZE,       DOMAIN_IO, 0, 1 ,0 ,0},
-	{ FLASH1_BASE,  FLASH1_START,   FLASH1_SIZE,    DOMAIN_IO, 0, 1 ,0 ,0},
-	{ FLASH2_BASE,  FLASH2_START,   FLASH2_SIZE,    DOMAIN_IO, 0, 1 ,0 ,0},
-	LAST_DESC
+	{ IO_BASE,	IO_START,	IO_SIZE,	MT_DEVICE },
+	{ IO_BASE_2,	IO_START_2,	IO_SIZE_2,	MT_DEVICE },
+	{ AUX_BASE,     AUX_START,      AUX_SIZE,       MT_DEVICE },
+	{ FLASH1_BASE,  FLASH1_START,   FLASH1_SIZE,    MT_DEVICE },
+	{ FLASH2_BASE,  FLASH2_START,   FLASH2_SIZE,    MT_DEVICE }
 };
 
 static void __init l7200_map_io(void)
 {
-	iotable_init(l7200_io_desc);
+	iotable_init(l7200_io_desc, ARRAY_SIZE(l7200_io_desc));
 }
 
 MACHINE_START(L7200, "LinkUp Systems L7200")
diff -Nru a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
--- a/arch/arm/mach-pxa/generic.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-pxa/generic.c	Sat Jun  8 22:31:36 2002
@@ -88,16 +88,15 @@
  * cache flush area.
  */
 static struct map_desc standard_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA0 IO */
-  { 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCMCIA1 IO */
-  { 0xfc000000, 0x40000000, 0x01400000, DOMAIN_IO, 0, 1, 0, 0 }, /* Devs */
-  { 0xfe000000, 0x44000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
-  { 0xff000000, 0x48000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Mem Ctl */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf6000000, 0x20000000, 0x01000000, MT_DEVICE }, /* PCMCIA0 IO */
+  { 0xf7000000, 0x30000000, 0x01000000, MT_DEVICE }, /* PCMCIA1 IO */
+  { 0xfc000000, 0x40000000, 0x01400000, MT_DEVICE }, /* Devs */
+  { 0xfe000000, 0x44000000, 0x00200000, MT_DEVICE }, /* LCD */
+  { 0xff000000, 0x48000000, 0x00200000, MT_DEVICE }  /* Mem Ctl */
 };
 
 void __init pxa_map_io(void)
 {
-	iotable_init(standard_io_desc);
+	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
 }
diff -Nru a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
--- a/arch/arm/mach-pxa/idp.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-pxa/idp.c	Sat Jun  8 22:31:35 2002
@@ -10,6 +10,7 @@
  *  2001-09-13: Cliff Brake <cbrake@accelent.com>
  *              Initial code
  */
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/major.h>
 #include <linux/fs.h>
@@ -69,45 +70,38 @@
 }
 
 static struct map_desc idp_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
+ /* virtual     physical    length      type */
 
 
 #ifndef PXA_IDP_REV02
   { IDP_CTRL_PORT_BASE,
     IDP_CTRL_PORT_PHYS,
     IDP_CTRL_PORT_SIZE,
-    DOMAIN_IO,
-    0, 1, 0, 0 },
+    MT_DEVICE },
 #endif
 
   { IDP_IDE_BASE,
     IDP_IDE_PHYS,
     IDP_IDE_SIZE,
-    DOMAIN_IO,
-    0, 1, 0, 0 },
+    MT_DEVICE },
   { IDP_ETH_BASE,
     IDP_ETH_PHYS,
     IDP_ETH_SIZE,
-    DOMAIN_IO,
-    0, 1, 0, 0 },
+    MT_DEVICE },
   { IDP_COREVOLT_BASE,
     IDP_COREVOLT_PHYS,
     IDP_COREVOLT_SIZE,
-    DOMAIN_IO,
-    0, 1, 0, 0 },
+    MT_DEVICE },
   { IDP_CPLD_BASE,
     IDP_CPLD_PHYS,
     IDP_CPLD_SIZE,
-    DOMAIN_IO,
-    0, 1, 0, 0 },
-
-  LAST_DESC
+    MT_DEVICE }
 };
 
 static void __init idp_map_io(void)
 {
 	pxa_map_io();
-	iotable_init(idp_io_desc);
+	iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 
 	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
 }
diff -Nru a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
--- a/arch/arm/mach-pxa/lubbock.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-pxa/lubbock.c	Sat Jun  8 22:31:37 2002
@@ -11,6 +11,7 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/major.h>
 #include <linux/fs.h>
@@ -120,18 +121,17 @@
 __initcall(lubbock_init);
 
 static struct map_desc lubbock_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
-  { 0xf1000000, 0x0c000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 IO */
-  { 0xf1100000, 0x0e000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN91C96 Attr */
-  { 0xf4000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE }, /* CPLD */
+  { 0xf1000000, 0x0c000000, 0x00100000, MT_DEVICE }, /* LAN91C96 IO */
+  { 0xf1100000, 0x0e000000, 0x00100000, MT_DEVICE }, /* LAN91C96 Attr */
+  { 0xf4000000, 0x10000000, 0x00400000, MT_DEVICE }  /* SA1111 */
 };
 
 static void __init lubbock_map_io(void)
 {
 	pxa_map_io();
-	iotable_init(lubbock_io_desc);
+	iotable_init(lubbock_io_desc, ARRAY_SIZE(lubbock_io_desc));
 
 	/* This enables the BTUART */
 	CKEN |= CKEN7_BTUART;
diff -Nru a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
--- a/arch/arm/mach-rpc/riscpc.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-rpc/riscpc.c	Sat Jun  8 22:31:36 2002
@@ -9,6 +9,7 @@
  *
  *  Architecture specific fixups.
  */
+#include <linux/kernel.h>
 #include <linux/tty.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
@@ -61,15 +62,14 @@
 #endif
 
 static struct map_desc rpc_io_desc[] __initdata = {
- { SCREEN_BASE,	SCREEN_START,	2*1048576, DOMAIN_IO, 0, 1, 0, 0 }, /* VRAM		*/
- { IO_BASE,	IO_START,	IO_SIZE	 , DOMAIN_IO, 0, 1, 0, 0 }, /* IO space		*/
- { EASI_BASE,	EASI_START,	EASI_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, /* EASI space	*/
- LAST_DESC
+ { SCREEN_BASE,	SCREEN_START,	2*1048576, MT_DEVICE }, /* VRAM		*/
+ { IO_BASE,	IO_START,	IO_SIZE	 , MT_DEVICE }, /* IO space		*/
+ { EASI_BASE,	EASI_START,	EASI_SIZE, MT_DEVICE }  /* EASI space	*/
 };
 
 void __init rpc_map_io(void)
 {
-	iotable_init(rpc_io_desc);
+	iotable_init(rpc_io_desc, ARRAY_SIZE(rpc_io_desc));
 
 	/*
 	 * RiscPC can't handle half-word loads and stores
diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c
--- a/arch/arm/mach-sa1100/adsbitsy.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/adsbitsy.c	Sat Jun  8 22:31:35 2002
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -77,9 +77,8 @@
 }
 
 static struct map_desc adsbitsy_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf4000000, 0x18000000, 0x00800000, MT_DEVICE }  /* SA1111 */
 };
 
 static int adsbitsy_uart_open(struct uart_port *port, struct uart_info *info)
@@ -106,7 +105,7 @@
 static void __init adsbitsy_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(adsbitsy_io_desc);
+	iotable_init(adsbitsy_io_desc, ARRAY_SIZE(adsbitsy_io_desc));
 
 	sa1100_register_uart_fns(&adsbitsy_port_fns);
 	sa1100_register_uart(0, 3);
diff -Nru a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
--- a/arch/arm/mach-sa1100/assabet.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/assabet.c	Sat Jun  8 22:31:35 2002
@@ -171,15 +171,6 @@
 }
 
 
-static struct map_desc assabet_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
-  /*  f3000000 - neponset system registers */
-  /*  f4000000 - neponset SA1111 registers */
-  LAST_DESC
-};
-
 static void assabet_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
 {
 	if (port->mapbase == _Ser1UTCR0) {
@@ -255,12 +246,18 @@
 	pm:		assabet_uart_pm,
 };
 
+static struct map_desc assabet_io_desc[] __initdata = {
+ /* virtual     physical    length      type */
+  { 0xf1000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
+  { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }  /* MQ200 */
+};
+
 static void __init assabet_map_io(void)
 {
 	extern void neponset_map_io(void);
 
 	sa1100_map_io();
-	iotable_init(assabet_io_desc);
+	iotable_init(assabet_io_desc, ARRAY_SIZE(assabet_io_desc));
 
 	if (machine_has_neponset()) {
 #ifdef CONFIG_ASSABET_NEPONSET
diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
--- a/arch/arm/mach-sa1100/badge4.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/badge4.c	Sat Jun  8 22:31:36 2002
@@ -145,17 +145,16 @@
 
 
 static struct map_desc badge4_io_desc[] __initdata = {
-  /*  virtual    physical    length      domain     r w c b		   */
-  {0xf1000000, 0x08000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM  bank 1 */
-  {0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SRAM  bank 2 */
-  {0xf4000000, 0x48000000, 0x00100000, DOMAIN_IO, 0,1,0,0},/* SA-1111      */
-  LAST_DESC
+  /*  virtual    physical    length    type */
+  {0xf1000000, 0x08000000, 0x00100000, MT_DEVICE },/* SRAM  bank 1 */
+  {0xf2000000, 0x10000000, 0x00100000, MT_DEVICE },/* SRAM  bank 2 */
+  {0xf4000000, 0x48000000, 0x00100000, MT_DEVICE } /* SA-1111      */
 };
 
 static void __init badge4_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(badge4_io_desc);
+	iotable_init(badge4_io_desc, ARRAY_SIZE(badge4_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
--- a/arch/arm/mach-sa1100/cerf.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/cerf.c	Sat Jun  8 22:31:37 2002
@@ -36,20 +36,19 @@
 }
 
 static struct map_desc cerf_io_desc[] __initdata = {
-  /* virtual	 physical    length	 domain     r  w  c  b */
-  { 0xf0000000, 0x08000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Crystal Ethernet Chip */
+  /* virtual	 physical    length	 type */
+  { 0xf0000000, 0x08000000, 0x00100000, MT_DEVICE }  /* Crystal Ethernet Chip */
 #ifdef CONFIG_SA1100_CERF_CPLD
-  { 0xf1000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD Chip */
-  { 0xf2000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Bluetooth */
-  { 0xf3000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* CerfPDA Serial */
+ ,{ 0xf1000000, 0x40000000, 0x00100000, MT_DEVICE }, /* CPLD Chip */
+  { 0xf2000000, 0x10000000, 0x00100000, MT_DEVICE }, /* CerfPDA Bluetooth */
+  { 0xf3000000, 0x18000000, 0x00100000, MT_DEVICE }  /* CerfPDA Serial */
 #endif
-  LAST_DESC
 };
 
 static void __init cerf_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(cerf_io_desc);
+	iotable_init(cerf_io_desc, ARRAY_SIZE(cerf_io_desc));
 
 	sa1100_register_uart(0, 3);
 #ifdef CONFIG_SA1100_CERF_IRDA_ENABLED
diff -Nru a/arch/arm/mach-sa1100/empeg.c b/arch/arm/mach-sa1100/empeg.c
--- a/arch/arm/mach-sa1100/empeg.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mach-sa1100/empeg.c	Sat Jun  8 22:31:51 2002
@@ -16,15 +16,14 @@
 #include "generic.h"
 
 static struct map_desc empeg_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { EMPEG_FLASHBASE, 0x00000000, 0x00200000, MT_DEVICE } /* Flash */
 };
 
 static void __init empeg_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(empeg_io_desc);
+	iotable_init(empeg_io_desc, ARRAY_SIZE(empeg_io_desc));
 
 	sa1100_register_uart(0, 1);
 	sa1100_register_uart(1, 3);
diff -Nru a/arch/arm/mach-sa1100/flexanet.c b/arch/arm/mach-sa1100/flexanet.c
--- a/arch/arm/mach-sa1100/flexanet.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/flexanet.c	Sat Jun  8 22:31:37 2002
@@ -152,18 +152,17 @@
 
 
 static struct map_desc flexanet_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
-  { 0xf1000000, 0x18000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Ethernet controller */
-  { 0xD0000000, 0x40000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Instrument boards */
-  { 0xD8000000, 0x48000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* External peripherals */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00001000, MT_DEVICE }, /* Board Control Register */
+  { 0xf1000000, 0x18000000, 0x01000000, MT_DEVICE }, /* Ethernet controller */
+  { 0xD0000000, 0x40000000, 0x01000000, MT_DEVICE }, /* Instrument boards */
+  { 0xD8000000, 0x48000000, 0x01000000, MT_DEVICE }  /* External peripherals */
 };
 
 static void __init flexanet_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(flexanet_io_desc);
+	iotable_init(flexanet_io_desc, ARRAY_SIZE(flexanet_io_desc));
 	flexanet_serial_init();
 
 	/* wakeup source is GPIO-0 only */
diff -Nru a/arch/arm/mach-sa1100/freebird.c b/arch/arm/mach-sa1100/freebird.c
--- a/arch/arm/mach-sa1100/freebird.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/freebird.c	Sat Jun  8 22:31:36 2002
@@ -43,8 +43,6 @@
 	if (machine_is_freebird()) {
 		sa1100fb_backlight_power = freebird_backlight_power;
 		sa1100fb_lcd_power = freebird_lcd_power;
-
-		set_GPIO_IRQ_edge(GPIO_FREEBIRD_UCB1300, GPIO_RISING_EDGE);
 	}
 	return 0;
 }
@@ -52,16 +50,15 @@
 __initcall(freebird_init);
 
 static struct map_desc freebird_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x12000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Board Control Register */
-  { 0xf2000000, 0x19000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0},
-   LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x12000000, 0x00100000, MT_DEVICE }, /* Board Control Register */
+  { 0xf2000000, 0x19000000, 0x00100000, MT_DEVICE }
 };
 
 static void __init freebird_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(freebird_io_desc);
+	iotable_init(freebird_io_desc, ARRAY_SIZE(freebird_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c
--- a/arch/arm/mach-sa1100/generic.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/generic.c	Sat Jun  8 22:31:36 2002
@@ -134,8 +134,6 @@
  *
  * Typically, static virtual address mappings are as follow:
  *
- * 0xe8000000-0xefffffff:	flash memory (especially when multiple flash
- * 				banks need to be mapped contigously)
  * 0xf0000000-0xf3ffffff:	miscellaneous stuff (CPLDs, etc.)
  * 0xf4000000-0xf4ffffff:	SA-1111
  * 0xf5000000-0xf5ffffff:	reserved (used by cache flushing area)
@@ -150,17 +148,16 @@
  */
 
 static struct map_desc standard_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
-  { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
-  { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
-  { 0xfe000000, 0xb0000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf8000000, 0x80000000, 0x00100000, MT_DEVICE }, /* PCM */
+  { 0xfa000000, 0x90000000, 0x00100000, MT_DEVICE }, /* SCM */
+  { 0xfc000000, 0xa0000000, 0x00100000, MT_DEVICE }, /* MER */
+  { 0xfe000000, 0xb0000000, 0x00200000, MT_DEVICE }  /* LCD + DMA */
 };
 
 void __init sa1100_map_io(void)
 {
-	iotable_init(standard_io_desc);
+	iotable_init(standard_io_desc, ARRAY_SIZE(standard_io_desc));
 }
 
 /*
@@ -203,3 +200,4 @@
 
 	local_irq_restore(flags);
 }
+
diff -Nru a/arch/arm/mach-sa1100/graphicsclient.c b/arch/arm/mach-sa1100/graphicsclient.c
--- a/arch/arm/mach-sa1100/graphicsclient.c	Sat Jun  8 22:31:52 2002
+++ b/arch/arm/mach-sa1100/graphicsclient.c	Sat Jun  8 22:31:52 2002
@@ -9,7 +9,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -121,10 +121,9 @@
 
 
 static struct map_desc graphicsclient_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
-  { 0xf1000000, 0x18000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00400000, MT_DEVICE }, /* CPLD */
+  { 0xf1000000, 0x18000000, 0x00400000, MT_DEVICE }  /* CAN */
 };
 
 static u_int graphicsclient_get_mctrl(struct uart_port *port)
@@ -187,7 +186,7 @@
 static void __init graphicsclient_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(graphicsclient_io_desc);
+	iotable_init(graphicsclient_io_desc, ARRAY_SIZE(graphicsclient_io_desc));
 
 	sa1100_register_uart_fns(&graphicsclient_port_fns);
 	sa1100_register_uart(0, 3);
diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c
--- a/arch/arm/mach-sa1100/graphicsmaster.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/graphicsmaster.c	Sat Jun  8 22:31:37 2002
@@ -7,7 +7,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -153,11 +153,10 @@
 
 
 static struct map_desc graphicsmaster_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CPLD */
-  { 0xf1000000, 0x40000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* CAN */
-  { 0xf4000000, 0x18000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00400000, MT_DEVICE }, /* CPLD */
+  { 0xf1000000, 0x40000000, 0x00400000, MT_DEVICE }, /* CAN */
+  { 0xf4000000, 0x18000000, 0x00800000, MT_DEVICE }  /* SA-1111 */
 };
 
 #error Old code.  Someone needs to decide what to do about this.
@@ -244,7 +243,7 @@
 static void __init graphicsmaster_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(graphicsmaster_io_desc);
+	iotable_init(graphicsmaster_io_desc, ARRAY_SIZE(graphicsmaster_io_desc));
 
 	sa1100_register_uart_fns(&graphicsmaster_port_fns);
 	sa1100_register_uart(0, 3);
diff -Nru a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
--- a/arch/arm/mach-sa1100/h3600.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/h3600.c	Sat Jun  8 22:31:36 2002
@@ -434,17 +434,16 @@
 };
 
 static struct map_desc h3600_io_desc[] __initdata = {
- /* virtual	       physical    length      domain	  r  w	c  b */
-  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0		 CS#5 */
-  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2  CS#2 */
-  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4  CS#4 */
-  LAST_DESC
+ /* virtual	       physical    length      type */
+  { H3600_EGPIO_VIRT,  0x49000000, 0x01000000, MT_DEVICE }, /* EGPIO 0		 CS#5 */
+  { H3600_BANK_2_VIRT, 0x10000000, 0x02800000, MT_DEVICE }, /* static memory bank 2  CS#2 */
+  { H3600_BANK_4_VIRT, 0x40000000, 0x00800000, MT_DEVICE }  /* static memory bank 4  CS#4 */
 };
 
 static void __init h3600_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(h3600_io_desc);
+	iotable_init(h3600_io_desc, ARRAY_SIZE(h3600_io_desc));
 
 	sa1100_register_uart_fns(&h3600_port_fns);
 	sa1100_register_uart(0, 3);
diff -Nru a/arch/arm/mach-sa1100/huw_webpanel.c b/arch/arm/mach-sa1100/huw_webpanel.c
--- a/arch/arm/mach-sa1100/huw_webpanel.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/huw_webpanel.c	Sat Jun  8 22:31:37 2002
@@ -60,16 +60,15 @@
    area size = 288 kByte (0x48000 Bytes)
 **/
 static struct map_desc huw_webpanel_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0xc1fb8000, 0x00048000, DOMAIN_IO, 0, 1, 0, 0 }, /* Parameter */
-  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0xc1fb8000, 0x00048000, MT_DEVICE }, /* Parameter */
+  { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE }  /* Paules CS3, write only */
 };
 
 static void __init huw_webpanel_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(huw_webpanel_io_desc);
+	iotable_init(huw_webpanel_io_desc, ARRAY_SIZE(huw_webpanel_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/itsy.c b/arch/arm/mach-sa1100/itsy.c
--- a/arch/arm/mach-sa1100/itsy.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/itsy.c	Sat Jun  8 22:31:37 2002
@@ -18,16 +18,14 @@
 /* BRADFIXME The egpio addresses aren't verifiably correct. (i.e. they're most
    likely wrong. */
 static struct map_desc itsy_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x49000000, 0x01000000, MT_DEVICE } /* EGPIO 0 */
 };
 
 static void __init itsy_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(itsy_io_desc);
+	iotable_init(itsy_io_desc, ARRAY_SIZE(itsy_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
--- a/arch/arm/mach-sa1100/jornada720.c	Sat Jun  8 22:31:43 2002
+++ b/arch/arm/mach-sa1100/jornada720.c	Sat Jun  8 22:31:43 2002
@@ -56,17 +56,16 @@
 __initcall(jornada720_init);
 
 static struct map_desc jornada720_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x48000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson registers */
-  { 0xf1000000, 0x48200000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Epson frame buffer */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x48000000, 0x00100000, MT_DEVICE }, /* Epson registers */
+  { 0xf1000000, 0x48200000, 0x00100000, MT_DEVICE }, /* Epson frame buffer */
+  { 0xf4000000, 0x40000000, 0x00100000, MT_DEVICE }  /* SA-1111 */
 };
 
 static void __init jornada720_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(jornada720_io_desc);
+	iotable_init(jornada720_io_desc, ARRAY_SIZE(jornada720_io_desc));
 	
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
--- a/arch/arm/mach-sa1100/lart.c	Sat Jun  8 22:31:52 2002
+++ b/arch/arm/mach-sa1100/lart.c	Sat Jun  8 22:31:52 2002
@@ -17,16 +17,15 @@
 
 
 static struct map_desc lart_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
-  { 0xec000000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xe8000000, 0x00000000, 0x00400000, MT_DEVICE }, /* main flash memory */
+  { 0xec000000, 0x08000000, 0x00400000, MT_DEVICE }  /* main flash, alternative location */
 };
 
 static void __init lart_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(lart_io_desc);
+	iotable_init(lart_io_desc, ARRAY_SIZE(lart_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/nanoengine.c b/arch/arm/mach-sa1100/nanoengine.c
--- a/arch/arm/mach-sa1100/nanoengine.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/nanoengine.c	Sat Jun  8 22:31:35 2002
@@ -25,17 +25,15 @@
 }
 
 static struct map_desc nanoengine_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
-  { 0xf1000000, 0x18A00000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Internal PCI Config Space */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00100000, MT_DEVICE }, /* System Registers */
+  { 0xf1000000, 0x18A00000, 0x00100000, MT_DEVICE }  /* Internal PCI Config Space */
 };
 
 static void __init nanoengine_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(nanoengine_io_desc);
+	iotable_init(nanoengine_io_desc, ARRAY_SIZE(nanoengine_io_desc));
 
 	sa1100_register_uart(0, 1);
 	sa1100_register_uart(1, 2);
diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
--- a/arch/arm/mach-sa1100/neponset.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/neponset.c	Sat Jun  8 22:31:37 2002
@@ -2,7 +2,7 @@
  * linux/arch/arm/mach-sa1100/neponset.c
  *
  */
-
+#include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
@@ -18,7 +18,9 @@
 #include <asm/mach/irq.h>
 #include <asm/mach/serial_sa1100.h>
 #include <asm/arch/assabet.h>
+#include <asm/arch/neponset.h>
 #include <asm/hardware/sa1111.h>
+#include <asm/sizes.h>
 
 #include "sa1111.h"
 
@@ -216,13 +218,12 @@
 __initcall(neponset_init);
 
 static struct map_desc neponset_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical    length type */
+  { 0xf3000000, 0x10000000, SZ_1M, MT_DEVICE }, /* System Registers */
+  { 0xf4000000, 0x40000000, SZ_1M, MT_DEVICE }  /* SA-1111 */
 };
 
 void __init neponset_map_io(void)
 {
-	iotable_init(neponset_io_desc);
+	iotable_init(neponset_io_desc, ARRAY_SIZE(neponset_io_desc));
 }
diff -Nru a/arch/arm/mach-sa1100/omnimeter.c b/arch/arm/mach-sa1100/omnimeter.c
--- a/arch/arm/mach-sa1100/omnimeter.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/omnimeter.c	Sat Jun  8 22:31:35 2002
@@ -41,15 +41,14 @@
 __initcall(omnimeter_init);
 
 static struct map_desc omnimeter_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xd2000000, 0x10000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* TS */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xd2000000, 0x10000000, 0x02000000, MT_DEVICE } /* TS */
 };
 
 static void __init omnimeter_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(omnimeter_io_desc);
+	iotable_init(omnimeter_io_desc, ARRAY_SIZE(omnimeter_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/pangolin.c b/arch/arm/mach-sa1100/pangolin.c
--- a/arch/arm/mach-sa1100/pangolin.c	Sat Jun  8 22:31:52 2002
+++ b/arch/arm/mach-sa1100/pangolin.c	Sat Jun  8 22:31:52 2002
@@ -16,15 +16,14 @@
 #include "generic.h"
 
 static struct map_desc pangolin_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE } /* MQ200 */
 };
 
 static void __init pangolin_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(pangolin_io_desc);
+	iotable_init(pangolin_io_desc, ARRAY_SIZE(pangolin_io_desc));
 
 	sa1100_register_uart(0, 1);
 	sa1100_register_uart(1, 3);
diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c
--- a/arch/arm/mach-sa1100/pfs168.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/pfs168.c	Sat Jun  8 22:31:35 2002
@@ -56,28 +56,26 @@
 }
 
 static struct map_desc pfs168_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
-  { 0xf0000000, 0x10000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port A (COM5) */
-  { 0xf0001000, 0x10800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* 16C752 DUART port B (COM6) */
-  { 0xf0002000, 0x11000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 RTS control (SYSC1RTS) */
-  { 0xf0003000, 0x11400000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Status LED control (SYSLED) */
-  { 0xf0004000, 0x11800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* DTMF code read (SYSDTMF) */
-  { 0xf0005000, 0x11c00000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD configure, enable (SYSLCDDE) */
-  { 0xf0006000, 0x12000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM1 DSR and motion sense (SYSC1DSR) */
-  { 0xf0007000, 0x12800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* COM3 xmit enable (SYSC3TEN) */
-  { 0xf0008000, 0x13000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register A (SYSCTLA) */
-  { 0xf0009000, 0x13800000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* Control register B (SYSCTLB) */
-  { 0xf000a000, 0x18000000, 0x00001000, DOMAIN_IO, 0, 1, 0, 0 }, /* SMC91C96 */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */
-  { 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00001000, MT_DEVICE }, /* 16C752 DUART port A (COM5) */
+  { 0xf0001000, 0x10800000, 0x00001000, MT_DEVICE }, /* 16C752 DUART port B (COM6) */
+  { 0xf0002000, 0x11000000, 0x00001000, MT_DEVICE }, /* COM1 RTS control (SYSC1RTS) */
+  { 0xf0003000, 0x11400000, 0x00001000, MT_DEVICE }, /* Status LED control (SYSLED) */
+  { 0xf0004000, 0x11800000, 0x00001000, MT_DEVICE }, /* DTMF code read (SYSDTMF) */
+  { 0xf0005000, 0x11c00000, 0x00001000, MT_DEVICE }, /* LCD configure, enable (SYSLCDDE) */
+  { 0xf0006000, 0x12000000, 0x00001000, MT_DEVICE }, /* COM1 DSR and motion sense (SYSC1DSR) */
+  { 0xf0007000, 0x12800000, 0x00001000, MT_DEVICE }, /* COM3 xmit enable (SYSC3TEN) */
+  { 0xf0008000, 0x13000000, 0x00001000, MT_DEVICE }, /* Control register A (SYSCTLA) */
+  { 0xf0009000, 0x13800000, 0x00001000, MT_DEVICE }, /* Control register B (SYSCTLB) */
+  { 0xf000a000, 0x18000000, 0x00001000, MT_DEVICE }, /* SMC91C96 */
+  { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }, /* MQ200 */
+  { 0xf4000000, 0x40000000, 0x00100000, MT_DEVICE }  /* SA-1111 */
 };
 
 static void __init pfs168_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(pfs168_io_desc);
+	iotable_init(pfs168_io_desc, ARRAY_SIZE(pfs168_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
--- a/arch/arm/mach-sa1100/pleb.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/pleb.c	Sat Jun  8 22:31:37 2002
@@ -15,17 +15,9 @@
 
 #include "generic.h"
 
-static struct map_desc pleb_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash memory */
-  { 0xe8400000, 0x08000000, 0x00400000, DOMAIN_IO, 0, 1, 0, 0 }, /* main flash, alternative location */
-  LAST_DESC
-};
-
 static void __init pleb_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(pleb_io_desc);
 
 	sa1100_register_uart(0, 3);
         sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c
--- a/arch/arm/mach-sa1100/pm.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/pm.c	Sat Jun  8 22:31:36 2002
@@ -18,12 +18,14 @@
  * 2001-08-29:	Nicolas Pitre <nico@cam.org>
  * 			Cleaned up, pushed platform dependent stuff
  * 			in the platform specific files.
+ *
+ * 2002-05-27:	Nicolas Pitre	Killed sleep.h and the kmalloced save array.
+ * 				Storage is local on the stack now.
  */
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/pm.h>
-#include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/sysctl.h>
@@ -35,7 +37,6 @@
 #include <asm/system.h>
 #include <asm/leds.h>
 
-#include "sleep.h"
 
 /*
  * Debug macros
@@ -45,20 +46,32 @@
 extern void sa1100_cpu_suspend(void);
 extern void sa1100_cpu_resume(void);
 
-extern unsigned long *sleep_save;	/* virtual address */
-extern unsigned long  sleep_save_p;	/* physical address */
-
 #define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
 #define RESTORE(x)	x = sleep_save[SLEEP_SAVE_##x]
 
+/*
+ * List of global SA11x0 peripheral registers to preserve.
+ * More ones like CP and general purpose register values are preserved
+ * on the stack and then the stack pointer is stored last in sleep.S.
+ */
+enum {	SLEEP_SAVE_SP = 0,
+
+	SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
+	SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
+
+	SLEEP_SAVE_GPDR, SLEEP_SAVE_GRER, SLEEP_SAVE_GFER, SLEEP_SAVE_GAFR,
+	SLEEP_SAVE_PPDR, SLEEP_SAVE_PPSR, SLEEP_SAVE_PPAR, SLEEP_SAVE_PSDR,
+
+	SLEEP_SAVE_ICMR,
+	SLEEP_SAVE_Ser1SDCR0,
+
+	SLEEP_SAVE_SIZE
+};
+
+
 int pm_do_suspend(void)
 {
-	/* set up pointer to sleep parameters */
-	sleep_save = kmalloc(SLEEP_SAVE_SIZE*sizeof(long), GFP_ATOMIC);
-	if (!sleep_save)
-		return -ENOMEM;
-
-	sleep_save_p = virt_to_phys(sleep_save);
+	unsigned long sleep_save[SLEEP_SAVE_SIZE];
 
 	cli();
 
@@ -146,8 +159,6 @@
 
 	sti();
 
-	kfree (sleep_save);
-
 	/*
 	 * Restore the CPU frequency settings.
 	 */
@@ -156,6 +167,11 @@
 #endif
 
 	return 0;
+}
+
+unsigned long sleep_phys_sp(void *sp)
+{
+	return virt_to_phys(sp);
 }
 
 #ifdef CONFIG_SYSCTL
diff -Nru a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
--- a/arch/arm/mach-sa1100/simpad.c	Sat Jun  8 22:31:35 2002
+++ b/arch/arm/mach-sa1100/simpad.c	Sat Jun  8 22:31:35 2002
@@ -1,6 +1,5 @@
 /*
  * linux/arch/arm/mach-sa1100/simpad.c
- *
  */
 
 #include <linux/config.h>
@@ -41,10 +40,9 @@
 }
 
 static struct map_desc simpad_io_desc[] __initdata = {
-  /* virtual	physical    length	domain	   r  w  c  b */
-  { 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* MQ200 */  
-  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* Paules CS3, write only */
-  LAST_DESC
+  /* virtual	physical    length	type */
+  { 0xf2800000, 0x4b800000, 0x00800000, MT_DEVICE }, /* MQ200 */  
+  { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE }  /* Paules CS3, write only */
 };
 
 
@@ -65,7 +63,7 @@
 static void __init simpad_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(simpad_io_desc);
+	iotable_init(simpad_io_desc, ARRAY_SIZE(simpad_io_desc));
 
 	PSPR = 0xc0008000;
 	GPDR &= ~GPIO_GPIO0;
diff -Nru a/arch/arm/mach-sa1100/sleep.S b/arch/arm/mach-sa1100/sleep.S
--- a/arch/arm/mach-sa1100/sleep.S	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/sleep.S	Sat Jun  8 22:31:36 2002
@@ -11,12 +11,20 @@
  * 2001-02-06: Cliff Brake         Initial code
  *
  * 2001-08-29:	Nicolas Pitre	Simplified.
+ *
+ * 2002-05-27:	Nicolas Pitre	Revisited, more cleanup and simplification.
+ *				Storage is on the stack now.
  */
 
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
-#include "sleep.h"
+
+
+
+		.text
+
+
 
 /*
  * sa1100_cpu_suspend()
@@ -25,35 +33,24 @@
  *
  */
 
-	.text
-
-ENTRY(sleep_save)	.word	0		@ virtual address of parameter array
-ENTRY(sleep_save_p)	.word	0		@ physical address of parameter array
-
 ENTRY(sa1100_cpu_suspend)
 
-	@ save registers on stack
-	stmfd	sp!, {r4 - r12, lr}
-
-	@ load virtual address for sleep_save array
-	ldr	r4, sleep_save
+	stmfd	sp!, {r4 - r12, lr}		@ save registers on stack
 
-	@ save stack pointer
-	str	sp, [r4, #(SLEEP_SAVE_SP*4)]
-
-	@ save coprocessor registers
-	mrc 	p15, 0, r1, c1, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R1*4)]
-	mrc 	p15, 0, r1, c2, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R2*4)]
-	mrc 	p15, 0, r1, c3, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R3*4)]
-	mrc 	p15, 0, r1, c5, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R5*4)]
-	mrc 	p15, 0, r1, c6, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R6*4)]
-	mrc 	p15, 0, r1, c13, c0, 0
-	str	r1, [r4, #(SLEEP_SAVE_CP15_R13*4)]
+	@ get coprocessor registers
+	mrc 	p15, 0, r4, c3, c0, 0		@ domain ID
+	mrc 	p15, 0, r5, c2, c0, 0		@ translation table base addr
+	mrc	p15, 0, r6, c13, c0, 0		@ PID
+	mrc 	p15, 0, r7, c1, c0, 0		@ control reg
+
+	@ store them plus current virtual stack ptr on stack
+	stmfd	sp!, {r4 - r7, sp}
+
+	@ preserve phys address of stack
+	mov	r0, sp
+	bl	sleep_phys_sp
+	ldr	r1, =sleep_save_sp
+	str	r0, [r1]
 
 	@ clean data cache and invalidate WB
 	bl	cpu_sa1100_cache_clean_invalidate_all
@@ -79,25 +76,24 @@
 	mov	r0, #90
 	bl	udelay
 
-
-/* setup up register contents for jump to page containing SA1110 SDRAM controller bug fix suspend code
- *
- * r0 points to MSC0 register
- * r1 points to MSC1 register
- * r2 points to MSC2 register
- * r3 is MSC0 value
- * r4 is MSC1 value
- * r5 is MSC2 value
- * r6 points to MDREFR register
- * r7 is first MDREFR value
- * r8 is second MDREFR value
- * r9 is pointer to MDCNFG register
- * r10 is MDCNFG value
- * r11 is third MDREFR value
- * r12 is pointer to PMCR register
- * r13 is PMCR value (1)
- *
- */
+	/*
+	 * SA1110 SDRAM controller workaround.  register values:
+	 *
+	 * r0  = &MSC0
+	 * r1  = &MSC1
+	 * r2  = &MSC2
+	 * r3  = MSC0 value
+	 * r4  = MSC1 value
+	 * r5  = MSC2 value
+	 * r6  = &MDREFR
+	 * r7  = first MDREFR value
+	 * r8  = second MDREFR value
+	 * r9  = &MDCNFG
+	 * r10 = MDCNFG value
+	 * r11 = third MDREFR value
+	 * r12 = &PMCR
+	 * r13 = PMCR value (1)
+	 */
 
 	ldr	r0, =MSC0
 	ldr	r1, =MSC1
@@ -170,69 +166,49 @@
  *
  * entry point from bootloader into kernel during resume
  *
+ * Note: Yes, part of the following code is located into the .data section.
+ *       This is to allow sleep_save_sp to be accessed with a relative load
+ *       while we can't rely on any MMU translation.  We could have put
+ *       sleep_save_sp in the .text section as well, but some setups might
+ *       insist on it to be truely read-only.
  */
 
+	.data
 	.align 5
 ENTRY(sa1100_cpu_resume)
-
-	@ set SVC, irqs off
 	mov	r0, #PSR_F_BIT | PSR_I_BIT | MODE_SVC
-	msr	cpsr_c, r0
+	msr	cpsr_c, r0			@ set SVC, irqs off
 
-	@ load physical address of sleep_save
-	ldr	r4, sleep_save_p
-
-	@ restore cp15_r3, domain id
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R3*4)]
-	mcr 	p15, 0, r1, c3, c0 ,0
-
-	@ restore cp15_r2, translation table base address
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R2*4)]
-	mcr 	p15, 0, r1, c2, c0 ,0
+	ldr	r0, sleep_save_sp		@ stack phys addr
+	ldr	r2, =resume_after_mmu		@ its absolute virtual address
+	ldmfd	r0, {r4 - r7, sp}		@ CP regs + virt stack ptr
 
 	mov	r1, #0
 	mcr	p15, 0, r1, c8, c7, 0   	@ flush I+D TLBs
 	mcr	p15, 0, r1, c7, c7, 0		@ flush I&D cache
+	mcr	p15, 0, r1, c9, c0, 0		@ invalidate RB
+	mcr     p15, 0, r1, c9, c0, 5		@ allow user space to use RB
 
-	@ get saved cp15 r1 (control register)
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R1*4)]
-
-	@ get address to jump to after turning on MMU
-	ldr	r2, =resume_after_mmu
-
-	cmp	r2, #0
-
-	b	resume_turn_on_mmu
+	mcr 	p15, 0, r4, c3, c0, 0		@ domain ID
+	mcr 	p15, 0, r5, c2, c0, 0		@ translation table base addr
+	mcr	p15, 0, r6, c13, c0, 0		@ PID
+	b	resume_turn_on_mmu		@ cache align execution
 
 	.align 5
 resume_turn_on_mmu:
-
-	@ turn on mmu
-	mcr 	p15, 0, r1, c1, c0 ,0
-
-	@ jump to resume_after_mmu
-	mov	pc, r2
+	mcr 	p15, 0, r7, c1, c0, 0		@ turn on MMU, caches, etc.
+	nop
+	mov	pc, r2				@ jump to virtual addr
+	nop
 	nop
 	nop
 
-	.align 5
-resume_after_mmu:
-
-	@ load virtual address for sleep_save array
-	ldr	r4, sleep_save
-
-	@ restore the rest of CPU state
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R13*4)]
-	mcr	p15, 0, r1, c13, c0, 0
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R5*4)]
-	mcr 	p15, 0, r1, c5, c0 ,0
-	ldr	r1, [r4, #(SLEEP_SAVE_CP15_R6*4)]
-	mcr 	p15, 0, r1, c6, c0 ,0
-
-	@ restore stack pointer
-	ldr	sp, [r4, #(SLEEP_SAVE_SP*4)]
+sleep_save_sp:
+	.word	0				@ preserve stack phys ptr here
 
-	@ return to caller
-	ldmfd	sp!, {r4 - r12, pc}
+	.text
+resume_after_mmu:
+	mcr     p15, 0, r1, c15, c1, 2		@ enable clock switching
+	ldmfd	sp!, {r4 - r12, pc}		@ return to caller
 
 
diff -Nru a/arch/arm/mach-sa1100/sleep.h b/arch/arm/mach-sa1100/sleep.h
--- a/arch/arm/mach-sa1100/sleep.h	Sat Jun  8 22:31:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,30 +0,0 @@
-/*
- * Offsets for register values preserved in RAM while in sleep mode
- */
-
-#define SLEEP_SAVE_OSCR		0
-#define SLEEP_SAVE_OSMR0	1
-#define SLEEP_SAVE_OSMR1	2
-#define SLEEP_SAVE_OSMR2	3
-#define SLEEP_SAVE_OSMR3	4
-#define SLEEP_SAVE_OIER		5
-#define SLEEP_SAVE_GPDR		6
-#define SLEEP_SAVE_GRER		7
-#define SLEEP_SAVE_GFER		8
-#define SLEEP_SAVE_GAFR		9
-#define SLEEP_SAVE_PPDR		10
-#define SLEEP_SAVE_PPSR		11
-#define SLEEP_SAVE_PPAR		12
-#define SLEEP_SAVE_PSDR		13
-#define SLEEP_SAVE_Ser1SDCR0	14
-#define SLEEP_SAVE_ICMR		15
-#define SLEEP_SAVE_SP		16
-#define SLEEP_SAVE_CP15_R1	17
-#define SLEEP_SAVE_CP15_R2	18
-#define SLEEP_SAVE_CP15_R3	19
-#define SLEEP_SAVE_CP15_R5	20
-#define SLEEP_SAVE_CP15_R6	21
-#define SLEEP_SAVE_CP15_R13	22
-
-#define SLEEP_SAVE_SIZE		23
-
diff -Nru a/arch/arm/mach-sa1100/stork.c b/arch/arm/mach-sa1100/stork.c
--- a/arch/arm/mach-sa1100/stork.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/stork.c	Sat Jun  8 22:31:36 2002
@@ -304,19 +304,17 @@
 
 
 struct map_desc stork_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash bank 0 */
-  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
-  { 0xf1000000, 0x10000000, 0x02800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 2 */
-  { 0xf3800000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* static memory bank 4 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { STORK_VM_BASE_CS1, STORK_VM_OFF_CS1, 0x01000000, MT_DEVICE }, /* EGPIO 0 */
+  { 0xf1000000, 0x10000000, 0x02800000, MT_DEVICE }, /* static memory bank 2 */
+  { 0xf3800000, 0x40000000, 0x00800000, MT_DEVICE }  /* static memory bank 4 */
 };
 
 int __init
 stork_map_io(void)
 {
     sa1100_map_io();
-    iotable_init(stork_io_desc);
+    iotable_init(stork_io_desc, ARRAY_SIZE(stork_io_desc));
 
     sa1100_register_uart(0, 1);	/* com port */
     sa1100_register_uart(1, 2);
diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c
--- a/arch/arm/mach-sa1100/system3.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/system3.c	Sat Jun  8 22:31:37 2002
@@ -95,10 +95,9 @@
  */
 
 static struct map_desc system3_io_desc[] __initdata = {
- /* virtual     physical        length      domain     r  w  c  b */
-  { 0xf3000000, PT_CPLD_BASE,   0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* System Registers */
-  { 0xf4000000, PT_SA1111_BASE, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical        length      type */
+  { 0xf3000000, PT_CPLD_BASE,   0x00100000, MT_DEVICE }, /* System Registers */
+  { 0xf4000000, PT_SA1111_BASE, 0x00100000, MT_DEVICE }  /* SA-1111 */
 };
 
 static struct sa1100_port_fns system3_port_fns __initdata = {
@@ -119,7 +118,7 @@
 {
 	DPRINTK( "%s\n", "START" );
 	sa1100_map_io();
-	iotable_init(system3_io_desc);
+	iotable_init(system3_io_desc, ARRAY_SIZE(system3_io_desc));
 
 	sa1100_register_uart_fns(&system3_port_fns);
 	sa1100_register_uart(0, 1);	/* com port */
diff -Nru a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c
--- a/arch/arm/mach-sa1100/xp860.c	Sat Jun  8 22:31:37 2002
+++ b/arch/arm/mach-sa1100/xp860.c	Sat Jun  8 22:31:37 2002
@@ -57,17 +57,16 @@
 __initcall(xp860_init);
 
 static struct map_desc xp860_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCSI */
-  { 0xf1000000, 0x18000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* LAN */
-  { 0xf4000000, 0x40000000, 0x00800000, DOMAIN_IO, 0, 1, 0, 0 }, /* SA-1111 */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x10000000, 0x00100000, MT_DEVICE }, /* SCSI */
+  { 0xf1000000, 0x18000000, 0x00100000, MT_DEVICE }, /* LAN */
+  { 0xf4000000, 0x40000000, 0x00800000, MT_DEVICE }  /* SA-1111 */
 };
 
 static void __init xp860_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(xp860_io_desc);
+	iotable_init(xp860_io_desc, ARRAY_SIZE(xp860_io_desc));
 
 	sa1100_register_uart(0, 3);
 	sa1100_register_uart(1, 1);
diff -Nru a/arch/arm/mach-sa1100/yopy.c b/arch/arm/mach-sa1100/yopy.c
--- a/arch/arm/mach-sa1100/yopy.c	Sat Jun  8 22:31:36 2002
+++ b/arch/arm/mach-sa1100/yopy.c	Sat Jun  8 22:31:36 2002
@@ -68,18 +68,15 @@
 
 
 static struct map_desc yopy_io_desc[] __initdata = {
- /* virtual     physical    length      domain     r  w  c  b */
-  { 0xe8000000, 0x00000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 0 */
-  { 0xec000000, 0x08000000, 0x04000000, DOMAIN_IO, 0, 1, 0, 0 }, /* Flash 1 */
-  { 0xf0000000, 0x48000000, 0x00300000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD */
-  { 0xf1000000, 0x10000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO */
-  LAST_DESC
+ /* virtual     physical    length      type */
+  { 0xf0000000, 0x48000000, 0x00300000, MT_DEVICE }, /* LCD */
+  { 0xf1000000, 0x10000000, 0x00100000, MT_DEVICE }  /* EGPIO */
 };
 
 static void __init yopy_map_io(void)
 {
 	sa1100_map_io();
-	iotable_init(yopy_io_desc);
+	iotable_init(yopy_io_desc, ARRAY_SIZE(yopy_io_desc));
 
 	sa1100_register_uart(0, 3);
 
diff -Nru a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
--- a/arch/arm/mach-shark/core.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mach-shark/core.c	Sat Jun  8 22:31:51 2002
@@ -3,18 +3,11 @@
  *
  *  Architecture specific stuff.
  */
-#include <linux/tty.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
 
-#include <asm/elf.h>
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
 #include <asm/io.h>
 
 #include <asm/mach/map.h>
@@ -23,13 +16,12 @@
 extern void shark_init_irq(void);
 
 static struct map_desc shark_io_desc[] __initdata = {
-	{ IO_BASE	, IO_START	, IO_SIZE	, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+	{ IO_BASE	, IO_START	, IO_SIZE	, MT_DEVICE }
 };
 
 static void __init shark_map_io(void)
 {
-	iotable_init(shark_io_desc);
+	iotable_init(shark_io_desc, ARRAY_SIZE(shark_io_desc));
 }
 
 MACHINE_START(SHARK, "Shark")
diff -Nru a/arch/arm/mach-tbox/core.c b/arch/arm/mach-tbox/core.c
--- a/arch/arm/mach-tbox/core.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mach-tbox/core.c	Sat Jun  8 22:31:52 2002
@@ -6,6 +6,7 @@
  *
  *  Extra MM routines for the Tbox architecture
  */
+#include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/init.h>
@@ -57,13 +58,12 @@
 
 static struct map_desc tbox_io_desc[] __initdata = {
 	/* See hardware.h for details */
-	{ IO_BASE,	IO_START,	0x00100000, DOMAIN_IO, 0, 1, 0, 0 },
-	LAST_DESC
+	{ IO_BASE,	IO_START,	0x00100000, MT_DEVICE }
 };
 
 static void __init tbox_map_io(void)
 {
-	iotable_init(tbox_io_desc);
+	iotable_init(tbox_io_desc, ARRAY_SIZE(tbox_io_desc));
 }
 
 MACHINE_START(TBOX, "unknown-TBOX")
diff -Nru a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
--- a/arch/arm/mm/mm-armv.c	Sat Jun  8 22:31:51 2002
+++ b/arch/arm/mm/mm-armv.c	Sat Jun  8 22:31:51 2002
@@ -220,16 +220,9 @@
 static void __init create_mapping(struct map_desc *md)
 {
 	unsigned long virt, length;
-	int prot_sect, prot_pte;
+	int prot_sect, prot_pte, domain;
 	long off;
 
-	if (md->prot_read && md->prot_write &&
-	    !md->cacheable && !md->bufferable) {
-		printk(KERN_WARNING "Security risk: creating user "
-		       "accessible mapping for 0x%08lx at 0x%08lx\n",
-		       md->physical, md->virtual);
-	}
-
 	if (md->virtual != vectors_base() && md->virtual < PAGE_OFFSET) {
 		printk(KERN_WARNING "MM: not creating mapping for "
 		       "0x%08lx at 0x%08lx in user region\n",
@@ -237,24 +230,49 @@
 		return;
 	}
 
-	prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
-		   (md->prot_read  ? L_PTE_USER       : 0) |
-		   (md->prot_write ? L_PTE_WRITE      : 0) |
-		   (md->cacheable  ? L_PTE_CACHEABLE  : 0) |
-		   (md->bufferable ? L_PTE_BUFFERABLE : 0);
-
-	prot_sect = PMD_TYPE_SECT | PMD_DOMAIN(md->domain) |
-		    (md->prot_read  ? PMD_SECT_AP_READ    : 0) |
-		    (md->prot_write ? PMD_SECT_AP_WRITE   : 0) |
-		    (md->cacheable  ? PMD_SECT_CACHEABLE  : 0) |
-		    (md->bufferable ? PMD_SECT_BUFFERABLE : 0);
+	prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY;
+	prot_sect = PMD_TYPE_SECT;
+
+	switch (md->type) {
+	case MT_DEVICE:
+		prot_pte  |= L_PTE_WRITE;
+		prot_sect |= PMD_SECT_AP_WRITE;
+		domain     = DOMAIN_IO;
+		break;
+
+	case MT_CACHECLEAN:
+		prot_pte  |= L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
+		prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
+		domain     = DOMAIN_KERNEL;
+		break;
+
+	case MT_MINICLEAN:
+		prot_pte  |= L_PTE_CACHEABLE;
+		prot_sect |= PMD_SECT_CACHEABLE;
+		domain     = DOMAIN_KERNEL;
+		break;
+
+	case MT_VECTORS:
+		prot_pte  |= L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
+		prot_sect |= PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
+		domain     = DOMAIN_USER;
+		break;
+
+	case MT_MEMORY:
+		prot_pte  |= L_PTE_WRITE | L_PTE_EXEC | L_PTE_CACHEABLE | L_PTE_BUFFERABLE;
+		prot_sect |= PMD_SECT_AP_WRITE | PMD_SECT_CACHEABLE | PMD_SECT_BUFFERABLE;
+		domain     = DOMAIN_KERNEL;
+		break;
+	}
+
+	prot_sect |= PMD_DOMAIN(domain);
 
 	virt   = md->virtual;
 	off    = md->physical - virt;
 	length = md->length;
 
 	while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
-		alloc_init_page(virt, virt + off, md->domain, prot_pte);
+		alloc_init_page(virt, virt + off, domain, prot_pte);
 
 		virt   += PAGE_SIZE;
 		length -= PAGE_SIZE;
@@ -268,7 +286,7 @@
 	}
 
 	while (length >= PAGE_SIZE) {
-		alloc_init_page(virt, virt + off, md->domain, prot_pte);
+		alloc_init_page(virt, virt + off, domain, prot_pte);
 
 		virt   += PAGE_SIZE;
 		length -= PAGE_SIZE;
@@ -319,12 +337,7 @@
 		p->physical   = mi->bank[i].start;
 		p->virtual    = __phys_to_virt(p->physical);
 		p->length     = mi->bank[i].size;
-		p->domain     = DOMAIN_KERNEL;
-		p->prot_read  = 0;
-		p->prot_write = 1;
-		p->cacheable  = 1;
-		p->bufferable = 1;
-
+		p->type       = MT_MEMORY;
 		p ++;
 	}
 
@@ -332,12 +345,7 @@
 	p->physical   = FLUSH_BASE_PHYS;
 	p->virtual    = FLUSH_BASE;
 	p->length     = PGDIR_SIZE;
-	p->domain     = DOMAIN_KERNEL;
-	p->prot_read  = 1;
-	p->prot_write = 0;
-	p->cacheable  = 1;
-	p->bufferable = 1;
-
+	p->type       = MT_CACHECLEAN;
 	p ++;
 #endif
 
@@ -345,12 +353,7 @@
 	p->physical   = FLUSH_BASE_PHYS + PGDIR_SIZE;
 	p->virtual    = FLUSH_BASE_MINICACHE;
 	p->length     = PGDIR_SIZE;
-	p->domain     = DOMAIN_KERNEL;
-	p->prot_read  = 1;
-	p->prot_write = 0;
-	p->cacheable  = 1;
-	p->bufferable = 0;
-
+	p->type       = MT_MINICLEAN;
 	p ++;
 #endif
 
@@ -380,25 +383,22 @@
 	init_maps->physical   = virt_to_phys(init_maps);
 	init_maps->virtual    = vectors_base();
 	init_maps->length     = PAGE_SIZE;
-	init_maps->domain     = DOMAIN_USER;
-	init_maps->prot_read  = 0;
-	init_maps->prot_write = 0;
-	init_maps->cacheable  = 1;
-	init_maps->bufferable = 0;
+	init_maps->type       = MT_VECTORS;
 
 	create_mapping(init_maps);
 
 	flush_cache_all();
+	flush_tlb_all();
 }
 
 /*
  * Create the architecture specific mappings
  */
-void __init iotable_init(struct map_desc *io_desc)
+void __init iotable_init(struct map_desc *io_desc, int nr)
 {
 	int i;
 
-	for (i = 0; io_desc[i].last == 0; i++)
+	for (i = 0; i < nr; i++)
 		create_mapping(io_desc + i);
 }
 
diff -Nru a/arch/cris/drivers/sync_serial.c b/arch/cris/drivers/sync_serial.c
--- a/arch/cris/drivers/sync_serial.c	Sat Jun  8 22:31:36 2002
+++ b/arch/cris/drivers/sync_serial.c	Sat Jun  8 22:31:36 2002
@@ -551,7 +551,8 @@
 	}
 
 	port = &ports[dev];
-	copy_from_user(port->out_buffer, buf, count);
+	if (copy_from_user(port->out_buffer, buf, count))
+		return -EFAULT;
 	port->outp = port->out_buffer;
 	port->out_count = count;
 	port->odd_output = 1;
@@ -597,7 +598,8 @@
 		return sync_serial_manual_write(file, buf, count, ppos); 
 	}
   
-	copy_from_user(port->out_buffer, buf, count);
+	if (copy_from_user(port->out_buffer, buf, count))
+		return -EFAULT;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	start_dma(port, buf, count);
@@ -658,7 +660,8 @@
 		avail = port->in_buffer + IN_BUFFER_SIZE - start;
   
 	count = count > avail ? avail : count;
-	copy_to_user(buf, start, count);
+	if (copy_to_user(buf, start, count))
+		return -EFAULT;
 
 	/* Disable interrupts while updating readp */
 	save_flags(flags);
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/Makefile	Sat Jun  8 22:31:37 2002
@@ -133,6 +133,7 @@
 	@$(MAKEBOOT) BOOTIMAGE=bzImage zdisk
 
 install: vmlinux
+	@echo 'Cleaning up (arch)'
 	@$(MAKEBOOT) BOOTIMAGE=bzImage install
 
 archclean:
diff -Nru a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
--- a/arch/i386/boot/Makefile	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/boot/Makefile	Sat Jun  8 22:31:37 2002
@@ -31,11 +31,11 @@
 		$(TOPDIR)/include/linux/autoconf.h \
 		$(TOPDIR)/include/asm/boot.h
 
-zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
+zImage: bootsect setup compressed/vmlinux tools/build
 	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
 	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
 
-bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
+bzImage: bbootsect bsetup compressed/bvmlinux tools/build
 	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
 	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
 
@@ -48,14 +48,14 @@
 zdisk: $(BOOTIMAGE)
 	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
 
-zlilo: $(CONFIGURE) $(BOOTIMAGE)
+zlilo: $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
 	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
 	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
-install: $(CONFIGURE) $(BOOTIMAGE)
+install: $(BOOTIMAGE)
 	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
 tools/build: tools/build.c
@@ -100,7 +100,8 @@
 dep:
 
 clean:
-	rm -f tools/build
-	rm -f setup bootsect zImage compressed/vmlinux.out
-	rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
+	@echo 'Cleaning up (boot)'
+	@rm -f tools/build
+	@rm -f setup bootsect zImage compressed/vmlinux.out
+	@rm -f bsetup bbootsect bzImage compressed/bvmlinux.out
 	@$(MAKE) -C compressed clean
diff -Nru a/arch/i386/boot/compressed/Makefile b/arch/i386/boot/compressed/Makefile
--- a/arch/i386/boot/compressed/Makefile	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/boot/compressed/Makefile	Sat Jun  8 22:31:36 2002
@@ -47,4 +47,4 @@
 	rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk
 
 clean:
-	rm -f vmlinux bvmlinux _tmp_*
+	@rm -f vmlinux bvmlinux _tmp_*
diff -Nru a/arch/i386/config.in b/arch/i386/config.in
--- a/arch/i386/config.in	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/config.in	Sat Jun  8 22:31:37 2002
@@ -209,9 +209,26 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'General options'
+comment 'Power management options (ACPI, APM)'
 
 source drivers/acpi/Config.in
+bool 'Power Management support' CONFIG_PM
+
+dep_tristate '  Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM
+if [ "$CONFIG_APM" != "n" ]; then
+   bool '    Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
+   bool '    Enable PM at boot time' CONFIG_APM_DO_ENABLE
+   bool '    Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
+   bool '    Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
+   bool '    RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
+   bool '    Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
+   bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
+fi
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Bus options (PCI, PCMCIA, EISA, MCA, ISA)'
 
 # Visual Workstation support is utterly broken.
 # If you want to see it working mail an VW540 to hch@infradead.org 8)
@@ -260,6 +277,11 @@
    define_bool CONFIG_HOTPLUG_PCI n
 fi
 
+endmenu
+
+mainmenu_option next_comment
+comment 'Executable file formats'
+
 if [ "$CONFIG_PROC_FS" = "y" ]; then
    choice 'Kernel core (/proc/kcore) format' \
 	"ELF		CONFIG_KCORE_ELF	\
@@ -268,19 +290,6 @@
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
-
-bool 'Power Management support' CONFIG_PM
-
-dep_tristate '  Advanced Power Management BIOS support' CONFIG_APM $CONFIG_PM
-if [ "$CONFIG_APM" != "n" ]; then
-   bool '    Ignore USER SUSPEND' CONFIG_APM_IGNORE_USER_SUSPEND
-   bool '    Enable PM at boot time' CONFIG_APM_DO_ENABLE
-   bool '    Make CPU Idle calls when idle' CONFIG_APM_CPU_IDLE
-   bool '    Enable console blanking using APM' CONFIG_APM_DISPLAY_BLANK
-   bool '    RTC stores time in GMT' CONFIG_APM_RTC_IS_GMT
-   bool '    Allow interrupts during APM BIOS calls' CONFIG_APM_ALLOW_INTS
-   bool '    Use real mode APM BIOS call to power off' CONFIG_APM_REAL_MODE_POWER_OFF
-fi
 
 endmenu
 
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/kernel/Makefile	Sat Jun  8 22:31:36 2002
@@ -2,7 +2,7 @@
 # Makefile for the linux kernel.
 #
 
-EXTRA_TARGETS := head.o init_task.o
+EXTRA_TARGETS := kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 
@@ -13,7 +13,9 @@
 		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
 		bootflag.o
 
+obj-y				+= cpu/
 obj-$(CONFIG_MCA)		+= mca.o
+obj-$(CONFIG_EISA)		+= eisa.o
 obj-$(CONFIG_MTRR)		+= mtrr.o
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
@@ -24,11 +26,12 @@
 obj-$(CONFIG_SMP)		+= smp.o smpboot.o trampoline.o
 obj-$(CONFIG_X86_LOCAL_APIC)	+= mpparse.o apic.o nmi.o
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspend.o
 ifdef CONFIG_VISWS
 obj-y += setup-visws.o
 obj-$(CONFIG_X86_VISWS_APIC)	+= visws_apic.o
 endif
 
-EXTRA_AFLAGS	:= -traditional
+EXTRA_AFLAGS   := -traditional
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/kernel/bluesmoke.c	Sat Jun  8 22:31:37 2002
@@ -18,8 +18,24 @@
 
 #ifdef CONFIG_X86_MCE
 
+/* as supported by the P4/Xeon family */
+struct intel_mce_extended_msrs {
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+	u32 esi;
+	u32 edi;
+	u32 ebp;
+	u32 esp;
+	u32 eflags;
+	u32 eip;
+	/* u32 *reserved[]; */
+};
+
 static int mce_disabled __initdata = 0;
 
+static int mce_num_extended_msrs = 0;
 static int banks;
 
 
@@ -75,47 +91,73 @@
 	if (!cpu_has(c, X86_FEATURE_ACC))
 		return;	/* -ENODEV */
 
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
 	/* first check if its enabled already, in which case there might
 	 * be some SMM goo which handles it, so we can't even put a handler
 	 * since it might be delivered via SMI already -zwanem.
 	 */
-
-	if (l & (1<<3)) {
-		printk(KERN_DEBUG "CPU#%d: Thermal monitoring already enabled\n", cpu);
-	} else {
-		wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
-		printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	h = apic_read(APIC_LVTTHMR);
+	if ((l & (1<<3)) && (h & APIC_DM_SMI)) {
+		printk(KERN_DEBUG "CPU#%d: Thermal monitoring handled by SMI\n", cpu);
+		return; /* -EBUSY */
 	}
 
-	/* check whether a vector already exists */	
-	l = apic_read(APIC_LVTTHMR);
-	if (l & 0xff) {
-		printk(KERN_DEBUG "CPU#%d: Thermal LVT already handled\n", cpu);
+	/* check whether a vector already exists, temporarily masked? */	
+	if (h & APIC_VECTOR_MASK) {
+		printk(KERN_DEBUG "CPU#%d: Thermal LVT vector (%#x) already installed\n",
+			cpu, (h & APIC_VECTOR_MASK));
 		return; /* -EBUSY */
 	}
 
-	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
-	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
-
 	/* The temperature transition interrupt handler setup */
-	l = THERMAL_APIC_VECTOR;		/* our delivery vector */
-	l |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
-	apic_write_around(APIC_LVTTHMR, l);
+	h = THERMAL_APIC_VECTOR;		/* our delivery vector */
+	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
+	apic_write_around(APIC_LVTTHMR, h);
 
 	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x3 , h);
+	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
 
 	/* ok we're good to go... */
 	vendor_thermal_interrupt = intel_thermal_interrupt;
+	
+	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
+	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+	
 	l = apic_read(APIC_LVTTHMR);
 	apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-
+	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
 	return;
 }
 #endif /* CONFIG_X86_MCE_P4THERMAL */
 
 
+/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
+
+static int inline intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+{
+	u32 h;
+
+	if (mce_num_extended_msrs == 0)
+		goto done;
+
+	rdmsr(MSR_IA32_MCG_EAX, r->eax, h);
+	rdmsr(MSR_IA32_MCG_EBX, r->ebx, h);
+	rdmsr(MSR_IA32_MCG_ECX, r->ecx, h);
+	rdmsr(MSR_IA32_MCG_EDX, r->edx, h);
+	rdmsr(MSR_IA32_MCG_ESI, r->esi, h);
+	rdmsr(MSR_IA32_MCG_EDI, r->edi, h);
+	rdmsr(MSR_IA32_MCG_EBP, r->ebp, h);
+	rdmsr(MSR_IA32_MCG_ESP, r->esp, h);
+	rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h);
+	rdmsr(MSR_IA32_MCG_EIP, r->eip, h);
+
+	/* can we rely on kmalloc to do a dynamic
+	 * allocation for the reserved registers?
+	 */
+done:
+	return mce_num_extended_msrs;
+}
+
 /*
  *	Machine Check Handler For PII/PIII
  */
@@ -126,6 +168,7 @@
 	u32 alow, ahigh, high, low;
 	u32 mcgstl, mcgsth;
 	int i;
+	struct intel_mce_extended_msrs dbg;
 
 	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
 	if(mcgstl&(1<<0))	/* Recoverable ? */
@@ -133,6 +176,15 @@
 
 	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
 
+	if (intel_get_extended_msrs(&dbg)) {
+		printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
+			smp_processor_id(), dbg.eip, dbg.eflags);
+		printk(KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+			dbg.eax, dbg.ebx, dbg.ecx, dbg.edx);
+		printk(KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
+			dbg.esi, dbg.edi, dbg.ebp, dbg.esp);
+	}
+
 	for (i=0;i<banks;i++) {
 		rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
 		if(high&(1<<31)) {
@@ -334,11 +386,24 @@
 	set_in_cr4(X86_CR4_MCE);
 	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
 
+	/*
+	 *	Check for P4/Xeon specific MCE extensions
+	 */
+
+	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15) {
+		/* Check for P4/Xeon extended MCE MSRs */
+		rdmsr(MSR_IA32_MCG_CAP, l, h);
+		if (l & (1<<9))	{/* MCG_EXT_P */
+			mce_num_extended_msrs = (l >> 16) & 0xff;
+			printk(KERN_INFO "CPU#%d: Intel P4/Xeon Extended MCE MSRs (%d) available\n",
+				smp_processor_id(), mce_num_extended_msrs);
+		}
+		
 #ifdef CONFIG_X86_MCE_P4THERMAL
-	/* Only enable thermal throttling warning on Pentium 4. */
-	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15)
+		/* Check for P4/Xeon Thermal monitor */
 		intel_init_thermal(c);
 #endif
+	}
 
 	done=1;
 }
diff -Nru a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/Makefile	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,16 @@
+#
+# Makefile for x86-compatible CPU details and quirks
+#
+
+obj-y	:=	common.o proc.o
+
+obj-y	+=	amd.o
+obj-y	+=	cyrix.o
+obj-y	+=	centaur.o
+obj-y	+=	transmeta.o
+obj-y	+=	intel.o
+obj-y	+=	rise.o
+obj-y	+=	nexgen.o
+obj-y	+=	umc.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/amd.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,217 @@
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+/*
+ *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
+ *	misexecution of code under Linux. Owners of such processors should
+ *	contact AMD for precise details and a CPU swap.
+ *
+ *	See	http://www.multimania.com/poulot/k6bug.html
+ *		http://www.amd.com/K6/k6docs/revgd.html
+ *
+ *	The following test is erm.. interesting. AMD neglected to up
+ *	the chip setting when fixing the bug but they also tweaked some
+ *	performance at the same time..
+ */
+ 
+extern void vide(void);
+__asm__(".align 4\nvide: ret");
+
+static void __init init_amd(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int mbytes = max_mapnr >> (20-PAGE_SHIFT);
+	int r;
+
+	/*
+	 *	FIXME: We should handle the K5 here. Set up the write
+	 *	range and also turn on MSR 83 bits 4 and 31 (write alloc,
+	 *	no bus pipeline)
+	 */
+
+	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+	clear_bit(0*32+31, c->x86_capability);
+	
+	r = get_model_name(c);
+
+	switch(c->x86)
+	{
+		case 5:
+			if( c->x86_model < 6 )
+			{
+				/* Based on AMD doc 20734R - June 2000 */
+				if ( c->x86_model == 0 ) {
+					clear_bit(X86_FEATURE_APIC, c->x86_capability);
+					set_bit(X86_FEATURE_PGE, c->x86_capability);
+				}
+				break;
+			}
+			
+			if ( c->x86_model == 6 && c->x86_mask == 1 ) {
+				const int K6_BUG_LOOP = 1000000;
+				int n;
+				void (*f_vide)(void);
+				unsigned long d, d2;
+				
+				printk(KERN_INFO "AMD K6 stepping B detected - ");
+				
+				/*
+				 * It looks like AMD fixed the 2.6.2 bug and improved indirect 
+				 * calls at the same time.
+				 */
+
+				n = K6_BUG_LOOP;
+				f_vide = vide;
+				rdtscl(d);
+				while (n--) 
+					f_vide();
+				rdtscl(d2);
+				d = d2-d;
+				
+				/* Knock these two lines out if it debugs out ok */
+				printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
+				printk(KERN_INFO "AMD K6 stepping B detected - ");
+				/* -- cut here -- */
+				if (d > 20*K6_BUG_LOOP) 
+					printk("system stability may be impaired when more than 32 MB are used.\n");
+				else 
+					printk("probably OK (after B9730xxxx).\n");
+				printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
+			}
+
+			/* K6 with old style WHCR */
+			if (c->x86_model < 8 ||
+			   (c->x86_model== 8 && c->x86_mask < 8)) {
+				/* We can only write allocate on the low 508Mb */
+				if(mbytes>508)
+					mbytes=508;
+
+				rdmsr(MSR_K6_WHCR, l, h);
+				if ((l&0x0000FFFF)==0) {
+					unsigned long flags;
+					l=(1<<0)|((mbytes/4)<<1);
+					local_irq_save(flags);
+					wbinvd();
+					wrmsr(MSR_K6_WHCR, l, h);
+					local_irq_restore(flags);
+					printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
+						mbytes);
+				}
+				break;
+			}
+
+			if ((c->x86_model == 8 && c->x86_mask >7) ||
+			     c->x86_model == 9 || c->x86_model == 13) {
+				/* The more serious chips .. */
+
+				if(mbytes>4092)
+					mbytes=4092;
+
+				rdmsr(MSR_K6_WHCR, l, h);
+				if ((l&0xFFFF0000)==0) {
+					unsigned long flags;
+					l=((mbytes>>2)<<22)|(1<<16);
+					local_irq_save(flags);
+					wbinvd();
+					wrmsr(MSR_K6_WHCR, l, h);
+					local_irq_restore(flags);
+					printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
+						mbytes);
+				}
+
+				/*  Set MTRR capability flag if appropriate */
+				if (c->x86_model == 13 || c->x86_model == 9 ||
+				   (c->x86_model == 8 && c->x86_mask >= 8))
+					set_bit(X86_FEATURE_K6_MTRR, c->x86_capability);
+				break;
+			}
+			break;
+
+		case 6: /* An Athlon/Duron */
+ 
+			/* Bit 15 of Athlon specific MSR 15, needs to be 0
+ 			 * to enable SSE on Palomino/Morgan CPU's.
+			 * If the BIOS didn't enable it already, enable it
+			 * here.
+			 */
+			if (c->x86_model == 6 || c->x86_model == 7) {
+				if (!test_bit(X86_FEATURE_XMM, c->x86_capability)) {
+					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
+					rdmsr(MSR_K7_HWCR, l, h);
+					l &= ~0x00008000;
+					wrmsr(MSR_K7_HWCR, l, h);
+					set_bit(X86_FEATURE_XMM, c->x86_capability);
+				}
+			}
+			break;
+
+	}
+
+	display_cacheinfo(c);
+//	return r;
+}
+
+static void amd_identify(struct cpuinfo_x86 * c)
+{
+	u32 xlvl;
+
+	if (have_cpuid_p()) {
+		generic_identify(c);
+
+		/* AMD-defined flags: level 0x80000001 */
+		xlvl = cpuid_eax(0x80000000);
+		if ( (xlvl & 0xffff0000) == 0x80000000 ) {
+			if ( xlvl >= 0x80000001 )
+				c->x86_capability[1] = cpuid_edx(0x80000001);
+			if ( xlvl >= 0x80000004 )
+				get_model_name(c); /* Default name */
+		}
+	}
+}
+
+static unsigned int amd_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+{
+	/* AMD errata T13 (order #21922) */
+	if ((c->x86 == 6)) {
+		if (c->x86_model == 3 && c->x86_mask == 0)	/* Duron Rev A0 */
+			size = 64;
+		if (c->x86_model == 4 &&
+		    (c->x86_mask==0 || c->x86_mask==1))	/* Tbird rev A1/A2 */
+			size = 256;
+	}
+	return size;
+}
+
+static struct cpu_dev amd_cpu_dev __initdata = {
+	c_vendor:	"AMD",
+	c_ident: 	{ "AuthenticAMD" },
+	c_models: {
+		{ X86_VENDOR_AMD,	4,
+		  {
+			  [3] "486 DX/2",
+			  [7] "486 DX/2-WB",
+			  [8] "486 DX/4", 
+			  [9] "486 DX/4-WB", 
+			  [14] "Am5x86-WT",
+			  [15] "Am5x86-WB" 
+		  }
+		},
+	},
+	c_init:		init_amd,
+	c_identify:	amd_identify,
+	c_size_cache:	amd_size_cache,
+};
+
+int __init amd_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_AMD] = &amd_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(amd_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/centaur.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,426 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include "cpu.h"
+
+#ifdef CONFIG_X86_OOSTORE
+
+static u32 __init power2(u32 x)
+{
+	u32 s=1;
+	while(s<=x)
+		s<<=1;
+	return s>>=1;
+}
+
+
+/*
+ *	Set up an actual MCR
+ */
+ 
+static void __init centaur_mcr_insert(int reg, u32 base, u32 size, int key)
+{
+	u32 lo, hi;
+	
+	hi = base & ~0xFFF;
+	lo = ~(size-1);		/* Size is a power of 2 so this makes a mask */
+	lo &= ~0xFFF;		/* Remove the ctrl value bits */
+	lo |= key;		/* Attribute we wish to set */
+	wrmsr(reg+MSR_IDT_MCR0, lo, hi);
+	mtrr_centaur_report_mcr(reg, lo, hi);	/* Tell the mtrr driver */
+}
+
+/*
+ *	Figure what we can cover with MCR's
+ *
+ *	Shortcut: We know you can't put 4Gig of RAM on a winchip
+ */
+
+static u32 __init ramtop(void)		/* 16388 */
+{
+	int i;
+	u32 top = 0;
+	u32 clip = 0xFFFFFFFFUL;
+	
+	for (i = 0; i < e820.nr_map; i++) {
+		unsigned long start, end;
+
+		if (e820.map[i].addr > 0xFFFFFFFFUL)
+			continue;
+		/*
+		 *	Don't MCR over reserved space. Ignore the ISA hole
+		 *	we frob around that catastrophy already
+		 */
+		 			
+		if (e820.map[i].type == E820_RESERVED)
+		{
+			if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip)
+				clip = e820.map[i].addr;
+			continue;
+		}
+		start = e820.map[i].addr;
+		end = e820.map[i].addr + e820.map[i].size;
+		if (start >= end)
+			continue;
+		if (end > top)
+			top = end;
+	}
+	/* Everything below 'top' should be RAM except for the ISA hole.
+	   Because of the limited MCR's we want to map NV/ACPI into our
+	   MCR range for gunk in RAM 
+	   
+	   Clip might cause us to MCR insufficient RAM but that is an
+	   acceptable failure mode and should only bite obscure boxes with
+	   a VESA hole at 15Mb
+	   
+	   The second case Clip sometimes kicks in is when the EBDA is marked
+	   as reserved. Again we fail safe with reasonable results
+	*/
+	
+	if(top>clip)
+		top=clip;
+		
+	return top;
+}
+
+/*
+ *	Compute a set of MCR's to give maximum coverage
+ */
+
+static int __init centaur_mcr_compute(int nr, int key)
+{
+	u32 mem = ramtop();
+	u32 root = power2(mem);
+	u32 base = root;
+	u32 top = root;
+	u32 floor = 0;
+	int ct = 0;
+	
+	while(ct<nr)
+	{
+		u32 fspace = 0;
+
+		/*
+		 *	Find the largest block we will fill going upwards
+		 */
+
+		u32 high = power2(mem-top);	
+
+		/*
+		 *	Find the largest block we will fill going downwards
+		 */
+
+		u32 low = base/2;
+
+		/*
+		 *	Don't fill below 1Mb going downwards as there
+		 *	is an ISA hole in the way.
+		 */		
+		 
+		if(base <= 1024*1024)
+			low = 0;
+			
+		/*
+		 *	See how much space we could cover by filling below
+		 *	the ISA hole
+		 */
+		 
+		if(floor == 0)
+			fspace = 512*1024;
+		else if(floor ==512*1024)
+			fspace = 128*1024;
+
+		/* And forget ROM space */
+		
+		/*
+		 *	Now install the largest coverage we get
+		 */
+		 
+		if(fspace > high && fspace > low)
+		{
+			centaur_mcr_insert(ct, floor, fspace, key);
+			floor += fspace;
+		}
+		else if(high > low)
+		{
+			centaur_mcr_insert(ct, top, high, key);
+			top += high;
+		}
+		else if(low > 0)
+		{
+			base -= low;
+			centaur_mcr_insert(ct, base, low, key);
+		}
+		else break;
+		ct++;
+	}
+	/*
+	 *	We loaded ct values. We now need to set the mask. The caller
+	 *	must do this bit.
+	 */
+	 
+	return ct;
+}
+
+static void __init centaur_create_optimal_mcr(void)
+{
+	int i;
+	/*
+	 *	Allocate up to 6 mcrs to mark as much of ram as possible
+	 *	as write combining and weak write ordered.
+	 *
+	 *	To experiment with: Linux never uses stack operations for 
+	 *	mmio spaces so we could globally enable stack operation wc
+	 *
+	 *	Load the registers with type 31 - full write combining, all
+	 *	writes weakly ordered.
+	 */
+	int used = centaur_mcr_compute(6, 31);
+
+	/*
+	 *	Wipe unused MCRs
+	 */
+	 
+	for(i=used;i<8;i++)
+		wrmsr(MSR_IDT_MCR0+i, 0, 0);
+}
+
+static void __init winchip2_create_optimal_mcr(void)
+{
+	u32 lo, hi;
+	int i;
+
+	/*
+	 *	Allocate up to 6 mcrs to mark as much of ram as possible
+	 *	as write combining, weak store ordered.
+	 *
+	 *	Load the registers with type 25
+	 *		8	-	weak write ordering
+	 *		16	-	weak read ordering
+	 *		1	-	write combining
+	 */
+
+	int used = centaur_mcr_compute(6, 25);
+	
+	/*
+	 *	Mark the registers we are using.
+	 */
+	 
+	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+	for(i=0;i<used;i++)
+		lo|=1<<(9+i);
+	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+	
+	/*
+	 *	Wipe unused MCRs
+	 */
+	 
+	for(i=used;i<8;i++)
+		wrmsr(MSR_IDT_MCR0+i, 0, 0);
+}
+
+/*
+ *	Handle the MCR key on the Winchip 2.
+ */
+
+static void __init winchip2_unprotect_mcr(void)
+{
+	u32 lo, hi;
+	u32 key;
+	
+	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+	lo&=~0x1C0;	/* blank bits 8-6 */
+	key = (lo>>17) & 7;
+	lo |= key<<6;	/* replace with unlock key */
+	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+}
+
+static void __init winchip2_protect_mcr(void)
+{
+	u32 lo, hi;
+	
+	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+	lo&=~0x1C0;	/* blank bits 8-6 */
+	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+}
+#endif
+
+static void __init init_centaur(struct cpuinfo_x86 *c)
+{
+	enum {
+		ECX8=1<<1,
+		EIERRINT=1<<2,
+		DPM=1<<3,
+		DMCE=1<<4,
+		DSTPCLK=1<<5,
+		ELINEAR=1<<6,
+		DSMC=1<<7,
+		DTLOCK=1<<8,
+		EDCTLB=1<<8,
+		EMMX=1<<9,
+		DPDC=1<<11,
+		EBRPRED=1<<12,
+		DIC=1<<13,
+		DDC=1<<14,
+		DNA=1<<15,
+		ERETSTK=1<<16,
+		E2MMX=1<<19,
+		EAMD3D=1<<20,
+	};
+
+	char *name;
+	u32  fcr_set=0;
+	u32  fcr_clr=0;
+	u32  lo,hi,newlo;
+	u32  aa,bb,cc,dd;
+
+	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+	clear_bit(0*32+31, c->x86_capability);
+
+	switch (c->x86) {
+
+		case 5:
+			switch(c->x86_model) {
+			case 4:
+				name="C6";
+				fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
+				fcr_clr=DPDC;
+				printk(KERN_NOTICE "Disabling bugged TSC.\n");
+				clear_bit(X86_FEATURE_TSC, c->x86_capability);
+#ifdef CONFIG_X86_OOSTORE
+				centaur_create_optimal_mcr();
+				/* Enable
+					write combining on non-stack, non-string
+					write combining on string, all types
+					weak write ordering 
+					
+				   The C6 original lacks weak read order 
+				   
+				   Note 0x120 is write only on Winchip 1 */
+				   
+				wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
+#endif				
+				break;
+			case 8:
+				switch(c->x86_mask) {
+				default:
+					name="2";
+					break;
+				case 7 ... 9:
+					name="2A";
+					break;
+				case 10 ... 15:
+					name="2B";
+					break;
+				}
+				fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D;
+				fcr_clr=DPDC;
+#ifdef CONFIG_X86_OOSTORE
+				winchip2_unprotect_mcr();
+				winchip2_create_optimal_mcr();
+				rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+				/* Enable
+					write combining on non-stack, non-string
+					write combining on string, all types
+					weak write ordering 
+				*/
+				lo|=31;				
+				wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+				winchip2_protect_mcr();
+#endif
+				break;
+			case 9:
+				name="3";
+				fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D;
+				fcr_clr=DPDC;
+#ifdef CONFIG_X86_OOSTORE
+				winchip2_unprotect_mcr();
+				winchip2_create_optimal_mcr();
+				rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
+				/* Enable
+					write combining on non-stack, non-string
+					write combining on string, all types
+					weak write ordering 
+				*/
+				lo|=31;				
+				wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
+				winchip2_protect_mcr();
+#endif
+				break;
+			case 10:
+				name="4";
+				/* no info on the WC4 yet */
+				break;
+			default:
+				name="??";
+			}
+
+			rdmsr(MSR_IDT_FCR1, lo, hi);
+			newlo=(lo|fcr_set) & (~fcr_clr);
+
+			if (newlo!=lo) {
+				printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo );
+				wrmsr(MSR_IDT_FCR1, newlo, hi );
+			} else {
+				printk(KERN_INFO "Centaur FCR is 0x%X\n",lo);
+			}
+			/* Emulate MTRRs using Centaur's MCR. */
+			set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability);
+			/* Report CX8 */
+			set_bit(X86_FEATURE_CX8, c->x86_capability);
+			/* Set 3DNow! on Winchip 2 and above. */
+			if (c->x86_model >=8)
+				set_bit(X86_FEATURE_3DNOW, c->x86_capability);
+			/* See if we can find out some more. */
+			if ( cpuid_eax(0x80000000) >= 0x80000005 ) {
+				/* Yes, we can. */
+				cpuid(0x80000005,&aa,&bb,&cc,&dd);
+				/* Add L1 data and code cache sizes. */
+				c->x86_cache_size = (cc>>24)+(dd>>24);
+			}
+			sprintf( c->x86_model_id, "WinChip %s", name );
+			break;
+
+		case 6:
+			switch (c->x86_model) {
+				case 6 ... 8:		/* Cyrix III family */
+					rdmsr (MSR_VIA_FCR, lo, hi);
+					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
+					wrmsr (MSR_VIA_FCR, lo, hi);
+
+					set_bit(X86_FEATURE_CX8, c->x86_capability);
+					set_bit(X86_FEATURE_3DNOW, c->x86_capability);
+
+					get_model_name(c);
+					display_cacheinfo(c);
+					break;
+			}
+			break;
+	}
+}
+
+static unsigned int centaur_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+{
+	/* VIA C3 CPUs (670-68F) need further shifting. */
+	if ((c->x86 == 6) && ((c->x86_model == 7) || (c->x86_model == 8)))
+		size >>= 8;
+	return size;
+}
+
+static struct cpu_dev centaur_cpu_dev __initdata = {
+	c_vendor:	"Centaur",
+	c_ident:	{ "CentaurHauls" },
+	c_init:		init_centaur,
+	c_size_cache:	centaur_size_cache,
+};
+
+int __init centaur_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(centaur_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/changelog b/arch/i386/kernel/cpu/changelog
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/changelog	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,63 @@
+/*
+ *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
+ *  and Martin Mares, November 1997.
+ *
+ *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
+ *  and Cyrix "coma bug" recognition by
+ *  Zoltán Böszörményi <zboszor@mail.externet.hu> February 1999.
+ * 
+ *  Force Centaur C6 processors to report MTRR capability.
+ *  Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999.
+ *
+ *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
+ *
+ *  IDT Winchip tweaks, misc clean ups.
+ *  Dave Jones <davej@suse.de>, August 1999
+ *
+ *  Better detection of Centaur/IDT WinChip models.
+ *  Bart Hartgers <bart@etpmod.phys.tue.nl>, August 1999.
+ *
+ *  Cleaned up cache-detection code
+ *  Dave Jones <davej@suse.de>, October 1999
+ *
+ *  Added proper L2 cache detection for Coppermine
+ *  Dragan Stancevic <visitor@valinux.com>, October 1999
+ *
+ *  Added the original array for capability flags but forgot to credit 
+ *  myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff
+ *  Jauder Ho <jauderho@carumba.com>, January 2000
+ *
+ *  Detection for Celeron coppermine, identify_cpu() overhauled,
+ *  and a few other clean ups.
+ *  Dave Jones <davej@suse.de>, April 2000
+ *
+ *  Pentium III FXSR, SSE support
+ *  General FPU state handling cleanups
+ *  Gareth Hughes <gareth@valinux.com>, May 2000
+ *
+ *  Added proper Cascades CPU and L2 cache detection for Cascades
+ *  and 8-way type cache happy bunch from Intel:^)
+ *  Dragan Stancevic <visitor@valinux.com>, May 2000 
+ *
+ *  Forward port AMD Duron errata T13 from 2.2.17pre
+ *  Dave Jones <davej@suse.de>, August 2000
+ *
+ *  Forward port lots of fixes/improvements from 2.2.18pre
+ *  Cyrix III, Pentium IV support.
+ *  Dave Jones <davej@suse.de>, October 2000
+ *
+ *  Massive cleanup of CPU detection and bug handling;
+ *  Transmeta CPU detection,
+ *  H. Peter Anvin <hpa@zytor.com>, November 2000
+ *
+ *  VIA C3 Support.
+ *  Dave Jones <davej@suse.de>, March 2001
+ *
+ *  AMD Athlon/Duron/Thunderbird bluesmoke support.
+ *  Dave Jones <davej@suse.de>, April 2001.
+ *
+ *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
+ *  Dave Jones <davej@suse.de>, September, October 2001.
+ *
+ */
+
diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/common.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,486 @@
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <asm/semaphore.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/io.h>
+#include <asm/mmu_context.h>
+
+#include "cpu.h"
+
+static int cachesize_override __initdata = -1;
+static int disable_x86_fxsr __initdata = 0;
+
+struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
+
+static struct cpu_dev default_cpu;
+static struct cpu_dev * this_cpu = &default_cpu;
+
+extern void mcheck_init(struct cpuinfo_x86 *c);
+
+static void default_init(struct cpuinfo_x86 * c)
+{
+	/* Not much we can do here... */
+	/* Check if at least it has cpuid */
+	if (c->cpuid_level == -1) {
+		/* No cpuid. It must be an ancient CPU */
+		if (c->x86 == 4)
+			strcpy(c->x86_model_id, "486");
+		else if (c->x86 == 3)
+			strcpy(c->x86_model_id, "386");
+	}
+}
+
+static struct cpu_dev default_cpu = {
+	c_init:	default_init,
+};
+
+static int __init cachesize_setup(char *str)
+{
+	get_option (&str, &cachesize_override);
+	return 1;
+}
+__setup("cachesize=", cachesize_setup);
+
+#ifndef CONFIG_X86_TSC
+static int tsc_disable __initdata = 0;
+
+static int __init tsc_setup(char *str)
+{
+	tsc_disable = 1;
+	return 1;
+}
+
+__setup("notsc", tsc_setup);
+#endif
+
+int __init get_model_name(struct cpuinfo_x86 *c)
+{
+	unsigned int *v;
+	char *p, *q;
+
+	if (cpuid_eax(0x80000000) < 0x80000004)
+		return 0;
+
+	v = (unsigned int *) c->x86_model_id;
+	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
+	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
+	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
+	c->x86_model_id[48] = 0;
+
+	/* Intel chips right-justify this string for some dumb reason;
+	   undo that brain damage */
+	p = q = &c->x86_model_id[0];
+	while ( *p == ' ' )
+	     p++;
+	if ( p != q ) {
+	     while ( *p )
+		  *q++ = *p++;
+	     while ( q <= &c->x86_model_id[48] )
+		  *q++ = '\0';	/* Zero-pad the rest */
+	}
+
+	return 1;
+}
+
+
+void __init display_cacheinfo(struct cpuinfo_x86 *c)
+{
+	unsigned int n, dummy, ecx, edx, l2size;
+
+	n = cpuid_eax(0x80000000);
+
+	if (n >= 0x80000005) {
+		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
+			edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
+		c->x86_cache_size=(ecx>>24)+(edx>>24);	
+	}
+
+	if (n < 0x80000006)	/* Some chips just has a large L1. */
+		return;
+
+	ecx = cpuid_ecx(0x80000006);
+	l2size = ecx >> 16;
+	
+	/* do processor-specific cache resizing */
+	if (this_cpu->c_size_cache)
+		l2size = this_cpu->c_size_cache(c,l2size);
+
+	/* Allow user to override all this if necessary. */
+	if (cachesize_override != -1)
+		l2size = cachesize_override;
+
+	if ( l2size == 0 )
+		return;		/* Again, no L2 cache is possible */
+
+	c->x86_cache_size = l2size;
+
+	printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
+	       l2size, ecx & 0xFF);
+}
+
+/* Naming convention should be: <Name> [(<Codename>)] */
+/* This table only is used unless init_<vendor>() below doesn't set it; */
+/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
+
+/* Look up CPU names by table lookup. */
+static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+{
+	struct cpu_model_info *info;
+
+	if ( c->x86_model >= 16 )
+		return NULL;	/* Range check */
+
+	if (!this_cpu)
+		return NULL;
+
+	info = this_cpu->c_models;
+
+	while (info && info->family) {
+		if (info->family == c->x86)
+			return info->model_names[c->x86_model];
+		info++;
+	}
+	return NULL;		/* Not found */
+}
+
+
+
+void __init get_cpu_vendor(struct cpuinfo_x86 *c)
+{
+	char *v = c->x86_vendor_id;
+	int i;
+
+	for (i = 0; i < X86_VENDOR_NUM; i++) {
+		if (cpu_devs[i]) {
+			if (!strcmp(v,cpu_devs[i]->c_ident[0]) ||
+			    (cpu_devs[i]->c_ident[1] && 
+			     !strcmp(v,cpu_devs[i]->c_ident[1]))) {
+				c->x86_vendor = i;
+				this_cpu = cpu_devs[i];
+				break;
+			}
+		}
+	}
+}
+
+
+static int __init x86_fxsr_setup(char * s)
+{
+	disable_x86_fxsr = 1;
+	return 1;
+}
+__setup("nofxsr", x86_fxsr_setup);
+
+
+/* Standard macro to see if a specific flag is changeable */
+static inline int flag_is_changeable_p(u32 flag)
+{
+	u32 f1, f2;
+
+	asm("pushfl\n\t"
+	    "pushfl\n\t"
+	    "popl %0\n\t"
+	    "movl %0,%1\n\t"
+	    "xorl %2,%0\n\t"
+	    "pushl %0\n\t"
+	    "popfl\n\t"
+	    "pushfl\n\t"
+	    "popl %0\n\t"
+	    "popfl\n\t"
+	    : "=&r" (f1), "=&r" (f2)
+	    : "ir" (flag));
+
+	return ((f1^f2) & flag) != 0;
+}
+
+
+/* Probe for the CPUID instruction */
+int __init have_cpuid_p(void)
+{
+	return flag_is_changeable_p(X86_EFLAGS_ID);
+}
+
+void __init generic_identify(struct cpuinfo_x86 * c)
+{
+	u32 tfms;
+	int junk;
+
+	if (have_cpuid_p()) {
+		/* Get vendor name */
+		cpuid(0x00000000, &c->cpuid_level,
+		      (int *)&c->x86_vendor_id[0],
+		      (int *)&c->x86_vendor_id[8],
+		      (int *)&c->x86_vendor_id[4]);
+		
+		get_cpu_vendor(c);
+		/* Initialize the standard set of capabilities */
+		/* Note that the vendor-specific code below might override */
+	
+		/* Intel-defined flags: level 0x00000001 */
+		if ( c->cpuid_level >= 0x00000001 ) {
+			u32 capability;
+			cpuid(0x00000001, &tfms, &junk, &junk, &capability);
+			c->x86_capability[0] = capability;
+			c->x86 = (tfms >> 8) & 15;
+			c->x86_model = (tfms >> 4) & 15;
+			c->x86_mask = tfms & 15;
+		} else {
+			/* Have CPUID level 0 only - unheard of */
+			c->x86 = 4;
+		}
+	}
+}
+
+/*
+ * This does the hard work of actually picking apart the CPU stuff...
+ */
+void __init identify_cpu(struct cpuinfo_x86 *c)
+{
+	int i;
+
+	c->loops_per_jiffy = loops_per_jiffy;
+	c->x86_cache_size = -1;
+	c->x86_vendor = X86_VENDOR_UNKNOWN;
+	c->cpuid_level = -1;	/* CPUID not detected */
+	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
+	c->x86_vendor_id[0] = '\0'; /* Unset */
+	c->x86_model_id[0] = '\0';  /* Unset */
+	memset(&c->x86_capability, 0, sizeof c->x86_capability);
+
+	if (!have_cpuid_p()) {
+		/* First of all, decide if this is a 486 or higher */
+		/* It's a 486 if we can modify the AC flag */
+		if ( flag_is_changeable_p(X86_EFLAGS_AC) )
+			c->x86 = 4;
+		else
+			c->x86 = 3;
+	}
+
+	if (this_cpu->c_identify)
+		this_cpu->c_identify(c);
+	else
+		generic_identify(c);
+
+	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08lx %08lx %08lx, vendor = %d\n",
+	       c->x86_capability[0],
+	       c->x86_capability[1],
+	       c->x86_capability[2],
+	       c->x86_vendor);
+
+	/*
+	 * Vendor-specific initialization.  In this section we
+	 * canonicalize the feature flags, meaning if there are
+	 * features a certain CPU supports which CPUID doesn't
+	 * tell us, CPUID claiming incorrect flags, or other bugs,
+	 * we handle them here.
+	 *
+	 * At the end of this section, c->x86_capability better
+	 * indicate the features this CPU genuinely supports!
+	 */
+	if (this_cpu->c_init)
+		this_cpu->c_init(c);
+
+	printk(KERN_DEBUG "CPU: After vendor init, caps: %08lx %08lx %08lx %08lx\n",
+	       c->x86_capability[0],
+	       c->x86_capability[1],
+	       c->x86_capability[2],
+	       c->x86_capability[3]);
+
+	/*
+	 * The vendor-specific functions might have changed features.  Now
+	 * we do "generic changes."
+	 */
+
+	/* TSC disabled? */
+#ifndef CONFIG_X86_TSC
+	if ( tsc_disable )
+		clear_bit(X86_FEATURE_TSC, c->x86_capability);
+#endif
+
+	/* FXSR disabled? */
+	if (disable_x86_fxsr) {
+		clear_bit(X86_FEATURE_FXSR, c->x86_capability);
+		clear_bit(X86_FEATURE_XMM, c->x86_capability);
+	}
+
+	/* Init Machine Check Exception if available. */
+	mcheck_init(c);
+
+	/* If the model name is still unset, do table lookup. */
+	if ( !c->x86_model_id[0] ) {
+		char *p;
+		p = table_lookup_model(c);
+		if ( p )
+			strcpy(c->x86_model_id, p);
+		else
+			/* Last resort... */
+			sprintf(c->x86_model_id, "%02x/%02x",
+				c->x86_vendor, c->x86_model);
+	}
+
+	/* Now the feature flags better reflect actual CPU features! */
+
+	printk(KERN_DEBUG "CPU:     After generic, caps: %08lx %08lx %08lx %08lx\n",
+	       c->x86_capability[0],
+	       c->x86_capability[1],
+	       c->x86_capability[2],
+	       c->x86_capability[3]);
+
+	/*
+	 * On SMP, boot_cpu_data holds the common feature set between
+	 * all CPUs; so make sure that we indicate which features are
+	 * common between the CPUs.  The first time this routine gets
+	 * executed, c == &boot_cpu_data.
+	 */
+	if ( c != &boot_cpu_data ) {
+		/* AND the already accumulated flags with these */
+		for ( i = 0 ; i < NCAPINTS ; i++ )
+			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
+	}
+
+	printk(KERN_DEBUG "CPU:             Common caps: %08lx %08lx %08lx %08lx\n",
+	       boot_cpu_data.x86_capability[0],
+	       boot_cpu_data.x86_capability[1],
+	       boot_cpu_data.x86_capability[2],
+	       boot_cpu_data.x86_capability[3]);
+}
+/*
+ *	Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
+ */
+ 
+void __init dodgy_tsc(void)
+{
+	get_cpu_vendor(&boot_cpu_data);
+	if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
+	    ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC   ))
+		cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data);
+}
+
+void __init print_cpu_info(struct cpuinfo_x86 *c)
+{
+	char *vendor = NULL;
+
+	if (c->x86_vendor < X86_VENDOR_NUM)
+		vendor = this_cpu->c_vendor;
+	else if (c->cpuid_level >= 0)
+		vendor = c->x86_vendor_id;
+
+	if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
+		printk("%s ", vendor);
+
+	if (!c->x86_model_id[0])
+		printk("%d86", c->x86);
+	else
+		printk("%s", c->x86_model_id);
+
+	if (c->x86_mask || c->cpuid_level >= 0) 
+		printk(" stepping %02x\n", c->x86_mask);
+	else
+		printk("\n");
+}
+
+unsigned long cpu_initialized __initdata = 0;
+
+/* This is hacky. :)
+ * We're emulating future behavior.
+ * In the future, the cpu-specific init functions will be called implicitly
+ * via the magic of initcalls.
+ * They will insert themselves into the cpu_devs structure.
+ * Then, when cpu_init() is called, we can just iterate over that array.
+ */
+
+extern int intel_cpu_init(void);
+extern int cyrix_init_cpu(void);
+extern int nsc_init_cpu(void);
+extern int amd_init_cpu(void);
+extern int centaur_init_cpu(void);
+extern int transmeta_init_cpu(void);
+extern int rise_init_cpu(void);
+extern int nexgen_init_cpu(void);
+extern int umc_init_cpu(void);
+
+void __init early_cpu_init(void)
+{
+	intel_cpu_init();
+	cyrix_init_cpu();
+	nsc_init_cpu();
+	amd_init_cpu();
+	centaur_init_cpu();
+	transmeta_init_cpu();
+	rise_init_cpu();
+	nexgen_init_cpu();
+	umc_init_cpu();
+}
+/*
+ * cpu_init() initializes state that is per-CPU. Some data is already
+ * initialized (naturally) in the bootstrap process, such as the GDT
+ * and IDT. We reload them nevertheless, this function acts as a
+ * 'CPU state barrier', nothing should get across.
+ */
+void __init cpu_init (void)
+{
+	int nr = smp_processor_id();
+	struct tss_struct * t = &init_tss[nr];
+
+	if (test_and_set_bit(nr, &cpu_initialized)) {
+		printk(KERN_WARNING "CPU#%d already initialized!\n", nr);
+		for (;;) __sti();
+	}
+	printk(KERN_INFO "Initializing CPU#%d\n", nr);
+
+	if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
+		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
+#ifndef CONFIG_X86_TSC
+	if (tsc_disable && cpu_has_tsc) {
+		printk(KERN_NOTICE "Disabling TSC...\n");
+		/**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
+		clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
+		set_in_cr4(X86_CR4_TSD);
+	}
+#endif
+
+	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
+	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
+
+	/*
+	 * Delete NT
+	 */
+	__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+
+	/*
+	 * set up and load the per-CPU TSS and LDT
+	 */
+	atomic_inc(&init_mm.mm_count);
+	current->active_mm = &init_mm;
+	if(current->mm)
+		BUG();
+	enter_lazy_tlb(&init_mm, current, nr);
+
+	t->esp0 = current->thread.esp0;
+	set_tss_desc(nr,t);
+	gdt_table[__TSS(nr)].b &= 0xfffffdff;
+	load_TR(nr);
+	load_LDT(&init_mm.context);
+
+	/* Clear %fs and %gs. */
+	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
+
+	/* Clear all 6 debug registers: */
+
+#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
+
+	CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
+
+#undef CD
+
+	/*
+	 * Force FPU initialization:
+	 */
+	clear_thread_flag(TIF_USEDFPU);
+	current->used_math = 0;
+	stts();
+}
diff -Nru a/arch/i386/kernel/cpu/cpu.h b/arch/i386/kernel/cpu/cpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cpu.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,28 @@
+
+struct cpu_model_info {
+	int vendor;
+	int family;
+	char *model_names[16];
+};
+
+/* attempt to consolidate cpu attributes */
+struct cpu_dev {
+	char	* c_vendor;
+
+	/* some have two possibilities for cpuid string */
+	char	* c_ident[2];	
+
+	struct		cpu_model_info c_models[4];
+
+	void		(*c_init)(struct cpuinfo_x86 * c);
+	void		(*c_identify)(struct cpuinfo_x86 * c);
+	unsigned int	(*c_size_cache)(struct cpuinfo_x86 * c, unsigned int size);
+};
+
+extern struct cpu_dev * cpu_devs [X86_VENDOR_NUM];
+
+extern int get_model_name(struct cpuinfo_x86 *c);
+extern void display_cacheinfo(struct cpuinfo_x86 *c);
+
+extern void generic_identify(struct cpuinfo_x86 * c);
+extern int have_cpuid_p(void);
diff -Nru a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/cyrix.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,352 @@
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+/*
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ */
+void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+{
+	unsigned char ccr2, ccr3;
+	unsigned long flags;
+	
+	/* we test for DEVID by checking whether CCR3 is writable */
+	local_irq_save(flags);
+	ccr3 = getCx86(CX86_CCR3);
+	setCx86(CX86_CCR3, ccr3 ^ 0x80);
+	getCx86(0xc0);   /* dummy to change bus */
+
+	if (getCx86(CX86_CCR3) == ccr3) {       /* no DEVID regs. */
+		ccr2 = getCx86(CX86_CCR2);
+		setCx86(CX86_CCR2, ccr2 ^ 0x04);
+		getCx86(0xc0);  /* dummy */
+
+		if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
+			*dir0 = 0xfd;
+		else {                          /* Cx486S A step */
+			setCx86(CX86_CCR2, ccr2);
+			*dir0 = 0xfe;
+		}
+	}
+	else {
+		setCx86(CX86_CCR3, ccr3);  /* restore CCR3 */
+
+		/* read DIR0 and DIR1 CPU registers */
+		*dir0 = getCx86(CX86_DIR0);
+		*dir1 = getCx86(CX86_DIR1);
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
+ * order to identify the Cyrix CPU model after we're out of setup.c
+ *
+ * Actually since bugs.h doesnt even reference this perhaps someone should
+ * fix the documentation ???
+ */
+static unsigned char Cx86_dir0_msb __initdata = 0;
+
+static char Cx86_model[][9] __initdata = {
+	"Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
+	"M II ", "Unknown"
+};
+static char Cx486_name[][5] __initdata = {
+	"SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
+	"SRx2", "DRx2"
+};
+static char Cx486S_name[][4] __initdata = {
+	"S", "S2", "Se", "S2e"
+};
+static char Cx486D_name[][4] __initdata = {
+	"DX", "DX2", "?", "?", "?", "DX4"
+};
+static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
+static char cyrix_model_mult1[] __initdata = "12??43";
+static char cyrix_model_mult2[] __initdata = "12233445";
+
+/*
+ * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
+ * BIOSes for compatability with DOS games.  This makes the udelay loop
+ * work correctly, and improves performance.
+ *
+ * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP
+ */
+
+extern void calibrate_delay(void) __init;
+
+static void __init check_cx686_slop(struct cpuinfo_x86 *c)
+{
+	unsigned long flags;
+	
+	if (Cx86_dir0_msb == 3) {
+		unsigned char ccr3, ccr5;
+
+		local_irq_save(flags);
+		ccr3 = getCx86(CX86_CCR3);
+		setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
+		ccr5 = getCx86(CX86_CCR5);
+		if (ccr5 & 2)
+			setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
+		setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
+		local_irq_restore(flags);
+
+		if (ccr5 & 2) { /* possible wrong calibration done */
+			printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
+			calibrate_delay();
+			c->loops_per_jiffy = loops_per_jiffy;
+		}
+	}
+}
+
+static void __init init_cyrix(struct cpuinfo_x86 *c)
+{
+	unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
+	char *buf = c->x86_model_id;
+	const char *p = NULL;
+
+	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
+	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
+	clear_bit(0*32+31, c->x86_capability);
+
+	/* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
+	if ( test_bit(1*32+24, c->x86_capability) ) {
+		clear_bit(1*32+24, c->x86_capability);
+		set_bit(X86_FEATURE_CXMMX, c->x86_capability);
+	}
+
+	do_cyrix_devid(&dir0, &dir1);
+
+	check_cx686_slop(c);
+
+	Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family"   */
+	dir0_lsn = dir0 & 0xf;                /* model or clock multiplier */
+
+	/* common case step number/rev -- exceptions handled below */
+	c->x86_model = (dir1 >> 4) + 1;
+	c->x86_mask = dir1 & 0xf;
+
+	/* Now cook; the original recipe is by Channing Corn, from Cyrix.
+	 * We do the same thing for each generation: we work out
+	 * the model, multiplier and stepping.  Black magic included,
+	 * to make the silicon step/rev numbers match the printed ones.
+	 */
+	 
+	switch (dir0_msn) {
+		unsigned char tmp;
+
+	case 0: /* Cx486SLC/DLC/SRx/DRx */
+		p = Cx486_name[dir0_lsn & 7];
+		break;
+
+	case 1: /* Cx486S/DX/DX2/DX4 */
+		p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5]
+			: Cx486S_name[dir0_lsn & 3];
+		break;
+
+	case 2: /* 5x86 */
+		Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+		p = Cx86_cb+2;
+		break;
+
+	case 3: /* 6x86/6x86L */
+		Cx86_cb[1] = ' ';
+		Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+		if (dir1 > 0x21) { /* 686L */
+			Cx86_cb[0] = 'L';
+			p = Cx86_cb;
+			(c->x86_model)++;
+		} else             /* 686 */
+			p = Cx86_cb+1;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
+		/* 6x86's contain this bug */
+		c->coma_bug = 1;
+		break;
+
+	case 4: /* MediaGX/GXm */
+#ifdef CONFIG_PCI
+		/* It isn't really a PCI quirk directly, but the cure is the
+		   same. The MediaGX has deep magic SMM stuff that handles the
+		   SB emulation. It thows away the fifo on disable_dma() which
+		   is wrong and ruins the audio. 
+
+		   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
+		   causes bad things. According to NatSemi VSA2 has another
+		   bug to do with 'hlt'. I've not seen any boards using VSA2
+		   and X doesn't seem to support it either so who cares 8).
+		   VSA1 we work around however.
+		*/
+
+		printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n");
+		isa_dma_bridge_buggy = 2;
+#endif		
+		c->x86_cache_size=16;	/* Yep 16K integrated cache thats it */
+
+		/* GXm supports extended cpuid levels 'ala' AMD */
+		if (c->cpuid_level == 2) {
+			/* Enable Natsemi MMX extensions */
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+
+			get_model_name(c);  /* get CPU marketing name */
+			/*
+			 *  The 5510/5520 companion chips have a funky PIT
+			 *  that breaks the TSC synchronizing, so turn it off
+			 */
+			if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+				pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+				clear_bit(X86_FEATURE_TSC, c->x86_capability);
+			return;
+		}
+		else {  /* MediaGX */
+			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
+			p = Cx86_cb+2;
+			c->x86_model = (dir1 & 0x20) ? 1 : 2;
+#ifndef CONFIG_CS5520
+			clear_bit(X86_FEATURE_TSC, c->x86_capability);
+#endif
+		}
+		break;
+
+        case 5: /* 6x86MX/M II */
+		if (dir1 > 7)
+		{
+			dir0_msn++;  /* M II */
+			/* Enable MMX extensions (App note 108) */
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
+		}
+		else
+		{
+			c->coma_bug = 1;      /* 6x86MX, it has the bug. */
+		}
+		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
+		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
+		p = Cx86_cb+tmp;
+        	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+			(c->x86_model)++;
+		/* Emulate MTRRs using Cyrix's ARRs. */
+		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
+		break;
+
+	case 0xf:  /* Cyrix 486 without DEVID registers */
+		switch (dir0_lsn) {
+		case 0xd:  /* either a 486SLC or DLC w/o DEVID */
+			dir0_msn = 0;
+			p = Cx486_name[(c->hard_math) ? 1 : 0];
+			break;
+
+		case 0xe:  /* a 486S A step */
+			dir0_msn = 0;
+			p = Cx486S_name[0];
+			break;
+		}
+		break;
+
+	default:  /* unknown (shouldn't happen, we know everyone ;-) */
+		dir0_msn = 7;
+		break;
+	}
+	strcpy(buf, Cx86_model[dir0_msn & 7]);
+	if (p) strcat(buf, p);
+	return;
+}
+
+/*
+ * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
+ * by the fact that they preserve the flags across the division of 5/2.
+ * PII and PPro exhibit this behavior too, but they have cpuid available.
+ */
+ 
+/*
+ * Perform the Cyrix 5/2 test. A Cyrix won't change
+ * the flags, while other 486 chips will.
+ */
+static inline int test_cyrix_52div(void)
+{
+	unsigned int test;
+
+	__asm__ __volatile__(
+	     "sahf\n\t"		/* clear flags (%eax = 0x0005) */
+	     "div %b2\n\t"	/* divide 5 by 2 */
+	     "lahf"		/* store flags into %ah */
+	     : "=a" (test)
+	     : "0" (5), "q" (2)
+	     : "cc");
+
+	/* AH is 0x02 on Cyrix after the divide.. */
+	return (unsigned char) (test >> 8) == 0x02;
+}
+
+static void cyrix_identify(struct cpuinfo_x86 * c)
+{
+	/* Detect Cyrix with disabled CPUID */
+	if ( c->x86 == 4 && test_cyrix_52div() ) {
+		unsigned char dir0, dir1;
+		
+		strcpy(c->x86_vendor_id, "CyrixInstead");
+	        c->x86_vendor = X86_VENDOR_CYRIX;
+	        
+	        /* Actually enable cpuid on the older cyrix */
+	    
+	    	/* Retrieve CPU revisions */
+	    	
+		do_cyrix_devid(&dir0, &dir1);
+
+		dir0>>=4;		
+		
+		/* Check it is an affected model */
+		
+   	        if (dir0 == 5 || dir0 == 3)
+   	        {
+			unsigned char ccr3, ccr4;
+			unsigned long flags;
+			printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
+			local_irq_save(flags);
+			ccr3 = getCx86(CX86_CCR3);
+			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
+			ccr4 = getCx86(CX86_CCR4);
+			setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
+			setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
+			local_irq_restore(flags);
+		}
+	}
+	generic_identify(c);
+}
+
+static struct cpu_dev cyrix_cpu_dev __initdata = {
+	c_vendor:	"Cyrix",
+	c_ident: 	{ "CyrixInstead" },
+	c_init:		init_cyrix,
+	c_identify:	cyrix_identify,
+};
+
+int __init cyrix_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_CYRIX] = &cyrix_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(cyrix_init_cpu);
+
+static struct cpu_dev nsc_cpu_dev __initdata = {
+	c_vendor:	"NSC",
+	c_ident: 	{ "Geode by NSC" },
+	c_init:		init_cyrix,
+	c_identify:	generic_identify,
+};
+
+int __init nsc_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(nsc_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/intel.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,378 @@
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/msr.h>
+
+#include "cpu.h"
+
+static int disable_x86_serial_nr __initdata = 1;
+static int disable_P4_HT __initdata = 0;
+extern int trap_init_f00f_bug(void);
+
+/*
+ *	Early probe support logic for ppro memory erratum #50
+ *
+ *	This is called before we do cpu ident work
+ */
+ 
+int __init ppro_with_ram_bug(void)
+{
+	char vendor_id[16];
+	int ident;
+
+	/* Must have CPUID */
+	if(!have_cpuid_p())
+		return 0;
+	if(cpuid_eax(0)<1)
+		return 0;
+	
+	/* Must be Intel */
+	cpuid(0, &ident, 
+		(int *)&vendor_id[0],
+		(int *)&vendor_id[8],
+		(int *)&vendor_id[4]);
+	
+	if(memcmp(vendor_id, "IntelInside", 12))
+		return 0;
+	
+	ident = cpuid_eax(1);
+
+	/* Model 6 */
+
+	if(((ident>>8)&15)!=6)
+		return 0;
+	
+	/* Pentium Pro */
+
+	if(((ident>>4)&15)!=1)
+		return 0;
+	
+	if((ident&15) < 8)
+	{
+		printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n");
+		return 1;
+	}
+	printk(KERN_INFO "Your Pentium Pro seems ok.\n");
+	return 0;
+}
+	
+static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+{
+	if( test_bit(X86_FEATURE_PN, c->x86_capability) &&
+	    disable_x86_serial_nr ) {
+		/* Disable processor serial number */
+		unsigned long lo,hi;
+		rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
+		lo |= 0x200000;
+		wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
+		printk(KERN_NOTICE "CPU serial number disabled.\n");
+		clear_bit(X86_FEATURE_PN, c->x86_capability);
+
+		/* Disabling the serial number may affect the cpuid level */
+		c->cpuid_level = cpuid_eax(0);
+	}
+}
+
+static int __init x86_serial_nr_setup(char *s)
+{
+	disable_x86_serial_nr = 0;
+	return 1;
+}
+__setup("serialnumber", x86_serial_nr_setup);
+
+static int __init P4_disable_ht(char *s)
+{
+	disable_P4_HT = 1;
+	return 1;
+}
+__setup("noht", P4_disable_ht);
+
+
+static void __init init_intel(struct cpuinfo_x86 *c)
+{
+	char *p = NULL;
+	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
+
+#ifdef CONFIG_X86_F00F_BUG
+	/*
+	 * All current models of Pentium and Pentium with MMX technology CPUs
+	 * have the F0 0F bug, which lets nonpriviledged users lock up the system.
+	 * Note that the workaround only should be initialized once...
+	 */
+	c->f00f_bug = 0;
+	if ( c->x86 == 5 ) {
+		static int f00f_workaround_enabled = 0;
+
+		c->f00f_bug = 1;
+		if ( !f00f_workaround_enabled ) {
+			trap_init_f00f_bug();
+			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
+			f00f_workaround_enabled = 1;
+		}
+	}
+#endif
+
+
+	if (c->cpuid_level > 1) {
+		/* supports eax=2  call */
+		int i, j, n;
+		int regs[4];
+		unsigned char *dp = (unsigned char *)regs;
+
+		/* Number of times to iterate */
+		n = cpuid_eax(2) & 0xFF;
+
+		for ( i = 0 ; i < n ; i++ ) {
+			cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
+			
+			/* If bit 31 is set, this is an unknown format */
+			for ( j = 0 ; j < 3 ; j++ ) {
+				if ( regs[j] < 0 ) regs[j] = 0;
+			}
+
+			/* Byte 0 is level count, not a descriptor */
+			for ( j = 1 ; j < 16 ; j++ ) {
+				unsigned char des = dp[j];
+				unsigned char dl, dh;
+				unsigned int cs;
+
+				dh = des >> 4;
+				dl = des & 0x0F;
+
+				/* Black magic... */
+
+				switch ( dh )
+				{
+				case 0:
+					switch ( dl ) {
+					case 6:
+						/* L1 I cache */
+						l1i += 8;
+						break;
+					case 8:
+						/* L1 I cache */
+						l1i += 16;
+						break;
+					case 10:
+						/* L1 D cache */
+						l1d += 8;
+						break;
+					case 12:
+						/* L1 D cache */
+						l1d += 16;
+						break;
+					default:;
+						/* TLB, or unknown */
+					}
+					break;
+				case 2:
+					if ( dl ) {
+						/* L3 cache */
+						cs = (dl-1) << 9;
+						l3 += cs;
+					}
+					break;
+				case 4:
+					if ( c->x86 > 6 && dl ) {
+						/* P4 family */
+						/* L3 cache */
+						cs = 128 << (dl-1);
+						l3 += cs;
+						break;
+					}
+					/* else same as 8 - fall through */
+				case 8:
+					if ( dl ) {
+						/* L2 cache */
+						cs = 128 << (dl-1);
+						l2 += cs;
+					}
+					break;
+				case 6:
+					if (dl > 5) {
+						/* L1 D cache */
+						cs = 8<<(dl-6);
+						l1d += cs;
+					}
+					break;
+				case 7:
+					if ( dl >= 8 ) 
+					{
+						/* L2 cache */
+						cs = 64<<(dl-8);
+						l2 += cs;
+					} else {
+						/* L0 I cache, count as L1 */
+						cs = dl ? (16 << (dl-1)) : 12;
+						l1i += cs;
+					}
+					break;
+				default:
+					/* TLB, or something else we don't know about */
+					break;
+				}
+			}
+		}
+		if ( l1i || l1d )
+			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
+			      l1i, l1d);
+		if ( l2 )
+			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
+		if ( l3 )
+			printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
+
+		/*
+		 * This assumes the L3 cache is shared; it typically lives in
+		 * the northbridge.  The L1 caches are included by the L2
+		 * cache, and so should not be included for the purpose of
+		 * SMP switching weights.
+		 */
+		c->x86_cache_size = l2 ? l2 : (l1i+l1d);
+	}
+
+	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
+	if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
+		clear_bit(X86_FEATURE_SEP, c->x86_capability);
+	
+	/* Names for the Pentium II/Celeron processors 
+	   detectable only by also checking the cache size.
+	   Dixon is NOT a Celeron. */
+	if (c->x86 == 6) {
+		switch (c->x86_model) {
+		case 5:
+			if (l2 == 0)
+				p = "Celeron (Covington)";
+			if (l2 == 256)
+				p = "Mobile Pentium II (Dixon)";
+			break;
+			
+		case 6:
+			if (l2 == 128)
+				p = "Celeron (Mendocino)";
+			break;
+			
+		case 8:
+			if (l2 == 128)
+				p = "Celeron (Coppermine)";
+			break;
+		}
+	}
+
+	if ( p )
+		strcpy(c->x86_model_id, p);
+	
+#ifdef CONFIG_SMP
+	if (test_bit(X86_FEATURE_HT, c->x86_capability) && !disable_P4_HT) {
+		extern	int phys_proc_id[NR_CPUS];
+		
+		u32 	eax, ebx, ecx, edx;
+		int 	index_lsb, index_msb, tmp;
+		int	initial_apic_id;
+		int 	cpu = smp_processor_id();
+
+		cpuid(1, &eax, &ebx, &ecx, &edx);
+		smp_num_siblings = (ebx & 0xff0000) >> 16;
+
+		if (smp_num_siblings == 1) {
+			printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
+		} else if (smp_num_siblings > 1 ) {
+			index_lsb = 0;
+			index_msb = 31;
+			/*
+			 * At this point we only support two siblings per
+			 * processor package.
+			 */
+#define NR_SIBLINGS	2
+			if (smp_num_siblings != NR_SIBLINGS) {
+				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
+				smp_num_siblings = 1;
+				goto too_many_siblings;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 1) == 0) {
+				tmp >>=1 ;
+				index_lsb++;
+			}
+			tmp = smp_num_siblings;
+			while ((tmp & 0x80000000 ) == 0) {
+				tmp <<=1 ;
+				index_msb--;
+			}
+			if (index_lsb != index_msb )
+				index_msb++;
+			initial_apic_id = ebx >> 24 & 0xff;
+			phys_proc_id[cpu] = initial_apic_id >> index_msb;
+
+			printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
+                               phys_proc_id[cpu]);
+		}
+
+	}
+too_many_siblings:
+
+	if (disable_P4_HT)
+		clear_bit(X86_FEATURE_HT, c->x86_capability);
+#endif
+
+	/* Disable the PN if appropriate */
+	squash_the_stupid_serial_number(c);
+}
+
+static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
+{
+	/* Intel PIII Tualatin. This comes in two flavours.
+	 * One has 256kb of cache, the other 512. We have no way
+	 * to determine which, so we use a boottime override
+	 * for the 512kb model, and assume 256 otherwise.
+	 */
+	if ((c->x86 == 6) && (c->x86_model == 11) && (size == 0))
+		size = 256;
+	return size;
+}
+
+static struct cpu_dev intel_cpu_dev __initdata = {
+	c_vendor:	"Intel",
+	c_ident: 	{ "GenuineIntel" },
+	c_models: {
+		{ X86_VENDOR_INTEL,	4,
+		  { 
+			  [0] "486 DX-25/33", 
+			  [1] "486 DX-50", 
+			  [2] "486 SX", 
+			  [3] "486 DX/2", 
+			  [4] "486 SL", 
+			  [5] "486 SX/2", 
+			  [7] "486 DX/2-WB", 
+			  [8] "486 DX/4", 
+			  [9] "486 DX/4-WB"
+		  }
+		},
+		{ X86_VENDOR_INTEL,	5,
+		  { 
+			  [0] "Pentium 60/66 A-step", 
+			  [1] "Pentium 60/66", 
+			  [2] "Pentium 75 - 200",
+			  [3] "OverDrive PODP5V83", 
+			  [4] "Pentium MMX",
+			  [7] "Mobile Pentium 75 - 200", 
+			  [8] "Mobile Pentium MMX"
+		  }
+		},
+	},
+	c_init:		init_intel,
+	c_identify:	generic_identify,
+	c_size_cache:	intel_size_cache,
+};
+
+__init int intel_cpu_init(void)
+{
+	cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
+	return 0;
+}
+
+// arch_initcall(intel_cpu_init);
+
diff -Nru a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/nexgen.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,60 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+/*
+ *	Detect a NexGen CPU running without BIOS hypercode new enough
+ *	to have CPUID. (Thanks to Herbert Oppmann)
+ */
+ 
+static int __init deep_magic_nexgen_probe(void)
+{
+	int ret;
+	
+	__asm__ __volatile__ (
+		"	movw	$0x5555, %%ax\n"
+		"	xorw	%%dx,%%dx\n"
+		"	movw	$2, %%cx\n"
+		"	divw	%%cx\n"
+		"	movl	$0, %%eax\n"
+		"	jnz	1f\n"
+		"	movl	$1, %%eax\n"
+		"1:\n" 
+		: "=a" (ret) : : "cx", "dx" );
+	return  ret;
+}
+
+static void __init init_nexgen(struct cpuinfo_x86 * c)
+{
+	c->x86_cache_size = 256; /* A few had 1 MB... */
+}
+
+static void nexgen_identify(struct cpuinfo_x86 * c)
+{
+	/* Detect NexGen with old hypercode */
+	if ( deep_magic_nexgen_probe() ) {
+		strcpy(c->x86_vendor_id, "NexGenDriven");
+	}
+	generic_identify(c);
+}
+
+static struct cpu_dev nexgen_cpu_dev __initdata = {
+	c_vendor:	"Nexgen",
+	c_ident:	{ "NexGenDriven" },
+	c_models: {
+		{ X86_VENDOR_NEXGEN,5, { [1] "Nx586" } },
+	},
+	c_init:		init_nexgen,
+	c_identify:	nexgen_identify,
+};
+
+int __init nexgen_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_NEXGEN] = &nexgen_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(nexgen_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/proc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,126 @@
+#include <linux/smp.h>
+#include <linux/timex.h>
+#include <linux/string.h>
+#include <asm/semaphore.h>
+#include <linux/seq_file.h>
+
+/*
+ *	Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+	/* 
+	 * These flag bits must match the definitions in <asm/cpufeature.h>.
+	 * NULL means this bit is undefined or reserved; either way it doesn't
+	 * have meaning as far as Linux is concerned.  Note that it's important
+	 * to realize there is a difference between this table and CPUID -- if
+	 * applications want to get the raw CPUID data, they should access
+	 * /dev/cpu/<cpu_nr>/cpuid instead.
+	 */
+	static char *x86_cap_flags[] = {
+		/* Intel-defined */
+	        "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
+	        "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
+	        "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
+	        "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
+
+		/* AMD-defined */
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL,
+		NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
+
+		/* Transmeta-defined */
+		"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+
+		/* Other (Linux-defined) */
+		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+	};
+	struct cpuinfo_x86 *c = v;
+	int i, n = c - cpu_data;
+	int fpu_exception;
+
+#ifdef CONFIG_SMP
+	if (!(cpu_online_map & (1<<n)))
+		return 0;
+#endif
+	seq_printf(m, "processor\t: %d\n"
+		"vendor_id\t: %s\n"
+		"cpu family\t: %d\n"
+		"model\t\t: %d\n"
+		"model name\t: %s\n",
+		n,
+		c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
+		c->x86,
+		c->x86_model,
+		c->x86_model_id[0] ? c->x86_model_id : "unknown");
+
+	if (c->x86_mask || c->cpuid_level >= 0)
+		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
+	else
+		seq_printf(m, "stepping\t: unknown\n");
+
+	if ( test_bit(X86_FEATURE_TSC, c->x86_capability) ) {
+		seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
+			cpu_khz / 1000, (cpu_khz % 1000));
+	}
+
+	/* Cache size */
+	if (c->x86_cache_size >= 0)
+		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
+	
+	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
+	fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
+	seq_printf(m, "fdiv_bug\t: %s\n"
+			"hlt_bug\t\t: %s\n"
+			"f00f_bug\t: %s\n"
+			"coma_bug\t: %s\n"
+			"fpu\t\t: %s\n"
+			"fpu_exception\t: %s\n"
+			"cpuid level\t: %d\n"
+			"wp\t\t: %s\n"
+			"flags\t\t:",
+		     c->fdiv_bug ? "yes" : "no",
+		     c->hlt_works_ok ? "no" : "yes",
+		     c->f00f_bug ? "yes" : "no",
+		     c->coma_bug ? "yes" : "no",
+		     c->hard_math ? "yes" : "no",
+		     fpu_exception ? "yes" : "no",
+		     c->cpuid_level,
+		     c->wp_works_ok ? "yes" : "no");
+
+	for ( i = 0 ; i < 32*NCAPINTS ; i++ )
+		if ( test_bit(i, c->x86_capability) &&
+		     x86_cap_flags[i] != NULL )
+			seq_printf(m, " %s", x86_cap_flags[i]);
+
+	seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
+		     c->loops_per_jiffy/(500000/HZ),
+		     (c->loops_per_jiffy/(5000/HZ)) % 100);
+	return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	++*pos;
+	return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+struct seq_operations cpuinfo_op = {
+	start:	c_start,
+	next:	c_next,
+	stop:	c_stop,
+	show:	show_cpuinfo,
+};
diff -Nru a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/rise.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,53 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/processor.h>
+
+#include "cpu.h"
+
+static void __init init_rise(struct cpuinfo_x86 *c)
+{
+	printk("CPU: Rise iDragon");
+	if (c->x86_model > 2)
+		printk(" II");
+	printk("\n");
+
+	/* Unhide possibly hidden capability flags
+	   The mp6 iDragon family don't have MSRs.
+	   We switch on extra features with this cpuid weirdness: */
+	__asm__ (
+		"movl $0x6363452a, %%eax\n\t"
+		"movl $0x3231206c, %%ecx\n\t"
+		"movl $0x2a32313a, %%edx\n\t"
+		"cpuid\n\t"
+		"movl $0x63634523, %%eax\n\t"
+		"movl $0x32315f6c, %%ecx\n\t"
+		"movl $0x2333313a, %%edx\n\t"
+		"cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
+	);
+	set_bit(X86_FEATURE_CX8, c->x86_capability);
+}
+
+static struct cpu_dev rise_cpu_dev __initdata = {
+	c_vendor:	"Rise",
+	c_ident:	{ "RiseRiseRise" },
+	c_models: {
+		{ X86_VENDOR_RISE,	5,
+		  { 
+			  [0] "iDragon", 
+			  [2] "iDragon", 
+			  [8] "iDragon II", 
+			  [9] "iDragon II"
+		  }
+		},
+	},
+	c_init:		init_rise,
+};
+
+int __init rise_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(rise_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/transmeta.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,95 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include "cpu.h"
+
+static void __init init_transmeta(struct cpuinfo_x86 *c)
+{
+	unsigned int cap_mask, uk, max, dummy;
+	unsigned int cms_rev1, cms_rev2;
+	unsigned int cpu_rev, cpu_freq, cpu_flags;
+	char cpu_info[65];
+
+	get_model_name(c);	/* Same as AMD/Cyrix */
+	display_cacheinfo(c);
+
+	/* Print CMS and CPU revision */
+	max = cpuid_eax(0x80860000);
+	if ( max >= 0x80860001 ) {
+		cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); 
+		printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
+		       (cpu_rev >> 24) & 0xff,
+		       (cpu_rev >> 16) & 0xff,
+		       (cpu_rev >> 8) & 0xff,
+		       cpu_rev & 0xff,
+		       cpu_freq);
+	}
+	if ( max >= 0x80860002 ) {
+		cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
+		printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n",
+		       (cms_rev1 >> 24) & 0xff,
+		       (cms_rev1 >> 16) & 0xff,
+		       (cms_rev1 >> 8) & 0xff,
+		       cms_rev1 & 0xff,
+		       cms_rev2);
+	}
+	if ( max >= 0x80860006 ) {
+		cpuid(0x80860003,
+		      (void *)&cpu_info[0],
+		      (void *)&cpu_info[4],
+		      (void *)&cpu_info[8],
+		      (void *)&cpu_info[12]);
+		cpuid(0x80860004,
+		      (void *)&cpu_info[16],
+		      (void *)&cpu_info[20],
+		      (void *)&cpu_info[24],
+		      (void *)&cpu_info[28]);
+		cpuid(0x80860005,
+		      (void *)&cpu_info[32],
+		      (void *)&cpu_info[36],
+		      (void *)&cpu_info[40],
+		      (void *)&cpu_info[44]);
+		cpuid(0x80860006,
+		      (void *)&cpu_info[48],
+		      (void *)&cpu_info[52],
+		      (void *)&cpu_info[56],
+		      (void *)&cpu_info[60]);
+		cpu_info[64] = '\0';
+		printk(KERN_INFO "CPU: %s\n", cpu_info);
+	}
+
+	/* Unhide possibly hidden capability flags */
+	rdmsr(0x80860004, cap_mask, uk);
+	wrmsr(0x80860004, ~0, uk);
+	c->x86_capability[0] = cpuid_edx(0x00000001);
+	wrmsr(0x80860004, cap_mask, uk);
+}
+
+static void transmeta_identify(struct cpuinfo_x86 * c)
+{
+	u32 xlvl;
+	generic_identify(c);
+
+	/* Transmeta-defined flags: level 0x80860001 */
+	xlvl = cpuid_eax(0x80860000);
+	if ( (xlvl & 0xffff0000) == 0x80860000 ) {
+		if (  xlvl >= 0x80860001 )
+			c->x86_capability[2] = cpuid_edx(0x80860001);
+	}
+}
+
+static struct cpu_dev transmeta_cpu_dev __initdata = {
+	c_vendor:	"Transmeta",
+	c_ident:	{ "GenuineTMx86", "TransmetaCPU" },
+	c_init:		init_transmeta,
+	c_identify:	transmeta_identify,
+};
+
+int __init transmeta_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(transmeta_init_cpu);
diff -Nru a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/umc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,33 @@
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <asm/processor.h>
+#include "cpu.h"
+
+/* UMC chips appear to be only either 386 or 486, so no special init takes place.
+ */
+static void __init init_umc(struct cpuinfo_x86 * c)
+{
+
+}
+
+static struct cpu_dev umc_cpu_dev __initdata = {
+	c_vendor:	"UMC",
+	c_ident: 	{ "UMC UMC UMC" },
+	c_models: {
+		{ X86_VENDOR_UMC,	4,
+		  { 
+			  [1] "U5D", 
+			  [2] "U5S", 
+		  }
+		},
+	},
+	c_init:		init_umc,
+};
+
+int __init umc_init_cpu(void)
+{
+	cpu_devs[X86_VENDOR_UMC] = &umc_cpu_dev;
+	return 0;
+}
+
+//early_arch_initcall(umc_init_cpu);
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/kernel/entry.S	Sat Jun  8 22:31:36 2002
@@ -83,13 +83,9 @@
 #define GET_CPU_IDX \
 		movl TI_CPU(%ebx), %eax;  \
 		shll $irq_array_shift, %eax
-#define GET_CURRENT_CPU_IDX \
-		GET_THREAD_INFO(%ebx); \
-		GET_CPU_IDX
 #define CPU_IDX (,%eax)
 #else
 #define GET_CPU_IDX
-#define GET_CURRENT_CPU_IDX GET_THREAD_INFO(%ebx)
 #define CPU_IDX
 #endif
 
@@ -236,6 +232,7 @@
 	movl TI_FLAGS(%ebx), %ecx
 	testb $_TIF_NEED_RESCHED, %cl
 	jz restore_all
+	GET_CPU_IDX
 	movl irq_stat+local_bh_count CPU_IDX, %ecx
 	addl irq_stat+local_irq_count CPU_IDX, %ecx
 	jnz restore_all
diff -Nru a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
--- a/arch/i386/kernel/microcode.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/kernel/microcode.c	Sat Jun  8 22:31:36 2002
@@ -67,6 +67,7 @@
 #include <linux/miscdevice.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
+#include <linux/mm.h>
 
 #include <asm/msr.h>
 #include <asm/uaccess.h>
diff -Nru a/arch/i386/kernel/setup-visws.c b/arch/i386/kernel/setup-visws.c
--- a/arch/i386/kernel/setup-visws.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/kernel/setup-visws.c	Sat Jun  8 22:31:36 2002
@@ -3,6 +3,8 @@
  *  Split out from setup.c by davej@suse.de
  */
 
+#include <linux/init.h>
+
 char visws_board_type = -1;
 char visws_board_rev = -1;
 
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/kernel/setup.c	Sat Jun  8 22:31:37 2002
@@ -3,73 +3,16 @@
  *
  *  Copyright (C) 1995  Linus Torvalds
  *
- *  Enhanced CPU type detection by Mike Jagdis, Patrick St. Jean
- *  and Martin Mares, November 1997.
- *
- *  Force Cyrix 6x86(MX) and M II processors to report MTRR capability
- *  and Cyrix "coma bug" recognition by
- *      Zoltán Böszörményi <zboszor@mail.externet.hu> February 1999.
- * 
- *  Force Centaur C6 processors to report MTRR capability.
- *      Bart Hartgers <bart@etpmod.phys.tue.nl>, May 1999.
- *
- *  Intel Mobile Pentium II detection fix. Sean Gilley, June 1999.
- *
- *  IDT Winchip tweaks, misc clean ups.
- *	Dave Jones <davej@suse.de>, August 1999
- *
  *  Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999
  *
- *  Better detection of Centaur/IDT WinChip models.
- *      Bart Hartgers <bart@etpmod.phys.tue.nl>, August 1999.
- *
  *  Memory region support
  *	David Parsons <orc@pell.chi.il.us>, July-August 1999
  *
- *  Cleaned up cache-detection code
- *	Dave Jones <davej@suse.de>, October 1999
- *
- *	Added proper L2 cache detection for Coppermine
- *	Dragan Stancevic <visitor@valinux.com>, October 1999
- *
- *  Added the original array for capability flags but forgot to credit 
- *  myself :) (~1998) Fixed/cleaned up some cpu_model_info and other stuff
- *  	Jauder Ho <jauderho@carumba.com>, January 2000
- *
- *  Detection for Celeron coppermine, identify_cpu() overhauled,
- *  and a few other clean ups.
- *  Dave Jones <davej@suse.de>, April 2000
- *
- *  Pentium III FXSR, SSE support
- *  General FPU state handling cleanups
- *	Gareth Hughes <gareth@valinux.com>, May 2000
- *
- *  Added proper Cascades CPU and L2 cache detection for Cascades
- *  and 8-way type cache happy bunch from Intel:^)
- *  Dragan Stancevic <visitor@valinux.com>, May 2000 
- *
- *  Forward port AMD Duron errata T13 from 2.2.17pre
- *  Dave Jones <davej@suse.de>, August 2000
- *
- *  Forward port lots of fixes/improvements from 2.2.18pre
- *  Cyrix III, Pentium IV support.
- *  Dave Jones <davej@suse.de>, October 2000
- *
- *  Massive cleanup of CPU detection and bug handling;
- *  Transmeta CPU detection,
- *  H. Peter Anvin <hpa@zytor.com>, November 2000
- *
  *  Added E820 sanitization routine (removes overlapping memory regions);
  *  Brian Moyle <bmoyle@mvista.com>, February 2001
  *
- *  VIA C3 Support.
- *  Dave Jones <davej@suse.de>, March 2001
- *
- *  AMD Athlon/Duron/Thunderbird bluesmoke support.
- *  Dave Jones <davej@suse.de>, April 2001.
- *
- *  CacheSize bug workaround updates for AMD, Intel & VIA Cyrix.
- *  Dave Jones <davej@suse.de>, September, October 2001.
+ * Moved CPU detection code to cpu/${cpu}.c
+ *    Patrick Mochel <mochel@osdl.org>, March 2002
  *
  */
 
@@ -77,45 +20,21 @@
  * This file handles the architecture-dependent parts of initialization
  */
 
-#include <linux/errno.h>
 #include <linux/sched.h>
-#include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/stddef.h>
-#include <linux/unistd.h>
-#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
 #include <linux/tty.h>
 #include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/config.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/apm_bios.h>
 #ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
-#include <linux/highmem.h>
 #include <linux/bootmem.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
 #include <linux/seq_file.h>
 #include <linux/console.h>
-#include <asm/processor.h>
-#include <asm/mtrr.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/cobalt.h>
-#include <asm/msr.h>
-#include <asm/desc.h>
+#include <linux/highmem.h>
 #include <asm/e820.h>
-#include <asm/dma.h>
 #include <asm/mpspec.h>
-#include <asm/mmu_context.h>
 
 /*
  * Machine setup..
@@ -126,11 +45,7 @@
 
 unsigned long mmu_cr4_features;
 
-/*
- * Bus types ..
- */
 int MCA_bus;
-
 /* for MCA, but anyone else can use it if they want */
 unsigned int machine_id;
 unsigned int machine_submodel_id;
@@ -158,20 +73,15 @@
 
 unsigned char aux_device_present;
 
-extern void mcheck_init(struct cpuinfo_x86 *c);
+extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 extern int blk_nohighio;
 void __init visws_get_board_type_and_rev(void);
 
-static int disable_x86_serial_nr __initdata = 1;
-static int disable_x86_fxsr __initdata = 0;
-
 unsigned long saved_videomode;
 
-extern unsigned long saved_videomode;
-
 /*
  * This is set up by the setup-routine at boot-time
  */
@@ -297,6 +207,22 @@
 	}
 }
 
+static void __init limit_regions (unsigned long long size)
+{
+	int i;
+	unsigned long long current_size = 0;
+
+	for (i = 0; i < e820.nr_map; i++) {
+		if (e820.map[i].type == E820_RAM) {
+			current_size += e820.map[i].size;
+			if (current_size >= size) {
+				e820.map[i].size -= current_size-size;
+				e820.nr_map = i + 1;
+				return;
+			}
+		}
+	}
+}
 static void __init add_memory_region(unsigned long long start,
                                   unsigned long long size, int type)
 {
@@ -598,7 +524,7 @@
 {
 	char c = ' ', *to = command_line, *from = COMMAND_LINE;
 	int len = 0;
-	int usermem = 0;
+	int userdef = 0;
 
 	/* Save unparsed command line copy for /proc/cmdline */
 	memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE);
@@ -621,32 +547,24 @@
 			} else if (!memcmp(from+4, "exactmap", 8)) {
 				from += 8+4;
 				e820.nr_map = 0;
-				usermem = 1;
+				userdef = 1;
 			} else {
 				/* If the user specifies memory size, we
-				 * blow away any automatically generated
-				 * size
+				 * limit the BIOS-provided memory map to
+				 * that size. exactmap can be used to specify
+				 * the exact map. mem=number can be used to
+				 * trim the existing memory map.
 				 */
 				unsigned long long start_at, mem_size;
  
-				if (usermem == 0) {
-					/* first time in: zap the whitelist
-					 * and reinitialize it with the
-					 * standard low-memory region.
-					 */
-					e820.nr_map = 0;
-					usermem = 1;
-					add_memory_region(0, LOWMEMSIZE(), E820_RAM);
-				}
 				mem_size = memparse(from+4, &from);
-				if (*from == '@')
+				if (*from == '@') {
 					start_at = memparse(from+1, &from);
-				else {
-					start_at = HIGH_MEMORY;
-					mem_size -= HIGH_MEMORY;
-					usermem=0;
+					add_memory_region(start_at, mem_size, E820_RAM);
+				} else {
+					limit_regions(mem_size);
+					userdef=1;
 				}
-				add_memory_region(start_at, mem_size, E820_RAM);
 			}
 		}
 		/*
@@ -666,7 +584,7 @@
 	}
 	*to = '\0';
 	*cmdline_p = command_line;
-	if (usermem) {
+	if (userdef) {
 		printk(KERN_INFO "user-defined physical RAM map:\n");
 		print_memory_map("user");
 	}
@@ -678,6 +596,8 @@
 	unsigned long start_pfn, max_low_pfn;
 	int i;
 
+	early_cpu_init();
+
 #ifdef CONFIG_VISWS
 	visws_get_board_type_and_rev();
 #endif
@@ -977,27 +897,6 @@
 	dmi_scan_machine();
 }
 
-static int cachesize_override __initdata = -1;
-static int __init cachesize_setup(char *str)
-{
-	get_option (&str, &cachesize_override);
-	return 1;
-}
-__setup("cachesize=", cachesize_setup);
-
-
-#ifndef CONFIG_X86_TSC
-static int tsc_disable __initdata = 0;
-
-static int __init tsc_setup(char *str)
-{
-	tsc_disable = 1;
-	return 1;
-}
-
-__setup("notsc", tsc_setup);
-#endif
-
 static int __init highio_setup(char *str)
 {
 	printk("i386: disabling HIGHMEM block I/O\n");
@@ -1006,1938 +905,6 @@
 }
 __setup("nohighio", highio_setup);
  
-static int __init get_model_name(struct cpuinfo_x86 *c)
-{
-	unsigned int *v;
-	char *p, *q;
-
-	if (cpuid_eax(0x80000000) < 0x80000004)
-		return 0;
-
-	v = (unsigned int *) c->x86_model_id;
-	cpuid(0x80000002, &v[0], &v[1], &v[2], &v[3]);
-	cpuid(0x80000003, &v[4], &v[5], &v[6], &v[7]);
-	cpuid(0x80000004, &v[8], &v[9], &v[10], &v[11]);
-	c->x86_model_id[48] = 0;
-
-	/* Intel chips right-justify this string for some dumb reason;
-	   undo that brain damage */
-	p = q = &c->x86_model_id[0];
-	while ( *p == ' ' )
-	     p++;
-	if ( p != q ) {
-	     while ( *p )
-		  *q++ = *p++;
-	     while ( q <= &c->x86_model_id[48] )
-		  *q++ = '\0';	/* Zero-pad the rest */
-	}
-
-	return 1;
-}
-
-
-static void __init display_cacheinfo(struct cpuinfo_x86 *c)
-{
-	unsigned int n, dummy, ecx, edx, l2size;
-
-	n = cpuid_eax(0x80000000);
-
-	if (n >= 0x80000005) {
-		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-		printk(KERN_INFO "CPU: L1 I Cache: %dK (%d bytes/line), D cache %dK (%d bytes/line)\n",
-			edx>>24, edx&0xFF, ecx>>24, ecx&0xFF);
-		c->x86_cache_size=(ecx>>24)+(edx>>24);	
-	}
-
-	if (n < 0x80000006)	/* Some chips just has a large L1. */
-		return;
-
-	ecx = cpuid_ecx(0x80000006);
-	l2size = ecx >> 16;
-
-	/* AMD errata T13 (order #21922) */
-	if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
-		if (c->x86_model == 3 && c->x86_mask == 0)	/* Duron Rev A0 */
-			l2size = 64;
-		if (c->x86_model == 4 &&
-			(c->x86_mask==0 || c->x86_mask==1))	/* Tbird rev A1/A2 */
-			l2size = 256;
-	}
-
-	/* Intel PIII Tualatin. This comes in two flavours.
-	 * One has 256kb of cache, the other 512. We have no way
-	 * to determine which, so we use a boottime override
-	 * for the 512kb model, and assume 256 otherwise.
-	 */
-	if ((c->x86_vendor == X86_VENDOR_INTEL) && (c->x86 == 6) &&
-		(c->x86_model == 11) && (l2size == 0))
-		l2size = 256;
-
-	/* VIA C3 CPUs (670-68F) need further shifting. */
-	if (c->x86_vendor == X86_VENDOR_CENTAUR && (c->x86 == 6) &&
-		((c->x86_model == 7) || (c->x86_model == 8))) {
-		l2size = l2size >> 8;
-	}
-
-	/* Allow user to override all this if necessary. */
-	if (cachesize_override != -1)
-		l2size = cachesize_override;
-
-	if ( l2size == 0 )
-		return;		/* Again, no L2 cache is possible */
-
-	c->x86_cache_size = l2size;
-
-	printk(KERN_INFO "CPU: L2 Cache: %dK (%d bytes/line)\n",
-	       l2size, ecx & 0xFF);
-}
-
-/*
- *	B step AMD K6 before B 9730xxxx have hardware bugs that can cause
- *	misexecution of code under Linux. Owners of such processors should
- *	contact AMD for precise details and a CPU swap.
- *
- *	See	http://www.multimania.com/poulot/k6bug.html
- *		http://www.amd.com/K6/k6docs/revgd.html
- *
- *	The following test is erm.. interesting. AMD neglected to up
- *	the chip setting when fixing the bug but they also tweaked some
- *	performance at the same time..
- */
- 
-extern void vide(void);
-__asm__(".align 4\nvide: ret");
-
-static int __init init_amd(struct cpuinfo_x86 *c)
-{
-	u32 l, h;
-	int mbytes = max_mapnr >> (20-PAGE_SHIFT);
-	int r;
-
-	/*
-	 *	FIXME: We should handle the K5 here. Set up the write
-	 *	range and also turn on MSR 83 bits 4 and 31 (write alloc,
-	 *	no bus pipeline)
-	 */
-
-	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, c->x86_capability);
-	
-	r = get_model_name(c);
-
-	switch(c->x86)
-	{
-		case 5:
-			if( c->x86_model < 6 )
-			{
-				/* Based on AMD doc 20734R - June 2000 */
-				if ( c->x86_model == 0 ) {
-					clear_bit(X86_FEATURE_APIC, c->x86_capability);
-					set_bit(X86_FEATURE_PGE, c->x86_capability);
-				}
-				break;
-			}
-			
-			if ( c->x86_model == 6 && c->x86_mask == 1 ) {
-				const int K6_BUG_LOOP = 1000000;
-				int n;
-				void (*f_vide)(void);
-				unsigned long d, d2;
-				
-				printk(KERN_INFO "AMD K6 stepping B detected - ");
-				
-				/*
-				 * It looks like AMD fixed the 2.6.2 bug and improved indirect 
-				 * calls at the same time.
-				 */
-
-				n = K6_BUG_LOOP;
-				f_vide = vide;
-				rdtscl(d);
-				while (n--) 
-					f_vide();
-				rdtscl(d2);
-				d = d2-d;
-				
-				/* Knock these two lines out if it debugs out ok */
-				printk(KERN_INFO "K6 BUG %ld %d (Report these if test report is incorrect)\n", d, 20*K6_BUG_LOOP);
-				printk(KERN_INFO "AMD K6 stepping B detected - ");
-				/* -- cut here -- */
-				if (d > 20*K6_BUG_LOOP) 
-					printk("system stability may be impaired when more than 32 MB are used.\n");
-				else 
-					printk("probably OK (after B9730xxxx).\n");
-				printk(KERN_INFO "Please see http://www.mygale.com/~poulot/k6bug.html\n");
-			}
-
-			/* K6 with old style WHCR */
-			if (c->x86_model < 8 ||
-			   (c->x86_model== 8 && c->x86_mask < 8)) {
-				/* We can only write allocate on the low 508Mb */
-				if(mbytes>508)
-					mbytes=508;
-
-				rdmsr(MSR_K6_WHCR, l, h);
-				if ((l&0x0000FFFF)==0) {
-					unsigned long flags;
-					l=(1<<0)|((mbytes/4)<<1);
-					local_irq_save(flags);
-					wbinvd();
-					wrmsr(MSR_K6_WHCR, l, h);
-					local_irq_restore(flags);
-					printk(KERN_INFO "Enabling old style K6 write allocation for %d Mb\n",
-						mbytes);
-				}
-				break;
-			}
-
-			if ((c->x86_model == 8 && c->x86_mask >7) ||
-			     c->x86_model == 9 || c->x86_model == 13) {
-				/* The more serious chips .. */
-
-				if(mbytes>4092)
-					mbytes=4092;
-
-				rdmsr(MSR_K6_WHCR, l, h);
-				if ((l&0xFFFF0000)==0) {
-					unsigned long flags;
-					l=((mbytes>>2)<<22)|(1<<16);
-					local_irq_save(flags);
-					wbinvd();
-					wrmsr(MSR_K6_WHCR, l, h);
-					local_irq_restore(flags);
-					printk(KERN_INFO "Enabling new style K6 write allocation for %d Mb\n",
-						mbytes);
-				}
-
-				/*  Set MTRR capability flag if appropriate */
-				if (c->x86_model == 13 || c->x86_model == 9 ||
-				   (c->x86_model == 8 && c->x86_mask >= 8))
-					set_bit(X86_FEATURE_K6_MTRR, c->x86_capability);
-				break;
-			}
-			break;
-
-		case 6: /* An Athlon/Duron */
- 
-			/* Bit 15 of Athlon specific MSR 15, needs to be 0
- 			 * to enable SSE on Palomino/Morgan CPU's.
-			 * If the BIOS didn't enable it already, enable it
-			 * here.
-			 */
-			if (c->x86_model == 6 || c->x86_model == 7) {
-				if (!cpu_has(c, X86_FEATURE_XMM)) {
-					printk(KERN_INFO "Enabling disabled K7/SSE Support.\n");
-					rdmsr(MSR_K7_HWCR, l, h);
-					l &= ~0x00008000;
-					wrmsr(MSR_K7_HWCR, l, h);
-					set_bit(X86_FEATURE_XMM, c->x86_capability);
-				}
-			}
-			break;
-
-	}
-
-	display_cacheinfo(c);
-	return r;
-}
-
-/*
- * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
- */
-static void __init do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
-{
-	unsigned char ccr2, ccr3;
-	unsigned long flags;
-	
-	/* we test for DEVID by checking whether CCR3 is writable */
-	local_irq_save(flags);
-	ccr3 = getCx86(CX86_CCR3);
-	setCx86(CX86_CCR3, ccr3 ^ 0x80);
-	getCx86(0xc0);   /* dummy to change bus */
-
-	if (getCx86(CX86_CCR3) == ccr3) {       /* no DEVID regs. */
-		ccr2 = getCx86(CX86_CCR2);
-		setCx86(CX86_CCR2, ccr2 ^ 0x04);
-		getCx86(0xc0);  /* dummy */
-
-		if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
-			*dir0 = 0xfd;
-		else {                          /* Cx486S A step */
-			setCx86(CX86_CCR2, ccr2);
-			*dir0 = 0xfe;
-		}
-	}
-	else {
-		setCx86(CX86_CCR3, ccr3);  /* restore CCR3 */
-
-		/* read DIR0 and DIR1 CPU registers */
-		*dir0 = getCx86(CX86_DIR0);
-		*dir1 = getCx86(CX86_DIR1);
-	}
-	local_irq_restore(flags);
-}
-
-/*
- * Cx86_dir0_msb is a HACK needed by check_cx686_cpuid/slop in bugs.h in
- * order to identify the Cyrix CPU model after we're out of setup.c
- *
- * Actually since bugs.h doesnt even reference this perhaps someone should
- * fix the documentation ???
- */
-static unsigned char Cx86_dir0_msb __initdata = 0;
-
-static char Cx86_model[][9] __initdata = {
-	"Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
-	"M II ", "Unknown"
-};
-static char Cx486_name[][5] __initdata = {
-	"SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
-	"SRx2", "DRx2"
-};
-static char Cx486S_name[][4] __initdata = {
-	"S", "S2", "Se", "S2e"
-};
-static char Cx486D_name[][4] __initdata = {
-	"DX", "DX2", "?", "?", "?", "DX4"
-};
-static char Cx86_cb[] __initdata = "?.5x Core/Bus Clock";
-static char cyrix_model_mult1[] __initdata = "12??43";
-static char cyrix_model_mult2[] __initdata = "12233445";
-
-/*
- * Reset the slow-loop (SLOP) bit on the 686(L) which is set by some old
- * BIOSes for compatability with DOS games.  This makes the udelay loop
- * work correctly, and improves performance.
- *
- * FIXME: our newer udelay uses the tsc. We dont need to frob with SLOP
- */
-
-extern void calibrate_delay(void) __init;
-
-static void __init check_cx686_slop(struct cpuinfo_x86 *c)
-{
-	unsigned long flags;
-
-	if (Cx86_dir0_msb == 3) {
-		unsigned char ccr3, ccr5;
-
-		local_irq_save(flags);
-		ccr3 = getCx86(CX86_CCR3);
-		setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-		ccr5 = getCx86(CX86_CCR5);
-		if (ccr5 & 2)
-			setCx86(CX86_CCR5, ccr5 & 0xfd);  /* reset SLOP */
-		setCx86(CX86_CCR3, ccr3);		  /* disable MAPEN */
-		local_irq_restore(flags);
-
-		if (ccr5 & 2) { /* possible wrong calibration done */
-			printk(KERN_INFO "Recalibrating delay loop with SLOP bit reset\n");
-			calibrate_delay();
-			c->loops_per_jiffy = loops_per_jiffy;
-		}
-	}
-}
-
-
-static void __init init_cyrix(struct cpuinfo_x86 *c)
-{
-	unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
-	char *buf = c->x86_model_id;
-	const char *p = NULL;
-
-	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, c->x86_capability);
-
-	/* Cyrix used bit 24 in extended (AMD) CPUID for Cyrix MMX extensions */
-	if ( test_bit(1*32+24, c->x86_capability) ) {
-		clear_bit(1*32+24, c->x86_capability);
-		set_bit(X86_FEATURE_CXMMX, c->x86_capability);
-	}
-
-	do_cyrix_devid(&dir0, &dir1);
-
-	check_cx686_slop(c);
-
-	Cx86_dir0_msb = dir0_msn = dir0 >> 4; /* identifies CPU "family"   */
-	dir0_lsn = dir0 & 0xf;                /* model or clock multiplier */
-
-	/* common case step number/rev -- exceptions handled below */
-	c->x86_model = (dir1 >> 4) + 1;
-	c->x86_mask = dir1 & 0xf;
-
-	/* Now cook; the original recipe is by Channing Corn, from Cyrix.
-	 * We do the same thing for each generation: we work out
-	 * the model, multiplier and stepping.  Black magic included,
-	 * to make the silicon step/rev numbers match the printed ones.
-	 */
-	 
-	switch (dir0_msn) {
-		unsigned char tmp;
-
-	case 0: /* Cx486SLC/DLC/SRx/DRx */
-		p = Cx486_name[dir0_lsn & 7];
-		break;
-
-	case 1: /* Cx486S/DX/DX2/DX4 */
-		p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5]
-			: Cx486S_name[dir0_lsn & 3];
-		break;
-
-	case 2: /* 5x86 */
-		Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
-		p = Cx86_cb+2;
-		break;
-
-	case 3: /* 6x86/6x86L */
-		Cx86_cb[1] = ' ';
-		Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
-		if (dir1 > 0x21) { /* 686L */
-			Cx86_cb[0] = 'L';
-			p = Cx86_cb;
-			(c->x86_model)++;
-		} else             /* 686 */
-			p = Cx86_cb+1;
-		/* Emulate MTRRs using Cyrix's ARRs. */
-		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
-		/* 6x86's contain this bug */
-		c->coma_bug = 1;
-		break;
-
-	case 4: /* MediaGX/GXm */
-#ifdef CONFIG_PCI
-		/* It isn't really a PCI quirk directly, but the cure is the
-		   same. The MediaGX has deep magic SMM stuff that handles the
-		   SB emulation. It thows away the fifo on disable_dma() which
-		   is wrong and ruins the audio. 
-
-		   Bug2: VSA1 has a wrap bug so that using maximum sized DMA 
-		   causes bad things. According to NatSemi VSA2 has another
-		   bug to do with 'hlt'. I've not seen any boards using VSA2
-		   and X doesn't seem to support it either so who cares 8).
-		   VSA1 we work around however.
-		*/
-
-		printk(KERN_INFO "Working around Cyrix MediaGX virtual DMA bugs.\n");
-		isa_dma_bridge_buggy = 2;
-#endif		
-		c->x86_cache_size=16;	/* Yep 16K integrated cache thats it */
-
-		/* GXm supports extended cpuid levels 'ala' AMD */
-		if (c->cpuid_level == 2) {
-			/* Enable Natsemi MMX extensions */
-			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
-
-			get_model_name(c);  /* get CPU marketing name */
-			/*
-			 *  The 5510/5520 companion chips have a funky PIT
-			 *  that breaks the TSC synchronizing, so turn it off
-			 */
-			if(pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
-				pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
-				clear_bit(X86_FEATURE_TSC, c->x86_capability);
-			return;
-		}
-		else {  /* MediaGX */
-			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
-			p = Cx86_cb+2;
-			c->x86_model = (dir1 & 0x20) ? 1 : 2;
-#ifndef CONFIG_CS5520
-			clear_bit(X86_FEATURE_TSC, c->x86_capability);
-#endif
-		}
-		break;
-
-        case 5: /* 6x86MX/M II */
-		if (dir1 > 7)
-		{
-			dir0_msn++;  /* M II */
-			/* Enable MMX extensions (App note 108) */
-			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
-		}
-		else
-		{
-			c->coma_bug = 1;      /* 6x86MX, it has the bug. */
-		}
-		tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
-		Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
-		p = Cx86_cb+tmp;
-	 	if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
-			(c->x86_model)++;
-		/* Emulate MTRRs using Cyrix's ARRs. */
-		set_bit(X86_FEATURE_CYRIX_ARR, c->x86_capability);
-		break;
-
-	case 0xf:  /* Cyrix 486 without DEVID registers */
-		switch (dir0_lsn) {
-		case 0xd:  /* either a 486SLC or DLC w/o DEVID */
-			dir0_msn = 0;
-			p = Cx486_name[(c->hard_math) ? 1 : 0];
-			break;
-
-		case 0xe:  /* a 486S A step */
-			dir0_msn = 0;
-			p = Cx486S_name[0];
-			break;
-		}
-		break;
-
-	default:  /* unknown (shouldn't happen, we know everyone ;-) */
-		dir0_msn = 7;
-		break;
-	}
-	strcpy(buf, Cx86_model[dir0_msn & 7]);
-	if (p) strcat(buf, p);
-	return;
-}
-
-#ifdef CONFIG_X86_OOSTORE
-
-static u32 __init power2(u32 x)
-{
-	u32 s=1;
-	while(s<=x)
-		s<<=1;
-	return s>>=1;
-}
-
-/*
- *	Set up an actual MCR
- */
- 
-static void __init winchip_mcr_insert(int reg, u32 base, u32 size, int key)
-{
-	u32 lo, hi;
-	
-	hi = base & ~0xFFF;
-	lo = ~(size-1);		/* Size is a power of 2 so this makes a mask */
-	lo &= ~0xFFF;		/* Remove the ctrl value bits */
-	lo |= key;		/* Attribute we wish to set */
-	wrmsr(reg+MSR_IDT_MCR0, lo, hi);
-	mtrr_centaur_report_mcr(reg, lo, hi);	/* Tell the mtrr driver */
-}
-
-/*
- *	Figure what we can cover with MCR's
- *
- *	Shortcut: We know you can't put 4Gig of RAM on a winchip
- */
-
-static u32 __init ramtop(void)		/* 16388 */
-{
-	int i;
-	u32 top = 0;
-	u32 clip = 0xFFFFFFFFUL;
-	
-	for (i = 0; i < e820.nr_map; i++) {
-		unsigned long start, end;
-
-		if (e820.map[i].addr > 0xFFFFFFFFUL)
-			continue;
-		/*
-		 *	Don't MCR over reserved space. Ignore the ISA hole
-		 *	we frob around that catastrophy already
-		 */
-		 			
-		if (e820.map[i].type == E820_RESERVED)
-		{
-			if(e820.map[i].addr >= 0x100000UL && e820.map[i].addr < clip)
-				clip = e820.map[i].addr;
-			continue;
-		}
-		start = e820.map[i].addr;
-		end = e820.map[i].addr + e820.map[i].size;
-		if (start >= end)
-			continue;
-		if (end > top)
-			top = end;
-	}
-	/* Everything below 'top' should be RAM except for the ISA hole.
-	   Because of the limited MCR's we want to map NV/ACPI into our
-	   MCR range for gunk in RAM 
-	   
-	   Clip might cause us to MCR insufficient RAM but that is an
-	   acceptable failure mode and should only bite obscure boxes with
-	   a VESA hole at 15Mb
-	   
-	   The second case Clip sometimes kicks in is when the EBDA is marked
-	   as reserved. Again we fail safe with reasonable results
-	*/
-	
-	if(top>clip)
-		top=clip;
-		
-	return top;
-}
-
-/*
- *	Compute a set of MCR's to give maximum coverage
- */
-
-static int __init winchip_mcr_compute(int nr, int key)
-{
-	u32 mem = ramtop();
-	u32 root = power2(mem);
-	u32 base = root;
-	u32 top = root;
-	u32 floor = 0;
-	int ct = 0;
-	
-	while(ct<nr)
-	{
-		u32 fspace = 0;
-
-		/*
-		 *	Find the largest block we will fill going upwards
-		 */
-
-		u32 high = power2(mem-top);	
-
-		/*
-		 *	Find the largest block we will fill going downwards
-		 */
-
-		u32 low = base/2;
-
-		/*
-		 *	Don't fill below 1Mb going downwards as there
-		 *	is an ISA hole in the way.
-		 */		
-		 
-		if(base <= 1024*1024)
-			low = 0;
-			
-		/*
-		 *	See how much space we could cover by filling below
-		 *	the ISA hole
-		 */
-		 
-		if(floor == 0)
-			fspace = 512*1024;
-		else if(floor ==512*1024)
-			fspace = 128*1024;
-
-		/* And forget ROM space */
-		
-		/*
-		 *	Now install the largest coverage we get
-		 */
-		 
-		if(fspace > high && fspace > low)
-		{
-			winchip_mcr_insert(ct, floor, fspace, key);
-			floor += fspace;
-		}
-		else if(high > low)
-		{
-			winchip_mcr_insert(ct, top, high, key);
-			top += high;
-		}
-		else if(low > 0)
-		{
-			base -= low;
-			winchip_mcr_insert(ct, base, low, key);
-		}
-		else break;
-		ct++;
-	}
-	/*
-	 *	We loaded ct values. We now need to set the mask. The caller
-	 *	must do this bit.
-	 */
-	 
-	return ct;
-}
-
-static void __init winchip_create_optimal_mcr(void)
-{
-	int i;
-	/*
-	 *	Allocate up to 6 mcrs to mark as much of ram as possible
-	 *	as write combining and weak write ordered.
-	 *
-	 *	To experiment with: Linux never uses stack operations for 
-	 *	mmio spaces so we could globally enable stack operation wc
-	 *
-	 *	Load the registers with type 31 - full write combining, all
-	 *	writes weakly ordered.
-	 */
-	int used = winchip_mcr_compute(6, 31);
-
-	/*
-	 *	Wipe unused MCRs
-	 */
-	 
-	for(i=used;i<8;i++)
-		wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-static void __init winchip2_create_optimal_mcr(void)
-{
-	u32 lo, hi;
-	int i;
-
-	/*
-	 *	Allocate up to 6 mcrs to mark as much of ram as possible
-	 *	as write combining, weak store ordered.
-	 *
-	 *	Load the registers with type 25
-	 *		8	-	weak write ordering
-	 *		16	-	weak read ordering
-	 *		1	-	write combining
-	 */
-
-	int used = winchip_mcr_compute(6, 25);
-	
-	/*
-	 *	Mark the registers we are using.
-	 */
-	 
-	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-	for(i=0;i<used;i++)
-		lo|=1<<(9+i);
-	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-	
-	/*
-	 *	Wipe unused MCRs
-	 */
-	 
-	for(i=used;i<8;i++)
-		wrmsr(MSR_IDT_MCR0+i, 0, 0);
-}
-
-/*
- *	Handle the MCR key on the Winchip 2.
- */
-
-static void __init winchip2_unprotect_mcr(void)
-{
-	u32 lo, hi;
-	u32 key;
-	
-	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-	lo&=~0x1C0;	/* blank bits 8-6 */
-	key = (lo>>17) & 7;
-	lo |= key<<6;	/* replace with unlock key */
-	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-
-static void __init winchip2_protect_mcr(void)
-{
-	u32 lo, hi;
-	
-	rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-	lo&=~0x1C0;	/* blank bits 8-6 */
-	wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-}
-	
-#endif
-
-static void __init init_centaur(struct cpuinfo_x86 *c)
-{
-	enum {
-		ECX8=1<<1,
-		EIERRINT=1<<2,
-		DPM=1<<3,
-		DMCE=1<<4,
-		DSTPCLK=1<<5,
-		ELINEAR=1<<6,
-		DSMC=1<<7,
-		DTLOCK=1<<8,
-		EDCTLB=1<<8,
-		EMMX=1<<9,
-		DPDC=1<<11,
-		EBRPRED=1<<12,
-		DIC=1<<13,
-		DDC=1<<14,
-		DNA=1<<15,
-		ERETSTK=1<<16,
-		E2MMX=1<<19,
-		EAMD3D=1<<20,
-	};
-
-	char *name;
-	u32  fcr_set=0;
-	u32  fcr_clr=0;
-	u32  lo,hi,newlo;
-	u32  aa,bb,cc,dd;
-
-	/* Bit 31 in normal CPUID used for nonstandard 3DNow ID;
-	   3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
-	clear_bit(0*32+31, c->x86_capability);
-
-	switch (c->x86) {
-
-		case 5:
-			switch(c->x86_model) {
-			case 4:
-				name="C6";
-				fcr_set=ECX8|DSMC|EDCTLB|EMMX|ERETSTK;
-				fcr_clr=DPDC;
-				printk(KERN_NOTICE "Disabling bugged TSC.\n");
-				clear_bit(X86_FEATURE_TSC, c->x86_capability);
-#ifdef CONFIG_X86_OOSTORE
-				winchip_create_optimal_mcr();
-				/* Enable
-					write combining on non-stack, non-string
-					write combining on string, all types
-					weak write ordering 
-					
-				   The C6 original lacks weak read order 
-				   
-				   Note 0x120 is write only on Winchip 1 */
-				   
-				wrmsr(MSR_IDT_MCR_CTRL, 0x01F0001F, 0);
-#endif				
-				break;
-			case 8:
-				switch(c->x86_mask) {
-				default:
-					name="2";
-					break;
-				case 7 ... 9:
-					name="2A";
-					break;
-				case 10 ... 15:
-					name="2B";
-					break;
-				}
-				fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D;
-				fcr_clr=DPDC;
-#ifdef CONFIG_X86_OOSTORE
-				winchip2_unprotect_mcr();
-				winchip2_create_optimal_mcr();
-				rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-				/* Enable
-					write combining on non-stack, non-string
-					write combining on string, all types
-					weak write ordering 
-				*/
-				lo|=31;				
-				wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-				winchip2_protect_mcr();
-#endif
-				break;
-			case 9:
-				name="3";
-				fcr_set=ECX8|DSMC|DTLOCK|EMMX|EBRPRED|ERETSTK|E2MMX|EAMD3D;
-				fcr_clr=DPDC;
-#ifdef CONFIG_X86_OOSTORE
-				winchip2_unprotect_mcr();
-				winchip2_create_optimal_mcr();
-				rdmsr(MSR_IDT_MCR_CTRL, lo, hi);
-				/* Enable
-					write combining on non-stack, non-string
-					write combining on string, all types
-					weak write ordering 
-				*/
-				lo|=31;				
-				wrmsr(MSR_IDT_MCR_CTRL, lo, hi);
-				winchip2_protect_mcr();
-#endif
-				break;
-			case 10:
-				name="4";
-				/* no info on the WC4 yet */
-				break;
-			default:
-				name="??";
-			}
-
-			rdmsr(MSR_IDT_FCR1, lo, hi);
-			newlo=(lo|fcr_set) & (~fcr_clr);
-
-			if (newlo!=lo) {
-				printk(KERN_INFO "Centaur FCR was 0x%X now 0x%X\n", lo, newlo );
-				wrmsr(MSR_IDT_FCR1, newlo, hi );
-			} else {
-				printk(KERN_INFO "Centaur FCR is 0x%X\n",lo);
-			}
-			/* Emulate MTRRs using Centaur's MCR. */
-			set_bit(X86_FEATURE_CENTAUR_MCR, c->x86_capability);
-			/* Report CX8 */
-			set_bit(X86_FEATURE_CX8, c->x86_capability);
-			/* Set 3DNow! on Winchip 2 and above. */
-			if (c->x86_model >=8)
-				set_bit(X86_FEATURE_3DNOW, c->x86_capability);
-			/* See if we can find out some more. */
-			if ( cpuid_eax(0x80000000) >= 0x80000005 ) {
-				/* Yes, we can. */
-				cpuid(0x80000005,&aa,&bb,&cc,&dd);
-				/* Add L1 data and code cache sizes. */
-				c->x86_cache_size = (cc>>24)+(dd>>24);
-			}
-			sprintf( c->x86_model_id, "WinChip %s", name );
-			break;
-
-		case 6:
-			switch (c->x86_model) {
-				case 6 ... 8:		/* Cyrix III family */
-					rdmsr (MSR_VIA_FCR, lo, hi);
-					lo |= (1<<1 | 1<<7);	/* Report CX8 & enable PGE */
-					wrmsr (MSR_VIA_FCR, lo, hi);
-
-					set_bit(X86_FEATURE_CX8, c->x86_capability);
-					set_bit(X86_FEATURE_3DNOW, c->x86_capability);
-
-					get_model_name(c);
-					display_cacheinfo(c);
-					break;
-			}
-			break;
-	}
-}
-
-
-static void __init init_transmeta(struct cpuinfo_x86 *c)
-{
-	unsigned int cap_mask, uk, max, dummy;
-	unsigned int cms_rev1, cms_rev2;
-	unsigned int cpu_rev, cpu_freq, cpu_flags;
-	char cpu_info[65];
-
-	get_model_name(c);	/* Same as AMD/Cyrix */
-	display_cacheinfo(c);
-
-	/* Print CMS and CPU revision */
-	max = cpuid_eax(0x80860000);
-	if ( max >= 0x80860001 ) {
-		cpuid(0x80860001, &dummy, &cpu_rev, &cpu_freq, &cpu_flags); 
-		printk(KERN_INFO "CPU: Processor revision %u.%u.%u.%u, %u MHz\n",
-		       (cpu_rev >> 24) & 0xff,
-		       (cpu_rev >> 16) & 0xff,
-		       (cpu_rev >> 8) & 0xff,
-		       cpu_rev & 0xff,
-		       cpu_freq);
-	}
-	if ( max >= 0x80860002 ) {
-		cpuid(0x80860002, &dummy, &cms_rev1, &cms_rev2, &dummy);
-		printk(KERN_INFO "CPU: Code Morphing Software revision %u.%u.%u-%u-%u\n",
-		       (cms_rev1 >> 24) & 0xff,
-		       (cms_rev1 >> 16) & 0xff,
-		       (cms_rev1 >> 8) & 0xff,
-		       cms_rev1 & 0xff,
-		       cms_rev2);
-	}
-	if ( max >= 0x80860006 ) {
-		cpuid(0x80860003,
-		      (void *)&cpu_info[0],
-		      (void *)&cpu_info[4],
-		      (void *)&cpu_info[8],
-		      (void *)&cpu_info[12]);
-		cpuid(0x80860004,
-		      (void *)&cpu_info[16],
-		      (void *)&cpu_info[20],
-		      (void *)&cpu_info[24],
-		      (void *)&cpu_info[28]);
-		cpuid(0x80860005,
-		      (void *)&cpu_info[32],
-		      (void *)&cpu_info[36],
-		      (void *)&cpu_info[40],
-		      (void *)&cpu_info[44]);
-		cpuid(0x80860006,
-		      (void *)&cpu_info[48],
-		      (void *)&cpu_info[52],
-		      (void *)&cpu_info[56],
-		      (void *)&cpu_info[60]);
-		cpu_info[64] = '\0';
-		printk(KERN_INFO "CPU: %s\n", cpu_info);
-	}
-
-	/* Unhide possibly hidden capability flags */
-	rdmsr(0x80860004, cap_mask, uk);
-	wrmsr(0x80860004, ~0, uk);
-	c->x86_capability[0] = cpuid_edx(0x00000001);
-	wrmsr(0x80860004, cap_mask, uk);
-}
-
-
-static void __init init_rise(struct cpuinfo_x86 *c)
-{
-	printk("CPU: Rise iDragon");
-	if (c->x86_model > 2)
-		printk(" II");
-	printk("\n");
-
-	/* Unhide possibly hidden capability flags
-	   The mp6 iDragon family don't have MSRs.
-	   We switch on extra features with this cpuid weirdness: */
-	__asm__ (
-		"movl $0x6363452a, %%eax\n\t"
-		"movl $0x3231206c, %%ecx\n\t"
-		"movl $0x2a32313a, %%edx\n\t"
-		"cpuid\n\t"
-		"movl $0x63634523, %%eax\n\t"
-		"movl $0x32315f6c, %%ecx\n\t"
-		"movl $0x2333313a, %%edx\n\t"
-		"cpuid\n\t" : : : "eax", "ebx", "ecx", "edx"
-	);
-	set_bit(X86_FEATURE_CX8, c->x86_capability);
-}
-
-
-extern void trap_init_f00f_bug(void);
-
-static void __init init_intel(struct cpuinfo_x86 *c)
-{
-	char *p = NULL;
-	unsigned int l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
-
-#ifdef CONFIG_X86_F00F_BUG
-	/*
-	 * All current models of Pentium and Pentium with MMX technology CPUs
-	 * have the F0 0F bug, which lets nonpriviledged users lock up the system.
-	 * Note that the workaround only should be initialized once...
-	 */
-	c->f00f_bug = 0;
-	if ( c->x86 == 5 ) {
-		static int f00f_workaround_enabled = 0;
-
-		c->f00f_bug = 1;
-		if ( !f00f_workaround_enabled ) {
-			trap_init_f00f_bug();
-			printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
-			f00f_workaround_enabled = 1;
-		}
-	}
-#endif
-
-
-	if (c->cpuid_level > 1) {
-		/* supports eax=2  call */
-		int i, j, n;
-		int regs[4];
-		unsigned char *dp = (unsigned char *)regs;
-
-		/* Number of times to iterate */
-		n = cpuid_eax(2) & 0xFF;
-
-		for ( i = 0 ; i < n ; i++ ) {
-			cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
-			
-			/* If bit 31 is set, this is an unknown format */
-			for ( j = 0 ; j < 3 ; j++ ) {
-				if ( regs[j] < 0 ) regs[j] = 0;
-			}
-
-			/* Byte 0 is level count, not a descriptor */
-			for ( j = 1 ; j < 16 ; j++ ) {
-				unsigned char des = dp[j];
-				unsigned char dl, dh;
-				unsigned int cs;
-
-				dh = des >> 4;
-				dl = des & 0x0F;
-
-				/* Black magic... */
-
-				switch ( dh )
-				{
-				case 0:
-					switch ( dl ) {
-					case 6:
-						/* L1 I cache */
-						l1i += 8;
-						break;
-					case 8:
-						/* L1 I cache */
-						l1i += 16;
-						break;
-					case 10:
-						/* L1 D cache */
-						l1d += 8;
-						break;
-					case 12:
-						/* L1 D cache */
-						l1d += 16;
-						break;
-					default:;
-						/* TLB, or unknown */
-					}
-					break;
-				case 2:
-					if ( dl ) {
-						/* L3 cache */
-						cs = (dl-1) << 9;
-						l3 += cs;
-					}
-					break;
-				case 4:
-					if ( c->x86 > 6 && dl ) {
-						/* P4 family */
-						/* L3 cache */
-						cs = 128 << (dl-1);
-						l3 += cs;
-						break;
-					}
-					/* else same as 8 - fall through */
-				case 8:
-					if ( dl ) {
-						/* L2 cache */
-						cs = 128 << (dl-1);
-						l2 += cs;
-					}
-					break;
-				case 6:
-					if (dl > 5) {
-						/* L1 D cache */
-						cs = 8<<(dl-6);
-						l1d += cs;
-					}
-					break;
-				case 7:
-					if ( dl >= 8 ) 
-					{
-						/* L2 cache */
-						cs = 64<<(dl-8);
-						l2 += cs;
-					} else {
-						/* L0 I cache, count as L1 */
-						cs = dl ? (16 << (dl-1)) : 12;
-						l1i += cs;
-					}
-					break;
-				default:
-					/* TLB, or something else we don't know about */
-					break;
-				}
-			}
-		}
-		if ( l1i || l1d )
-			printk(KERN_INFO "CPU: L1 I cache: %dK, L1 D cache: %dK\n",
-			      l1i, l1d);
-		if ( l2 )
-			printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
-		if ( l3 )
-			printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
-
-		/*
-		 * This assumes the L3 cache is shared; it typically lives in
-		 * the northbridge.  The L1 caches are included by the L2
-		 * cache, and so should not be included for the purpose of
-		 * SMP switching weights.
-		 */
-		c->x86_cache_size = l2 ? l2 : (l1i+l1d);
-	}
-
-	/* SEP CPUID bug: Pentium Pro reports SEP but doesn't have it */
-	if ( c->x86 == 6 && c->x86_model < 3 && c->x86_mask < 3 )
-		clear_bit(X86_FEATURE_SEP, c->x86_capability);
-	
-	/* Names for the Pentium II/Celeron processors 
-	   detectable only by also checking the cache size.
-	   Dixon is NOT a Celeron. */
-	if (c->x86 == 6) {
-		switch (c->x86_model) {
-		case 5:
-			if (l2 == 0)
-				p = "Celeron (Covington)";
-			if (l2 == 256)
-				p = "Mobile Pentium II (Dixon)";
-			break;
-			
-		case 6:
-			if (l2 == 128)
-				p = "Celeron (Mendocino)";
-			break;
-			
-		case 8:
-			if (l2 == 128)
-				p = "Celeron (Coppermine)";
-			break;
-		}
-	}
-
-	if ( p )
-		strcpy(c->x86_model_id, p);
-	
-#ifdef CONFIG_SMP
-	if (cpu_has(c, X86_FEATURE_HT)) {
-		extern	int phys_proc_id[NR_CPUS];
-		
-		u32 	eax, ebx, ecx, edx;
-		int 	index_lsb, index_msb, tmp;
-		int	initial_apic_id;
-		int 	cpu = smp_processor_id();
-
-		cpuid(1, &eax, &ebx, &ecx, &edx);
-		smp_num_siblings = (ebx & 0xff0000) >> 16;
-
-		if (smp_num_siblings == 1) {
-			printk(KERN_INFO  "CPU: Hyper-Threading is disabled\n");
-		} else if (smp_num_siblings > 1 ) {
-			index_lsb = 0;
-			index_msb = 31;
-			/*
-			 * At this point we only support two siblings per
-			 * processor package.
-			 */
-#define NR_SIBLINGS	2
-			if (smp_num_siblings != NR_SIBLINGS) {
-				printk(KERN_WARNING "CPU: Unsupported number of the siblings %d", smp_num_siblings);
-				smp_num_siblings = 1;
-				goto too_many_siblings;
-			}
-			tmp = smp_num_siblings;
-			while ((tmp & 1) == 0) {
-				tmp >>=1 ;
-				index_lsb++;
-			}
-			tmp = smp_num_siblings;
-			while ((tmp & 0x80000000 ) == 0) {
-				tmp <<=1 ;
-				index_msb--;
-			}
-			if (index_lsb != index_msb )
-				index_msb++;
-			initial_apic_id = ebx >> 24 & 0xff;
-			phys_proc_id[cpu] = initial_apic_id >> index_msb;
-
-			printk(KERN_INFO  "CPU: Physical Processor ID: %d\n",
-                               phys_proc_id[cpu]);
-		}
-
-	}
-too_many_siblings:
-#endif
-}
-
-void __init get_cpu_vendor(struct cpuinfo_x86 *c)
-{
-	char *v = c->x86_vendor_id;
-
-	if (!strcmp(v, "GenuineIntel"))
-		c->x86_vendor = X86_VENDOR_INTEL;
-	else if (!strcmp(v, "AuthenticAMD"))
-		c->x86_vendor = X86_VENDOR_AMD;
-	else if (!strcmp(v, "CyrixInstead"))
-		c->x86_vendor = X86_VENDOR_CYRIX;
-	else if (!strcmp(v, "Geode by NSC"))
-		c->x86_vendor = X86_VENDOR_NSC;
-	else if (!strcmp(v, "UMC UMC UMC "))
-		c->x86_vendor = X86_VENDOR_UMC;
-	else if (!strcmp(v, "CentaurHauls"))
-		c->x86_vendor = X86_VENDOR_CENTAUR;
-	else if (!strcmp(v, "NexGenDriven"))
-		c->x86_vendor = X86_VENDOR_NEXGEN;
-	else if (!strcmp(v, "RiseRiseRise"))
-		c->x86_vendor = X86_VENDOR_RISE;
-	else if (!strcmp(v, "GenuineTMx86") ||
-		 !strcmp(v, "TransmetaCPU"))
-		c->x86_vendor = X86_VENDOR_TRANSMETA;
-	else
-		c->x86_vendor = X86_VENDOR_UNKNOWN;
-}
-
-struct cpu_model_info {
-	int vendor;
-	int family;
-	char *model_names[16];
-};
-
-/* Naming convention should be: <Name> [(<Codename>)] */
-/* This table only is used unless init_<vendor>() below doesn't set it; */
-/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
-static struct cpu_model_info cpu_models[] __initdata = {
-	{ X86_VENDOR_INTEL,	4,
-	  { "486 DX-25/33", "486 DX-50", "486 SX", "486 DX/2", "486 SL", 
-	    "486 SX/2", NULL, "486 DX/2-WB", "486 DX/4", "486 DX/4-WB", NULL, 
-	    NULL, NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_INTEL,	5,
-	  { "Pentium 60/66 A-step", "Pentium 60/66", "Pentium 75 - 200",
-	    "OverDrive PODP5V83", "Pentium MMX", NULL, NULL,
-	    "Mobile Pentium 75 - 200", "Mobile Pentium MMX", NULL, NULL, NULL,
-	    NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_INTEL,	6,
-	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
-	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II",
-	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL,
-	    "Pentium III (Cascades)", NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_AMD,	4,
-	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
-	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
-	    "Am5x86-WB" }},
-	{ X86_VENDOR_AMD,	5, /* Is this this really necessary?? */
-	  { "K5/SSA5", "K5",
-	    "K5", "K5", NULL, NULL,
-	    "K6", "K6", "K6-2",
-	    "K6-3", NULL, NULL, NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_AMD,	6, /* Is this this really necessary?? */
-	  { "Athlon", "Athlon",
-	    "Athlon", NULL, "Athlon", NULL,
-	    NULL, NULL, NULL,
-	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_UMC,	4,
-	  { NULL, "U5D", "U5S", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	    NULL, NULL, NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_NEXGEN,	5,
-	  { "Nx586", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	    NULL, NULL, NULL, NULL, NULL, NULL, NULL }},
-	{ X86_VENDOR_RISE,	5,
-	  { "iDragon", NULL, "iDragon", NULL, NULL, NULL, NULL,
-	    NULL, "iDragon II", "iDragon II", NULL, NULL, NULL, NULL, NULL, NULL }},
-};
-
-/* Look up CPU names by table lookup. */
-static char __init *table_lookup_model(struct cpuinfo_x86 *c)
-{
-	struct cpu_model_info *info = cpu_models;
-	int i;
-
-	if ( c->x86_model >= 16 )
-		return NULL;	/* Range check */
-
-	for ( i = 0 ; i < sizeof(cpu_models)/sizeof(struct cpu_model_info) ; i++ ) {
-		if ( info->vendor == c->x86_vendor &&
-		     info->family == c->x86 ) {
-			return info->model_names[c->x86_model];
-		}
-		info++;
-	}
-	return NULL;		/* Not found */
-}
-
-/*
- *	Detect a NexGen CPU running without BIOS hypercode new enough
- *	to have CPUID. (Thanks to Herbert Oppmann)
- */
- 
-static int __init deep_magic_nexgen_probe(void)
-{
-	int ret;
-	
-	__asm__ __volatile__ (
-		"	movw	$0x5555, %%ax\n"
-		"	xorw	%%dx,%%dx\n"
-		"	movw	$2, %%cx\n"
-		"	divw	%%cx\n"
-		"	movl	$0, %%eax\n"
-		"	jnz	1f\n"
-		"	movl	$1, %%eax\n"
-		"1:\n" 
-		: "=a" (ret) : : "cx", "dx" );
-	return  ret;
-}
-
-static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
-{
-	if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
-		/* Disable processor serial number */
-		unsigned long lo,hi;
-		rdmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
-		lo |= 0x200000;
-		wrmsr(MSR_IA32_BBL_CR_CTL,lo,hi);
-		printk(KERN_NOTICE "CPU serial number disabled.\n");
-		clear_bit(X86_FEATURE_PN, c->x86_capability);
-
-		/* Disabling the serial number may affect the cpuid level */
-		c->cpuid_level = cpuid_eax(0);
-	}
-}
-
-
-static int __init x86_serial_nr_setup(char *s)
-{
-	disable_x86_serial_nr = 0;
-	return 1;
-}
-__setup("serialnumber", x86_serial_nr_setup);
-
-static int __init x86_fxsr_setup(char * s)
-{
-	disable_x86_fxsr = 1;
-	return 1;
-}
-__setup("nofxsr", x86_fxsr_setup);
-
-
-/* Standard macro to see if a specific flag is changeable */
-static inline int flag_is_changeable_p(u32 flag)
-{
-	u32 f1, f2;
-
-	asm("pushfl\n\t"
-	    "pushfl\n\t"
-	    "popl %0\n\t"
-	    "movl %0,%1\n\t"
-	    "xorl %2,%0\n\t"
-	    "pushl %0\n\t"
-	    "popfl\n\t"
-	    "pushfl\n\t"
-	    "popl %0\n\t"
-	    "popfl\n\t"
-	    : "=&r" (f1), "=&r" (f2)
-	    : "ir" (flag));
-
-	return ((f1^f2) & flag) != 0;
-}
-
-
-/* Probe for the CPUID instruction */
-static int __init have_cpuid_p(void)
-{
-	return flag_is_changeable_p(X86_EFLAGS_ID);
-}
-
-/*
- * Cyrix CPUs without cpuid or with cpuid not yet enabled can be detected
- * by the fact that they preserve the flags across the division of 5/2.
- * PII and PPro exhibit this behavior too, but they have cpuid available.
- */
- 
-/*
- * Perform the Cyrix 5/2 test. A Cyrix won't change
- * the flags, while other 486 chips will.
- */
-static inline int test_cyrix_52div(void)
-{
-	unsigned int test;
-
-	__asm__ __volatile__(
-	     "sahf\n\t"		/* clear flags (%eax = 0x0005) */
-	     "div %b2\n\t"	/* divide 5 by 2 */
-	     "lahf"		/* store flags into %ah */
-	     : "=a" (test)
-	     : "0" (5), "q" (2)
-	     : "cc");
-
-	/* AH is 0x02 on Cyrix after the divide.. */
-	return (unsigned char) (test >> 8) == 0x02;
-}
-
-/* Try to detect a CPU with disabled CPUID, and if so, enable.  This routine
-   may also be used to detect non-CPUID processors and fill in some of
-   the information manually. */
-static int __init id_and_try_enable_cpuid(struct cpuinfo_x86 *c)
-{
-	/* First of all, decide if this is a 486 or higher */
-	/* It's a 486 if we can modify the AC flag */
-	if ( flag_is_changeable_p(X86_EFLAGS_AC) )
-		c->x86 = 4;
-	else
-		c->x86 = 3;
-
-	/* Detect Cyrix with disabled CPUID */
-	if ( c->x86 == 4 && test_cyrix_52div() ) {
-		unsigned char dir0, dir1;
-		
-		strcpy(c->x86_vendor_id, "CyrixInstead");
-	        c->x86_vendor = X86_VENDOR_CYRIX;
-	        
-	        /* Actually enable cpuid on the older cyrix */
-	    
-	    	/* Retrieve CPU revisions */
-	    	
-		do_cyrix_devid(&dir0, &dir1);
-
-		dir0>>=4;		
-		
-		/* Check it is an affected model */
-		
-   	        if (dir0 == 5 || dir0 == 3)
-   	        {
-			unsigned char ccr3, ccr4;
-			unsigned long flags;
-			printk(KERN_INFO "Enabling CPUID on Cyrix processor.\n");
-			local_irq_save(flags);
-			ccr3 = getCx86(CX86_CCR3);
-			setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */
-			ccr4 = getCx86(CX86_CCR4);
-			setCx86(CX86_CCR4, ccr4 | 0x80);          /* enable cpuid  */
-			setCx86(CX86_CCR3, ccr3);                 /* disable MAPEN */
-			local_irq_restore(flags);
-		}
-	} else
-
-	/* Detect NexGen with old hypercode */
-	if ( deep_magic_nexgen_probe() ) {
-		strcpy(c->x86_vendor_id, "NexGenDriven");
-	}
-
-	return have_cpuid_p();	/* Check to see if CPUID now enabled? */
-}
-
-/*
- * This does the hard work of actually picking apart the CPU stuff...
- */
-void __init identify_cpu(struct cpuinfo_x86 *c)
-{
-	int junk, i;
-	u32 xlvl, tfms;
-
-	c->loops_per_jiffy = loops_per_jiffy;
-	c->x86_cache_size = -1;
-	c->x86_vendor = X86_VENDOR_UNKNOWN;
-	c->cpuid_level = -1;	/* CPUID not detected */
-	c->x86_model = c->x86_mask = 0;	/* So far unknown... */
-	c->x86_vendor_id[0] = '\0'; /* Unset */
-	c->x86_model_id[0] = '\0';  /* Unset */
-	memset(&c->x86_capability, 0, sizeof c->x86_capability);
-
-	if ( !have_cpuid_p() && !id_and_try_enable_cpuid(c) ) {
-		/* CPU doesn't have CPUID */
-
-		/* If there are any capabilities, they're vendor-specific */
-		/* enable_cpuid() would have set c->x86 for us. */
-	} else {
-		/* CPU does have CPUID */
-
-		/* Get vendor name */
-		cpuid(0x00000000, &c->cpuid_level,
-		      (int *)&c->x86_vendor_id[0],
-		      (int *)&c->x86_vendor_id[8],
-		      (int *)&c->x86_vendor_id[4]);
-		
-		get_cpu_vendor(c);
-		/* Initialize the standard set of capabilities */
-		/* Note that the vendor-specific code below might override */
-
-		/* Intel-defined flags: level 0x00000001 */
-		if ( c->cpuid_level >= 0x00000001 ) {
-			u32 capability;
-			cpuid(0x00000001, &tfms, &junk, &junk, &capability);
-			c->x86_capability[0] = capability;
-			c->x86 = (tfms >> 8) & 15;
-			c->x86_model = (tfms >> 4) & 15;
-			c->x86_mask = tfms & 15;
-		} else {
-			/* Have CPUID level 0 only - unheard of */
-			c->x86 = 4;
-		}
-
-		/* AMD-defined flags: level 0x80000001 */
-		xlvl = cpuid_eax(0x80000000);
-		if ( (xlvl & 0xffff0000) == 0x80000000 ) {
-			if ( xlvl >= 0x80000001 )
-				c->x86_capability[1] = cpuid_edx(0x80000001);
-			if ( xlvl >= 0x80000004 )
-				get_model_name(c); /* Default name */
-		}
-
-		/* Transmeta-defined flags: level 0x80860001 */
-		xlvl = cpuid_eax(0x80860000);
-		if ( (xlvl & 0xffff0000) == 0x80860000 ) {
-			if (  xlvl >= 0x80860001 )
-				c->x86_capability[2] = cpuid_edx(0x80860001);
-		}
-	}
-
-	printk(KERN_DEBUG "CPU: Before vendor init, caps: %08lx %08lx %08lx, vendor = %d\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_vendor);
-
-	/*
-	 * Vendor-specific initialization.  In this section we
-	 * canonicalize the feature flags, meaning if there are
-	 * features a certain CPU supports which CPUID doesn't
-	 * tell us, CPUID claiming incorrect flags, or other bugs,
-	 * we handle them here.
-	 *
-	 * At the end of this section, c->x86_capability better
-	 * indicate the features this CPU genuinely supports!
-	 */
-	switch ( c->x86_vendor ) {
-	case X86_VENDOR_AMD:
-		init_amd(c);
-		break;
-
-	case X86_VENDOR_CENTAUR:
-		init_centaur(c);
-		break;
-
-	case X86_VENDOR_CYRIX:
-		init_cyrix(c);
-		break;
-
-	case X86_VENDOR_INTEL:
-		init_intel(c);
-		break;
-
-	case X86_VENDOR_NEXGEN:
-		c->x86_cache_size = 256; /* A few had 1 MB... */
-		break;
-
-	case X86_VENDOR_NSC:
-        init_cyrix(c);
-		break;
-
-	case X86_VENDOR_RISE:
-		init_rise(c);
-		break;
-
-	case X86_VENDOR_TRANSMETA:
-		init_transmeta(c);
-		break;
-
-	case X86_VENDOR_UNKNOWN:
-	default:
-		/* Not much we can do here... */
-		/* Check if at least it has cpuid */
-		if (c->cpuid_level == -1)
-		{
-			/* No cpuid. It must be an ancient CPU */
-			if (c->x86 == 4)
-				strcpy(c->x86_model_id, "486");
-			else if (c->x86 == 3)
-				strcpy(c->x86_model_id, "386");
-		}
-		break;
-
-	}
-
-	printk(KERN_DEBUG "CPU: After vendor init, caps: %08lx %08lx %08lx %08lx\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_capability[3]);
-
-	/*
-	 * The vendor-specific functions might have changed features.  Now
-	 * we do "generic changes."
-	 */
-
-	/* TSC disabled? */
-#ifndef CONFIG_X86_TSC
-	if ( tsc_disable )
-		clear_bit(X86_FEATURE_TSC, c->x86_capability);
-#endif
-
-	/* FXSR disabled? */
-	if (disable_x86_fxsr) {
-		clear_bit(X86_FEATURE_FXSR, c->x86_capability);
-		clear_bit(X86_FEATURE_XMM, c->x86_capability);
-	}
-
-	/* Disable the PN if appropriate */
-	squash_the_stupid_serial_number(c);
-
-	/* Init Machine Check Exception if available. */
-	mcheck_init(c);
-
-	/* If the model name is still unset, do table lookup. */
-	if ( !c->x86_model_id[0] ) {
-		char *p;
-		p = table_lookup_model(c);
-		if ( p )
-			strcpy(c->x86_model_id, p);
-		else
-			/* Last resort... */
-			sprintf(c->x86_model_id, "%02x/%02x",
-				c->x86_vendor, c->x86_model);
-	}
-
-	/* Now the feature flags better reflect actual CPU features! */
-
-	printk(KERN_DEBUG "CPU:     After generic, caps: %08lx %08lx %08lx %08lx\n",
-	       c->x86_capability[0],
-	       c->x86_capability[1],
-	       c->x86_capability[2],
-	       c->x86_capability[3]);
-
-	/*
-	 * On SMP, boot_cpu_data holds the common feature set between
-	 * all CPUs; so make sure that we indicate which features are
-	 * common between the CPUs.  The first time this routine gets
-	 * executed, c == &boot_cpu_data.
-	 */
-	if ( c != &boot_cpu_data ) {
-		/* AND the already accumulated flags with these */
-		for ( i = 0 ; i < NCAPINTS ; i++ )
-			boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
-	}
-
-	printk(KERN_DEBUG "CPU:             Common caps: %08lx %08lx %08lx %08lx\n",
-	       boot_cpu_data.x86_capability[0],
-	       boot_cpu_data.x86_capability[1],
-	       boot_cpu_data.x86_capability[2],
-	       boot_cpu_data.x86_capability[3]);
-}
-/*
- *	Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
- */
- 
-void __init dodgy_tsc(void)
-{
-	get_cpu_vendor(&boot_cpu_data);
-
-	if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) ||
-	    ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC   ))
-		init_cyrix(&boot_cpu_data);
-}
-
-
-/* These need to match <asm/processor.h> */
-static char *cpu_vendor_names[] __initdata = {
-	"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta", "NSC" };
-
-
-void __init print_cpu_info(struct cpuinfo_x86 *c)
-{
-	char *vendor = NULL;
-
-	if (c->x86_vendor < sizeof(cpu_vendor_names)/sizeof(char *))
-		vendor = cpu_vendor_names[c->x86_vendor];
-	else if (c->cpuid_level >= 0)
-		vendor = c->x86_vendor_id;
-
-	if (vendor && strncmp(c->x86_model_id, vendor, strlen(vendor)))
-		printk("%s ", vendor);
-
-	if (!c->x86_model_id[0])
-		printk("%d86", c->x86);
-	else
-		printk("%s", c->x86_model_id);
-
-	if (c->x86_mask || c->cpuid_level >= 0) 
-		printk(" stepping %02x\n", c->x86_mask);
-	else
-		printk("\n");
-}
-
-/*
- *	Get CPU information for use by the procfs.
- */
-static int show_cpuinfo(struct seq_file *m, void *v)
-{
-	/* 
-	 * These flag bits must match the definitions in <asm/cpufeature.h>.
-	 * NULL means this bit is undefined or reserved; either way it doesn't
-	 * have meaning as far as Linux is concerned.  Note that it's important
-	 * to realize there is a difference between this table and CPUID -- if
-	 * applications want to get the raw CPUID data, they should access
-	 * /dev/cpu/<cpu_nr>/cpuid instead.
-	 */
-	static char *x86_cap_flags[] = {
-		/* Intel-defined */
-		"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
-		"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
-		"pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
-		"fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", NULL,
-
-		/* AMD-defined */
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, "mp", NULL, NULL, "mmxext", NULL,
-		NULL, NULL, NULL, NULL, NULL, "lm", "3dnowext", "3dnow",
-
-		/* Transmeta-defined */
-		"recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-
-		/* Other (Linux-defined) */
-		"cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-	};
-	struct cpuinfo_x86 *c = v;
-	int i, n = c - cpu_data;
-	int fpu_exception;
-
-#ifdef CONFIG_SMP
-	if (!(cpu_online_map & (1<<n)))
-		return 0;
-#endif
-	seq_printf(m, "processor\t: %d\n"
-		"vendor_id\t: %s\n"
-		"cpu family\t: %d\n"
-		"model\t\t: %d\n"
-		"model name\t: %s\n",
-		n,
-		c->x86_vendor_id[0] ? c->x86_vendor_id : "unknown",
-		c->x86,
-		c->x86_model,
-		c->x86_model_id[0] ? c->x86_model_id : "unknown");
-
-	if (c->x86_mask || c->cpuid_level >= 0)
-		seq_printf(m, "stepping\t: %d\n", c->x86_mask);
-	else
-		seq_printf(m, "stepping\t: unknown\n");
-
-	if ( cpu_has(c, X86_FEATURE_TSC) ) {
-		seq_printf(m, "cpu MHz\t\t: %lu.%03lu\n",
-			cpu_khz / 1000, (cpu_khz % 1000));
-	}
-
-	/* Cache size */
-	if (c->x86_cache_size >= 0)
-		seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size);
-	
-	/* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */
-	fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu);
-	seq_printf(m, "fdiv_bug\t: %s\n"
-			"hlt_bug\t\t: %s\n"
-			"f00f_bug\t: %s\n"
-			"coma_bug\t: %s\n"
-			"fpu\t\t: %s\n"
-			"fpu_exception\t: %s\n"
-			"cpuid level\t: %d\n"
-			"wp\t\t: %s\n"
-			"flags\t\t:",
-		     c->fdiv_bug ? "yes" : "no",
-		     c->hlt_works_ok ? "no" : "yes",
-		     c->f00f_bug ? "yes" : "no",
-		     c->coma_bug ? "yes" : "no",
-		     c->hard_math ? "yes" : "no",
-		     fpu_exception ? "yes" : "no",
-		     c->cpuid_level,
-		     c->wp_works_ok ? "yes" : "no");
-
-	for ( i = 0 ; i < 32*NCAPINTS ; i++ )
-		if ( test_bit(i, c->x86_capability) &&
-		     x86_cap_flags[i] != NULL )
-			seq_printf(m, " %s", x86_cap_flags[i]);
-
-	seq_printf(m, "\nbogomips\t: %lu.%02lu\n\n",
-		     c->loops_per_jiffy/(500000/HZ),
-		     (c->loops_per_jiffy/(5000/HZ)) % 100);
-	return 0;
-}
-
-static void *c_start(struct seq_file *m, loff_t *pos)
-{
-	return *pos < NR_CPUS ? cpu_data + *pos : NULL;
-}
-static void *c_next(struct seq_file *m, void *v, loff_t *pos)
-{
-	++*pos;
-	return c_start(m, pos);
-}
-static void c_stop(struct seq_file *m, void *v)
-{
-}
-struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo,
-};
-
-unsigned long cpu_initialized __initdata = 0;
-
-/*
- * cpu_init() initializes state that is per-CPU. Some data is already
- * initialized (naturally) in the bootstrap process, such as the GDT
- * and IDT. We reload them nevertheless, this function acts as a
- * 'CPU state barrier', nothing should get across.
- */
-void __init cpu_init (void)
-{
-	int nr = smp_processor_id();
-	struct tss_struct * t = &init_tss[nr];
-
-	if (test_and_set_bit(nr, &cpu_initialized)) {
-		printk(KERN_WARNING "CPU#%d already initialized!\n", nr);
-		for (;;) __sti();
-	}
-	printk(KERN_INFO "Initializing CPU#%d\n", nr);
-
-	if (cpu_has_vme || cpu_has_tsc || cpu_has_de)
-		clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-#ifndef CONFIG_X86_TSC
-	if (tsc_disable && cpu_has_tsc) {
-		printk(KERN_NOTICE "Disabling TSC...\n");
-		/**** FIX-HPA: DOES THIS REALLY BELONG HERE? ****/
-		clear_bit(X86_FEATURE_TSC, boot_cpu_data.x86_capability);
-		set_in_cr4(X86_CR4_TSD);
-	}
-#endif
-
-	__asm__ __volatile__("lgdt %0": "=m" (gdt_descr));
-	__asm__ __volatile__("lidt %0": "=m" (idt_descr));
-
-	/*
-	 * Delete NT
-	 */
-	__asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
-
-	/*
-	 * set up and load the per-CPU TSS and LDT
-	 */
-	atomic_inc(&init_mm.mm_count);
-	current->active_mm = &init_mm;
-	if(current->mm)
-		BUG();
-	enter_lazy_tlb(&init_mm, current, nr);
-
-	t->esp0 = current->thread.esp0;
-	set_tss_desc(nr,t);
-	gdt_table[__TSS(nr)].b &= 0xfffffdff;
-	load_TR(nr);
-	load_LDT(&init_mm.context);
-
-	/* Clear %fs and %gs. */
-	asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
-
-	/* Clear all 6 debug registers: */
-
-#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
-
-	CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
-
-#undef CD
-
-	/*
-	 * Force FPU initialization:
-	 */
-	clear_thread_flag(TIF_USEDFPU);
-	current->used_math = 0;
-	stts();
-}
-
-/*
- *	Early probe support logic for ppro memory erratum #50
- *
- *	This is called before we do cpu ident work
- */
- 
-int __init ppro_with_ram_bug(void)
-{
-	char vendor_id[16];
-	int ident;
-
-	/* Must have CPUID */
-	if(!have_cpuid_p())
-		return 0;
-	if(cpuid_eax(0)<1)
-		return 0;
-	
-	/* Must be Intel */
-	cpuid(0, &ident, 
-		(int *)&vendor_id[0],
-		(int *)&vendor_id[8],
-		(int *)&vendor_id[4]);
-	
-	if(memcmp(vendor_id, "IntelInside", 12))
-		return 0;
-	
-	ident = cpuid_eax(1);
-
-	/* Model 6 */
-
-	if(((ident>>8)&15)!=6)
-		return 0;
-	
-	/* Pentium Pro */
-
-	if(((ident>>4)&15)!=1)
-		return 0;
-	
-	if((ident&15) < 8)
-	{
-		printk(KERN_INFO "Pentium Pro with Errata#50 detected. Taking evasive action.\n");
-		return 1;
-	}
-	printk(KERN_INFO "Your Pentium Pro seems ok.\n");
-	return 0;
-}
-	
 /*
  * Local Variables:
  * mode:c
diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
--- a/arch/i386/kernel/smp.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/kernel/smp.c	Sat Jun  8 22:31:36 2002
@@ -359,10 +359,12 @@
 
 asmlinkage void smp_invalidate_interrupt (void)
 {
-	unsigned long cpu = smp_processor_id();
+	unsigned long cpu;
+
+	cpu = get_cpu();
 
 	if (!test_bit(cpu, &flush_cpumask))
-		return;
+		goto out;
 		/* 
 		 * This was a BUG() but until someone can quote me the
 		 * line from the intel manual that guarantees an IPI to
@@ -383,6 +385,9 @@
 	}
 	ack_APIC_irq();
 	clear_bit(cpu, &flush_cpumask);
+
+out:
+	put_cpu();
 }
 
 static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm,
@@ -432,16 +437,23 @@
 void flush_tlb_current_task(void)
 {
 	struct mm_struct *mm = current->mm;
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 
 	local_flush_tlb();
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+	preempt_enable();
 }
 
 void flush_tlb_mm (struct mm_struct * mm)
 {
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 
 	if (current->active_mm == mm) {
 		if (current->mm)
@@ -451,12 +463,17 @@
 	}
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+	preempt_enable();
 }
 
 void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
 {
 	struct mm_struct *mm = vma->vm_mm;
-	unsigned long cpu_mask = mm->cpu_vm_mask & ~(1 << smp_processor_id());
+	unsigned long cpu_mask;
+
+	preempt_disable();
+	cpu_mask = mm->cpu_vm_mask & ~(1UL << smp_processor_id());
 
 	if (current->active_mm == mm) {
 		if(current->mm)
@@ -467,6 +484,8 @@
 
 	if (cpu_mask)
 		flush_tlb_others(cpu_mask, mm, va);
+
+	preempt_enable();
 }
 
 static inline void do_flush_tlb_all_local(void)
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/suspend.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,302 @@
+/*
+ * Suspend support specific for i386.
+ *
+ * Distribute under GPLv2
+ *
+ * Copyright (c) 2002 Pavel Machek <pavel@suse.cz>
+ */
+
+#define ACPI_C
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/sysrq.h>
+#include <linux/compatmac.h>
+#include <linux/proc_fs.h>
+#include <linux/irq.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <asm/uaccess.h>
+#include <asm/acpi.h>
+#include <asm/tlbflush.h>
+
+
+static struct saved_context saved_context;
+
+/*
+ * save_processor_context
+ * 
+ * Save the state of the processor before we go to sleep.
+ *
+ * return_stack is the value of the stack pointer (%esp) as the caller sees it.
+ * A good way could not be found to obtain it from here (don't want to make _too_
+ * many assumptions about the layout of the stack this far down.) Also, the 
+ * handy little __builtin_frame_pointer(level) where level > 0, is blatantly 
+ * buggy - it returns the value of the stack at the proper location, not the 
+ * location, like it should (as of gcc 2.91.66)
+ * 
+ * Note that the context and timing of this function is pretty critical.
+ * With a minimal amount of things going on in the caller and in here, gcc
+ * does a good job of being just a dumb compiler.  Watch the assembly output
+ * if anything changes, though, and make sure everything is going in the right
+ * place. 
+ */
+static inline void save_processor_context (void)
+{
+	kernel_fpu_begin();
+
+	/*
+	 * descriptor tables
+	 */
+	asm volatile ("sgdt (%0)" : "=m" (saved_context.gdt_limit));
+	asm volatile ("sidt (%0)" : "=m" (saved_context.idt_limit));
+	asm volatile ("sldt (%0)" : "=m" (saved_context.ldt));
+	asm volatile ("str (%0)"  : "=m" (saved_context.tr));
+
+	/*
+	 * save the general registers.
+	 * note that gcc has constructs to specify output of certain registers,
+	 * but they're not used here, because it assumes that you want to modify
+	 * those registers, so it tries to be smart and save them beforehand.
+	 * It's really not necessary, and kinda fishy (check the assembly output),
+	 * so it's avoided. 
+	 */
+	asm volatile ("movl %%esp, (%0)" : "=m" (saved_context.esp));
+	asm volatile ("movl %%eax, (%0)" : "=m" (saved_context.eax));
+	asm volatile ("movl %%ebx, (%0)" : "=m" (saved_context.ebx));
+	asm volatile ("movl %%ecx, (%0)" : "=m" (saved_context.ecx));
+	asm volatile ("movl %%edx, (%0)" : "=m" (saved_context.edx));
+	asm volatile ("movl %%ebp, (%0)" : "=m" (saved_context.ebp));
+	asm volatile ("movl %%esi, (%0)" : "=m" (saved_context.esi));
+	asm volatile ("movl %%edi, (%0)" : "=m" (saved_context.edi));
+
+	/*
+	 * segment registers
+	 */
+	asm volatile ("movw %%es, %0" : "=r" (saved_context.es));
+	asm volatile ("movw %%fs, %0" : "=r" (saved_context.fs));
+	asm volatile ("movw %%gs, %0" : "=r" (saved_context.gs));
+	asm volatile ("movw %%ss, %0" : "=r" (saved_context.ss));
+
+	/*
+	 * control registers 
+	 */
+	asm volatile ("movl %%cr0, %0" : "=r" (saved_context.cr0));
+	asm volatile ("movl %%cr2, %0" : "=r" (saved_context.cr2));
+	asm volatile ("movl %%cr3, %0" : "=r" (saved_context.cr3));
+	asm volatile ("movl %%cr4, %0" : "=r" (saved_context.cr4));
+
+	/*
+	 * eflags
+	 */
+	asm volatile ("pushfl ; popl (%0)" : "=m" (saved_context.eflags));
+}
+
+/*
+ * restore_processor_context
+ * 
+ * Restore the processor context as it was before we went to sleep
+ * - descriptor tables
+ * - control registers
+ * - segment registers
+ * - flags
+ * 
+ * Note that it is critical that this function is declared inline.  
+ * It was separated out from restore_state to make that function
+ * a little clearer, but it needs to be inlined because we won't have a
+ * stack when we get here (so we can't push a return address).
+ */
+static inline void restore_processor_context (void)
+{
+	/*
+	 * first restore %ds, so we can access our data properly
+	 */
+	asm volatile (".align 4");
+	asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
+
+
+	/*
+	 * control registers
+	 */
+	asm volatile ("movl %0, %%cr4" :: "r" (saved_context.cr4));
+	asm volatile ("movl %0, %%cr3" :: "r" (saved_context.cr3));
+	asm volatile ("movl %0, %%cr2" :: "r" (saved_context.cr2));
+	asm volatile ("movl %0, %%cr0" :: "r" (saved_context.cr0));
+	
+	/*
+	 * segment registers
+	 */
+	asm volatile ("movw %0, %%es" :: "r" (saved_context.es));
+	asm volatile ("movw %0, %%fs" :: "r" (saved_context.fs));
+	asm volatile ("movw %0, %%gs" :: "r" (saved_context.gs));
+	asm volatile ("movw %0, %%ss" :: "r" (saved_context.ss));
+
+	/*
+	 * the other general registers
+	 *
+	 * note that even though gcc has constructs to specify memory 
+	 * input into certain registers, it will try to be too smart
+	 * and save them at the beginning of the function.  This is esp.
+	 * bad since we don't have a stack set up when we enter, and we 
+	 * want to preserve the values on exit. So, we set them manually.
+	 */
+	asm volatile ("movl %0, %%esp" :: "m" (saved_context.esp));
+	asm volatile ("movl %0, %%ebp" :: "m" (saved_context.ebp));
+	asm volatile ("movl %0, %%eax" :: "m" (saved_context.eax));
+	asm volatile ("movl %0, %%ebx" :: "m" (saved_context.ebx));
+	asm volatile ("movl %0, %%ecx" :: "m" (saved_context.ecx));
+	asm volatile ("movl %0, %%edx" :: "m" (saved_context.edx));
+	asm volatile ("movl %0, %%esi" :: "m" (saved_context.esi));
+	asm volatile ("movl %0, %%edi" :: "m" (saved_context.edi));
+
+	/*
+	 * now restore the descriptor tables to their proper values
+	 * ltr is done i fix_processor_context().
+	 */
+	asm volatile ("lgdt (%0)" :: "m" (saved_context.gdt_limit));
+	asm volatile ("lidt (%0)" :: "m" (saved_context.idt_limit));
+	asm volatile ("lldt (%0)" :: "m" (saved_context.ldt));
+
+	fix_processor_context();
+
+	/*
+	 * the flags
+	 */
+	asm volatile ("pushl %0 ; popfl" :: "m" (saved_context.eflags));
+
+	do_fpu_end();
+}
+
+#ifdef CONFIG_ACPI_SLEEP
+void do_suspend_lowlevel(int resume)
+{
+/*
+ * FIXME: This function should really be written in assembly. Actually
+ * requirement is that it does not touch stack, because %esp will be
+ * wrong during resume before restore_processor_context(). Check
+ * assembly if you modify this.
+ */
+	if (!resume) {
+		save_processor_context();
+		acpi_save_register_state((unsigned long)&&acpi_sleep_done);
+		acpi_enter_sleep_state(3);
+		return;
+	}
+acpi_sleep_done:
+	acpi_restore_register_state();
+	restore_processor_context();
+}
+#endif
+
+void fix_processor_context(void)
+{
+	int nr = smp_processor_id();
+	struct tss_struct * t = &init_tss[nr];
+
+	set_tss_desc(nr,t);	/* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */
+        gdt_table[__TSS(nr)].b &= 0xfffffdff;
+
+	load_TR(nr);		/* This does ltr */
+
+	load_LDT(&current->mm->context);	/* This does lldt */
+
+	/*
+	 * Now maybe reload the debug registers
+	 */
+	if (current->thread.debugreg[7]){
+                loaddebug(&current->thread, 0);
+                loaddebug(&current->thread, 1);
+                loaddebug(&current->thread, 2);
+                loaddebug(&current->thread, 3);
+                /* no 4 and 5 */
+                loaddebug(&current->thread, 6);
+                loaddebug(&current->thread, 7);
+	}
+
+}
+
+static void
+do_fpu_end(void)
+{
+        /* restore FPU regs if necessary */
+	/* Do it out of line so that gcc does not move cr0 load to some stupid place */
+        kernel_fpu_end();
+}
+
+/* Local variables for do_magic */
+static int loop __nosavedata = 0;
+static int loop2 __nosavedata = 0;
+
+/*
+ * (KG): Since we affect stack here, we make this function as flat and easy
+ * as possible in order to not provoke gcc to use local variables on the stack.
+ * Note that on resume, all (expect nosave) variables will have the state from
+ * the time of writing (suspend_save_image) and the registers (including the
+ * stack pointer, but excluding the instruction pointer) will be loaded with 
+ * the values saved at save_processor_context() time.
+ */
+void do_magic(int resume)
+{
+	/* DANGER WILL ROBINSON!
+	 *
+	 * If this function is too difficult for gcc to optimize, it will crash and burn!
+	 * see above.
+	 *
+	 * DO NOT TOUCH.
+	 */
+
+	if (!resume) {
+		do_magic_suspend_1();
+		save_processor_context();	/* We need to capture registers and memory at "same time" */
+		do_magic_suspend_2();		/* If everything goes okay, this function does not return */
+		return;
+	}
+
+	/* We want to run from swapper_pg_dir, since swapper_pg_dir is stored in constant
+	 * place in memory 
+	 */
+
+        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
+
+/*
+ * Final function for resuming: after copying the pages to their original
+ * position, it restores the register state.
+ *
+ * What about page tables? Writing data pages may toggle
+ * accessed/dirty bits in our page tables. That should be no problems
+ * with 4MB page tables. That's why we require have_pse.  
+ *
+ * This loops destroys stack from under itself, so it better should
+ * not use any stack space, itself. When this function is entered at
+ * resume time, we move stack to _old_ place.  This is means that this
+ * function must use no stack and no local variables in registers,
+ * until calling restore_processor_context();
+ *
+ * Critical section here: noone should touch saved memory after
+ * do_magic_resume_1; copying works, because nr_copy_pages,
+ * pagedir_nosave, loop and loop2 are nosavedata.
+ */
+	do_magic_resume_1();
+
+	for (loop=0; loop < nr_copy_pages; loop++) {
+		/* You may not call something (like copy_page) here: see above */
+		for (loop2=0; loop2 < PAGE_SIZE; loop2++) {
+			*(((char *)((pagedir_nosave+loop)->orig_address))+loop2) =
+				*(((char *)((pagedir_nosave+loop)->address))+loop2);
+			__flush_tlb();
+		}
+	}
+
+	restore_processor_context();
+
+/* Ahah, we now run with our old stack, and with registers copied from
+   suspend time */
+
+	do_magic_resume_2();
+}
diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/mm/ioremap.c	Sat Jun  8 22:31:36 2002
@@ -9,6 +9,7 @@
  */
 
 #include <linux/vmalloc.h>
+#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/pgalloc.h>
 #include <asm/fixmap.h>
diff -Nru a/arch/i386/pci/acpi.c b/arch/i386/pci/acpi.c
--- a/arch/i386/pci/acpi.c	Sat Jun  8 22:31:51 2002
+++ b/arch/i386/pci/acpi.c	Sat Jun  8 22:31:51 2002
@@ -1,5 +1,6 @@
 #include <linux/pci.h>
 #include <linux/acpi.h>
+#include <linux/init.h>
 #include "pci.h"
 
 static int __init pci_acpi_init(void)
diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c
--- a/arch/i386/pci/common.c	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/pci/common.c	Sat Jun  8 22:31:37 2002
@@ -7,6 +7,7 @@
 #include <linux/sched.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #include <asm/segment.h>
 #include <asm/io.h>
diff -Nru a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
--- a/arch/i386/pci/direct.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/pci/direct.c	Sat Jun  8 22:31:36 2002
@@ -3,6 +3,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/init.h>
 #include "pci.h"
 
 /*
diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- a/arch/i386/pci/fixup.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/pci/fixup.c	Sat Jun  8 22:31:36 2002
@@ -3,6 +3,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/init.h>
 #include "pci.h"
 
 
@@ -174,6 +175,9 @@
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		pci_fixup_latency },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5598,		pci_fixup_latency },
  	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_3,	pci_fixup_piix4_acpi },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_10,	pci_fixup_ide_trash },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801CA_11,	pci_fixup_ide_trash },
+ 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_9,	pci_fixup_ide_trash },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8622,	        pci_fixup_via_northbridge_bug },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8361,	        pci_fixup_via_northbridge_bug },
diff -Nru a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c
--- a/arch/i386/pci/legacy.c	Sat Jun  8 22:31:37 2002
+++ b/arch/i386/pci/legacy.c	Sat Jun  8 22:31:37 2002
@@ -1,6 +1,7 @@
 /*
  * legacy.c - traditional, old school PCI bus probing
  */
+#include <linux/init.h>
 #include <linux/pci.h>
 #include "pci.h"
 
diff -Nru a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c
--- a/arch/i386/pci/numa.c	Sat Jun  8 22:31:36 2002
+++ b/arch/i386/pci/numa.c	Sat Jun  8 22:31:36 2002
@@ -2,6 +2,7 @@
  * numa.c - Low-level PCI access for NUMA-Q machines
  */
 #include <linux/pci.h>
+#include <linux/init.h>
 
 #include "pci.h"
 
diff -Nru a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c
--- a/arch/i386/pci/pcbios.c	Sat Jun  8 22:31:35 2002
+++ b/arch/i386/pci/pcbios.c	Sat Jun  8 22:31:35 2002
@@ -3,6 +3,7 @@
  */
 
 #include <linux/pci.h>
+#include <linux/init.h>
 #include "pci.h"
 
 
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Sat Jun  8 22:31:51 2002
+++ b/arch/ia64/ia32/sys_ia32.c	Sat Jun  8 22:31:51 2002
@@ -278,7 +278,8 @@
 		return -ENOMEM;
 
 	if (old_prot)
-		copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE);
+		if (copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE))
+			return -EFAULT;
 
 	down_write(&current->mm->mmap_sem);
 	{
diff -Nru a/arch/ia64/sn/io/ifconfig_net.c b/arch/ia64/sn/io/ifconfig_net.c
--- a/arch/ia64/sn/io/ifconfig_net.c	Sat Jun  8 22:31:37 2002
+++ b/arch/ia64/sn/io/ifconfig_net.c	Sat Jun  8 22:31:37 2002
@@ -202,16 +202,30 @@
 	 * Read in the header and see how big of a buffer we really need to 
 	 * allocate.
 	 */
-	ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), 
-			GFP_KERNEL);
-	copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num));
+	ifname_num = kmalloc(sizeof(struct ifname_num), GFP_KERNEL);
+	if (!ifname_num)
+		return -ENOMEM;
+	if (copy_from_user(ifname_num, (char *)arg,
+			   sizeof(struct ifname_num))) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	size = ifname_num->size;
 	kfree(ifname_num);
-	ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL);
+	ifname_num = kmalloc(size, GFP_KERNEL);
+	if (!ifname_num)
+		return -ENOMEM;
 	ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) );
 
-	copy_from_user( ifname_num, (char *) arg, size);
+	if (copy_from_user(ifname_num, (char *)arg, size)) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	new_devices =  kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL);
+	if (!new_devices) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	temp_new_devices = new_devices;
 
 	memset(new_devices, 0, size - sizeof(struct ifname_num));
@@ -257,9 +271,9 @@
 	/*
 	 * Copy back to the User Buffer area any new devices encountered.
 	 */
-	copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, 
-			size - sizeof(struct ifname_num));
-
+	if (copy_to_user((char *)arg + (sizeof(struct ifname_num)),
+			 new_devices, size - sizeof(struct ifname_num)))
+		return -EFAULT;
 	return(0);
 
 }
diff -Nru a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
--- a/arch/mips/boot/Makefile	Sat Jun  8 22:31:51 2002
+++ b/arch/mips/boot/Makefile	Sat Jun  8 22:31:51 2002
@@ -26,7 +26,7 @@
 
 all: vmlinux.ecoff addinitrd
 
-vmlinux.ecoff:	$(CONFIGURE) elf2ecoff $(TOPDIR)/vmlinux
+vmlinux.ecoff:	elf2ecoff $(TOPDIR)/vmlinux
 	./elf2ecoff $(TOPDIR)/vmlinux vmlinux.ecoff $(E2EFLAGS)
 
 elf2ecoff: elf2ecoff.c
diff -Nru a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
--- a/arch/mips/kernel/sysirix.c	Sat Jun  8 22:31:52 2002
+++ b/arch/mips/kernel/sysirix.c	Sat Jun  8 22:31:52 2002
@@ -1048,10 +1048,7 @@
 
 asmlinkage int irix_gettimeofday(struct timeval *tv)
 {
-	int retval;
-
-	retval = copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0;
-	return retval;
+	return copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0;
 }
 
 #define IRIX_MAP_AUTOGROW 0x40
diff -Nru a/arch/mips64/boot/Makefile b/arch/mips64/boot/Makefile
--- a/arch/mips64/boot/Makefile	Sat Jun  8 22:31:52 2002
+++ b/arch/mips64/boot/Makefile	Sat Jun  8 22:31:52 2002
@@ -17,7 +17,7 @@
 
 all: vmlinux.ecoff addinitrd
 
-vmlinux.ecoff:	$(CONFIGURE) elf2ecoff $(TOPDIR)/vmlinux
+vmlinux.ecoff:	elf2ecoff $(TOPDIR)/vmlinux
 	./elf2ecoff $(TOPDIR)/vmlinux vmlinux.ecoff $(E2EFLAGS)
 
 elf2ecoff: elf2ecoff.c
diff -Nru a/arch/ppc/iSeries/mf.c b/arch/ppc/iSeries/mf.c
--- a/arch/ppc/iSeries/mf.c	Sat Jun  8 22:31:37 2002
+++ b/arch/ppc/iSeries/mf.c	Sat Jun  8 22:31:37 2002
@@ -950,7 +950,10 @@
 	return -ENOMEM;
     }
 
-    copy_from_user(page, buffer, size);
+    if (copy_from_user(page, buffer, size)) {
+	    rc = -EFAULT;
+	    goto out;
+    }
     memset(&myVspCmd, 0, sizeof(myVspCmd));
 
     myVspCmd.xCmd = 30;
@@ -973,7 +976,7 @@
 	    rc = -ENOMEM;
 	}
     }
-
+out:
     pci_free_consistent(NULL, size, page, dma_addr);
 
     return rc;
diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
--- a/arch/ppc/kernel/ppc_htab.c	Sat Jun  8 22:31:35 2002
+++ b/arch/ppc/kernel/ppc_htab.c	Sat Jun  8 22:31:35 2002
@@ -223,7 +223,8 @@
 		n = strlen(buffer) - *ppos;
 	if (n > count)
 		n = count;
-	copy_to_user(buf, buffer + *ppos, n);
+	if (copy_to_user(buf, buffer + *ppos, n))
+		return -EFAULT;
 	*ppos += n;
 	return n;
 }
diff -Nru a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
--- a/arch/ppc64/kernel/rtasd.c	Sat Jun  8 22:31:37 2002
+++ b/arch/ppc64/kernel/rtasd.c	Sat Jun  8 22:31:37 2002
@@ -99,9 +99,7 @@
 	rtas_log_size -= 1;
 	spin_unlock(&rtas_log_lock);
 
-	copy_to_user(buf, tmp, count);
-	error = count;
-
+	error = copy_to_user(buf, tmp, count) ? -EFAULT : count;
 out:
 	kfree(tmp);
 	return error;
diff -Nru a/arch/s390/Config.help b/arch/s390/Config.help
--- a/arch/s390/Config.help	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/Config.help	Sat Jun  8 22:31:36 2002
@@ -155,7 +155,10 @@
   IPL device.
 
 CONFIG_IPL_TAPE
-  Select this option if you want to IPL the image from a Tape.
+  Select "tape" if you want to IPL the image from a Tape.
+
+  Select "vm_reader" if you are running under VM/ESA and want
+  to IPL the image from the emulated card reader.
 
 CONFIG_FAST_IRQ
   Select this option in order to get the interrupts processed faster
@@ -164,8 +167,57 @@
   interrupts which will also be processed before leaving the interrupt
   context.  This speeds up the I/O a lot. Say "Y".
 
+CONFIG_MACHCHK_WARNING
+  Select this option if you want the machine check handler on IBM S/390 or 
+  zSeries to process warning machine checks (e.g. on power failures). 
+  If unsure, say "Y".
+
+CONFIG_CHSC
+  Select this option if you want the s390 common I/O layer to use information
+  obtained by channel subsystem calls. This will enable Linux to process link
+  failures and resource accessibility events. Moreover, if you have procfs
+  enabled, you'll be able to toggle chpids logically offline and online. Even
+  if you don't understand what this means, you should say "Y".
+
 CONFIG_PROCESS_DEBUG
   Say Y to print all process fault locations to the console.  This is
   a debugging option; you probably do not want to set it unless you
   are an S390 port maintainer.
+
+CONFIG_PFAULT
+  Select this option, if you want to use PFAULT pseudo page fault
+  handling under VM. If running native or in LPAR, this option
+  has no effect. If your VM does not support PFAULT, PAGEEX
+  pseudo page fault handling will be used.
+  Note that VM 4.2 supports PFAULT but has a bug in its
+  implementation that causes some problems.
+  Everybody who wants to run Linux under VM != VM4.2 should select
+  this option.
+
+CONFIG_SHARED_KERNEL
+  Select this option, if you want to share the text segment of the
+  Linux kernel between different VM guests. This reduces memory
+  usage with lots of guests but greatly increases kernel size.
+  You should only select this option if you know what you are
+  doing and want to exploit this feature.
+
+CONFIG_QDIO
+  This driver provides the Queued Direct I/O base support for the
+  IBM S/390 (G5 and G6) and eServer zSeries (z800 and z900).
+
+  For details please refer to the documentation provided by IBM at
+  <http://www10.software.ibm.com/developerworks/opensource/linux390>
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qdio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say Y.
+
+Performance statistics for QDIO base support
+CONFIG_QDIO_PERF_STATS
+  Say Y here to get performance statistics in /proc/qdio_perf
+
+  If unsure, say N.
 
diff -Nru a/arch/s390/Makefile b/arch/s390/Makefile
--- a/arch/s390/Makefile	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/Makefile	Sat Jun  8 22:31:36 2002
@@ -1,4 +1,4 @@
-
+#
 # s390/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -14,14 +14,14 @@
 #
 
 LD=$(CROSS_COMPILE)ld -m elf_s390
-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)
+  LINKSCRIPT := arch/s390/vmlinux-shared.lds
 else
-LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
+  LINKSCRIPT := arch/s390/vmlinux.lds
 endif
+LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
@@ -29,14 +29,15 @@
 
 HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
-SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
-           drivers/s390 arch/s390/math-emu
+SUBDIRS += arch/s390/mm arch/s390/kernel arch/s390/lib drivers/s390
 CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES)
-DRIVERS := $(DRIVERS) drivers/s390/built-in.o
 LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
 
+DRIVERS += drivers/s390/built-in.o
+
 ifeq ($(CONFIG_MATHEMU),y)
-  CORE_FILES := $(CORE_FILES) arch/s390/math-emu/math-emu.o
+  SUBDIRS += arch/s390/math-emu
+  DRIVERS += arch/s390/math-emu/math-emu.o
 endif
 
 all: image listing
@@ -46,13 +47,19 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
+vmlinux: $(LINKSCRIPT)
+
 image: vmlinux 
 	@$(MAKEBOOT) image
 
 archclean:
 	@$(MAKEBOOT) clean
+	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
 
 archdep:
 	@$(MAKEBOOT) dep
+
+install: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=image install
diff -Nru a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
--- a/arch/s390/boot/Makefile	Sat Jun  8 22:31:43 2002
+++ b/arch/s390/boot/Makefile	Sat Jun  8 22:31:43 2002
@@ -1,16 +1,9 @@
 #
 # 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
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
 
 OBJCOPY = $(CROSS_COMPILE)objcopy
 
-O_TARGET := 
-
 EXTRA_AFLAGS := -traditional
 
 include $(TOPDIR)/Rules.make
@@ -21,7 +14,7 @@
 %.boot: %.lnk
 	$(OBJCOPY) -O binary $< $@
 
-image: $(CONFIGURE) $(TOPDIR)/vmlinux \
+image: $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
 	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
 	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
@@ -33,4 +26,7 @@
 
 clean:
 	rm -f image listing iplfba.boot ipleckd.boot ipldump.boot
+
+install: $(CONFIGURE) $(BOOTIMAGE)
+	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)"
 
diff -Nru a/arch/s390/boot/install.sh b/arch/s390/boot/install.sh
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/s390/boot/install.sh	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/s390x/boot/install.sh
+#
+# 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.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for s390 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+	mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+	mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
diff -Nru a/arch/s390/config.in b/arch/s390/config.in
--- a/arch/s390/config.in	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/config.in	Sat Jun  8 22:31:36 2002
@@ -7,8 +7,8 @@
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
 define_bool CONFIG_UID16 y
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 mainmenu_name "Linux Kernel Configuration"
@@ -23,8 +23,16 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'General setup'
+comment 'Base setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
+bool 'Use chscs for Common I/O' CONFIG_CHSC
+
+tristate 'QDIO support' CONFIG_QDIO
+  if [ "$CONFIG_QDIO" != "n" ]; then
+    bool '   Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
+  fi
+
 bool 'Builtin IPL record support' CONFIG_IPL
 if [ "$CONFIG_IPL" = "y" ]; then
   choice 'IPL method generated into head.S' \
@@ -39,6 +47,16 @@
 bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
+
 source drivers/s390/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
@@ -51,9 +69,9 @@
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-if [ "$CONFIG_CTC" = "y" ]; then
-  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
-fi
+#if [ "$CONFIG_CTC" = "y" ]; then
+#  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+#fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
diff -Nru a/arch/s390/defconfig b/arch/s390/defconfig
--- a/arch/s390/defconfig	Sat Jun  8 22:31:52 2002
+++ b/arch/s390/defconfig	Sat Jun  8 22:31:52 2002
@@ -5,9 +5,9 @@
 # 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_GENERIC_BUST_SPINLOCK=n
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
 CONFIG_ARCH_S390=y
 
 #
@@ -16,6 +16,14 @@
 CONFIG_EXPERIMENTAL=y
 
 #
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+
+#
 # Loadable module support
 #
 CONFIG_MODULES=y
@@ -29,16 +37,16 @@
 CONFIG_MATHEMU=y
 
 #
-# General setup
+# Base setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
+CONFIG_QDIO=m
+# CONFIG_QDIO_PERF_STATS is not set
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
@@ -47,6 +55,77 @@
 # CONFIG_SHARED_KERNEL is not set
 
 #
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=10
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_REPORT_LUNS is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
 # Block device drivers
 #
 CONFIG_BLK_DEV_LOOP=y
@@ -103,8 +182,8 @@
 #
 # S/390 tape hardware support
 #
-CONFIG_S390_TAPE_3490=y
-CONFIG_S390_TAPE_3480=y
+CONFIG_S390_TAPE_3490=m
+CONFIG_S390_TAPE_3480=m
 
 #
 # Network device drivers
@@ -123,6 +202,7 @@
 #
 CONFIG_CHANDEV=y
 CONFIG_HOTPLUG=y
+CONFIG_LCS=m
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -131,8 +211,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -144,18 +222,24 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
-# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -164,7 +248,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
+CONFIG_NET_FASTROUTE=y
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
@@ -176,18 +260,20 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
@@ -198,12 +284,15 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_DEBUG is not set
 # CONFIG_HPFS_FS is not set
@@ -232,8 +321,10 @@
 # CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+CONFIG_EXPORTFS=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
@@ -245,7 +336,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -262,6 +352,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -269,3 +360,10 @@
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Nru a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
--- a/arch/s390/kernel/Makefile	Sat Jun  8 22:31:52 2002
+++ b/arch/s390/kernel/Makefile	Sat Jun  8 22:31:52 2002
@@ -2,8 +2,10 @@
 # Makefile for the linux kernel.
 #
 
-O_TARGET	:= kernel.o
 EXTRA_TARGETS	:= head.o init_task.o
+EXTRA_AFLAGS	:= -traditional
+
+O_TARGET	:= kernel.o
 
 export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
 obj-y	:= entry.o bitmap.o traps.o time.o process.o irq.o \
@@ -18,7 +20,27 @@
 #
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-stub.o #gdb-low.o 
 
-EXTRA_AFLAGS := -traditional
-
 include $(TOPDIR)/Rules.make
+
+.PHONY: asm-offsets.h
+
+entry.S: asm-offsets.h
+
+asm-offsets.h: asm-offsets.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \
+	(echo "#ifndef __ASM_OFFSETS_H__"; \
+	 echo "#define __ASM_OFFSETS_H__"; \
+	 echo "/*"; \
+	 echo " * DO NOT MODIFY"; \
+	 echo " *"; \
+	 echo " * This file was generated by arch/s390/kernel/Makefile"; \
+	 echo " */"; \
+	 sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \
+	     -e "s:->::"; \
+	 echo "#endif" \
+	) > asm-offsets.h
+
+clean:
+	rm -f asm-offsets.h
+
 
diff -Nru a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/s390/kernel/asm-offsets.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,31 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val, marker) \
+	asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
+	DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),);
+	DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),);
+	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
+	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+	BLANK();
+	DEFINE(__TI_task, offsetof(struct thread_info, task),);
+	DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
+	DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
+	DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
+	DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
+	return 0;
+}
diff -Nru a/arch/s390/kernel/bitmap.S b/arch/s390/kernel/bitmap.S
--- a/arch/s390/kernel/bitmap.S	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/kernel/bitmap.S	Sat Jun  8 22:31:37 2002
@@ -35,3 +35,22 @@
          .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
          .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
 
+         .globl _sb_findmap
+_sb_findmap:
+         .byte  8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+
diff -Nru a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
--- a/arch/s390/kernel/debug.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/kernel/debug.c	Sat Jun  8 22:31:36 2002
@@ -68,12 +68,6 @@
 			   size_t user_len, loff_t * offset);
 static int debug_open(struct inode *inode, struct file *file);
 static int debug_close(struct inode *inode, struct file *file);
-static struct proc_dir_entry 
-*debug_create_proc_dir_entry(struct proc_dir_entry *root,
-			     const char *name, mode_t mode,
-			     struct file_operations *fops);
-static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
-					struct proc_dir_entry *entry);
 static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
@@ -155,7 +149,6 @@
 static int initialized = 0;
 
 static struct file_operations debug_file_ops = {
-	owner:	THIS_MODULE,
 	read:    debug_output,
 	write:   debug_input,	
 	open:    debug_open,
@@ -217,8 +210,10 @@
 	strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
 	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
 	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+#ifdef CONFIG_PROC_FS
 	memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
 		sizeof(struct proc_dir_entry*));
+#endif /* CONFIG_PROC_FS */
 	atomic_set(&(rc->ref_count), 0);
 
 	return rc;
@@ -265,11 +260,9 @@
 
 
 	/* create proc rood directory */
-
         rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry);
 
 	/* append new element to linked list */
-
         if (debug_area_first == NULL) {
                 /* first element in list */
                 debug_area_first = rc;
@@ -331,16 +324,22 @@
 	if (!db_info)
 		return;
 	if (atomic_dec_and_test(&db_info->ref_count)) {
+#ifdef DEBUG
 		printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
 		       db_info, db_info->name);
+#endif
 		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-			if (db_info->views[i] != NULL)
-				debug_delete_proc_dir_entry
-				    (db_info->proc_root_entry,
-				     db_info->proc_entries[i]);
+			if (db_info->views[i] == NULL)
+				continue;
+#ifdef CONFIG_PROC_FS
+			remove_proc_entry(db_info->proc_entries[i]->name,
+					  db_info->proc_root_entry);
+#endif
 		}
-		debug_delete_proc_dir_entry(debug_proc_root_entry,
-					    db_info->proc_root_entry);
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry(db_info->proc_root_entry->name,
+				  debug_proc_root_entry);
+#endif
 		if(db_info == debug_area_first)
 			debug_area_first = db_info->next;
 		if(db_info == debug_area_last)
@@ -497,6 +496,7 @@
 #ifdef DEBUG
 	printk("debug_open\n");
 #endif
+	MOD_INC_USE_COUNT;
 	down(&debug_lock);
 
 	/* find debug log and view */
@@ -524,14 +524,18 @@
 	debug_info_snapshot = debug_info_copy(debug_info);
 
 	if(!debug_info_snapshot){
+#ifdef DEBUG
 		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
+#endif
 		rc = -ENOMEM;
 		goto out;
 	}
 
 	if ((file->private_data =
 	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+#ifdef DEBUG
 		printk(KERN_ERR "debug_open: kmalloc failed\n");
+#endif
 		debug_info_free(debug_info_snapshot);	
 		rc = -ENOMEM;
 		goto out;
@@ -549,6 +553,8 @@
 
       out:
 	up(&debug_lock);
+	if (rc != 0)
+		MOD_DEC_USE_COUNT;
 	return rc;
 }
 
@@ -568,36 +574,11 @@
 	debug_info_free(p_info->debug_info_snap);
 	debug_info_put(p_info->debug_info_org);
 	kfree(file->private_data);
+	MOD_DEC_USE_COUNT;
 	return 0;		/* success */
 }
 
 /*
- * debug_create_proc_dir_entry:
- * - initializes proc-dir-entry and registers it
- */
-
-static struct proc_dir_entry *debug_create_proc_dir_entry
-    (struct proc_dir_entry *root, const char *name, mode_t mode,
-     struct file_operations *fops) 
-{
-	struct proc_dir_entry *rc = create_proc_entry(name, mode, root);
-	if (rc && fops)
-		rc->proc_fops = fops;
-	return rc;
-}
-
-
-/*
- * delete_proc_dir_entry:
- */
-
-static void debug_delete_proc_dir_entry
-    (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) 
-{
-	remove_proc_entry(proc_entry->name, root);
-}
-
-/*
  * debug_register:
  * - creates and initializes debug area for the caller
  * - returns handle for debug area
@@ -620,9 +601,11 @@
 		goto out;
 	debug_register_view(rc, &debug_level_view);
         debug_register_view(rc, &debug_flush_view);
+#ifdef DEBUG
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
+#endif
       out:
         if (rc == NULL){
 		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
@@ -642,7 +625,9 @@
 	if (!id)
 		goto out;
 	down(&debug_lock);
+#ifdef DEBUG
 	printk(KERN_INFO "debug: unregistering %s\n", id->name);
+#endif
 	debug_info_put(id);
 	up(&debug_lock);
 
@@ -849,7 +834,9 @@
 
 	down(&debug_lock);
 	if (!initialized) {
+#ifdef CONFIG_PROC_FS
 		debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
+#endif /* CONFIG_PROC_FS */
 		printk(KERN_INFO "debug: Initialization complete\n");
 		initialized = 1;
 	}
@@ -889,10 +876,10 @@
 			mode |= S_IRUSR;
 		if (view->input_proc)
 			mode |= S_IWUSR;
-		id->proc_entries[i] =
-		    debug_create_proc_dir_entry(id->proc_root_entry,
-						view->name, mode,
-						&debug_file_ops);
+		id->proc_entries[i] = create_proc_entry(view->name, mode,
+							id->proc_root_entry);
+		if (id->proc_entries[i] != NULL)
+			id->proc_entries[i]->proc_fops = &debug_file_ops;
 		rc = 0;
 	}
 	spin_unlock_irqrestore(&id->lock, flags);
@@ -920,8 +907,10 @@
 	if (i == DEBUG_MAX_VIEWS)
 		rc = -1;
 	else {
-		debug_delete_proc_dir_entry(id->proc_root_entry,
-					    id->proc_entries[i]);		
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry(id->proc_entries[i]->name,
+				  id->proc_root_entry);
+#endif
 		id->views[i] = NULL;
 		rc = 0;
 	}
@@ -1209,7 +1198,9 @@
 #ifdef DEBUG
 	printk("debug_cleanup_module: \n");
 #endif
-	debug_delete_proc_dir_entry(NULL, debug_proc_root_entry);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(debug_proc_root_entry->name, NULL);
+#endif /* CONFIG_PROC_FS */
 	return;
 }
 
diff -Nru a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
--- a/arch/s390/kernel/entry.S	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/kernel/entry.S	Sat Jun  8 22:31:36 2002
@@ -17,6 +17,9 @@
 #include <asm/errno.h>
 #include <asm/smp.h>
 #include <asm/ptrace.h>
+#include <asm/thread_info.h>
+
+#include "asm-offsets.h"
 
 /*
  * Stack layout for the system_call stack entry.
@@ -44,42 +47,9 @@
 SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
 /* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
-#if CONFIG_REMOTE_DEBUG
-SP_CRREGS    =  (SP_TRAP+4)
-/* fpu registers are saved & restored by the gdb stub itself */
-SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
-SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
-#else
-SP_PGM_OLD_ILC= (SP_TRAP+4)
-#endif
-SP_SIZE      =  (SP_PGM_OLD_ILC+4)
-/*
- * these defines are offsets into the thread_struct
- */
-_TSS_PTREGS  = 0
-_TSS_FPRS    = (_TSS_PTREGS+8)
-_TSS_AR2     = (_TSS_FPRS+136)
-_TSS_AR4     = (_TSS_AR2+4)
-_TSS_KSP     = (_TSS_AR4+4)
-_TSS_USERSEG = (_TSS_KSP+4)
-_TSS_ERROR   = (_TSS_USERSEG+4)
-_TSS_PROT    = (_TSS_ERROR+4)
-_TSS_TRAP    = (_TSS_PROT+4)
-_TSS_MM      = (_TSS_TRAP+4)
-_TSS_PER     = (_TSS_MM+8)
-_TSS_IEEE    = (_TSS_PER+36)
-_TSS_FLAGS   = (_TSS_IEEE+4)
-
-/*
- * these are offsets into the task-struct.
- */
-state        =  0
-flags        =  4
-#error sigpending   =  8
-#error need_resched = 24
-#error tsk_ptrace   = 28
-processor    = 56
+SP_SIZE      =  (SP_TRAP+4)
+
+_TIF_WORK_MASK = (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
 /*
  * Base Address of this Module --- saved in __LC_ENTRY_BASE
@@ -97,12 +67,15 @@
  *    R15 - kernel stack pointer
  */
 
-        .macro  SAVE_ALL psworg,sync      # system entry macro
+        .macro  SAVE_ALL_BASE
         stm     %r13,%r15,__LC_SAVE_AREA
         basr    %r13,0                    #  temp base pointer
-        l       %r13,.Lentry_base-.(%r13) # load &entry_base to %r13 
+0:	stam    %a2,%a4,__LC_SAVE_AREA+12
+        l       %r13,.Lentry_base-0b(%r13)# load &entry_base to %r13
+	.endm
+
+        .macro  SAVE_ALL psworg,sync      # system entry macro
         tm      \psworg+1,0x01            # test problem state bit
-        stam    %a2,%a4,__LC_SAVE_AREA+12
 	.if	\sync
         bz      BASED(1f)                 # skip stack setup save
 	.else
@@ -138,7 +111,7 @@
         lpsw    __LC_RETURN_PSW           # back to caller
         .endm
 
-        .macro  GET_CURRENT
+        .macro  GET_THREAD_INFO
 	l	%r9,BASED(.Lc0xffffe000)  # load pointer to task_struct to %r9
 	al	%r9,__LC_KERNEL_STACK
         .endm
@@ -146,8 +119,8 @@
 
 /*
  * Scheduler resume function, called by switch_to
- *  grp2 = (thread_struct *) prev->tss
- *  grp3 = (thread_struct *) next->tss
+ *  gpr2 = (task_struct *) prev
+ *  gpr3 = (task_struct *) next
  * Returns:
  *  gpr2 = prev
  */
@@ -155,30 +128,25 @@
 resume:
         basr    %r1,0
 resume_base:
-        l       %r4,_TSS_PTREGS(%r3)
-        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
-        bz      resume_noper-resume_base(%r1) # if not we're fine
-        stctl   %c9,%c11,24(%r15)             # We are using per stuff
-        clc     _TSS_PER(12,%r3),24(%r15)
-        be      resume_noper-resume_base(%r1) # we got away w/o bashing TLB's
-        lctl    %c9,%c11,_TSS_PER(%r3)        # Nope we didn't
+	tm	__THREAD_per(%r3),0xe8		# new process is using per ?
+	bz	resume_noper-resume_base(%r1)	# if not we're fine
+        stctl   %c9,%c11,24(%r15)		# We are using per stuff
+        clc     __THREAD_per(12,%r3),24(%r15)
+        be      resume_noper-resume_base(%r1)	# we got away w/o bashing TLB's
+        lctl    %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 resume_noper:
         stm     %r6,%r15,24(%r15)       # store resume registers of prev task
-        st      %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
-        lr      %r0,%r15
-        n       %r0,.Lc0xffffe000-resume_base(%r1)
-        l       %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
-        l       %r1,.Lc8191-resume_base(%r1)
-        or      %r1,%r15
-        la      %r1,1(%r1)
-        st      %r1,__LC_KERNEL_STACK   # __LC_KERNEL_STACK = new kernel stack
-        stam    %a2,%a2,_TSS_AR2(%r2)   # store kernel access reg. 2
-        stam    %a4,%a4,_TSS_AR4(%r2)   # store kernel access reg. 4
-        lam     %a2,%a2,_TSS_AR2(%r3)   # load kernel access reg. 2
-        lam     %a4,%a4,_TSS_AR4(%r3)   # load kernel access reg. 4
-        lr      %r2,%r0                 # return task_struct of last task
-        lm      %r6,%r15,24(%r15)       # load resume registers of next task
-        br      %r14
+	st	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
+	l	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
+	stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
+	stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
+	lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
+	lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
+	lm	%r6,%r15,24(%r15)	# load resume registers of next task
+	l	%r3,__THREAD_info(%r3)  # load thread_info from task struct
+	ahi	%r3,8192
+	st	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
+	br	%r14
 
 /*
  * do_softirq calling function. We want to run the softirq functions on the
@@ -209,73 +177,48 @@
 
 	.globl  system_call
 system_call:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
-pgm_system_call:	
-        GET_CURRENT               # load pointer to task_struct to R9
-        slr     %r8,%r8           # gpr 8 is call save (-> tracesys)
-        ic      %r8,0x8B          # get svc number from lowcore
-        stosm   24(%r15),0x03     # reenable interrupts
+	lh	%r8,0x8a	  # get svc number from lowcore
         sll     %r8,2
-        l       %r8,sys_call_table-entry_base(8,%r13) # get address of system call
-#error        tm      tsk_ptrace+3(%r9),0x02 # PT_TRACESYS
-        bnz     BASED(sysc_tracesys)
+        GET_THREAD_INFO           # load pointer to task_struct to R9
+        stosm   24(%r15),0x03     # reenable interrupts
+        l       %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr.
+	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
+        bo      BASED(sysc_tracesys)
         basr    %r14,%r8          # call sys_xxxx
         st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
                                   # ATTENTION: check sys_execve_glue before
                                   # changing anything here !!
 
 sysc_return:
-        tm      SP_PSW+1(%r15),0x01 # returning to user ?
-        bno     BASED(sysc_leave) # no-> skip resched & signal
-#
-# check, if reschedule is needed
-#
-#error        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
-        bnz     BASED(sysc_reschedule)
-#error        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
-        bnz     BASED(sysc_signal_return)
+	stnsm   24(%r15),0xfc     # disable I/O and ext. interrupts
+	tm	__TI_flags+3(%r9),_TIF_WORK_MASK
+	bnz	BASED(sysc_work)  # there is work to do (signals etc.)
 sysc_leave:
-	tm      SP_PGM_OLD_ILC(%r15),0xff
-        bz      BASED(pgm_svcret)
-	stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
         RESTORE_ALL 1
 
 #
+# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
+# _TIF_NEED_RESCHED is on. Find out which one.
+#
+sysc_work:
+        tm      SP_PSW+1(%r15),0x01 # returning to user ?
+        bno     BASED(sysc_leave) # no-> skip resched & signal
+	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
+	bo	BASED(sysc_reschedule)
+	# add a test for TIF_NOTIFY_RESUME here when it is used.
+	# _TIF_SIGPENDING is the only flag left
+#
 # call do_signal before return
 #
 sysc_signal_return:     
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sr      %r3,%r3           # clear *oldset
         l       %r1,BASED(.Ldo_signal)
-	la      %r14,BASED(sysc_leave)
-        br      %r1               # return point is sysc_leave
-
-#
-# call trace before and after sys_call
-#
-sysc_tracesys:
-        l       %r1,BASED(.Ltrace)
-	l       %r7,BASED(.Lc_ENOSYS)
-	st      %r7,SP_R2(%r15)   # give sysc_trace an -ENOSYS retval
-        basr    %r14,%r1
-	l       %r2,SP_R2(%r15)
-	cr      %r2,%r7 # compare with saved -ENOSYS
-	be      BASED(sysc_tracesys_dn1)
-	# strace wants to change the syscall
-	sll     %r2,24
-	srl     %r2,22
-        l       %r8,sys_call_table-entry_base(2,%r13) # get address of system call    
-sysc_tracesys_dn1:		
-	lm      %r3,%r6,SP_R3(%r15)
-	l       %r2,SP_ORIG_R2(%r15)
-        basr    %r14,%r8          # call sys_xxx
-        st      %r2,SP_R2(%r15)   # store return value
-        l       %r1,BASED(.Ltrace)
 	la      %r14,BASED(sysc_return)
         br      %r1               # return point is sysc_return
 
-
 #
 # call schedule with sysc_return as return-address
 #
@@ -285,22 +228,44 @@
         br      %r1               # call scheduler, return to sysc_return
 
 #
+# call trace before and after sys_call
+#
+sysc_tracesys:
+        l       %r1,BASED(.Ltrace)
+	mvc	SP_R2(4,%r15),BASED(.Lc_ENOSYS)
+	basr	%r14,%r1
+	clc	SP_R2(4,%r15),BASED(.Lc256)
+	bnl	BASED(sysc_tracego)
+	l	%r8,SP_R2(%r15)   # strace changed the syscall
+	sll     %r8,2
+	l	%r8,sys_call_table-entry_base(%r8,%r13)
+sysc_tracego:
+	lm	%r3,%r6,SP_R3(%r15)
+	l	%r2,SP_ORIG_R2(%r15)
+	basr	%r14,%r8          # call sys_xxx
+	st	%r2,SP_R2(%r15)   # store return value
+	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
+        bno     BASED(sysc_return)
+	l	%r1,BASED(.Ltrace)
+	la	%r14,BASED(sysc_return)
+	br	%r1
+
+#
 # a new process exits the kernel with ret_from_fork
 #
         .globl  ret_from_fork
 ret_from_fork:  
         basr    %r13,0
         l       %r13,.Lentry_base-.(%r13)  # setup base pointer to &entry_base
-        GET_CURRENT               # load pointer to task_struct to R9
-        stosm   24(%r15),0x03     # reenable interrupts
+        GET_THREAD_INFO           # load pointer to task_struct to R9
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-#if CONFIG_SMP || CONFIG_PREEMPT
+#ifdef CONFIG_SMP
         l       %r1,BASED(.Lschedtail)
 	la      %r14,BASED(sysc_return)
         br      %r1               # call schedule_tail, return to sysc_return
 #else
-        b       BASED(sysc_return)
+	b	BASED(sysc_return)
 #endif
 
 #
@@ -597,13 +562,27 @@
         .long  sys_madvise
 	.long  sys_getdents64		 /* 220 */
         .long  sys_fcntl64 
-	.long  sys_ni_syscall		 /* 222 - reserved for posix_acl */
-	.long  sys_ni_syscall		 /* 223 - reserved for posix_acl */
-	.long  sys_ni_syscall		 /* 224 - reserved for posix_acl */
-	.rept  255-224
+	.long  sys_readahead
+	.long  sys_sendfile64
+	.long  sys_setxattr
+	.long  sys_lsetxattr		 /* 225 */
+	.long  sys_fsetxattr
+	.long  sys_getxattr
+	.long  sys_lgetxattr
+	.long  sys_fgetxattr
+	.long  sys_listxattr		 /* 230 */
+	.long  sys_llistxattr
+	.long  sys_flistxattr
+	.long  sys_removexattr
+	.long  sys_lremovexattr
+	.long  sys_fremovexattr		 /* 235 */
+	.long  sys_gettid
+	.long  sys_tkill
+	.long  sys_futex
+	.long  sys_sched_setaffinity
+	.long  sys_sched_getaffinity	 /* 240 */
+	.rept  255-240
 	.long  sys_ni_syscall
-	.long  sys_gettid		/* 226 */
-	.long  sys_tkill		/* 227 */
 	.endr
 
 /*
@@ -625,93 +604,107 @@
  * we just ignore the PER event (FIXME: is there anything we have to do
  * for LPSW?).
  */
-	stm     %r13,%r15,__LC_SAVE_AREA
-	basr    %r13,0                   # temp base pointer
-	l       %r13,.Lentry_base-.(%r13)# load &entry_base to %r13
+	SAVE_ALL_BASE
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
-	stam    %a2,%a4,__LC_SAVE_AREA+12
-        bz      BASED(pgm_sv)            # skip if not
+        bnz     BASED(pgm_per)           # got per exception -> special case
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+        l       %r7,BASED(.Ljump_table)
+        lh      %r8,__LC_PGM_INT_CODE
+        sll     %r8,2
+	GET_THREAD_INFO
+        l       %r7,0(%r8,%r7)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+        l       %r3,__LC_PGM_ILC         # load program interruption code
+	la      %r14,BASED(sysc_return)
+	br      %r7			 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
-        bnz     BASED(pgm_sv)            # skip if it is
+        bnz     BASED(pgm_per_std)       # ok, normal per event from user space
 # ok its one of the special cases, now we need to find out which one
         clc     __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
         be      BASED(pgm_svcper)
 # no interesting special case, ignore PER event
         lm      %r13,%r15,__LC_SAVE_AREA
 	lpsw    0x28
+
+#
+# Normal per exception
+#
+pgm_per_std:
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+	GET_THREAD_INFO
+	la	%r4,0x7f
+	l	%r3,__LC_PGM_ILC	 # load program interruption code
+        nr      %r4,%r3                  # clear per-event-bit and ilc
+        be      BASED(pgm_per_only)      # only per or per+check ?
+        l       %r1,BASED(.Ljump_table)
+        sll     %r4,2
+        l       %r1,0(%r4,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+	basr    %r14,%r1		 # branch to interrupt-handler
+pgm_per_only:
+	la      %r2,SP_PTREGS(15)	 # address of register-save area
+        l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
+        la      %r14,BASED(sysc_return)  # load adr. of system return
+        br      %r1			 # branch to handle_per_exception
+
+#
 # it was a single stepped SVC that is causing all the trouble
+#
 pgm_svcper:
-        tm      0x21,0x01                # test problem state bit
-	bz	BASED(.+12)              # skip stack & access regs setup
-	l	%r15,__LC_KERNEL_STACK   # problem state -> load ksp
-	lam     %a2,%a4,BASED(.Lc_ac)    # set ac.reg. 2 to primary space
-                                         # and access reg. 4 to home space
-	s       %r15,BASED(.Lc_spsize)   # make room for registers & psw
-        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
-        stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
-        st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
-        mvc     SP_PSW(8,%r15),0x20      # move user PSW to stack
-        la      %r0,0x20                 # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(4,%r15),0(%r15)        # clear back chain
-        mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
-        b       BASED(pgm_system_call)   # now do the svc
-pgm_svcret:
-        mvi     SP_TRAP+3(%r15),0x28     # set trap indication back to pgm_chk
-        lh      %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-	b       BASED(pgm_no_sv)
-pgm_sv:
-        tm      0x29,0x01                # test problem state bit
-	bz	BASED(.+12)              # skip stack & access regs setup
-	l	%r15,__LC_KERNEL_STACK   # problem state -> load ksp
-	lam     %a2,%a4,BASED(.Lc_ac)    # set ac.reg. 2 to primary space
-                                         # and access reg. 4 to home space
-	s       %r15,BASED(.Lc_spsize)   # make room for registers & psw
-        n       %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8
-        stm     %r0,%r12,SP_R0(%r15)     # store gprs 0-12 to kernel stack
-        st      %r2,SP_ORIG_R2(%r15)     # store original content of gpr 2
-        mvc     SP_R13(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack
-        stam    %a0,%a15,SP_AREGS(%r15)  # store access registers to kst.
-	mvc     SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs
-        mvc     SP_PSW(8,%r15),0x28      # move user PSW to stack
-        la      %r0,0x28                 # store trap indication
-        st      %r0,SP_TRAP(%r15)
-        xc      0(4,%r15),0(%r15)        # clear back chain
-	mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-        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
-	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
-        l       %r1,0(%r3,%r1)    # load address of handler routine
-        la      %r2,SP_PTREGS(%r15) # address of register-save area
-        srl     %r3,2
-        cl      %r3,BASED(.Lc4)   # protection-exception ?
-        bne     BASED(pgm_per)    # if not,
-        l       %r5,SP_PSW+4(15)  # load psw addr
-        sr      %r5,%r7           # substract ilc from psw
-        st      %r5,SP_PSW+4(15)  # store corrected psw addr
-pgm_per:basr    %r14,%r1          # branch to interrupt-handler
-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
-        la      %r14,BASED(sysc_return) # load adr. of system return
-        br      %r1               # branch to handle_per_exception
+	SAVE_ALL __LC_SVC_OLD_PSW,1
+        GET_THREAD_INFO           # load pointer to task_struct to R9
+	lh	%r8,0x8a	  # get svc number from lowcore
+        sll     %r8,2
+        stosm   24(%r15),0x03     # reenable interrupts
+        l       %r8,sys_call_table-entry_base(%r8,%r13) # get system call addr.
+	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
+        bo      BASED(pgm_tracesys)
+        basr    %r14,%r8          # call sys_xxxx
+        st      %r2,SP_R2(%r15)   # store return value (change R2 on stack)
+                                  # ATTENTION: check sys_execve_glue before
+                                  # changing anything here !!
 
+pgm_svcret:
+	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
+	bo	BASED(pgm_svcper_nosig)
+	la	%r2,SP_PTREGS(%r15) # load pt_regs
+	sr	%r3,%r3		  # clear *oldset
+	l	%r1,BASED(.Ldo_signal)
+	basr	%r4,%r1		  # call do_signal
+	
+pgm_svcper_nosig:
+        mvi     SP_TRAP+3(%r15),0x28     # set trap indication to pgm check
+	la      %r2,SP_PTREGS(15)        # address of register-save area
+        l       %r1,BASED(.Lhandle_per)  # load adr. of per handler
+        la      %r14,BASED(sysc_return)  # load adr. of system return
+        br      %r1                      # branch to handle_per_exception
 #
-# the backend code is the same as for sys-call
+# call trace before and after sys_call
 #
-pgm_return:
-        b       BASED(sysc_return)
+pgm_tracesys:
+        l       %r1,BASED(.Ltrace)
+	mvc	SP_R2(%r15),BASED(.Lc_ENOSYS)
+        basr    %r14,%r1
+	clc	SP_R2(4,%r15),BASED(.Lc256)
+	bnl	BASED(pgm_svc_go)
+	l	%r8,SP_R2(%r15)   # strace changed the syscall
+	sll     %r8,2
+	l	%r8,sys_call_table-entry_base(%r8,%r13)
+pgm_svc_go:
+	lm      %r3,%r6,SP_R3(%r15)
+	l       %r2,SP_ORIG_R2(%r15)
+        basr    %r14,%r8          # call sys_xxx
+        st      %r2,SP_R2(%r15)   # store return value
+	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
+        bno     BASED(pgm_svcret)
+        l       %r1,BASED(.Ltrace)
+	la	%r14,BASED(pgm_svcret)
+        br      %r1
 
 /*
  * IO interrupt handler routine
@@ -719,39 +712,31 @@
 
         .globl io_int_handler
 io_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_IO_OLD_PSW,0
-        GET_CURRENT               # load pointer to task_struct to R9
+        GET_THREAD_INFO           # load pointer to task_struct to R9
+        l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         la      %r2,SP_PTREGS(%r15) # address of register-save area
         sr      %r3,%r3
-        icm     %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int
+        icm     %r3,3,__LC_SUBCHANNEL_NR   # load subchannel nr & extend to int
         l       %r4,__LC_IO_INT_PARM       # load interuption parm
 	l       %r5,__LC_IO_INT_WORD       # load interuption word
-        l       %r1,BASED(.Ldo_IRQ)        # load address of do_IRQ
         basr    %r14,%r1          # branch to standard irq handler
 
 io_return:
-#
+#	
 # check, if bottom-half has to be done
 #
-        l       %r1,processor(%r9)    # get cpu number from task struture
+        l       %r1,__TI_cpu(%r9)
         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
+        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:
-
-        tm      SP_PSW+1(%r15),0x01 # returning to user ?
-        bno     BASED(io_leave)   # no-> skip resched & signal
-        stosm   24(%r15),0x03     # reenable interrupts
-#
-# check, if reschedule is needed
-#
-#error        icm     %r0,15,need_resched(%r9) # get need_resched from task_struct
-        bnz     BASED(io_reschedule)
-#error        icm     %r0,15,sigpending(%r9)   # get sigpending from task_struct
-        bnz     BASED(io_signal_return)
+	tm	__TI_flags+3(%r9),_TIF_WORK_MASK
+	bnz	BASED(io_work)         # there is work to do (signals etc.)
 io_leave:
-        stnsm   24(%r15),0xfc            # disable I/O and ext. interrupts
+        stnsm   24(%r15),0xfc          # disable I/O and ext. interrupts
         RESTORE_ALL 0
 
 #
@@ -763,12 +748,17 @@
         br      %r1               # call do_softirq
 
 #
-# call schedule with io_return as return-address
+# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
+# _TIF_NEED_RESCHED is on. Find out which one.
 #
-io_reschedule:        
-        l       %r1,BASED(.Lschedule)
-	la      %r14,BASED(io_return)
-        br      %r1               # call scheduler, return to io_return
+io_work:
+        tm      SP_PSW+1(%r15),0x01    # returning to user ?
+        bno     BASED(io_leave)        # no-> skip resched & signal
+        stosm   24(%r15),0x03          # reenable interrupts
+	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
+	bo	BASED(io_reschedule)
+	# add a test for TIF_NOTIFY_RESUME here when it is used.
+	# _TIF_SIGPENDING is the only flag left
 
 #
 # call do_signal before return
@@ -780,33 +770,42 @@
 	la      %r14,BASED(io_leave)
         br      %r1               # return point is io_leave
 
+#
+# call schedule with io_return as return-address
+#
+io_reschedule:        
+        l       %r1,BASED(.Lschedule)
+	la      %r14,BASED(io_return)
+        br      %r1               # call scheduler, return to io_return
+
 /*
  * External interrupt handler routine
  */
 
         .globl  ext_int_handler
 ext_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_EXT_OLD_PSW,0
-        GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        lh      %r3,__LC_EXT_INT_CODE  # error code
-        lr      %r1,%r3                # calculate index = code & 0xff
-        n       %r1,BASED(.Lc0xff)
-        sll     %r1,2
-        l       %r4,BASED(.Lext_hash)
-        l       %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltr     %r4,%r4                # == NULL ?
-        bz      BASED(io_return)       # yes, nothing to do, exit
+        GET_THREAD_INFO                # load pointer to task_struct to R9
+	lh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lr	%r1,%r6		       # calculate index = code & 0xff
+	n	%r1,BASED(.Lc0xff)
+	sll	%r1,2
+	l	%r7,BASED(.Lext_hash)
+	l	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltr	%r7,%r7		       # == NULL ?
+	bz	BASED(io_return)       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,8(%r4)             # compare external interrupt code
-        be      BASED(ext_int_found)
-        icm     %r4,15,0(%r4)          # next list entry
-        bnz     BASED(ext_int_loop)
-        b       BASED(io_return)
-ext_int_found:
-        l       %r4,4(%r4)             # get handler address
-        la      %r14,BASED(io_return)
-        br      %r4                    # branch to ext call handler
+	ch	%r6,8(%r7)	       # compare external interrupt code
+	bne	BASED(ext_int_next)
+	l	%r1,4(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	icm	%r7,15,0(%r7)	       # next list entry
+	bnz	BASED(ext_int_loop)
+	b	BASED(io_return)
 
 /*
  * Machine check handler routines
@@ -814,6 +813,7 @@
 
         .globl mcck_int_handler
 mcck_int_handler:
+	SAVE_ALL_BASE
         SAVE_ALL __LC_MCK_OLD_PSW,0
 	l       %r1,BASED(.Ls390_mcck)
 	basr    %r14,%r1	  # call machine check handler
@@ -870,13 +870,14 @@
 .Lc0x4000:     .long  0x4000
 .Lc0xff:       .long  0xff
 .Lc128:        .long  128
+.Lc256:        .long  256
 
 /*
  * Symbol constants
  */
 .Ls390_mcck:   .long  s390_do_machine_check
 .Ldo_IRQ:      .long  do_IRQ
-#error .Ldo_signal:   .long  do_signal
+.Ldo_signal:   .long  do_signal
 .Ldo_softirq:  .long  do_softirq
 .Lentry_base:  .long  entry_base
 .Lext_hash:    .long  ext_int_hash
@@ -893,10 +894,10 @@
 .Lsigreturn:   .long  sys_sigreturn
 .Lsigsuspend:  .long  sys_sigsuspend
 .Lsigaltstack: .long  sys_sigaltstack
-#error .Ltrace:       .long  syscall_trace
+.Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
-
-#if CONFIG_SMP || CONFIG_PREEMPT
+#ifdef CONFIG_SMP
 .Lschedtail:   .long  schedule_tail
 #endif
+
 
diff -Nru a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
--- a/arch/s390/kernel/head.S	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/kernel/head.S	Sat Jun  8 22:31:36 2002
@@ -649,7 +649,7 @@
 #
             .align 8
 .Ldw:	    .long  0x000a0000,0x00000000
-.Linittu:   .long  init_task_union
+.Linittu:   .long  init_thread_union
 .Lstart:    .long  start_kernel
 .Lbss_bgn:  .long  __bss_start
 .Lbss_end:  .long  _end
diff -Nru a/arch/s390/kernel/ieee.h b/arch/s390/kernel/ieee.h
--- a/arch/s390/kernel/ieee.h	Sat Jun  8 22:31:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/ieee.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- */
-
-#include <linux/sched.h>
-
-static    inline void _adddf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd +
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _subdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd -
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _muldf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd *
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _divdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = current->tss.fprs[R1].fd /
-                             current->tss.fprs[R2].fd;
-}
-
-static    inline void _negdf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = -current->tss.fprs[R1].fd;
-}
-
-static    inline void _fixdfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].fd;
-}
-
-static    inline void _extendsidf(int R1,int R2)
-{
-  current->tss.fprs[R1].fd = (double) current->tss.regs->gprs[R2];
-}
-
-
-static    inline  void _addsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff +
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline  void _subsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff -
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _mulsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff *
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _divsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = current->tss.fprs[R1].ff /
-                             current->tss.fprs[R2].ff;
-}
-
-static    inline void _negsf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = -current->tss.fprs[R1].ff;
-}
-
-static    inline void _fixsfsi(int R1,int R2)
-{
-  current->tss.regs->gprs[R1] = (__u32) current->tss.fprs[R2].ff;
-}
-
-static    inline void _extendsisf(int R1,int R2)
-{
-  current->tss.fprs[R1].ff = (double) current->tss.regs->gprs[R2];
-}
-
-
diff -Nru a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c
--- a/arch/s390/kernel/init_task.c	Sat Jun  8 22:31:51 2002
+++ b/arch/s390/kernel/init_task.c	Sat Jun  8 22:31:51 2002
@@ -13,21 +13,26 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
- * Initial task structure.
+ * Initial thread structure.
  *
  * We need to make sure that this is 8192-byte aligned due to the
- * way process stacks are handled. This is done by making sure
- * the linker maps this in the .text segment right after head.S,
- * and making head.S ensure the proper alignment.
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union 
+	__attribute__((__section__(".data.init_task"))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
  *
- * The things we do for performance..
+ * All other task structs will be allocated on slabs in fork.c
  */
-union task_union init_task_union __attribute__((aligned(8192))) = 
-  { INIT_TASK(init_task_union.task) };
+struct task_struct init_task = INIT_TASK(init_task);
+
diff -Nru a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
--- a/arch/s390/kernel/irq.c	Sat Jun  8 22:31:43 2002
+++ b/arch/s390/kernel/irq.c	Sat Jun  8 22:31:43 2002
@@ -63,7 +63,6 @@
 int show_interrupts(struct seq_file *p, void *v)
 {
 	int i, j;
-	struct irqaction * action;
 
 	seq_puts(p, "           ");
 
@@ -76,36 +75,13 @@
 		if (ioinfo[i] == INVALID_STORAGE_AREA)
 			continue;
 
-		action = ioinfo[i]->irq_desc.action;
-		
-  		if (!action)
-			continue;
-
 		seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-		seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-		for (j=0; j<smp_num_cpus; j++)
-			seq_printf( p, "%10u ",
-			              kstat.irqs[cpu_logical_map(j)][i]);
-#endif
-		seq_printf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
-		seq_printf(p, "  %s", action->name);
-
-		for (action=action->next; action; action = action->next)
-		{
-			seq_printf(p, ", %s", action->name);
-
-		} /* endfor */
+		seq_printf(p, "  %s", ioinfo[i]->irq_desc.name);
 
 		seq_putc(p, '\n');
 	
 	} /* endfor */
 
-	seq_printf(p, "NMI: %10u\n", nmi_counter);
-#ifdef CONFIG_SMP
-	seq_printf(p, "IPI: %10u\n", atomic_read(&ipi_count));
-#endif
 	return 0;
 }
 
@@ -132,10 +108,10 @@
  */
 #define check_smp_invalidate(cpu)
 
+extern void show_stack(unsigned long* esp);
+
 static void show(char * str)
 {
-	int i;
-	unsigned long *stack;
 	int cpu = smp_processor_id();
 
 	printk("\n%s, CPU %d:\n", str, cpu);
@@ -143,13 +119,7 @@
 	       atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
 	printk("bh:   %d [%d]\n",
 	       atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
-	stack = (unsigned long *) &str;
-	for (i = 40; i ; i--) {
-		unsigned long x = *++stack;
-		if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
-			printk("<[%08lx]> ", x);
-		}
-	}
+	show_stack(NULL);
 }
 
 #define MAXCOUNT 100000000
diff -Nru a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
--- a/arch/s390/kernel/process.c	Sat Jun  8 22:31:51 2002
+++ b/arch/s390/kernel/process.c	Sat Jun  8 22:31:51 2002
@@ -47,200 +47,80 @@
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 /*
- * The idle loop on a S390...
+ * Return saved PC of a blocked thread. used in kernel/sched.
+ * resume in entry.S does not create a new stack frame, it
+ * just stores the registers %r6-%r15 to the frame given by
+ * schedule. We want to return the address of the caller of
+ * schedule, so we have to walk the backchain one time to
+ * find the frame schedule() store its return address.
  */
-
-static psw_t wait_psw;
-
-int cpu_idle(void *unused)
+unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-	/* endless idle loop with no priority at all */
-        init_idle();
-	current->nice = 20;
-	wait_psw.mask = _WAIT_PSW_MASK;
-	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
-	while(1) {
-                if (need_resched()) {
-                        schedule();
-                        check_pgt_cache();
-                        continue;
-                }
-
-		/* load wait psw */
-		asm volatile (
-                        "lpsw %0"
-                        : : "m" (wait_psw) );
-idle_wakeup:
-	}
+	unsigned long bc;
+
+	bc = *((unsigned long *) tsk->thread.ksp);
+	return *((unsigned long *) (bc+56));
 }
 
 /*
-  As all the register will only be made displayable to the root
-  user ( via printk ) or checking if the uid of the user is 0 from
-  the /proc filesystem please god this will be secure enough DJB.
-  The lines are given one at a time so as not to chew stack space in
-  printk on a crash & also for the proc filesystem when you get
-  0 returned you know you've got all the lines
+ * The idle loop on a S390...
  */
 
-static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+void default_idle(void)
 {
-	int linelen=0;
-	int regno,chaincnt;
-	u32 backchain,prev_backchain,endchain;
-	u32 ksp = 0;
-	char *mode = "???";
-
-	enum
-	{
-		sp_linefeed,
-		sp_psw,
-		sp_ksp,
-		sp_gprs,
-		sp_gprs1,
-		sp_gprs2,
-		sp_gprs3,
-		sp_gprs4,
-		sp_acrs,
-		sp_acrs1,
-		sp_acrs2,
-		sp_acrs3,
-		sp_acrs4,
-		sp_kern_backchain,
-		sp_kern_backchain1
-	};
-
-	if (task)
-		ksp = task->thread.ksp;
-	if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
-		ksp = regs->gprs[15];
-
-	if (regs)
-		mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
-		       "User" : "Kernel";
-
-	switch(line)
-	{
-	case sp_linefeed: 
-		linelen=sprintf(buff,"\n");
-		break;
-	case sp_psw:
-		if(regs)
-			linelen=sprintf(buff, "%s PSW:    %08lx %08lx    %s\n", mode,
-				(unsigned long) regs->psw.mask,
-				(unsigned long) regs->psw.addr,
-				print_tainted());
-		else
-			linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
-		break;
-	case sp_ksp:
-		linelen=sprintf(&buff[linelen],
-				"task: %08x ksp: %08x pt_regs: %08x\n",
-				(addr_t)task, (addr_t)ksp, (addr_t)regs);
-		break;
-	case sp_gprs:
-		if(regs)
-			linelen=sprintf(buff, "%s GPRS:\n", mode);
-		break;
-	case sp_gprs1 ... sp_gprs4:
-		if(regs)
-		{
-			regno=(line-sp_gprs1)*4;
-			linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
-					regs->gprs[regno], 
-					regs->gprs[regno+1],
-					regs->gprs[regno+2],
-					regs->gprs[regno+3]);
-		}
-		break;
-	case sp_acrs:
-		if(regs)
-			linelen=sprintf(buff, "%s ACRS:\n", mode);
-		break;	
-        case sp_acrs1 ... sp_acrs4:
-		if(regs)
-		{
-			regno=(line-sp_acrs1)*4;
-			linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
-					regs->acrs[regno],
-					regs->acrs[regno+1],
-					regs->acrs[regno+2],
-					regs->acrs[regno+3]);
-		}
-		break;
-	case sp_kern_backchain:
-		if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
-			break;	
-		if (ksp)
-			linelen=sprintf(buff, "Kernel BackChain  CallChain\n");
-		break;
-	default:
-		if (ksp)
-		{
-			
-			backchain=ksp&PSW_ADDR_MASK;
-			endchain=((backchain&(-8192))+8192);
-			prev_backchain=backchain-1;
-			line-=sp_kern_backchain1;
-			for(chaincnt=0;;chaincnt++)
-			{
-				if((backchain==0)||(backchain>=endchain)
-				   ||(chaincnt>=8)||(prev_backchain>=backchain))
-					break;
-				if(chaincnt==line)
-				{
-					linelen+=sprintf(&buff[linelen],"       %08x   [<%08lx>]\n",
-							 backchain,
-							 *(u32 *)(backchain+56)&PSW_ADDR_MASK);
-					break;
-				}
-				prev_backchain=backchain;
-				backchain=(*((u32 *)backchain))&PSW_ADDR_MASK;
-			}
-		}
-	}
-	return(linelen);
+	psw_t wait_psw;
+	unsigned long reg;
+
+        if (need_resched()) {
+                schedule();
+                return;
+        }
+
+	/* 
+	 * Wait for external, I/O or machine check interrupt and
+	 * switch of machine check bit after the wait has ended.
+	 */
+	wait_psw.mask = _WAIT_PSW_MASK;
+	asm volatile (
+		"    basr %0,0\n"
+		"0:  la   %0,1f-0b(%0)\n"
+		"    st   %0,4(%1)\n"
+		"    oi   4(%1),0x80\n"
+		"    lpsw 0(%1)\n"
+		"1:  la   %0,2f-1b(%0)\n"
+		"    st   %0,4(%1)\n"
+		"    oi   4(%1),0x80\n"
+		"    ni   1(%1),0xf9\n"
+		"    lpsw 0(%1)\n"
+		"2:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+int cpu_idle(void)
+{
+	for (;;)
+		default_idle();
+	return 0;
 }
 
+extern void show_registers(struct pt_regs *regs);
+extern void show_trace(unsigned long *sp);
 
 void show_regs(struct pt_regs *regs)
 {
-	char buff[80];
-	int i, line;
-
-        printk("CPU:    %d\n",smp_processor_id());
-        printk("Process %s (pid: %d, stackpage=%08X)\n",
-                current->comm, current->pid, 4096+(addr_t)current);
-	
-	for (line = 0; sprintf_regs(line, buff, current, regs); line++)
-		printk(buff);
-
-	if (regs->psw.mask & PSW_PROBLEM_STATE)
-	{
-		printk("User Code:\n");
-		memset(buff, 0, 20);
-		copy_from_user(buff,
-			       (char *) (regs->psw.addr & PSW_ADDR_MASK), 20);
-		for (i = 0; i < 20; i++)
-			printk("%02x ", buff[i]);
-		printk("\n");
-	}
-}
-
-char *task_show_regs(struct task_struct *task, char *buffer)
-{
-	int line, len;
+	struct task_struct *tsk = current;
 
-	for (line = 0; ; line++)
-	{
-		len = sprintf_regs(line, buffer, task, task->thread.regs);
-		if (!len) break;
-		buffer += len;
-	}
-	return buffer;
+        printk("CPU:    %d    %s\n", tsk->thread_info->cpu, print_tainted());
+        printk("Process %s (pid: %d, task: %08lx, ksp: %08x)\n",
+	       current->comm, current->pid, (unsigned long) tsk,
+	       tsk->thread.ksp);
+
+	show_registers(regs);
+	/* Show stack backtrace if pt_regs is from kernel mode */
+	if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+		show_trace((unsigned long *) regs->gprs[15]);
 }
 
-
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
         int clone_arg = flags | CLONE_VM;
@@ -279,7 +159,7 @@
 {
 
         current->used_math = 0;
-        current->flags &= ~PF_USEDFPU;
+	clear_tsk_thread_flag(current, TIF_USEDFPU);
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -300,16 +180,11 @@
             unsigned long gprs[10];    /* gprs 6 -15                       */
             unsigned long fprs[4];     /* fpr 4 and 6                      */
             unsigned long empty[4];
-#if CONFIG_REMOTE_DEBUG
-	    struct gdb_pt_regs childregs;
-#else
             struct pt_regs childregs;
-#endif
           } *frame;
 
-        frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
-        frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
-        p->thread.regs = (struct pt_regs *)&frame->childregs;
+        frame = ((struct stack_frame *)
+		 (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
         p->thread.ksp = (unsigned long) frame;
         memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
         frame->childregs.gprs[15] = new_stackp;
@@ -317,14 +192,14 @@
 
         /* new return point is ret_from_sys_call */
         frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
+	/* start disabled because of schedule_tick and rq->lock being held */
+	frame->childregs.psw.mask &= ~0x03000000;
 
         /* fake return stack for resume(), don't go back to schedule */
         frame->gprs[9]  = (unsigned long) frame;
-	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
-        p->thread.fs = USER_DS;
         /* Don't copy debug registers */
         memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
         return 0;
diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
--- a/arch/s390/kernel/ptrace.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/kernel/ptrace.c	Sat Jun  8 22:31:37 2002
@@ -41,7 +41,7 @@
 
 void FixPerRegisters(struct task_struct *task)
 {
-	struct pt_regs *regs = task->thread.regs;
+	struct pt_regs *regs = __KSTK_PTREGS(task);
 	per_struct *per_info=
 			(per_struct *)&task->thread.per_info;
 
@@ -155,7 +155,7 @@
 		mask=0xffffffff;
 		if(useraddr<PT_FPC)
 		{
-			realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]);
+			realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
 			if(useraddr<PT_PSWMASK)
 			{
 				copymax=PT_PSWMASK;
@@ -217,7 +217,6 @@
 {
 	struct task_struct *child;
 	int ret = -EPERM;
-	unsigned long flags;
 	unsigned long tmp;
 	int copied;
 	ptrace_area   parea; 
@@ -236,16 +235,18 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -254,14 +255,14 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
-		if (child->p_pptr != current)
-			goto out;
+		if (child->parent != current)
+			goto out_tsk;
 	}
 	switch (request) 
 	{
@@ -271,9 +272,9 @@
 		copied = access_process_vm(child,ADDR_BITS_REMOVE(addr), &tmp, sizeof(tmp), 0);
 		ret = -EIO;
 		if (copied != sizeof(tmp))
-			goto out;
+			break;
 		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
+		break;
 
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
@@ -285,9 +286,8 @@
 	case PTRACE_POKEDATA:
 		ret = 0;
 		if (access_process_vm(child,ADDR_BITS_REMOVE(addr), &data, sizeof(data), 1) == sizeof(data))
-			goto out;
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
@@ -300,9 +300,9 @@
 		if ((unsigned long) data >= _NSIG)
 			break;
 		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		else
-			child->ptrace &= ~PT_TRACESYS;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		/* make sure the single step bit is not set. */
 		clear_single_step(child);
@@ -329,7 +329,7 @@
 		ret = -EIO;
 		if ((unsigned long) data >= _NSIG)
 			break;
-		child->ptrace &= ~PT_TRACESYS;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		set_single_step(child);
 		/* give it a chance to run. */
@@ -346,10 +346,20 @@
 		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
 				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
 		break;
+	case PTRACE_SETOPTIONS: {
+		if (data & PTRACE_O_TRACESYSGOOD)
+			child->ptrace |= PT_TRACESYSGOOD;
+		else
+			child->ptrace &= ~PT_TRACESYSGOOD;
+		ret = 0;
+		break;
+	}
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	put_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
@@ -357,12 +367,13 @@
 
 asmlinkage void syscall_trace(void)
 {
-	lock_kernel();
-	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
-	    != (PT_PTRACED|PT_TRACESYS))
-		goto out;
-	current->exit_code = SIGTRAP;
-	set_current_state(TASK_STOPPED);
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
+	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
@@ -374,6 +385,4 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
- out:
-	unlock_kernel();
 }
diff -Nru a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
--- a/arch/s390/kernel/reipl.S	Sat Jun  8 22:31:35 2002
+++ b/arch/s390/kernel/reipl.S	Sat Jun  8 22:31:35 2002
@@ -21,8 +21,10 @@
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
         	msch    .Lschib-.Lpg0(%r13) 
-		ssch	.Liplorb-.Lpg0(%r13)           
-		jz	.L001   
+                lhi     %r0,5
+.Lssch:		ssch	.Liplorb-.Lpg0(%r13)           
+		jz	.L001
+                brct    %r0,.Lssch  
 		bas	%r14,.Ldisab-.Lpg0(%r13)
 .L001:		mvc	__LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpsw	.Lwaitpsw-.Lpg0(%r13)          
diff -Nru a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
--- a/arch/s390/kernel/s390_ext.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/kernel/s390_ext.c	Sat Jun  8 22:31:37 2002
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/errno.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -21,34 +22,31 @@
  * 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;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                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);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,9 +71,31 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
+}
+
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
 }
 
 EXPORT_SYMBOL(register_external_interrupt);
diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
--- a/arch/s390/kernel/s390_ksyms.c	Sat Jun  8 22:31:35 2002
+++ b/arch/s390/kernel/s390_ksyms.c	Sat Jun  8 22:31:35 2002
@@ -5,9 +5,11 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <linux/smp.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
@@ -18,8 +20,9 @@
 EXPORT_SYMBOL_NOVERS(_oi_bitmap);
 EXPORT_SYMBOL_NOVERS(_ni_bitmap);
 EXPORT_SYMBOL_NOVERS(_zb_findmap);
-EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup);
-EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup);
+EXPORT_SYMBOL_NOVERS(__copy_from_user_asm);
+EXPORT_SYMBOL_NOVERS(__copy_to_user_asm);
+EXPORT_SYMBOL_NOVERS(__clear_user_asm);
 
 /*
  * semaphore ops
@@ -27,7 +30,6 @@
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
-EXPORT_SYMBOL(__down_trylock);
 
 /*
  * string functions
@@ -35,6 +37,7 @@
 EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(memscan);
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strcmp);
@@ -44,7 +47,6 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
 /*
@@ -57,5 +59,3 @@
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
-
-
diff -Nru a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
--- a/arch/s390/kernel/semaphore.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/kernel/semaphore.c	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/S390/kernel/semaphore.c
+ *  linux/arch/s390/kernel/semaphore.c
  *
  *  S390 version
  *    Copyright (C) 1998-2000 IBM Corporation
@@ -10,151 +10,97 @@
  *
  */
 #include <linux/sched.h>
+#include <linux/errno.h>
 
 #include <asm/semaphore.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to acquire the semaphore, while the "sleeping"
- * variable is a count of such acquires.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * "sleeping" and the contention routine ordering is
- * protected by the semaphore spinlock.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Atomically update sem->count. Equivalent to:
+ *   old_val = sem->count.counter;
+ *   new_val = ((old_val >= 0) ? old_val : 0) + incr;
+ *   sem->count.counter = new_val;
+ *   return old_val;
  */
+static inline int __sem_update_count(struct semaphore *sem, int incr)
+{
+	int old_val, new_val;
+
+        __asm__ __volatile__("   l     %0,0(%3)\n"
+                             "0: ltr   %1,%0\n"
+			     "   jhe   1f\n"
+			     "   lhi   %1,0\n"
+			     "1: ar    %1,%4\n"
+                             "   cs    %0,%1,0(%3)\n"
+                             "   jl    0b\n"
+                             : "=&d" (old_val), "=&d" (new_val),
+			       "+m" (sem->count)
+			     : "a" (&sem->count), "d" (incr) : "cc" );
+	return old_val;
+}
 
 /*
- * Logic:
- *  - only on a boundary condition do we need to care. When we go
- *    from a negative count to a non-negative, we wake people up.
- *  - when we go from a non-negative count to a negative do we
- *    (a) synchronize with the "sleeper" count and (b) make sure
- *    that we're on the wakeup list before we synchronize so that
- *    we cannot lose wakeup events.
+ * The inline function up() incremented count but the result
+ * was <= 0. This indicates that some process is waiting on
+ * the semaphore. The semaphore is free and we'll wake the
+ * first sleeping process, so we set count to 1 unless some
+ * other cpu has called up in the meantime in which case
+ * we just increment count by 1.
  */
-
 void __up(struct semaphore *sem)
 {
+	__sem_update_count(sem, 1);
 	wake_up(&sem->wait);
 }
 
-static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
-
+/*
+ * The inline function down() decremented count and the result
+ * was < 0. The wait loop will atomically test and update the
+ * semaphore counter following the rules:
+ *   count > 0: decrement count, wake up queue and exit.
+ *   count <= 0: set count to -1, go to sleep.
+ */
 void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+
 	tsk->state = TASK_UNINTERRUPTIBLE;
 	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers++;
-	for (;;) {
-		int sleepers = sem->sleepers;
-
-		/*
-		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock.
-		 */
-		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-			sem->sleepers = 0;
-			break;
-		}
-		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
-
+	while (__sem_update_count(sem, -1) <= 0) {
 		schedule();
 		tsk->state = TASK_UNINTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
 	remove_wait_queue(&sem->wait, &wait);
 	tsk->state = TASK_RUNNING;
 	wake_up(&sem->wait);
 }
 
+/*
+ * Same as __down() with an additional test for signals.
+ * If a signal is pending the count is updated as follows:
+ *   count > 0: wake up queue and exit.
+ *   count <= 0: set count to 0, wake up queue and exit.
+ */
 int __down_interruptible(struct semaphore * sem)
 {
 	int retval = 0;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+
 	tsk->state = TASK_INTERRUPTIBLE;
 	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers ++;
-	for (;;) {
-		int sleepers = sem->sleepers;
-
-		/*
-		 * With signals pending, this turns into
-		 * the trylock failure case - we won't be
-		 * sleeping, and we* can't get the lock as
-		 * it has contention. Just correct the count
-		 * and exit.
-		 */
+	while (__sem_update_count(sem, -1) <= 0) {
 		if (signal_pending(current)) {
+			__sem_update_count(sem, 0);
 			retval = -EINTR;
-			sem->sleepers = 0;
-			atomic_add(sleepers, &sem->count);
-			break;
-		}
-
-		/*
-		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock. The
-		 * "-1" is because we're still hoping to get
-		 * the lock.
-		 */
-		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-			sem->sleepers = 0;
 			break;
 		}
-		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
-
 		schedule();
 		tsk->state = TASK_INTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
-	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
 	wake_up(&sem->wait);
 	return retval;
 }
 
-/*
- * Trylock failed - make sure we correct for
- * having decremented the count.
- */
-int __down_trylock(struct semaphore * sem)
-{
-        unsigned long flags;
-	int sleepers;
-
-	spin_lock_irqsave(&semaphore_lock, flags);
-	sleepers = sem->sleepers + 1;
-	sem->sleepers = 0;
-
-	/*
-	 * Add "everybody else" and us into it. They aren't
-	 * playing, because we own the spinlock.
-	 */
-	if (!atomic_add_negative(sleepers, &sem->count))
-		wake_up(&sem->wait);
-
-	spin_unlock_irqrestore(&semaphore_lock, flags);
-	return 1;
-}
diff -Nru a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
--- a/arch/s390/kernel/setup.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/kernel/setup.c	Sat Jun  8 22:31:36 2002
@@ -48,7 +48,7 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
-struct { unsigned long addr, size, type; } memory_chunk[16];
+struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
 #define CHUNK_READ_WRITE 0
 #define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
@@ -99,7 +99,7 @@
         /*
          * Force FPU initialization:
          */
-        current->flags &= ~PF_USEDFPU;
+        clear_thread_flag(TIF_USEDFPU);
         current->used_math = 0;
 
         /* Setup active_mm for idle_task  */
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,31 +233,62 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
+ /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
 /*
  * Setup function called from init/main.c just after the banner
  * was printed.
@@ -284,8 +315,8 @@
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
-	       "We are running under VM\n" :
-	       "We are running native\n");
+	       "We are running under VM (31 bit mode)\n" :
+	       "We are running native (31 bit mode)\n");
 	printk((MACHINE_HAS_IEEE) ?
 	       "This machine has an IEEE fpu\n" :
 	       "This machine has no IEEE fpu\n");
@@ -436,9 +467,10 @@
 	lowcore->io_new_psw.mask = _IO_PSW_MASK;
 	lowcore->io_new_psw.addr = _ADDR_31 + (addr_t) &io_int_handler;
 	lowcore->ipl_device = S390_lowcore.ipl_device;
-	lowcore->kernel_stack = ((__u32) &init_task_union) + 8192;
+	lowcore->kernel_stack = ((__u32) &init_thread_union) + 8192;
 	lowcore->async_stack = (__u32)
 		__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192;
+	lowcore->jiffy_timer = -1LL;
 	set_prefix((__u32) lowcore);
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
@@ -485,17 +517,18 @@
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
         struct cpuinfo_S390 *cpuinfo;
-	unsigned n = v;
+	unsigned long n = (unsigned long) v - 1;
 
-	if (!n--) {
+	if (!n) {
 		seq_printf(m, "vendor_id       : IBM/S390\n"
 			       "# processors    : %i\n"
 			       "bogomips per cpu: %lu.%02lu\n",
 			       smp_num_cpus, loops_per_jiffy/(500000/HZ),
 			       (loops_per_jiffy/(5000/HZ))%100);
-	} else if (cpu_online_map & (1 << n)) {
-		cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
-		seq_printf(m, "processor %i: "
+	}
+	if (cpu_online_map & (1 << n)) {
+		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
+		seq_printf(m, "processor %li: "
 			       "version = %02X,  "
 			       "identification = %06X,  "
 			       "machine = %04X\n",
@@ -508,7 +541,7 @@
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-	return *pos <= NR_CPUS ? (void)(*pos+1) : NULL;
+	return *pos <= NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
 }
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
diff -Nru a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
--- a/arch/s390/kernel/signal.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/kernel/signal.c	Sat Jun  8 22:31:36 2002
@@ -24,7 +24,9 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/tty.h>
 #include <linux/personality.h>
+#include <linux/binfmts.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
@@ -267,10 +269,10 @@
 
 static inline int map_signal(int sig)
 {
-	if (current->exec_domain
-	    && current->exec_domain->signal_invmap
+	if (current_thread_info()->exec_domain
+	    && current_thread_info()->exec_domain->signal_invmap
 	    && sig < 32)
-		return current->exec_domain->signal_invmap[sig];
+		return current_thread_info()->exec_domain->signal_invmap[sig];
 	else
 		return sig;
 }
@@ -301,6 +303,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -335,7 +341,7 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->gprs[15]),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
@@ -353,6 +359,10 @@
 		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, 
 	                          (u16 *)(frame->retcode));
 	}
+
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
diff -Nru a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
--- a/arch/s390/kernel/smp.c	Sat Jun  8 22:31:35 2002
+++ b/arch/s390/kernel/smp.c	Sat Jun  8 22:31:35 2002
@@ -36,6 +36,7 @@
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
+#include <asm/tlbflush.h>
 
 /* prototypes */
 extern int cpu_idle(void * unused);
@@ -49,16 +50,15 @@
 static int       max_cpus = NR_CPUS;	  /* Setup configured maximum number of CPUs to activate	*/
 int              smp_num_cpus;
 struct _lowcore *lowcore_ptr[NR_CPUS];
-unsigned int     prof_multiplier[NR_CPUS];
-unsigned int     prof_old_multiplier[NR_CPUS];
-unsigned int     prof_counter[NR_CPUS];
 cycles_t         cacheflush_time=0;
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
 spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-unsigned long	 cpu_online_map;
+volatile unsigned long phys_cpu_present_map;
+volatile unsigned long cpu_online_map;
+unsigned long    cache_decay_ticks = 0;
 
 /*
  *      Setup routine for controlling SMP activation
@@ -179,58 +179,123 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i, rc;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+			continue;
+		do {
+			rc = signal_processor_ps(&dummy, 0, i, sigp_stop);
+		} while (rc == sigp_busy);
+	}
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i, rc;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+			continue;
+		low_core_addr = (unsigned long)get_cpu_lowcore(i);
+		do {
+			rc = signal_processor_ps(&dummy, low_core_addr, i,
+						 sigp_store_status_at_address);
+		} while(rc == sigp_busy);
+        }
+}
 
 /*
- * Various special callbacks
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
  */
+void smp_send_stop(void)
+{
+        /* write magic number to zero page (absolute 0) */
+        get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
 
-void do_machine_restart(void)
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
+
+/*
+ * Reboot, halt and power_off routines for SMP.
+ */
+static volatile unsigned long cpu_restart_map;
+
+static void do_machine_restart(void * __unused)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-                for (;;);
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-                for (;;);
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-                for (;;);
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,19 +312,11 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
         do {
                 bits = atomic_read(&S390_lowcore.ext_call_fast);
         } while (atomic_compare_and_swap(bits,0,&S390_lowcore.ext_call_fast));
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
 	if (test_bit(ec_call_function, &bits)) 
 		do_call_function();
 }
@@ -270,7 +327,7 @@
  */
 static sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig)
 {
-        struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
+        struct _lowcore *lowcore = get_cpu_lowcore(cpu);
         sigp_ccode ccode;
 
         /*
@@ -288,65 +345,18 @@
 static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
         struct _lowcore *lowcore;
-        sigp_ccode ccode;
         int i;
 
         for (i = 0; i < smp_num_cpus; i++) {
                 if (smp_processor_id() == i)
                         continue;
-                lowcore = &get_cpu_lowcore(i);
+                lowcore = get_cpu_lowcore(i);
                 /*
                  * Set signaling bit in lowcore of target cpu and kick it
                  */
                 atomic_set_mask(1<<sig, &lowcore->ext_call_fast);
-                ccode = signal_processor(i, sigp_external_call);
-        }
-}
-
-/*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)&get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
+                while (signal_processor(i, sigp_external_call) == sigp_busy)
+			udelay(10);
         }
 }
 
@@ -369,7 +379,6 @@
  * it goes straight through and wastes no time serializing
  * anything. Worst case is that we lose a reschedule ...
  */
-
 void smp_send_reschedule(int cpu)
 {
         smp_ext_bitcall(cpu, ec_schedule);
@@ -452,8 +461,9 @@
 {
         int curr_cpu;
 
-        current->processor = 0;
+        current_thread_info()->cpu = 0;
         smp_num_cpus = 1;
+	phys_cpu_present_map = 1;
 	cpu_online_map = 1;
         for (curr_cpu = 0;
              curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
@@ -463,6 +473,7 @@
                 if (signal_processor(smp_num_cpus, sigp_sense) ==
                     sigp_not_operational)
                         continue;
+		set_bit(smp_num_cpus, &phys_cpu_present_map);
                 smp_num_cpus++;
         }
         printk("Detected %d CPU's\n",(int) smp_num_cpus);
@@ -473,7 +484,7 @@
 /*
  *      Activate a secondary processor.
  */
-extern void init_100hz_timer(void);
+extern void init_cpu_timer(void);
 extern int pfault_init(void);
 extern int pfault_token(void);
 
@@ -481,13 +492,15 @@
 {
         /* Setup the cpu */
         cpu_init();
+	/* Mark this cpu as online */
+	set_bit(smp_processor_id(), &cpu_online_map);
         /* Print info about this processor */
-        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data);
         /* Wait for completion of smp startup */
         while (!atomic_read(&smp_commenced))
                 /* nothing */ ;
-        /* init per CPU 100 hz timer */
-        init_100hz_timer();
+        /* init per CPU timer */
+        init_cpu_timer();
 #ifdef CONFIG_PFAULT
 	/* Enable pfault pseudo page faults on this cpu. */
 	pfault_init();
@@ -496,15 +509,6 @@
         return cpu_idle(NULL);
 }
 
-/*
- * The restart interrupt handler jumps to start_secondary directly
- * without the detour over initialize_secondary. We defined it here
- * so that the linker doesn't complain.
- */
-void __init initialize_secondary(void)
-{
-}
-
 static struct task_struct *__init fork_by_hand(void)
 {
        struct pt_regs regs;
@@ -529,16 +533,13 @@
          * We remove it from the pidhash and the runqueue
          * once we got the process:
          */
-        idle->processor = cpu;
-	idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
+	init_idle(idle, cpu);
 
-        del_from_runqueue(idle);
         unhash_process(idle);
-        init_tasks[cpu] = idle;
 
-        cpu_lowcore=&get_cpu_lowcore(cpu);
+        cpu_lowcore = get_cpu_lowcore(cpu);
 	cpu_lowcore->save_area[15] = idle->thread.ksp;
-	cpu_lowcore->kernel_stack = (idle->thread.ksp | 8191) + 1;
+	cpu_lowcore->kernel_stack = (__u32) idle->thread_info + 8192;
         __asm__ __volatile__("la    1,%0\n\t"
 			     "stctl 0,15,0(1)\n\t"
 			     "la    1,%1\n\t"
@@ -549,8 +550,6 @@
 
         eieio();
         signal_processor(cpu,sigp_restart);
-	/* Mark this cpu as online */
-	set_bit(cpu, &cpu_online_map);
 }
 
 /*
@@ -589,28 +588,15 @@
         
         /*
          *      Initialize the logical to physical CPU number mapping
-         *      and the per-CPU profiling counter/multiplier
          */
-        
-        for (i = 0; i < NR_CPUS; i++) {
-                prof_counter[i] = 1;
-                prof_old_multiplier[i] = 1;
-                prof_multiplier[i] = 1;
-        }
-
-        print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data);
 
-        for(i = 0; i < smp_num_cpus; i++)
-        {
+        for(i = 0; i < smp_num_cpus; i++) {
 		lowcore_ptr[i] = (struct _lowcore *)
 			__get_free_page(GFP_KERNEL|GFP_DMA);
-                if (lowcore_ptr[i] == NULL)
-                        panic("smp_boot_cpus failed to "
-			      "allocate prefix memory\n");
 		async_stack = __get_free_pages(GFP_KERNEL,1);
-		if (async_stack == 0)
-			panic("smp_boot_cpus failed to allocate "
-			      "asyncronous interrupt stack\n");
+		if (lowcore_ptr[i] == NULL || async_stack == 0UL)
+			panic("smp_boot_cpus failed to allocate memory\n");
 
                 memcpy(lowcore_ptr[i], &S390_lowcore, sizeof(struct _lowcore));
 		lowcore_ptr[i]->async_stack = async_stack + (2 * PAGE_SIZE);
@@ -618,21 +604,22 @@
                  * Most of the parameters are set up when the cpu is
                  * started up.
                  */
-		if (smp_processor_id() == i)
+		if (smp_processor_id() == i) {
 			set_prefix((u32) lowcore_ptr[i]);
-		else {
-			ccode = signal_processor_p((u32)(lowcore_ptr[i]),
-						   i, sigp_set_prefix);
-			if (ccode)
-				/* if this gets troublesome I'll have to do
-				 * something about it. */
-				printk("ccode %d for cpu %d  returned when "
-				       "setting prefix in smp_boot_cpus not good.\n",
-				       (int) ccode, (int) i);
-			else
-				do_boot_cpu(i);
+			continue;
 		}
+		ccode = signal_processor_p((u32)(lowcore_ptr[i]),
+					   i, sigp_set_prefix);
+		if (ccode)
+			panic("sigp_set_prefix failed for cpu %d "
+			      "with condition code %d\n",
+			      (int) i, (int) ccode);
+		do_boot_cpu(i);
 	}
+	/*
+	 * Now wait until all of the cpus are online.
+	 */
+	while (phys_cpu_present_map != cpu_online_map);
 }
 
 /*
@@ -646,60 +633,9 @@
         return 0;
 }
 
-/*
- * Local timer interrupt handler. It does both profiling and
- * process statistics/rescheduling.
- *
- * We do profiling in every local tick, statistics/rescheduling
- * happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing the new multiplier
- * value into /proc/profile.
- */
-
-void smp_local_timer_interrupt(struct pt_regs * regs)
-{
-	int user = (user_mode(regs) != 0);
-        int cpu = smp_processor_id();
-
-        /*
-         * The profiling function is SMP safe. (nothing can mess
-         * around with "current", and the profiling counters are
-         * updated with atomic operations). This is especially
-         * useful with a profiling multiplier != 1
-         */
-        if (!user_mode(regs))
-                s390_do_profile(regs->psw.addr);
-
-        if (!--prof_counter[cpu]) {
-
-                /*
-                 * The multiplier may have changed since the last time we got
-                 * to this point as a result of the user writing to
-                 * /proc/profile.  In this case we need to adjust the APIC
-                 * timer accordingly.
-                 *
-                 * Interrupts are already masked off at this point.
-                 */
-                prof_counter[cpu] = prof_multiplier[cpu];
-                if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
-			/* FIXME setup_APIC_timer(calibration_result/prof_counter[cpu]
-			   ); */
-                  prof_old_multiplier[cpu] = prof_counter[cpu];
-                }
-
-                /*
-                 * After doing the above, we need to make like
-                 * a normal interrupt - otherwise timer interrupts
-                 * ignore the global interrupt lock, which is the
-                 * WrongThing (tm) to do.
-                 */
-
-		update_process_times(user);
-        }
-}
-
 EXPORT_SYMBOL(lowcore_ptr);
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
diff -Nru a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
--- a/arch/s390/kernel/time.c	Sat Jun  8 22:31:35 2002
+++ b/arch/s390/kernel/time.c	Sat Jun  8 22:31:35 2002
@@ -33,19 +33,19 @@
 
 #include <asm/irq.h>
 
-
 /* change this if you have some constant time drift */
-#define USECS_PER_JIFFY ((signed long)1000000/HZ)
-#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
+#define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
 #define TICK_SIZE tick
 
-static uint64_t init_timer_cc, last_timer_cc;
+static ext_int_info_t ext_int_info_timer;
+static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
-void tod_to_timeval(uint64_t todval, struct timeval *xtime)
+void tod_to_timeval(__u64 todval, struct timeval *xtime)
 {
         const int high_bit = 0x80000000L;
         const int c_f4240 = 0xf4240L;
@@ -79,13 +79,15 @@
 		      : "cc", "memory", "2", "3", "4" );
 }
 
-unsigned long do_gettimeoffset(void) 
+static inline unsigned long do_gettimeoffset(void) 
 {
-	__u64 timer_cc;
+	__u64 now;
 
-	asm volatile ("STCK %0" : "=m" (timer_cc));
-        /* We require the offset from the previous interrupt */
-        return ((unsigned long)((timer_cc - last_timer_cc)>>12));
+	asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
+        now = (now - init_timer_cc) >> 12;
+	/* We require the offset from the latest update of xtime */
+	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
+	return (unsigned long) now;
 }
 
 /*
@@ -95,15 +97,10 @@
 {
 	unsigned long flags;
 	unsigned long usec, sec;
-	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);
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
+	usec = xtime.tv_usec + do_gettimeoffset();
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	while (usec >= 1000000) {
@@ -149,51 +146,31 @@
 extern __u16 boot_cpu_addr;
 #endif
 
-void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
+static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
 {
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, 0);
 
-        /*
-         * reset timer to 10ms minus time already elapsed
-         * since timer-interrupt pending
-         */
+	/*
+	 * set clock comparator for next tick
+	 */
+        S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
+        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
+
 #ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
 		write_lock(&xtime_lock);
-		last_timer_cc = S390_lowcore.jiffy_timer_cc;
-	}
-#else
-        last_timer_cc = S390_lowcore.jiffy_timer_cc;
-#endif
-        /* set clock comparator */
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
 
-/*
- * In the SMP case we use the local timer interrupt to do the
- * profiling, except when we simulate SMP mode on a uniprocessor
- * system, in that case we have to call the local interrupt handler.
- */
-#ifdef CONFIG_SMP
-        /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
-           but only do the rest for the boot CPU */
-        smp_local_timer_interrupt(regs);
-#else
-        if (!user_mode(regs))
-                s390_do_profile(regs->psw.addr);
-#endif
+	update_process_times(user_mode(regs));
 
-#ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
-#endif
-	{
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
 		do_timer(regs);
-#ifdef CONFIG_SMP
 		write_unlock(&xtime_lock);
-#endif
 	}
+#else
+	do_timer(regs);
+#endif
 
 	irq_exit(cpu, 0);
 }
@@ -201,19 +178,17 @@
 /*
  * Start the clock comparator on the current CPU
  */
-static long cr0 __attribute__ ((aligned (8)));
-
-void init_100hz_timer(void)
+void init_cpu_timer(void)
 {
+	unsigned long cr0;
+
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
-        /* set clock comparator */
-        /* read the TOD clock */
-        asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc));
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
@@ -222,12 +197,14 @@
  */
 void __init time_init(void)
 {
+        __u64 set_time_cc;
 	int cc;
 
         /* kick the TOD clock */
-        asm volatile ("STCK %1\n\t"
+        asm volatile ("STCK 0(%1)\n\t"
                       "IPM  %0\n\t"
-                      "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
+                      "SRL  %0,28" : "=r" (cc) : "a" (&init_timer_cc) 
+				   : "memory", "cc");
         switch (cc) {
         case 0: /* clock in set state: all is fine */
                 break;
@@ -241,12 +218,17 @@
                 printk("time_init: TOD clock stopped/non-operational\n");
                 break;
         }
+
+	/* set xtime */
+        set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
+                      (0x3c26700LL*1000000*4096);
+        tod_to_timeval(set_time_cc, &xtime);
+
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
-                panic("Couldn't request external interrupts 0x1004");
-        init_100hz_timer();
-        init_timer_cc = S390_lowcore.jiffy_timer_cc;
-        init_timer_cc -= 0x8126d60e46000000LL -
-                         (0x3c26700LL*1000000*4096);
-        tod_to_timeval(init_timer_cc, &xtime);
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
+                panic("Couldn't request external interrupt 0x1004");
+
+        /* init CPU timer */
+        init_cpu_timer();
 }
diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
--- a/arch/s390/kernel/traps.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/kernel/traps.c	Sat Jun  8 22:31:37 2002
@@ -26,15 +26,13 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
 #include <asm/mathemu.h>
-#if CONFIG_REMOTE_DEBUG
-#include <asm/gdb-stub.h>
-#endif
 #include <asm/cpcmd.h>
 #include <asm/s390_ext.h>
 
@@ -52,14 +50,214 @@
 #endif
 #endif
 
-extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_segment_exception;
+extern pgm_check_handler_t do_page_exception;
 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);
+static ext_int_info_t ext_int_pfault;
 #endif
 
+int kstack_depth_to_print = 12;
+
+/*
+ * If the address is either in the .text section of the
+ * kernel, or in the vmalloc'ed module regions, it *may* 
+ * be the address of a calling routine
+ */
+extern char _stext, _etext;
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	return (addr >= (unsigned long) &_stext &&
+		addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+void show_trace(unsigned long * stack)
+{
+	unsigned long backchain, low_addr, high_addr, ret_addr;
+	int i;
+
+	if (!stack)
+		stack = (unsigned long*)&stack;
+
+	printk("Call Trace: ");
+	low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
+	high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
+	/* Skip the first frame (biased stack) */
+	backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
+	/* Print up to 8 lines */
+	for (i = 0; i < 8; i++) {
+		if (backchain < low_addr || backchain >= high_addr)
+			break;
+		ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
+		if (!kernel_text_address(ret_addr))
+			break;
+		if (i && ((i % 6) == 0))
+			printk("\n   ");
+		printk("[<%08lx>] ", ret_addr);
+		low_addr = backchain;
+		backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	/*
+	 * We can't print the backtrace of a running process. It is
+	 * unreliable at best and can cause kernel oopses.
+	 */
+	if (tsk->state == TASK_RUNNING)
+		return;
+	show_trace((unsigned long *) tsk->thread.ksp);
+}
+
+void show_stack(unsigned long *sp)
+{
+	unsigned long *stack;
+	int i;
+
+	// debugging aid: "show_stack(NULL);" prints the
+	// back trace for this cpu.
+
+	if(sp == NULL)
+		sp = (unsigned long*) &sp;
+
+	stack = sp;
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
+			break;
+		if (i && ((i % 8) == 0))
+			printk("\n       ");
+		printk("%08lx ", *stack++);
+	}
+	printk("\n");
+	show_trace(sp);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+	mm_segment_t old_fs;
+	char *mode;
+	int i;
+
+	mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
+	printk("%s PSW : %08lx %08lx\n",
+	       mode, (unsigned long) regs->psw.mask,
+	       (unsigned long) regs->psw.addr);
+	printk("%s GPRS: %08x %08x %08x %08x\n", mode,
+	       regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
+	printk("%s ACRS: %08x %08x %08x %08x\n", mode,
+	       regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
+
+	/*
+	 * Print the first 20 byte of the instruction stream at the
+	 * time of the fault.
+	 */
+	old_fs = get_fs();
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
+		set_fs(USER_DS);
+	else
+		set_fs(KERNEL_DS);
+	printk("%s Code: ", mode);
+	for (i = 0; i < 20; i++) {
+		unsigned char c;
+		if (__get_user(c, (char *)(regs->psw.addr + i))) {
+			printk(" Bad PSW.");
+			break;
+		}
+		printk("%02x ", c);
+	}
+	set_fs(old_fs);
+
+	printk("\n");
+}	
+
+/* This is called from fs/proc/array.c */
+char *task_show_regs(struct task_struct *task, char *buffer)
+{
+	struct pt_regs *regs;
+
+	regs = __KSTK_PTREGS(task);
+	buffer += sprintf(buffer, "task: %08lx, ksp: %08x\n",
+			  (unsigned long) task, task->thread.ksp);
+	buffer += sprintf(buffer, "User PSW : %08lx %08lx\n",
+			  (unsigned long) regs->psw.mask, 
+			  (unsigned long) regs->psw.addr);
+	buffer += sprintf(buffer, "User GPRS: %08x %08x %08x %08x\n",
+			  regs->gprs[0], regs->gprs[1],
+			  regs->gprs[2], regs->gprs[3]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->gprs[4], regs->gprs[5],
+			  regs->gprs[6], regs->gprs[7]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->gprs[8], regs->gprs[9],
+			  regs->gprs[10], regs->gprs[11]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->gprs[12], regs->gprs[13],
+			  regs->gprs[14], regs->gprs[15]);
+	buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n",
+			  regs->acrs[0], regs->acrs[1],
+			  regs->acrs[2], regs->acrs[3]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->acrs[4], regs->acrs[5],
+			  regs->acrs[6], regs->acrs[7]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->acrs[8], regs->acrs[9],
+			  regs->acrs[10], regs->acrs[11]);
+	buffer += sprintf(buffer, "           %08x %08x %08x %08x\n",
+			  regs->acrs[12], regs->acrs[13],
+			  regs->acrs[14], regs->acrs[15]);
+	return buffer;
+}
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -74,23 +272,6 @@
         do_exit(SIGSEGV);
 }
 
-#define DO_ERROR(signr, str, name) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-	do_trap(interruption_code, signr, str, regs, NULL); \
-}
-
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-        siginfo_t info; \
-        info.si_signo = signr; \
-        info.si_errno = 0; \
-        info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
-}
-
 static void inline do_trap(long interruption_code, int signr, char *str,
                            struct pt_regs *regs, siginfo_t *info)
 {
@@ -104,7 +285,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 struct task_struct *tsk = current;
 
-                tsk->thread.trap_no = interruption_code;
+                tsk->thread.trap_no = interruption_code & 0xffff;
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -131,6 +312,11 @@
         }
 }
 
+static inline void *get_check_address(struct pt_regs *regs)
+{
+	return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+}
+
 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
 	if(regs->psw.mask&PSW_PROBLEM_STATE)
@@ -145,7 +331,7 @@
 #if CONFIG_REMOTE_DEBUG
 		if(gdb_stub_initialised)
 		{
-			gdb_stub_handle_exception((struct gdb_pt_regs *)regs,signal);
+			gdb_stub_handle_exception(regs, signal);
 			return 0;
 		}
 #endif
@@ -154,14 +340,68 @@
 	return 0;
 }
 
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+        siginfo_t info; \
+        info.si_signo = signr; \
+        info.si_errno = 0; \
+        info.si_code = sicode; \
+        info.si_addr = (void *)siaddr; \
+        do_trap(interruption_code, signr, str, regs, &info); \
+}
+
 DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
-DO_ERROR(SIGILL,  "privileged operation", privileged_op)
-DO_ERROR(SIGILL,  "execute exception", execute_exception)
-DO_ERROR(SIGSEGV, "addressing exception", addressing_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)
+
+DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
+	      BUS_ADRERR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
+	      FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
+	      ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void *location,
+           int fpc, long interruption_code)
+{
+	siginfo_t si;
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_addr = location;
+	si.si_code = 0;
+	/* FPC[2] is Data Exception Code */
+	if ((fpc & 0x00000300) == 0) {
+		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
+		if (fpc & 0x8000) /* invalid fp operation */
+			si.si_code = FPE_FLTINV;
+		else if (fpc & 0x4000) /* div by 0 */
+			si.si_code = FPE_FLTDIV;
+		else if (fpc & 0x2000) /* overflow */
+			si.si_code = FPE_FLTOVF;
+		else if (fpc & 0x1000) /* underflow */
+			si.si_code = FPE_FLTUND;
+		else if (fpc & 0x0800) /* inexact */
+			si.si_code = FPE_FLTRES;
+	}
+	current->thread.ieee_instruction_pointer = (addr_t) location;
+	do_trap(interruption_code, SIGFPE,
+		"floating point exception", regs, &si);
+}
 
 asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
@@ -212,11 +452,10 @@
 #endif 
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal)
 		do_trap(interruption_code, signal,
 			"illegal operation", regs, NULL);
 }
@@ -231,7 +470,7 @@
 	__u16 *location = NULL;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -271,25 +510,30 @@
                 }
         } else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-        } else if (signal)
-                do_trap(interruption_code, signal,
-			"specification exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"specification exception", regs, &info);
+	}
 }
 #else
-DO_ERROR(SIGILL, "specification exception", specification_exception)
+DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
+	      ILL_ILLOPN, get_check_address(regs));
 #endif
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 {
-        __u8 opcode[6];
 	__u16 *location;
 	int signal = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -304,6 +548,7 @@
 
 #ifdef CONFIG_MATHEMU
         else if (regs->psw.mask & PSW_PROBLEM_STATE) {
+        	__u8 opcode[6];
 		get_user(*((__u16 *) opcode), location);
 		switch (opcode[0]) {
 		case 0x28: /* LDR Rx,Ry   */
@@ -360,13 +605,18 @@
 		signal = SIGFPE;
 	else
 		signal = SIGILL;
-        if (signal == SIGFPE) {
-		current->thread.ieee_instruction_pointer = (addr_t) location;
-		do_trap(interruption_code, signal,
-			"floating point exception", regs, NULL);
-	} else if (signal) 
-                do_trap(interruption_code, signal,
-			"data exception", regs, NULL);
+        if (signal == SIGFPE)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else if (signal) {
+		siginfo_t info;
+		info.si_signo = signal;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, signal, 
+			"data exception", regs, &info);
+	}
 }
 
 
@@ -382,13 +632,13 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
-        pgm_check_table[4] = &do_page_fault;
+        pgm_check_table[4] = &do_protection_exception;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
         pgm_check_table[9] = &divide_exception;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
+        pgm_check_table[0x10] = &do_segment_exception;
+        pgm_check_table[0x11] = &do_page_exception;
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
  	pgm_check_table[0x14] = &do_pseudo_page_fault;
@@ -397,7 +647,8 @@
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 0)
 			panic("Couldn't request external interrupt 0x2603");
 		/*
 		 * First try to get pfault pseudo page faults going.
@@ -405,8 +656,9 @@
 		 */
 		if (pfault_init() != 0) {
 			/* Tough luck, no pfault. */
-			unregister_external_interrupt(0x2603,
-						      pfault_interrupt);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 			cpcmd("SET PAGEX ON", NULL, 0);
 		}
 	}
diff -Nru a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S
--- a/arch/s390/lib/uaccess.S	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/lib/uaccess.S	Sat Jun  8 22:31:36 2002
@@ -6,46 +6,83 @@
  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
- *  These functions have a non-standard call interface
+ *  These functions have standard call interface
  */
 
 #include <asm/lowcore.h>
 
         .text
         .align 4
-        .globl __copy_from_user_fixup
-__copy_from_user_fixup:
-        l     1,__LC_PGM_OLD_PSW+4
-        sll   4,1
-        srl   4,1
-0:      lhi   3,-4096
-        sll   3,1
-        srl   3,1
-        n     3,__LC_TRANS_EXC_ADDR
-        sr    3,4
-        bm    4(1)
-1:      mvcle 2,4,0
-        b     4(1)
+        .globl __copy_from_user_asm
+__copy_from_user_asm:
+	lr	%r5,%r3
+	sacf	512
+0:	mvcle	%r2,%r4,0
+	jo	0b
+1:	sacf	0
+	lr	%r2,%r5
+	br	%r14
+2:      sll	%r4,1
+        srl	%r4,1
+        lhi	%r3,-4096
+        sll	%r3,1
+        srl	%r3,1
+        n	%r3,__LC_TRANS_EXC_ADDR
+        sr	%r3,%r4
+        jm	1b
+	j	0b
         .section __ex_table,"a"
-	.long 1b,0b
+	.long	0b,2b
         .previous
 
         .align 4
         .text
-        .globl __copy_to_user_fixup
-__copy_to_user_fixup:
-        l     1,__LC_PGM_OLD_PSW+4
-        sll   4,1
-        srl   4,1
-0:      lhi   5,-4096
-        sll   5,1
-        srl   5,1
-        n     5,__LC_TRANS_EXC_ADDR
-        sr    5,4
-        bm    4(1)
-1:      mvcle 4,2,0
-        b     4(1)
+        .globl __copy_to_user_asm
+__copy_to_user_asm:
+	lr	%r5,%r3
+	sacf	512
+0:	mvcle	%r4,%r2,0
+	jo	0b
+1:	sacf	0
+	lr	%r2,%r3
+	br	%r14
+2:      sll	%r4,1
+        srl	%r4,1
+        lhi	%r5,-4096
+        sll	%r5,1
+        srl	%r5,1
+        n	%r5,__LC_TRANS_EXC_ADDR
+        sr	%r5,%r4
+        jm	1b
+	j	0b
         .section __ex_table,"a"
-        .long 1b,0b
+	.long   0b,2b
+        .previous
+
+        .align 4
+        .text
+        .globl __clear_user_asm
+__clear_user_asm:
+	lr	%r4,%r2
+	lr	%r5,%r3
+	sr	%r2,%r2
+	sr	%r3,%r3
+	sacf	512
+0:	mvcle	%r4,%r2,0
+	jo	0b
+1:	sacf	0
+	lr	%r2,%r3
+	br	%r14
+2:      sll	%r4,1
+        srl	%r4,1
+        lhi	%r5,-4096
+        sll	%r5,1
+        srl	%r5,1
+        n	%r5,__LC_TRANS_EXC_ADDR
+        sr	%r5,%r4
+	jm	1b
+	j	0b
+        .section __ex_table,"a"
+	.long   0b,2b
         .previous
 
diff -Nru a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
--- a/arch/s390/math-emu/math.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/math-emu/math.c	Sat Jun  8 22:31:37 2002
@@ -96,7 +96,7 @@
                         return SIGSEGV; \
         } while (0)
 
-static void display_emulation_not_implemented(char *instr)
+static void display_emulation_not_implemented(struct pt_regs *regs, char *instr)
 {
         struct pt_regs *regs;
         __u16 *location;
@@ -105,7 +105,6 @@
         if(sysctl_ieee_emulation_warnings)
 #endif
         {
-                regs = current->thread.regs;
                 location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
                 printk("%s ieee fpu instruction not emulated "
                        "process name: %s pid: %d \n",
@@ -116,10 +115,9 @@
         }
 }
 
-static inline void emu_set_CC (int cc)
+static inline void emu_set_CC (struct pt_regs *regs, int cc)
 {
-        current->thread.regs->psw.mask = 
-		(current->thread.regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
+        regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
 }
 
 /*
@@ -129,24 +127,24 @@
  *  2 : Result is greater than zero
  *  3 : Result is NaN or INF
  */
-static inline void emu_set_CC_cs(int class, int sign)
+static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign)
 {
         switch (class) {
         case FP_CLS_NORMAL:
         case FP_CLS_INF:
-                emu_set_CC(sign ? 1 : 2);
+                emu_set_CC(regs, sign ? 1 : 2);
                 break;
         case FP_CLS_ZERO:
-                emu_set_CC(0);
+                emu_set_CC(regs, 0);
                 break;
         case FP_CLS_NAN:
-                emu_set_CC(3);
+                emu_set_CC(regs, 3);
                 break;
         }
 }
 
 /* Add long double */
-static int emu_axbr (int rx, int ry) {
+static int emu_axbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -163,12 +161,12 @@
         FP_PACK_QP(&cvt.ld, QR);
         current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
         current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
-        emu_set_CC_cs(QR_c, QR_s);
+        emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Add double */
-static int emu_adbr (int rx, int ry) {
+static int emu_adbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -178,12 +176,12 @@
         FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
         FP_ADD_D(DR, DA, DB);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Add double */
-static int emu_adb (int rx, double *val) {
+static int emu_adb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -193,12 +191,12 @@
         FP_UNPACK_DP(DB, val);
         FP_ADD_D(DR, DA, DB);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Add float */
-static int emu_aebr (int rx, int ry) {
+static int emu_aebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -208,12 +206,12 @@
         FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
         FP_ADD_S(SR, SA, SB);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Add float */
-static int emu_aeb (int rx, float *val) {
+static int emu_aeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -223,12 +221,12 @@
         FP_UNPACK_SP(SB, val);
         FP_ADD_S(SR, SA, SB);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Compare long double */
-static int emu_cxbr (int rx, int ry) {
+static int emu_cxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB);
 	mathemu_ldcv cvt;
         int IR;
@@ -244,12 +242,12 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         return 0;
 }
 
 /* Compare double */
-static int emu_cdbr (int rx, int ry) {
+static int emu_cdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB);
         int IR;
 
@@ -260,12 +258,12 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         return 0;
 }
 
 /* Compare double */
-static int emu_cdb (int rx, double *val) {
+static int emu_cdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB);
         int IR;
 
@@ -276,12 +274,12 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         return 0;
 }
 
 /* Compare float */
-static int emu_cebr (int rx, int ry) {
+static int emu_cebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB);
         int IR;
 
@@ -292,12 +290,12 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         return 0;
 }
 
 /* Compare float */
-static int emu_ceb (int rx, float *val) {
+static int emu_ceb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB);
         int IR;
 
@@ -308,12 +306,12 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         return 0;
 }
 
 /* Compare and signal long double */
-static int emu_kxbr (int rx, int ry) {
+static int emu_kxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -330,14 +328,14 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         if (IR == 3)
                 FP_SET_EXCEPTION (FP_EX_INVALID);
         return _fex;
 }
 
 /* Compare and signal double */
-static int emu_kdbr (int rx, int ry) {
+static int emu_kdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB);
         FP_DECL_EX;
         int IR;
@@ -349,14 +347,14 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         if (IR == 3)
                 FP_SET_EXCEPTION (FP_EX_INVALID);
         return _fex;
 }
 
 /* Compare and signal double */
-static int emu_kdb (int rx, double *val) {
+static int emu_kdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB);
         FP_DECL_EX;
         int IR;
@@ -368,14 +366,14 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         if (IR == 3)
                 FP_SET_EXCEPTION (FP_EX_INVALID);
         return _fex;
 }
 
 /* Compare and signal float */
-static int emu_kebr (int rx, int ry) {
+static int emu_kebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB);
         FP_DECL_EX;
         int IR;
@@ -387,14 +385,14 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         if (IR == 3)
                 FP_SET_EXCEPTION (FP_EX_INVALID);
         return _fex;
 }
 
 /* Compare and signal float */
-static int emu_keb (int rx, float *val) {
+static int emu_keb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB);
         FP_DECL_EX;
         int IR;
@@ -406,14 +404,14 @@
          * IR == -1 if DA < DB, IR == 0 if DA == DB,
          * IR == 1 if DA > DB and IR == 3 if unorderded
          */
-        emu_set_CC((IR == -1) ? 1 : (IR == 1) ? 2 : IR);
+        emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
         if (IR == 3)
                 FP_SET_EXCEPTION (FP_EX_INVALID);
         return _fex;
 }
 
 /* Convert from fixed long double */
-static int emu_cxfbr (int rx, int ry) {
+static int emu_cxfbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -421,7 +419,7 @@
         int mode;
 
 	mode = current->thread.fp_regs.fpc & 3;
-        si = current->thread.regs->gprs[ry];
+        si = regs->gprs[ry];
         FP_FROM_INT_Q(QR, si, 32, int);
         FP_PACK_QP(&cvt.ld, QR);
         current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
@@ -430,35 +428,35 @@
 }
 
 /* Convert from fixed double */
-static int emu_cdfbr (int rx, int ry) {
+static int emu_cdfbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DR);
         FP_DECL_EX;
         __s32 si;
         int mode;
 
 	mode = current->thread.fp_regs.fpc & 3;
-        si = current->thread.regs->gprs[ry];
+        si = regs->gprs[ry];
         FP_FROM_INT_D(DR, si, 32, int);
         FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
         return _fex;
 }
 
 /* Convert from fixed float */
-static int emu_cefbr (int rx, int ry) {
+static int emu_cefbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SR);
         FP_DECL_EX;
         __s32 si;
         int mode;
 
 	mode = current->thread.fp_regs.fpc & 3;
-        si = current->thread.regs->gprs[ry];
+        si = regs->gprs[ry];
         FP_FROM_INT_S(SR, si, 32, int);
         FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
         return _fex;
 }
 
 /* Convert to fixed long double */
-static int emu_cfxbr (int rx, int ry, int mask) {
+static int emu_cfxbr (struct pt_regs *regs, int rx, int ry, int mask) {
         FP_DECL_Q(QA);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -475,13 +473,13 @@
         cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
         FP_UNPACK_QP(QA, &cvt.ld);
         FP_TO_INT_ROUND_Q(si, QA, 32, 1);
-        current->thread.regs->gprs[rx] = si;
-        emu_set_CC_cs(QA_c, QA_s);
+        regs->gprs[rx] = si;
+        emu_set_CC_cs(regs, QA_c, QA_s);
         return _fex;
 }
 
 /* Convert to fixed double */
-static int emu_cfdbr (int rx, int ry, int mask) {
+static int emu_cfdbr (struct pt_regs *regs, int rx, int ry, int mask) {
         FP_DECL_D(DA);
         FP_DECL_EX;
         __s32 si;
@@ -495,13 +493,13 @@
 		mode = mask - 4;
         FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
         FP_TO_INT_ROUND_D(si, DA, 32, 1);
-        current->thread.regs->gprs[rx] = si;
-        emu_set_CC_cs(DA_c, DA_s);
+        regs->gprs[rx] = si;
+        emu_set_CC_cs(regs, DA_c, DA_s);
         return _fex;
 }
 
 /* Convert to fixed float */
-static int emu_cfebr (int rx, int ry, int mask) {
+static int emu_cfebr (struct pt_regs *regs, int rx, int ry, int mask) {
         FP_DECL_S(SA);
         FP_DECL_EX;
         __s32 si;
@@ -515,13 +513,13 @@
 		mode = mask - 4;
         FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
         FP_TO_INT_ROUND_S(si, SA, 32, 1);
-        current->thread.regs->gprs[rx] = si;
-        emu_set_CC_cs(SA_c, SA_s);
+        regs->gprs[rx] = si;
+        emu_set_CC_cs(regs, SA_c, SA_s);
         return _fex;
 }
 
 /* Divide long double */
-static int emu_dxbr (int rx, int ry) {
+static int emu_dxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -542,7 +540,7 @@
 }
 
 /* Divide double */
-static int emu_ddbr (int rx, int ry) {
+static int emu_ddbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -556,7 +554,7 @@
 }
 
 /* Divide double */
-static int emu_ddb (int rx, double *val) {
+static int emu_ddb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -570,7 +568,7 @@
 }
 
 /* Divide float */
-static int emu_debr (int rx, int ry) {
+static int emu_debr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -584,7 +582,7 @@
 }
 
 /* Divide float */
-static int emu_deb (int rx, float *val) {
+static int emu_deb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -598,25 +596,25 @@
 }
 
 /* Divide to integer double */
-static int emu_didbr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("didbr");
+static int emu_didbr (struct pt_regs *regs, int rx, int ry, int mask) {
+        display_emulation_not_implemented(regs, "didbr");
         return 0;
 }
 
 /* Divide to integer float */
-static int emu_diebr (int rx, int ry, int mask) {
-        display_emulation_not_implemented("diebr");
+static int emu_diebr (struct pt_regs *regs, int rx, int ry, int mask) {
+        display_emulation_not_implemented(regs, "diebr");
         return 0;
 }
 
 /* Extract fpc */
-static int emu_efpc (int rx, int ry) {
-        current->thread.regs->gprs[rx] = current->thread.fp_regs.fpc;
+static int emu_efpc (struct pt_regs *regs, int rx, int ry) {
+        regs->gprs[rx] = current->thread.fp_regs.fpc;
         return 0;
 }
 
 /* Load and test long double */
-static int emu_ltxbr (int rx, int ry) {
+static int emu_ltxbr (struct pt_regs *regs, int rx, int ry) {
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
 	mathemu_ldcv cvt;
         FP_DECL_Q(QA);
@@ -627,36 +625,36 @@
         FP_UNPACK_QP(QA, &cvt.ld);
         fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
         fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui;
-        emu_set_CC_cs(QA_c, QA_s);
+        emu_set_CC_cs(regs, QA_c, QA_s);
         return _fex;
 }
 
 /* Load and test double */
-static int emu_ltdbr (int rx, int ry) {
+static int emu_ltdbr (struct pt_regs *regs, int rx, int ry) {
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
         FP_DECL_D(DA);
         FP_DECL_EX;
 
         FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
         fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
-        emu_set_CC_cs(DA_c, DA_s);
+        emu_set_CC_cs(regs, DA_c, DA_s);
         return _fex;
 }
 
 /* Load and test double */
-static int emu_ltebr (int rx, int ry) {
+static int emu_ltebr (struct pt_regs *regs, int rx, int ry) {
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
         FP_DECL_S(SA);
         FP_DECL_EX;
 
         FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
         fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
-        emu_set_CC_cs(SA_c, SA_s);
+        emu_set_CC_cs(regs, SA_c, SA_s);
         return _fex;
 }
 
 /* Load complement long double */
-static int emu_lcxbr (int rx, int ry) {
+static int emu_lcxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -670,12 +668,12 @@
         FP_PACK_QP(&cvt.ld, QR);
         current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
         current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
-        emu_set_CC_cs(QR_c, QR_s);
+        emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Load complement double */
-static int emu_lcdbr (int rx, int ry) {
+static int emu_lcdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -684,12 +682,12 @@
         FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
 	FP_NEG_D(DR, DA);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Load complement float */
-static int emu_lcebr (int rx, int ry) {
+static int emu_lcebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -698,12 +696,12 @@
         FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
 	FP_NEG_S(SR, SA);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Load floating point integer long double */
-static int emu_fixbr (int rx, int ry, int mask) {
+static int emu_fixbr (struct pt_regs *regs, int rx, int ry, int mask) {
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
         FP_DECL_Q(QA);
         FP_DECL_EX;
@@ -728,7 +726,7 @@
 }
 
 /* Load floating point integer double */
-static int emu_fidbr (int rx, int ry, int mask) {
+static int emu_fidbr (struct pt_regs *regs, int rx, int ry, int mask) {
 	/* FIXME: rounding mode !! */
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
         FP_DECL_D(DA);
@@ -749,7 +747,7 @@
 }
 
 /* Load floating point integer float */
-static int emu_fiebr (int rx, int ry, int mask) {
+static int emu_fiebr (struct pt_regs *regs, int rx, int ry, int mask) {
         s390_fp_regs *fp_regs = &current->thread.fp_regs;
         FP_DECL_S(SA);
         FP_DECL_EX;
@@ -769,7 +767,7 @@
 }
 
 /* Load lengthened double to long double */
-static int emu_lxdbr (int rx, int ry) {
+static int emu_lxdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -785,7 +783,7 @@
 }
 
 /* Load lengthened double to long double */
-static int emu_lxdb (int rx, double *val) {
+static int emu_lxdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -801,7 +799,7 @@
 }
 
 /* Load lengthened float to long double */
-static int emu_lxebr (int rx, int ry) {
+static int emu_lxebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -817,7 +815,7 @@
 }
 
 /* Load lengthened float to long double */
-static int emu_lxeb (int rx, float *val) {
+static int emu_lxeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -833,7 +831,7 @@
 }
 
 /* Load lengthened float to double */
-static int emu_ldebr (int rx, int ry) {
+static int emu_ldebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -846,7 +844,7 @@
 }
 
 /* Load lengthened float to double */
-static int emu_ldeb (int rx, float *val) {
+static int emu_ldeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -859,7 +857,7 @@
 }
 
 /* Load negative long double */
-static int emu_lnxbr (int rx, int ry) {
+static int emu_lnxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -880,12 +878,12 @@
 		current->thread.fp_regs.fprs[rx+2].ui =
 			current->thread.fp_regs.fprs[ry+2].ui;
 	}
-	emu_set_CC_cs(QR_c, QR_s);
+	emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Load negative double */
-static int emu_lndbr (int rx, int ry) {
+static int emu_lndbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -898,12 +896,12 @@
 	} else
 		current->thread.fp_regs.fprs[rx].ui =
 			current->thread.fp_regs.fprs[ry].ui;
-	emu_set_CC_cs(DR_c, DR_s);
+	emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Load negative float */
-static int emu_lnebr (int rx, int ry) {
+static int emu_lnebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SR);
 	FP_DECL_EX;
         int mode;
@@ -916,12 +914,12 @@
 	} else
 		current->thread.fp_regs.fprs[rx].ui =
 			current->thread.fp_regs.fprs[ry].ui;
-	emu_set_CC_cs(SR_c, SR_s);
+	emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Load positive long double */
-static int emu_lpxbr (int rx, int ry) {
+static int emu_lpxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -942,12 +940,12 @@
 		current->thread.fp_regs.fprs[rx+2].ui =
 			current->thread.fp_regs.fprs[ry+2].ui;
 	}
-	emu_set_CC_cs(QR_c, QR_s);
+	emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Load positive double */
-static int emu_lpdbr (int rx, int ry) {
+static int emu_lpdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -960,12 +958,12 @@
 	} else
 		current->thread.fp_regs.fprs[rx].ui =
 			current->thread.fp_regs.fprs[ry].ui;
-	emu_set_CC_cs(DR_c, DR_s);
+	emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Load positive float */
-static int emu_lpebr (int rx, int ry) {
+static int emu_lpebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SR);
 	FP_DECL_EX;
         int mode;
@@ -978,12 +976,12 @@
 	} else
 		current->thread.fp_regs.fprs[rx].ui =
 			current->thread.fp_regs.fprs[ry].ui;
-	emu_set_CC_cs(SR_c, SR_s);
+	emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Load rounded long double to double */
-static int emu_ldxbr (int rx, int ry) {
+static int emu_ldxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_D(DR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -999,7 +997,7 @@
 }
 
 /* Load rounded long double to float */
-static int emu_lexbr (int rx, int ry) {
+static int emu_lexbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_S(SR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1015,7 +1013,7 @@
 }
 
 /* Load rounded double to float */
-static int emu_ledbr (int rx, int ry) {
+static int emu_ledbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_S(SR);
 	FP_DECL_EX;
         int mode;
@@ -1028,7 +1026,7 @@
 }
 
 /* Multiply long double */
-static int emu_mxbr (int rx, int ry) {
+static int emu_mxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1049,7 +1047,7 @@
 }
 
 /* Multiply double */
-static int emu_mdbr (int rx, int ry) {
+static int emu_mdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1063,7 +1061,7 @@
 }
 
 /* Multiply double */
-static int emu_mdb (int rx, double *val) {
+static int emu_mdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1077,7 +1075,7 @@
 }
 
 /* Multiply double to long double */
-static int emu_mxdbr (int rx, int ry) {
+static int emu_mxdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
 	FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1096,7 +1094,7 @@
 }
 
 /* Multiply double to long double */
-static int emu_mxdb (int rx, long double *val) {
+static int emu_mxdb (struct pt_regs *regs, int rx, long double *val) {
         FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1115,7 +1113,7 @@
 }
 
 /* Multiply float */
-static int emu_meebr (int rx, int ry) {
+static int emu_meebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1129,7 +1127,7 @@
 }
 
 /* Multiply float */
-static int emu_meeb (int rx, float *val) {
+static int emu_meeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1143,7 +1141,7 @@
 }
 
 /* Multiply float to double */
-static int emu_mdebr (int rx, int ry) {
+static int emu_mdebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -1159,7 +1157,7 @@
 }
 
 /* Multiply float to double */
-static int emu_mdeb (int rx, float *val) {
+static int emu_mdeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
 	FP_DECL_EX;
         int mode;
@@ -1175,7 +1173,7 @@
 }
 
 /* Multiply and add double */
-static int emu_madbr (int rx, int ry, int rz) {
+static int emu_madbr (struct pt_regs *regs, int rx, int ry, int rz) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1191,7 +1189,7 @@
 }
 
 /* Multiply and add double */
-static int emu_madb (int rx, double *val, int rz) {
+static int emu_madb (struct pt_regs *regs, int rx, double *val, int rz) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1207,7 +1205,7 @@
 }
 
 /* Multiply and add float */
-static int emu_maebr (int rx, int ry, int rz) {
+static int emu_maebr (struct pt_regs *regs, int rx, int ry, int rz) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1223,7 +1221,7 @@
 }
 
 /* Multiply and add float */
-static int emu_maeb (int rx, float *val, int rz) {
+static int emu_maeb (struct pt_regs *regs, int rx, float *val, int rz) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1239,7 +1237,7 @@
 }
 
 /* Multiply and subtract double */
-static int emu_msdbr (int rx, int ry, int rz) {
+static int emu_msdbr (struct pt_regs *regs, int rx, int ry, int rz) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1255,7 +1253,7 @@
 }
 
 /* Multiply and subtract double */
-static int emu_msdb (int rx, double *val, int rz) {
+static int emu_msdb (struct pt_regs *regs, int rx, double *val, int rz) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1271,7 +1269,7 @@
 }
 
 /* Multiply and subtract float */
-static int emu_msebr (int rx, int ry, int rz) {
+static int emu_msebr (struct pt_regs *regs, int rx, int ry, int rz) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1287,7 +1285,7 @@
 }
 
 /* Multiply and subtract float */
-static int emu_mseb (int rx, float *val, int rz) {
+static int emu_mseb (struct pt_regs *regs, int rx, float *val, int rz) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1303,10 +1301,10 @@
 }
 
 /* Set floating point control word */
-static int emu_sfpc (int rx, int ry) {
+static int emu_sfpc (struct pt_regs *regs, int rx, int ry) {
         __u32 temp;
 
-        temp = current->thread.regs->gprs[rx];
+        temp = regs->gprs[rx];
         if ((temp & ~FPC_VALID_MASK) != 0)
 		return SIGILL;
 	current->thread.fp_regs.fpc = temp;
@@ -1314,7 +1312,7 @@
 }
 
 /* Square root long double */
-static int emu_sqxbr (int rx, int ry) {
+static int emu_sqxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1328,12 +1326,12 @@
         FP_PACK_QP(&cvt.ld, QR);
         current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
         current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
-        emu_set_CC_cs(QR_c, QR_s);
+        emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Square root double */
-static int emu_sqdbr (int rx, int ry) {
+static int emu_sqdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1342,12 +1340,12 @@
         FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
 	FP_SQRT_D(DR, DA);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Square root double */
-static int emu_sqdb (int rx, double *val) {
+static int emu_sqdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1356,12 +1354,12 @@
         FP_UNPACK_DP(DA, val);
 	FP_SQRT_D(DR, DA);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Square root float */
-static int emu_sqebr (int rx, int ry) {
+static int emu_sqebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1370,12 +1368,12 @@
         FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
 	FP_SQRT_S(SR, SA);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Square root float */
-static int emu_sqeb (int rx, float *val) {
+static int emu_sqeb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1384,12 +1382,12 @@
         FP_UNPACK_SP(SA, val);
 	FP_SQRT_S(SR, SA);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Subtract long double */
-static int emu_sxbr (int rx, int ry) {
+static int emu_sxbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
         FP_DECL_EX;
 	mathemu_ldcv cvt;
@@ -1406,12 +1404,12 @@
         FP_PACK_QP(&cvt.ld, QR);
         current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
         current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
-        emu_set_CC_cs(QR_c, QR_s);
+        emu_set_CC_cs(regs, QR_c, QR_s);
         return _fex;
 }
 
 /* Subtract double */
-static int emu_sdbr (int rx, int ry) {
+static int emu_sdbr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1421,12 +1419,12 @@
         FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
         FP_SUB_D(DR, DA, DB);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Subtract double */
-static int emu_sdb (int rx, double *val) {
+static int emu_sdb (struct pt_regs *regs, int rx, double *val) {
         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
         FP_DECL_EX;
         int mode;
@@ -1436,12 +1434,12 @@
         FP_UNPACK_DP(DB, val);
         FP_SUB_D(DR, DA, DB);
 	FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
-        emu_set_CC_cs(DR_c, DR_s);
+        emu_set_CC_cs(regs, DR_c, DR_s);
         return _fex;
 }
 
 /* Subtract float */
-static int emu_sebr (int rx, int ry) {
+static int emu_sebr (struct pt_regs *regs, int rx, int ry) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1451,12 +1449,12 @@
         FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
         FP_SUB_S(SR, SA, SB);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Subtract float */
-static int emu_seb (int rx, float *val) {
+static int emu_seb (struct pt_regs *regs, int rx, float *val) {
         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
         FP_DECL_EX;
         int mode;
@@ -1466,12 +1464,12 @@
         FP_UNPACK_SP(SB, val);
         FP_SUB_S(SR, SA, SB);
 	FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
-        emu_set_CC_cs(SR_c, SR_s);
+        emu_set_CC_cs(regs, SR_c, SR_s);
         return _fex;
 }
 
 /* Test data class long double */
-static int emu_tcxb (int rx, long val) {
+static int emu_tcxb (struct pt_regs *regs, int rx, long val) {
         FP_DECL_Q(QA);
 	mathemu_ldcv cvt;
 	int bit;
@@ -1500,12 +1498,12 @@
 	}
 	if (!QA_s)
 		bit++;
-	emu_set_CC(((__u32) val >> bit) & 1);
+	emu_set_CC(regs, ((__u32) val >> bit) & 1);
         return 0;
 }
 
 /* Test data class double */
-static int emu_tcdb (int rx, long val) {
+static int emu_tcdb (struct pt_regs *regs, int rx, long val) {
         FP_DECL_D(DA);
 	int bit;
 
@@ -1531,12 +1529,12 @@
 	}
 	if (!DA_s)
 		bit++;
-	emu_set_CC(((__u32) val >> bit) & 1);
+	emu_set_CC(regs, ((__u32) val >> bit) & 1);
         return 0;
 }
 
 /* Test data class float */
-static int emu_tceb (int rx, long val) {
+static int emu_tceb (struct pt_regs *regs, int rx, long val) {
         FP_DECL_S(SA);
 	int bit;
 
@@ -1562,7 +1560,7 @@
 	}
 	if (!SA_s)
 		bit++;
-	emu_set_CC(((__u32) val >> bit) & 1);
+	emu_set_CC(regs, ((__u32) val >> bit) & 1);
         return 0;
 }
 
@@ -1666,8 +1664,9 @@
                 emu_store_regd(opcode[3] & 15);
                 emu_store_regd((opcode[3] & 15) + 2);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *,int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
                 emu_load_regd(opcode[3] & 15);
@@ -1677,8 +1676,9 @@
                 emu_store_regd((opcode[3] >> 4) & 15);
                 emu_store_regd(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(opcode[3] & 15);
 		break;
@@ -1686,8 +1686,9 @@
                 emu_store_rege((opcode[3] >> 4) & 15);
                 emu_store_rege(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_rege((opcode[3] >> 4) & 15);
                 emu_load_rege(opcode[3] & 15);
 		break;
@@ -1699,8 +1700,9 @@
                 emu_store_regd(opcode[3] & 15);
                 emu_store_regd((opcode[3] & 15) + 2);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
                 emu_load_regd(opcode[3] & 15);
@@ -1711,8 +1713,9 @@
                 emu_store_regd((opcode[3] >> 4) & 15);
                 emu_store_regd(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
                 emu_load_regd((opcode[2] >> 4) & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(opcode[3] & 15);
@@ -1722,8 +1725,9 @@
                 emu_store_rege((opcode[3] >> 4) & 15);
                 emu_store_rege(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
                 emu_load_rege((opcode[2] >> 4) & 15);
                 emu_load_rege((opcode[3] >> 4) & 15);
                 emu_load_rege(opcode[3] & 15);
@@ -1732,21 +1736,24 @@
                 /* call the emulation function */
                 if (opcode[3] & 0x20)
 			return SIGILL;
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
 		break;
         case 8: /* RRE format, cdfbr instruction */
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
 		break;
         case 9: /* RRE format, cefbr instruction */
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_rege((opcode[3] >> 4) & 15);
 		break;
         case 10: /* RRF format, cfxbr instruction */
@@ -1758,8 +1765,9 @@
                 emu_store_regd(opcode[3] & 15);
                 emu_store_regd((opcode[3] & 15) + 2);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
 		break;
         case 11: /* RRF format, cfdbr instruction */
                 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
@@ -1767,8 +1775,9 @@
 			return SIGILL;
                 emu_store_regd(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
 		break;
         case 12: /* RRF format, cfebr instruction */
                 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
@@ -1776,8 +1785,9 @@
 			return SIGILL;
                 emu_store_rege(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
 		break;
         case 13: /* RRE format, ldxbr & mdxbr instruction */
                 /* double store but long double load */
@@ -1786,8 +1796,9 @@
                 emu_store_regd((opcode[3] >> 4) & 15);
                 emu_store_regd(opcode[3]  & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
 		break;
@@ -1798,8 +1809,9 @@
                 emu_store_rege((opcode[3] >> 4) & 15);
                 emu_store_rege(opcode[3]  & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
 		break;
@@ -1808,8 +1820,9 @@
                 emu_store_rege((opcode[3] >> 4) & 15);
                 emu_store_rege(opcode[3]  & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
 		break;
         case 16: /* RRE format, ldxbr instruction */
@@ -1819,8 +1832,9 @@
                 emu_store_regd(opcode[3] & 15);
                 emu_store_regd((opcode[3] & 15) + 2);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_regd((opcode[3] >> 4) & 15);
                 break;
         case 17: /* RRE format, ldxbr instruction */
@@ -1830,22 +1844,25 @@
                 emu_store_regd(opcode[3] & 15);
                 emu_store_regd((opcode[3] & 15) + 2);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_rege((opcode[3] >> 4) & 15);
                 break;
         case 18: /* RRE format, ledbr instruction */
                 /* double store but float load */
                 emu_store_regd(opcode[3] & 15);
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 emu_load_rege((opcode[3] >> 4) & 15);
                 break;
         case 19: /* RRE format, efpc & sfpc instruction */
                 /* call the emulation function */
-                _fex = ((int (*)(int, int)) jump_table[opcode[1]])
-                        (opcode[3] >> 4, opcode[3] & 15);
+                _fex = ((int (*)(struct pt_regs *, int, int))
+			jump_table[opcode[1]])
+                        (regs, opcode[3] >> 4, opcode[3] & 15);
                 break;
         default: /* invalid operation */
                 return SIGILL;
@@ -1904,8 +1921,9 @@
                 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_copy_from_user(&temp, dxb, 8);
                 /* call the emulation function */
-                _fex = ((int (*)(int, double *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (double *) &temp);
+                _fex = ((int (*)(struct pt_regs *, int, double *))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (double *) &temp);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
@@ -1918,8 +1936,9 @@
                 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (float *) &temp);
+                _fex = ((int (*)(struct pt_regs *, int, float *))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (float *) &temp);
                 emu_load_rege((opcode[1] >> 4) & 15);
                 break;
         }
@@ -1933,8 +1952,9 @@
                 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_copy_from_user(&temp, dxb, 8);
                 /* call the emulation function */
-                _fex = ((int (*)(int, double *, int)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, double *, int))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
@@ -1948,8 +1968,9 @@
                 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                _fex = ((int (*)(int, float *, int)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
+                _fex = ((int (*)(struct pt_regs *, int, float *, int))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
                 emu_load_rege((opcode[4] >> 4) & 15);
                 break;
         }
@@ -1965,8 +1986,9 @@
                 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_copy_from_user(&temp, dxb, 8);
                 /* call the emulation function */
-                _fex = ((int (*)(int, double *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (double *) &temp);
+                _fex = ((int (*)(struct pt_regs *, int, double *))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (double *) &temp);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
                 break;
@@ -1981,8 +2003,9 @@
                 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (float *) &temp);
+                _fex = ((int (*)(struct pt_regs *, int, float *))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (float *) &temp);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 break;
         }
@@ -1998,8 +2021,9 @@
                 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 mathemu_get_user(temp, dxb);
                 /* call the emulation function */
-                _fex = ((int (*)(int, float *)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, (float *) &temp);
+                _fex = ((int (*)(struct pt_regs *, int, float *))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, (float *) &temp);
                 emu_load_regd((opcode[1] >> 4) & 15);
                 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
                 break;
@@ -2012,8 +2036,9 @@
                 opc = *((__u32 *) opcode);
                 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 /* call the emulation function */
-                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, dxb);
+                _fex = ((int (*)(struct pt_regs *, int, long))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, dxb);
                 break;
         }
         case 9: /* RXE format, RX address used as int value */ {
@@ -2024,8 +2049,9 @@
                 opc = *((__u32 *) opcode);
                 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 /* call the emulation function */
-                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, dxb);
+                _fex = ((int (*)(struct pt_regs *, int, long))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, dxb);
                 break;
         }
         case 10: /* RXE format, RX address used as int value */ {
@@ -2039,8 +2065,9 @@
                 opc = *((__u32 *) opcode);
                 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
                 /* call the emulation function */
-                _fex = ((int (*)(int, long)) jump_table[opcode[5]])
-                        (opcode[1] >> 4, dxb);
+                _fex = ((int (*)(struct pt_regs *, int, long))
+			jump_table[opcode[5]])
+                        (regs, opcode[1] >> 4, dxb);
                 break;
         }
         default: /* invalid operation */
diff -Nru a/arch/s390/mm/extable.c b/arch/s390/mm/extable.c
--- a/arch/s390/mm/extable.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/mm/extable.c	Sat Jun  8 22:31:36 2002
@@ -43,7 +43,6 @@
 search_exception_table(unsigned long addr)
 {
 	unsigned long ret = 0;
-	unsigned long flags;
 
 #ifndef CONFIG_MODULES
         addr &= 0x7fffffff;  /* remove amode bit from address */
@@ -52,6 +51,7 @@
 	if (ret) ret = FIX_PSW(ret);
 	return ret;
 #else
+	unsigned long flags;
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
         addr &= 0x7fffffff;  /* remove amode bit from address */
diff -Nru a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
--- a/arch/s390/mm/fault.c	Sat Jun  8 22:31:51 2002
+++ b/arch/s390/mm/fault.c	Sat Jun  8 22:31:51 2002
@@ -36,7 +36,6 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
-static void force_sigsegv(struct task_struct *tsk, int code, void *address);
 
 extern spinlock_t timerlist_lock;
 
@@ -66,25 +65,95 @@
 }
 
 /*
+ * Check which address space is addressed by the access
+ * register in S390_lowcore.exc_access_id.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static int __check_access_register(struct pt_regs *regs, int error_code)
+{
+	int areg = S390_lowcore.exc_access_id;
+
+	if (areg == 0)
+		/* Access via access register 0 -> kernel address */
+		return 0;
+	if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1)
+		/*
+		 * access register contains 0 -> kernel address,
+		 * access register contains 1 -> user space address
+		 */
+		return regs->acrs[areg];
+
+	/* Something unhealthy was done with the access registers... */
+	die("page fault via unknown access register", regs, error_code);
+	do_exit(SIGKILL);
+	return 0;
+}
+
+/*
+ * Check which address space the address belongs to.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static inline int check_user_space(struct pt_regs *regs, int error_code)
+{
+	/*
+	 * The lowest two bits of S390_lowcore.trans_exc_code indicate
+	 * which paging table was used:
+	 *   0: Primary Segment Table Descriptor
+	 *   1: STD determined via access register
+	 *   2: Secondary Segment Table Descriptor
+	 *   3: Home Segment Table Descriptor
+	 */
+	int descriptor = S390_lowcore.trans_exc_code & 3;
+	if (descriptor == 1)
+		return __check_access_register(regs, error_code);
+	return descriptor >> 1;
+}
+
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
+			  int si_code, unsigned long address)
+{
+	struct siginfo si;
+
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+#if defined(CONFIG_SYSCTL)
+	if (sysctl_userprocess_debug)
+#endif
+	{
+		printk("User process fault: interruption code 0x%lX\n",
+		       error_code);
+		printk("failing address: %lX\n", address);
+		show_regs(regs);
+	}
+#endif
+	si.si_signo = SIGSEGV;
+	si.si_code = si_code;
+	si.si_addr = (void *) address;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+/*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  *
  * error_code:
- *             ****0004       Protection           ->  Write-Protection  (suprression)
- *             ****0010       Segment translation  ->  Not present       (nullification)
- *             ****0011       Page translation     ->  Not present       (nullification)
+ *   04       Protection           ->  Write-Protection  (suprression)
+ *   10       Segment translation  ->  Not present       (nullification)
+ *   11       Page translation     ->  Not present       (nullification)
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
 {
         struct task_struct *tsk;
         struct mm_struct *mm;
         struct vm_area_struct * vma;
         unsigned long address;
+	int user_address;
         unsigned long fixup;
-        int write;
 	int si_code = SEGV_MAPERR;
-	int kernel_address = 0;
 
         tsk = current;
         mm = tsk->mm;
@@ -94,13 +163,13 @@
 	 * as a special case because the translation exception code 
 	 * field is not guaranteed to contain valid data in this case.
 	 */
-	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+	if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) {
 
 		/* Low-address protection hit in kernel mode means 
 		   NULL pointer write access in kernel mode.  */
  		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
 			address = 0;
-			kernel_address = 1;
+			user_address = 0;
 			goto no_context;
 		}
 
@@ -114,52 +183,15 @@
          * more specific the segment and page table portion of 
          * the address 
          */
-
         address = S390_lowcore.trans_exc_code&0x7ffff000;
-
-
-	/*
-	 * Check which address space the address belongs to
-	 */
-	switch (S390_lowcore.trans_exc_code & 3)
-	{
-	case 0: /* Primary Segment Table Descriptor */
-		kernel_address = 1;
-		goto no_context;
-
-	case 1: /* STD determined via access register */
-		if (S390_lowcore.exc_access_id == 0)
-		{
-			kernel_address = 1;
-			goto no_context;
-		}
-		if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
-		{
-			if (regs->acrs[S390_lowcore.exc_access_id] == 0)
-			{
-				kernel_address = 1;
-				goto no_context;
-			}
-			if (regs->acrs[S390_lowcore.exc_access_id] == 1)
-			{
-				/* user space address */
-				break;
-			}
-		}
-		die("page fault via unknown access register", regs, error_code);
-        	do_exit(SIGKILL);
-		break;
-
-	case 2: /* Secondary Segment Table Descriptor */
-	case 3: /* Home Segment Table Descriptor */
-		/* user space address */
-		break;
-	}
+	user_address = check_user_space(regs, error_code);
 
 	/*
-	 * Check whether we have a user MM in the first place.
+	 * Verify that the fault happened in user space, that
+	 * we are not in an interrupt and that there is a 
+	 * user context.
 	 */
-        if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT))
+        if (user_address == 0 || in_interrupt() || !mm)
                 goto no_context;
 
 	/*
@@ -167,7 +199,6 @@
 	 * task's user address space, so we can switch on the
 	 * interrupts again and then search the VMAs
 	 */
-
 	__sti();
 
         down_read(&mm->mmap_sem);
@@ -186,30 +217,23 @@
  * we can handle it..
  */
 good_area:
-        write = 0;
 	si_code = SEGV_ACCERR;
+	if (error_code != 4) {
+		/* page not present, check vm flags */
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+			goto bad_area;
+	} else {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	}
 
-        switch (error_code & 0xFF) {
-                case 0x04:                                /* write, present*/
-                        write = 1;
-                        break;
-                case 0x10:                                   /* not present*/
-                case 0x11:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-                                goto bad_area;
-                        break;
-                default:
-                       printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
-                       goto bad_area;
-        }
-
- survive:
+survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, write)) {
+	switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
 	case 1:
 		tsk->min_flt++;
 		break;
@@ -236,22 +260,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
-#ifndef CONFIG_SYSCTL
-#ifdef CONFIG_PROCESS_DEBUG
-                printk("User process fault: interruption code 0x%lX\n",error_code);
-                printk("failing address: %lX\n",address);
-		show_regs(regs);
-#endif
-#else
-		if (sysctl_userprocess_debug) {
-			printk("User process fault: interruption code 0x%lX\n",
-			       error_code);
-			printk("failing address: %lX\n", address);
-			show_regs(regs);
-		}
-#endif
-
-		force_sigsegv(tsk, si_code, (void *)address);
+		force_sigsegv(regs, error_code, si_code, address);
                 return;
 	}
 
@@ -266,8 +275,7 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
-
-        if (kernel_address)
+        if (user_address == 0)
                 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
         	       " at virtual kernel address %08lx\n", address);
         else
@@ -285,9 +293,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
 	printk("VM: killing process %s\n", tsk->comm);
@@ -311,17 +317,20 @@
 		goto no_context;
 }
 
-/*
- * Send SIGSEGV to task.  This is an external routine
- * to keep the stack usage of do_page_fault small.
- */
-static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
 {
-	struct siginfo si;
-	si.si_signo = SIGSEGV;
-	si.si_code = code;
-	si.si_addr = address;
-	force_sig_info(SIGSEGV, &si, tsk);
+	regs->psw.addr -= (error_code >> 16);
+	do_exception(regs, 4);
+}
+
+void do_segment_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x10);
+}
+
+void do_page_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x11);
 }
 
 typedef struct _pseudo_wait_t {
@@ -343,7 +352,6 @@
         pseudo_wait_t wait_struct;
         pseudo_wait_t *ptr, *last, *next;
         unsigned long address;
-        int kernel_address;
 
         /*
          * get the failing address
@@ -393,21 +401,7 @@
 			 * while we are running disabled. VM will then swap
 			 * in the page synchronously.
                          */
-			kernel_address = 0;
-                         switch (S390_lowcore.trans_exc_code & 3) {
-                         case 0: /* Primary Segment Table Descriptor */
-                                 kernel_address = 1;
-                                 break;
-                         case 1: /* STD determined via access register */
-                                 if (S390_lowcore.exc_access_id == 0 ||
-                                     regs->acrs[S390_lowcore.exc_access_id]==0)
-                                         kernel_address = 1;
-                                 break;
-                         case 2: /* Secondary Segment Table Descriptor */
-                         case 3: /* Home Segment Table Descriptor */
-                                 break;
-                         }
-                         if (kernel_address)
+                         if (check_user_space(regs, error_code) == 0)
                                  /* dereference a virtual kernel address */
                                  __asm__ __volatile__ (
                                          "  ic 0,0(%0)"
diff -Nru a/arch/s390/mm/init.c b/arch/s390/mm/init.c
--- a/arch/s390/mm/init.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/mm/init.c	Sat Jun  8 22:31:36 2002
@@ -36,34 +36,13 @@
 #include <asm/dma.h>
 #include <asm/lowcore.h>
 #include <asm/tlb.h>
+#include <asm/tlbflush.h>
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
-int do_check_pgt_cache(int low, int high)
-{
-        int freed = 0;
-        if(pgtable_cache_size > high) {
-                do {
-                        if(pgd_quicklist) {
-                                free_pgd_slow(get_pgd_fast());
-				freed += 2;
-			}
-                        if(pmd_quicklist) {
-                                pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-                        if(pte_quicklist) {
-                                pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed++;
-			}
-                } while(pgtable_cache_size > low);
-        }
-        return freed;
-}
-
 void show_mem(void)
 {
         int i, total = 0, reserved = 0;
@@ -86,7 +65,6 @@
         printk("%d reserved pages\n",reserved);
         printk("%d pages shared\n",shared);
         printk("%d pages swap cached\n",cached);
-        printk("%ld pages in page table cache\n",pgtable_cache_size);
 }
 
 /* References to section boundaries */
diff -Nru a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c
--- a/arch/s390/mm/ioremap.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390/mm/ioremap.c	Sat Jun  8 22:31:36 2002
@@ -16,6 +16,8 @@
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
         unsigned long phys_addr, unsigned long flags)
@@ -55,7 +57,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
diff -Nru a/arch/s390/vmlinux-shared.lds b/arch/s390/vmlinux-shared.lds
--- a/arch/s390/vmlinux-shared.lds	Sat Jun  8 22:31:52 2002
+++ b/arch/s390/vmlinux-shared.lds	Sat Jun  8 22:31:52 2002
@@ -14,6 +14,9 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x0700
+
+  _etext = .;			/* End of text section */
+
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
@@ -26,13 +29,9 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
-  __start___kallsyms = .;       /* All kernel symbols */
-  __kallsyms : { *(__kallsyms) }
-  __stop___kallsyms = .;
-
   . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
 
-  _etext = .;			/* End of text section */
+  _eshared = .;			/* End of shareable data */
 
   .data : {			/* Data */
 	*(.data)
@@ -48,9 +47,7 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-
+  . = ALIGN(256);
   __setup_start = .;
   .setup.init : { *(.setup.init) }
   __setup_end = .;
@@ -65,6 +62,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(256);
+  __per_cpu_start = .;
+  .date.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -Nru a/arch/s390/vmlinux.lds b/arch/s390/vmlinux.lds
--- a/arch/s390/vmlinux.lds	Sat Jun  8 22:31:37 2002
+++ b/arch/s390/vmlinux.lds	Sat Jun  8 22:31:37 2002
@@ -14,6 +14,9 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x0700
+
+  _etext = .;			/* End of text section */
+
   .rodata : { *(.rodata) *(.rodata.*) }
   .kstrtab : { *(.kstrtab) }
 
@@ -26,12 +29,6 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
-  __start___kallsyms = .;       /* All kernel symbols */
-  __kallsyms : { *(__kallsyms) }
-  __stop___kallsyms = .;
-
-  _etext = .;			/* End of text section */
-
   .data : {			/* Data */
 	*(.data)
 	CONSTRUCTORS
@@ -46,9 +43,7 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-
+  . = ALIGN(256);
   __setup_start = .;
   .setup.init : { *(.setup.init) }
   __setup_end = .;
@@ -63,6 +58,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(256);
+  __per_cpu_start = .;
+  .date.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
@@ -71,7 +70,6 @@
 
   . = ALIGN(4096);
   .data.page_aligned : { *(.data.idt) }
-
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -Nru a/arch/s390x/Config.help b/arch/s390x/Config.help
--- a/arch/s390x/Config.help	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/Config.help	Sat Jun  8 22:31:36 2002
@@ -154,7 +154,10 @@
   IPL device.
 
 CONFIG_IPL_TAPE
-  Select this option if you want to IPL the image from a Tape.
+  Select "tape" if you want to IPL the image from a Tape.
+
+  Select "vm_reader" if you are running under VM/ESA and want
+  to IPL the image from the emulated card reader.
 
 CONFIG_FAST_IRQ
   Select this option in order to get the interrupts processed faster
@@ -163,6 +166,18 @@
   interrupts which will also be processed before leaving the interrupt
   context.  This speeds up the I/O a lot. Say "Y".
 
+CONFIG_MACHCHK_WARNING
+  Select this option if you want the machine check handler on IBM S/390 or
+  zSeries to process warning machine checks (e.g. on power failures). 
+  If unsure, say "Y".
+
+CONFIG_CHSC
+  Select this option if you want the s390 common I/O layer to use information
+  obtained by channel subsystem calls. This will enable Linux to process link
+  failures and resource accessibility events. Moreover, if you have procfs
+  enabled, you'll be able to toggle chpids logically offline and online. Even
+  if you don't understand what this means, you should say "Y".
+
 CONFIG_S390_SUPPORT
   Select this option if you want to enable your system kernel to
   handle system-calls from ELF binaries for 31 bit ESA.  This option
@@ -174,3 +189,39 @@
   a debugging option; you probably do not want to set it unless you
   are an S390 port maintainer.
 
+CONFIG_PFAULT
+  Select this option, if you want to use PFAULT pseudo page fault
+  handling under VM. If running native or in LPAR, this option
+  has no effect. If your VM does not support PFAULT, PAGEEX
+  pseudo page fault handling will be used.
+  Note that VM 4.2 supports PFAULT but has a bug in its
+  implementation that causes some problems.
+  Everybody who wants to run Linux under VM != VM4.2 should select
+  this option.
+
+CONFIG_SHARED_KERNEL
+  Select this option, if you want to share the text segment of the
+  Linux kernel between different VM guests. This reduces memory
+  usage with lots of guests but greatly increases kernel size.
+  You should only select this option if you know what you are
+  doing and want to exploit this feature.
+
+CONFIG_QDIO
+  This driver provides the Queued Direct I/O base support for the
+  IBM S/390 (G5 and G6) and eServer zSeries (z800 and z900).
+
+  For details please refer to the documentation provided by IBM at
+  <http://www10.software.ibm.com/developerworks/opensource/linux390>
+
+  This driver is also available as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called qdio.o. If you want to compile it as a
+  module, say M here and read <file:Documentation/modules.txt>.
+
+  If unsure, say Y.
+
+Performance statistics for QDIO base support
+CONFIG_QDIO_PERF_STATS
+  Say Y here to get performance statistics in /proc/qdio_perf
+
+  If unsure, say N.
diff -Nru a/arch/s390x/Makefile b/arch/s390x/Makefile
--- a/arch/s390x/Makefile	Sat Jun  8 22:31:49 2002
+++ b/arch/s390x/Makefile	Sat Jun  8 22:31:49 2002
@@ -18,10 +18,11 @@
 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)
+  LINKSCRIPT := arch/s390x/vmlinux-shared.lds
 else
-LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux.lds $(LDFLAGS)
+  LINKSCRIPT := arch/s390x/vmlinux.lds
 endif
+LINKFLAGS =-T $(TOPDIR)/$(LINKSCRIPT) $(LDFLAGS)
 MODFLAGS += -fpic
 
 CFLAGS_PIPE := -pipe
@@ -30,8 +31,7 @@
 
 HEAD := arch/s390x/kernel/head.o arch/s390x/kernel/init_task.o
 
-SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
-           drivers/s390
+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 := $(DRIVERS) drivers/s390/built-in.o
 LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
@@ -43,11 +43,17 @@
 
 MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot
 
+vmlinux: $(LINKSCRIPT)
+
 image: vmlinux 
 	@$(MAKEBOOT) image
 
+install: vmlinux
+	@$(MAKEBOOT) BOOTIMAGE=image install
+
 archclean:
 	@$(MAKEBOOT) clean
+	$(MAKE) -C arch/$(ARCH)/kernel clean
 
 archmrproper:
 
diff -Nru a/arch/s390x/boot/Makefile b/arch/s390x/boot/Makefile
--- a/arch/s390x/boot/Makefile	Sat Jun  8 22:31:49 2002
+++ b/arch/s390x/boot/Makefile	Sat Jun  8 22:31:49 2002
@@ -1,27 +1,22 @@
 #
 # 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
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definition is now in the main makefile...
 
 OBJCOPY = $(CROSS_COMPILE)objcopy
 
 O_TARGET := 
 
-include $(TOPDIR)/Rules.make
-
 EXTRA_AFLAGS := -traditional
 
+include $(TOPDIR)/Rules.make
+
 %.lnk: %.o
 	$(LD) -Ttext 0x0 -o $@ $<
 
 %.boot: %.lnk
 	$(OBJCOPY) -O binary $< $@
 
-image: $(CONFIGURE) $(TOPDIR)/vmlinux \
+image: $(TOPDIR)/vmlinux \
 	iplfba.boot ipleckd.boot ipldump.boot
 	$(OBJCOPY) -O binary $(TOPDIR)/vmlinux image
 	$(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map
@@ -34,3 +29,5 @@
 clean:
 	rm -f image listing iplfba.boot ipleckd.boot ipldump.boot
 
+install: $(CONFIGURE) $(BOOTIMAGE)
+	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)"
diff -Nru a/arch/s390x/boot/install.sh b/arch/s390x/boot/install.sh
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/s390x/boot/install.sh	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# arch/s390x/boot/install.sh
+#
+# 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.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for s390 architecture
+#
+# Arguments:
+#   $1 - kernel version
+#   $2 - kernel image file
+#   $3 - kernel map file
+#   $4 - default install path (blank if root directory)
+#
+
+# User may have a custom install script
+
+if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi
+if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi
+
+# Default install - same as make zlilo
+
+if [ -f $4/vmlinuz ]; then
+	mv $4/vmlinuz $4/vmlinuz.old
+fi
+
+if [ -f $4/System.map ]; then
+	mv $4/System.map $4/System.old
+fi
+
+cat $2 > $4/vmlinuz
+cp $3 $4/System.map
diff -Nru a/arch/s390x/config.in b/arch/s390x/config.in
--- a/arch/s390x/config.in	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/config.in	Sat Jun  8 22:31:36 2002
@@ -6,8 +6,8 @@
 define_bool CONFIG_ISA n
 define_bool CONFIG_EISA n
 define_bool CONFIG_MCA n
-define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y
-define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n
+define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n
+define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y
 define_bool CONFIG_GENERIC_BUST_SPINLOCK n
 
 mainmenu_name "Linux Kernel Configuration"
@@ -15,6 +15,7 @@
 define_bool CONFIG_ARCH_S390X y
 
 source init/Config.in
+
 mainmenu_option next_comment
 comment 'Processor type and features'
 bool 'Symmetric multi-processing support' CONFIG_SMP
@@ -25,8 +26,16 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'General setup'
+comment 'Base setup'
 bool 'Fast IRQ handling' CONFIG_FAST_IRQ
+bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
+bool 'Use chscs for Common I/O' CONFIG_CHSC
+  
+tristate 'QDIO support' CONFIG_QDIO
+  if [ "$CONFIG_QDIO" != "n" ]; then
+    bool '   Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
+  fi
+
 bool 'Builtin IPL record support' CONFIG_IPL
 if [ "$CONFIG_IPL" = "y" ]; then
   choice 'IPL method generated into head.S' \
@@ -41,6 +50,15 @@
 bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
+mainmenu_option next_comment
+comment 'SCSI support'
+
+tristate 'SCSI support' CONFIG_SCSI
+
+if [ "$CONFIG_SCSI" != "n" ]; then
+   source drivers/scsi/Config.in
+fi
+endmenu
 
 source drivers/s390/Config.in
 
@@ -54,9 +72,9 @@
 comment 'Kernel hacking'
 
 #bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
-if [ "$CONFIG_CTC" = "y" ]; then
-  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
-fi
+#if [ "$CONFIG_CTC" = "y" ]; then
+#  bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
+#fi
 bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
 
diff -Nru a/arch/s390x/defconfig b/arch/s390x/defconfig
--- a/arch/s390x/defconfig	Sat Jun  8 22:31:35 2002
+++ b/arch/s390x/defconfig	Sat Jun  8 22:31:35 2002
@@ -4,9 +4,9 @@
 # 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_GENERIC_BUST_SPINLOCK=n
+# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+# CONFIG_GENERIC_BUST_SPINLOCK is not set
 CONFIG_ARCH_S390=y
 CONFIG_ARCH_S390X=y
 
@@ -16,11 +16,12 @@
 CONFIG_EXPERIMENTAL=y
 
 #
-# Processor type and features
+# General setup
 #
-CONFIG_SMP=y
-CONFIG_S390_SUPPORT=y
-CONFIG_BINFMT_ELF32=y
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
 
 #
 # Loadable module support
@@ -30,16 +31,23 @@
 CONFIG_KMOD=y
 
 #
-# General setup
+# Processor type and features
+#
+CONFIG_SMP=y
+CONFIG_S390_SUPPORT=y
+CONFIG_BINFMT_ELF32=y
+
+#
+# Base setup
 #
 CONFIG_FAST_IRQ=y
+CONFIG_MACHCHK_WARNING=y
+CONFIG_CHSC=y
+CONFIG_QDIO=m
+# CONFIG_QDIO_PERF_STATS is not set
 CONFIG_IPL=y
 # CONFIG_IPL_TAPE is not set
 CONFIG_IPL_VM=y
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
@@ -48,6 +56,77 @@
 # CONFIG_SHARED_KERNEL is not set
 
 #
+# SCSI support
+#
+CONFIG_SCSI=m
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+CONFIG_SD_EXTRA_DEVS=40
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=10
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_REPORT_LUNS is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_SCSI_7000FASST is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AHA1542 is not set
+# CONFIG_SCSI_AHA1740 is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_AM53C974 is not set
+# CONFIG_SCSI_MEGARAID is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_EATA_DMA is not set
+# CONFIG_SCSI_EATA_PIO is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_PPA is not set
+# CONFIG_SCSI_IMM is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_NCR53C7xx is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PCI2000 is not set
+# CONFIG_SCSI_PCI2220I is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SIM710 is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_SCSI_PCMCIA is not set
+
+#
 # Block device drivers
 #
 CONFIG_BLK_DEV_LOOP=y
@@ -103,8 +182,8 @@
 #
 # S/390 tape hardware support
 #
-CONFIG_S390_TAPE_3490=y
-CONFIG_S390_TAPE_3480=y
+CONFIG_S390_TAPE_3490=m
+CONFIG_S390_TAPE_3480=m
 
 #
 # Network device drivers
@@ -123,6 +202,7 @@
 #
 CONFIG_CHANDEV=y
 CONFIG_HOTPLUG=y
+CONFIG_LCS=m
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -131,8 +211,6 @@
 #
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK=y
-# CONFIG_RTNETLINK is not set
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
@@ -144,18 +222,24 @@
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
 CONFIG_IPV6=m
-# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
 
 #
 #  
 #
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
+
+#
+# Appletalk devices
+#
+# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -164,7 +248,7 @@
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
-# CONFIG_NET_FASTROUTE is not set
+CONFIG_NET_FASTROUTE=y
 # CONFIG_NET_HW_FLOWCONTROL is not set
 
 #
@@ -176,18 +260,20 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_QFMT_V1 is not set
+# CONFIG_QFMT_V2 is not set
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
 # CONFIG_REISERFS_FS is not set
 # CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
 # CONFIG_ADFS_FS is not set
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
 # CONFIG_BFS_FS is not set
-# CONFIG_CMS_FS is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
+CONFIG_EXT3_FS=y
+CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
@@ -198,12 +284,15 @@
 # CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
-# CONFIG_RAMFS is not set
+CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
-# CONFIG_FREEVXFS_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_DEBUG is not set
 # CONFIG_HPFS_FS is not set
@@ -232,8 +321,10 @@
 # CONFIG_ROOT_NFS is not set
 # CONFIG_NFSD is not set
 # CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
 # CONFIG_NCPFS_PACKET_SIGNING is not set
@@ -245,7 +336,6 @@
 # CONFIG_NCPFS_NLS is not set
 # CONFIG_NCPFS_EXTRAS is not set
 # CONFIG_ZISOFS_FS is not set
-# CONFIG_ZLIB_FS_INFLATE is not set
 
 #
 # Partition Types
@@ -262,6 +352,7 @@
 # CONFIG_SGI_PARTITION is not set
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
 # CONFIG_SMB_NLS is not set
 # CONFIG_NLS is not set
 
@@ -269,3 +360,10 @@
 # Kernel hacking
 #
 CONFIG_MAGIC_SYSRQ=y
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
+# CONFIG_ZLIB_INFLATE is not set
+# CONFIG_ZLIB_DEFLATE is not set
diff -Nru a/arch/s390x/kernel/Makefile b/arch/s390x/kernel/Makefile
--- a/arch/s390x/kernel/Makefile	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/Makefile	Sat Jun  8 22:31:37 2002
@@ -2,8 +2,10 @@
 # Makefile for the linux kernel.
 #
 
-O_TARGET	:= kernel.o
 EXTRA_TARGETS	:= head.o init_task.o
+EXTRA_AFLAGS	:= -traditional
+
+O_TARGET	:= kernel.o
 
 export-objs	:= debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o \
 		   exec32.o
@@ -20,15 +22,38 @@
 #
 obj-$(CONFIG_REMOTE_DEBUG)	+= gdb-stub.o #gdb-low.o 
 
-obj-$(CONFIG_S390_SUPPORT)	+= linux32.o signal32.o ioctl32.o wrapper32.o exec32.o
+obj-$(CONFIG_S390_SUPPORT)	+= linux32.o signal32.o ioctl32.o wrapper32.o \
+					 exec32.o exec_domain32.o
 obj-$(CONFIG_BINFMT_ELF32)	+= binfmt_elf32.o
 
-EXTRA_AFLAGS := -traditional
-
 include $(TOPDIR)/Rules.make
 
 #
 # This is just to get the dependencies...
 #
 binfmt_elf32.o:	$(TOPDIR)/fs/binfmt_elf.c
+
+.PHONY: asm-offsets.h
+
+entry.S: asm-offsets.h
+
+#
+# Automatic offset generation for assembler files.
+#
+asm-offsets.h: asm-offsets.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -S $< -o - | grep -- "->" | \
+	(echo "#ifndef __ASM_OFFSETS_H__"; \
+	 echo "#define __ASM_OFFSETS_H__"; \
+	 echo "/*"; \
+	 echo " * DO NOT MODIFY"; \
+	 echo " *"; \
+	 echo " * This file was generated by arch/s390/kernel/Makefile"; \
+	 echo " */"; \
+	 sed -e "s:^->\([^ ]*\) \([^ ]*\) \(.*\):#define \\1 \\2 /* \\3*/:" \
+	     -e "s:->::"; \
+	 echo "#endif" \
+	) > asm-offsets.h
+
+clean:
+	rm -f asm-offsets.h
 
diff -Nru a/arch/s390x/kernel/asm-offsets.c b/arch/s390x/kernel/asm-offsets.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/s390x/kernel/asm-offsets.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,31 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+
+/* Use marker if you need to separate the values later */
+
+#define DEFINE(sym, val, marker) \
+	asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+	DEFINE(__THREAD_info, offsetof(struct task_struct, thread_info),);
+	DEFINE(__THREAD_ar2, offsetof(struct task_struct, thread.ar2),);
+	DEFINE(__THREAD_ar4, offsetof(struct task_struct, thread.ar4),);
+	DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
+	DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+	BLANK();
+	DEFINE(__TI_task, offsetof(struct thread_info, task),);
+	DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
+	DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
+	DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
+	DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
+	return 0;
+}
diff -Nru a/arch/s390x/kernel/binfmt_elf32.c b/arch/s390x/kernel/binfmt_elf32.c
--- a/arch/s390x/kernel/binfmt_elf32.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/binfmt_elf32.c	Sat Jun  8 22:31:37 2002
@@ -87,7 +87,13 @@
 #define ELF_PLATFORM (NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {							\
+	if (ibcs2)                                      \
+		set_personality(PER_SVR4);              \
+	else if (current->personality != PER_LINUX32)   \
+		set_personality(PER_LINUX);             \
+} while (0)
 #endif 
 
 #include "linux32.h"
@@ -108,6 +114,7 @@
 #include <linux/module.h>
 #include <linux/config.h>
 #include <linux/elfcore.h>
+#include <linux/binfmts.h>
 
 int setup_arg_pages32(struct linux_binprm *bprm);
 
diff -Nru a/arch/s390x/kernel/bitmap.S b/arch/s390x/kernel/bitmap.S
--- a/arch/s390x/kernel/bitmap.S	Sat Jun  8 22:31:51 2002
+++ b/arch/s390x/kernel/bitmap.S	Sat Jun  8 22:31:51 2002
@@ -35,3 +35,22 @@
          .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4
          .byte  0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
 
+         .globl _sb_findmap
+_sb_findmap:
+         .byte  8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+         .byte  4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0
+
diff -Nru a/arch/s390x/kernel/debug.c b/arch/s390x/kernel/debug.c
--- a/arch/s390x/kernel/debug.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/debug.c	Sat Jun  8 22:31:36 2002
@@ -68,12 +68,6 @@
 			   size_t user_len, loff_t * offset);
 static int debug_open(struct inode *inode, struct file *file);
 static int debug_close(struct inode *inode, struct file *file);
-static struct proc_dir_entry 
-*debug_create_proc_dir_entry(struct proc_dir_entry *root,
-			     const char *name, mode_t mode,
-			     struct file_operations *fops);
-static void debug_delete_proc_dir_entry(struct proc_dir_entry *root,
-					struct proc_dir_entry *entry);
 static debug_info_t*  debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
 static void debug_info_get(debug_info_t *);
 static void debug_info_put(debug_info_t *);
@@ -150,11 +144,7 @@
 
 static debug_info_t *debug_area_first = NULL;
 static debug_info_t *debug_area_last = NULL;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
-static struct semaphore debug_lock = MUTEX;
-#else
 DECLARE_MUTEX(debug_lock);
-#endif
 
 static int initialized = 0;
 
@@ -220,8 +210,10 @@
 	strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1)));
 	rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0;
 	memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
+#ifdef CONFIG_PROC_FS
 	memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
 		sizeof(struct proc_dir_entry*));
+#endif /* CONFIG_PROC_FS */
 	atomic_set(&(rc->ref_count), 0);
 
 	return rc;
@@ -268,16 +260,14 @@
 
 
 	/* create proc rood directory */
-
         rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry);
-	/* append new element to linked list */
 
-        if(debug_area_first == NULL){
+	/* append new element to linked list */
+        if (debug_area_first == NULL) {
                 /* first element in list */
                 debug_area_first = rc;
                 rc->prev = NULL;
-        }
-        else{
+        } else {
                 /* append element to end of list */
                 debug_area_last->next = rc;
                 rc->prev = debug_area_last;
@@ -334,16 +324,22 @@
 	if (!db_info)
 		return;
 	if (atomic_dec_and_test(&db_info->ref_count)) {
+#ifdef DEBUG
 		printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
 		       db_info, db_info->name);
+#endif
 		for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
-			if (db_info->views[i] != NULL)
-				debug_delete_proc_dir_entry
-				    (db_info->proc_root_entry,
-				     db_info->proc_entries[i]);
+			if (db_info->views[i] == NULL)
+				continue;
+#ifdef CONFIG_PROC_FS
+			remove_proc_entry(db_info->proc_entries[i]->name,
+					  db_info->proc_root_entry);
+#endif
 		}
-		debug_delete_proc_dir_entry(debug_proc_root_entry,
-					    db_info->proc_root_entry);
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry(db_info->proc_root_entry->name,
+				  debug_proc_root_entry);
+#endif
 		if(db_info == debug_area_first)
 			debug_area_first = db_info->next;
 		if(db_info == debug_area_last)
@@ -528,14 +524,18 @@
 	debug_info_snapshot = debug_info_copy(debug_info);
 
 	if(!debug_info_snapshot){
+#ifdef DEBUG
 		printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
+#endif
 		rc = -ENOMEM;
 		goto out;
 	}
 
 	if ((file->private_data =
 	     kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
+#ifdef DEBUG
 		printk(KERN_ERR "debug_open: kmalloc failed\n");
+#endif
 		debug_info_free(debug_info_snapshot);	
 		rc = -ENOMEM;
 		goto out;
@@ -579,32 +579,6 @@
 }
 
 /*
- * debug_create_proc_dir_entry:
- * - initializes proc-dir-entry and registers it
- */
-
-static struct proc_dir_entry *debug_create_proc_dir_entry
-    (struct proc_dir_entry *root, const char *name, mode_t mode,
-     struct file_operations *fops) 
-{
-	struct proc_dir_entry *rc = create_proc_entry(name, mode, root);
-	if (rc && fops)
-		rc->proc_fops = fops;
-	return rc;
-}
-
-
-/*
- * delete_proc_dir_entry:
- */
-
-static void debug_delete_proc_dir_entry
-    (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) 
-{
-	remove_proc_entry(proc_entry->name, root);
-}
-
-/*
  * debug_register:
  * - creates and initializes debug area for the caller
  * - returns handle for debug area
@@ -627,9 +601,11 @@
 		goto out;
 	debug_register_view(rc, &debug_level_view);
         debug_register_view(rc, &debug_flush_view);
+#ifdef DEBUG
 	printk(KERN_INFO
 	       "debug: reserved %d areas of %d pages for debugging %s\n",
 	       nr_areas, 1 << page_order, rc->name);
+#endif
       out:
         if (rc == NULL){
 		printk(KERN_ERR "debug: debug_register failed for %s\n",name);
@@ -649,7 +625,9 @@
 	if (!id)
 		goto out;
 	down(&debug_lock);
+#ifdef DEBUG
 	printk(KERN_INFO "debug: unregistering %s\n", id->name);
+#endif
 	debug_info_put(id);
 	up(&debug_lock);
 
@@ -856,7 +834,9 @@
 
 	down(&debug_lock);
 	if (!initialized) {
+#ifdef CONFIG_PROC_FS
 		debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
+#endif /* CONFIG_PROC_FS */
 		printk(KERN_INFO "debug: Initialization complete\n");
 		initialized = 1;
 	}
@@ -896,10 +876,10 @@
 			mode |= S_IRUSR;
 		if (view->input_proc)
 			mode |= S_IWUSR;
-		id->proc_entries[i] =
-		    debug_create_proc_dir_entry(id->proc_root_entry,
-						view->name, mode,
-						&debug_file_ops);
+		id->proc_entries[i] = create_proc_entry(view->name, mode,
+							id->proc_root_entry);
+		if (id->proc_entries[i] != NULL)
+			id->proc_entries[i]->proc_fops = &debug_file_ops;
 		rc = 0;
 	}
 	spin_unlock_irqrestore(&id->lock, flags);
@@ -927,8 +907,10 @@
 	if (i == DEBUG_MAX_VIEWS)
 		rc = -1;
 	else {
-		debug_delete_proc_dir_entry(id->proc_root_entry,
-					    id->proc_entries[i]);		
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry(id->proc_entries[i]->name,
+				  id->proc_root_entry);
+#endif
 		id->views[i] = NULL;
 		rc = 0;
 	}
@@ -1216,7 +1198,9 @@
 #ifdef DEBUG
 	printk("debug_cleanup_module: \n");
 #endif
-	debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry);
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry(debug_proc_root_entry->name, NULL);
+#endif /* CONFIG_PROC_FS */
 	return;
 }
 
diff -Nru a/arch/s390x/kernel/entry.S b/arch/s390x/kernel/entry.S
--- a/arch/s390x/kernel/entry.S	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/entry.S	Sat Jun  8 22:31:36 2002
@@ -17,7 +17,9 @@
 #include <asm/errno.h>
 #include <asm/smp.h>
 #include <asm/ptrace.h>
+#include <asm/thread_info.h>
 
+#include "asm-offsets.h"
 
 /*
  * Stack layout for the system_call stack entry.
@@ -45,41 +47,9 @@
 SP_ORIG_R2   =  STACK_FRAME_OVERHEAD + PT_ORIGGPR2
 /* Now the additional entries */
 SP_TRAP      =  (SP_ORIG_R2+GPR_SIZE)
-#if CONFIG_REMOTE_DEBUG
-SP_CRREGS    =  (SP_TRAP+4)
-/* fpu registers are saved & restored by the gdb stub itself */
-SP_FPC       =  (SP_CRREGS+(NUM_CRS*CR_SIZE))
-SP_FPRS      =  (SP_FPC+FPC_SIZE+FPC_PAD_SIZE)
-SP_PGM_OLD_ILC= (SP_FPRS+(NUM_FPRS*FPR_SIZE))
-#else
-SP_PGM_OLD_ILC= (SP_TRAP+4)
-#endif
-SP_SIZE      =  (SP_PGM_OLD_ILC+4)
-/*
- * these defines are offsets into the thread_struct
- */
-_TSS_PTREGS  = 0
-_TSS_FPRS    = (_TSS_PTREGS+8)
-_TSS_AR2     = (_TSS_FPRS+136)
-_TSS_AR4     = (_TSS_AR2+4)
-_TSS_KSP     = (_TSS_AR4+4)
-_TSS_USERSEG = (_TSS_KSP+8)
-_TSS_PROT    = (_TSS_USERSEG+8)
-_TSS_ERROR   = (_TSS_PROT+8)
-_TSS_TRAP    = (_TSS_ERROR+4)
-_TSS_PER     = (_TSS_TRAP+4)
-_TSS_IEEE    = (_TSS_PER+72)
-_TSS_FLAGS   = (_TSS_IEEE+8)
-
-/*
- * these are offsets into the task-struct.
- */
-state        =  0
-flags        =  8
-#error sigpending   = 16
-#error need_resched = 32
-#error tsk_ptrace   = 40
-processor    = 92
+SP_SIZE      =  (SP_TRAP+4)
+
+_TIF_WORK_MASK = (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED)
 
 /*
  * Register usage in interrupt handlers:
@@ -128,7 +98,7 @@
         lpswe   __LC_RETURN_PSW          # back to caller
         .endm
 
-        .macro  GET_CURRENT
+        .macro  GET_THREAD_INFO
 	lg	%r9,__LC_KERNEL_STACK    # load pointer to task_struct to %r9
 	aghi	%r9,-16384
         .endm
@@ -136,37 +106,32 @@
 
 /*
  * Scheduler resume function, called by switch_to
- *  grp2 = (thread_struct *) prev->tss
- *  grp3 = (thread_struct *) next->tss
+ *  gpr2 = (task_struct *) prev
+ *  gpr3 = (task_struct *) next
  * Returns:
  *  gpr2 = prev
  */
         .globl  resume
 resume:
-        lg      %r4,_TSS_PTREGS(%r3)
-        tm      SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ?
-        jz      resume_noper            # if not we're fine
+	tm	__THREAD_per+4(%r3),0xe8 # is the new process using per ?
+	jz	resume_noper		# if not we're fine
         stctg   %c9,%c11,48(%r15)       # We are using per stuff
-        clc     _TSS_PER(24,%r3),48(%r15)
+        clc     __THREAD_per(24,%r3),48(%r15)
         je      resume_noper            # we got away without bashing TLB's
-        lctlg   %c9,%c11,_TSS_PER(%r3)  # Nope we didn't
+        lctlg   %c9,%c11,__THREAD_per(%r3)	# Nope we didn't
 resume_noper:
         stmg    %r6,%r15,48(%r15)       # store resume registers of prev task
-        stg     %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp
-        lghi    %r0,-16384
-        ngr     %r0,%r15
-        lg      %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp
-        lghi    %r1,16383
-        ogr     %r1,%r15
-        aghi    %r1,1
-        stg     %r1,__LC_KERNEL_STACK   # __LC_KERNEL_STACK = new kernel stack
-        stam    %a2,%a2,_TSS_AR2(%r2)   # store kernel access reg. 2
-        stam    %a4,%a4,_TSS_AR4(%r2)   # store kernel access reg. 4
-        lam     %a2,%a2,_TSS_AR2(%r3)   # load kernel access reg. 2
-        lam     %a4,%a4,_TSS_AR4(%r3)   # load kernel access reg. 4
-        lgr     %r2,%r0                 # return task_struct of last task
+	stg	%r15,__THREAD_ksp(%r2)	# store kernel stack to prev->tss.ksp
+	lg	%r15,__THREAD_ksp(%r3)	# load kernel stack from next->tss.ksp
+        stam    %a2,%a2,__THREAD_ar2(%r2)	# store kernel access reg. 2
+        stam    %a4,%a4,__THREAD_ar4(%r2)	# store kernel access reg. 4
+        lam     %a2,%a2,__THREAD_ar2(%r3)	# load kernel access reg. 2
+        lam     %a4,%a4,__THREAD_ar4(%r3)	# load kernel access reg. 4
         lmg     %r6,%r15,48(%r15)       # load resume registers of next task
-        br      %r14
+	lg	%r3,__THREAD_info(%r3)  # load thread_info from task struct
+	aghi	%r3,16384
+	stg	%r3,__LC_KERNEL_STACK	# __LC_KERNEL_STACK = new kernel stack
+	br	%r14
 
 /*
  * do_softirq calling function. We want to run the softirq functions on the
@@ -195,96 +160,94 @@
 	.globl  system_call
 system_call:
         SAVE_ALL __LC_SVC_OLD_PSW,1
-	mvi     SP_PGM_OLD_ILC(%r15),1  # mark PGM_OLD_ILC as invalid
-pgm_system_call:
-        GET_CURRENT               # load pointer to task_struct to R9
-	larl    %r7,sys_call_table
-	llgc    %r8,__LC_SVC_INT_CODE+1 # get svc number from lowcore
+	llgh    %r8,__LC_SVC_INT_CODE # get svc number from lowcore
+        GET_THREAD_INFO           # load pointer to task_struct to R9
 	stosm   48(%r15),0x03     # reenable interrupts
+	larl    %r7,sys_call_table
         sll     %r8,3
         tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
         jo      sysc_noemu
-	la      %r8,4(%r8)        # use 31 bit emulation system calls
+	la      %r7,4(%r7)        # use 31 bit emulation system calls
 sysc_noemu:
         lgf     %r8,0(%r8,%r7)    # load address of system call routine
-        tm      tsk_ptrace+7(%r9),0x02 # PT_TRACESYS
-        jnz     sysc_tracesys
+	tm	__TI_flags+7(%r9),_TIF_SYSCALL_TRACE
+        jo      sysc_tracesys
         basr    %r14,%r8          # call sys_xxxx
         stg     %r2,SP_R2(%r15)   # store return value (change R2 on stack)
                                   # ATTENTION: check sys_execve_glue before
                                   # changing anything here !!
 
 sysc_return:
-        tm      SP_PSW+1(%r15),0x01 # returning to user ?
-        jno     sysc_leave        # no-> skip bottom half, resched & signal
-#
-# check, if reschedule is needed
-#
-#error	lg      %r0,need_resched(%r9) # get need_resched from task_struct
-	ltgr    %r0,%r0
-        jnz     sysc_reschedule
-#error        icm     %r0,15,sigpending(%r9)     # get sigpending from task_struct
-        jnz     sysc_signal_return
+	stnsm   48(%r15),0xfc     # disable I/O and ext. interrupts
+	tm	__TI_flags+7(%r9),_TIF_WORK_MASK
+	jnz	sysc_work         # there is work to do (signals etc.)
 sysc_leave:
-        tm      SP_PGM_OLD_ILC(%r15),0xff
-        jz      pgm_svcret
-	stnsm   48(%r15),0xfc         # disable I/O and ext. interrupts
         RESTORE_ALL 1
 
 #
+# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
+# _TIF_NEED_RESCHED is on. Find out which one.
+#
+sysc_work:
+        tm      SP_PSW+1(%r15),0x01 # returning to user ?
+        jno     sysc_leave        # no-> skip resched & signal
+	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
+	jo	sysc_reschedule
+	# add a test for TIF_NOTIFY_RESUME here when it is used.
+	# _TIF_SIGPENDING is the only flag left
+
+#
 # call do_signal before return
 #
 sysc_signal_return:     
         la      %r2,SP_PTREGS(%r15) # load pt_regs
         sgr     %r3,%r3             # clear *oldset
-	larl    %r14,sysc_leave
-	jg      do_signal           # return point is sysc_leave
+	larl    %r14,sysc_return
+	jg      do_signal           # return point is sysc_return
 
 #
-# call trace before and after sys_call
+# call schedule with sysc_return as return-address
+#
+sysc_reschedule:        
+	larl    %r14,sysc_return
+        jg      schedule            # return point is sysc_return
+
+#
+# call syscall_trace before and after system call
+# special linkage: %r12 contains the return address for trace_svc
 #
 sysc_tracesys:
-	lghi    %r2,-ENOSYS
-	stg     %r2,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
-#error        brasl   %r14,syscall_trace
+	lghi    %r0,-ENOSYS
+	stg     %r0,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+        brasl   %r14,syscall_trace
+	larl	%r6,.Lc256
+	clc	SP_R2(8,%r15),0(%r6)
+	jnl	sysc_tracego
 	lg      %r2,SP_R2(%r15)
-	cghi    %r2,-ENOSYS
-	je      sysc_tracesys_dn1   
-	sllg    %r2,%r2,56          # strace wants to change the syscall
-	srlg    %r2,%r2,53          # zap unused bits & multiply by 8
-	tm      SP_PSW+3(%r15),0x01 # are we running in 31 bit mode ?
-        jo      sysc_tracesys_noemu
-	la      %r2,4(%r2)          # use 31 bit emulation system calls
-sysc_tracesys_noemu:
-	lgf	%r8,0(%r2,%r7)      # load address of system call routine
-sysc_tracesys_dn1:	
+	sllg    %r2,%r2,3           # strace wants to change the syscall
+	lgf	%r8,0(%r2,%r7)
+sysc_tracego:
 	lmg     %r3,%r6,SP_R3(%r15)
 	lg      %r2,SP_ORIG_R2(%r15)
         basr    %r14,%r8            # call sys_xxx
         stg     %r2,SP_R2(%r15)     # store return value
-	larl    %r14,sysc_return
-#error        jg      syscall_trace       # return point is sysc_return
-
-#
-# call schedule with sysc_return as return-address
-#
-sysc_reschedule:        
-	larl    %r14,sysc_return
-        jg      schedule            # return point is sysc_return
+	tm	__TI_flags+7(%r9),_TIF_SYSCALL_TRACE
+        jno     sysc_return
+	larl	%r14,sysc_return    # return point is sysc_return
+	jg	syscall_trace
 
 #
 # a new process exits the kernel with ret_from_fork
 #
         .globl  ret_from_fork
 ret_from_fork:  
-        GET_CURRENT               # load pointer to task_struct to R9
-        stosm   48(%r15),0x03     # reenable interrupts
+        GET_THREAD_INFO           # load pointer to task_struct to R9
 	xc      SP_R2(8,%r15),SP_R2(%r15) # child returns 0
-#if CONFIG_SMP || CONFIG_PREEMPT
+#ifdef CONFIG_SMP
 	larl    %r14,sysc_return
         jg      schedule_tail     # return to sysc_return
 #else
-        j       sysc_return
+	j	sysc_return
 #endif
 
 #
@@ -433,7 +396,7 @@
         .long  SYSCALL(sys_oldumount,sys32_oldumount_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys32_setuid16_wrapper)   /* old setuid16 syscall*/
         .long  SYSCALL(sys_ni_syscall,sys32_getuid16)   /* old getuid16 syscall*/
-        .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 25 old stime syscall */
+        .long  SYSCALL(sys_ni_syscall,sys32_stime_wrapper) /* 25 old stime syscall */
         .long  SYSCALL(sys_ptrace,sys32_ptrace_wrapper)
         .long  SYSCALL(sys_alarm,sys32_alarm_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* old fstat syscall */
@@ -530,7 +493,7 @@
         .long  SYSCALL(sys_sigreturn_glue,sys32_sigreturn_glue)
         .long  SYSCALL(sys_clone_glue,sys_clone_glue) /* 120 */
         .long  SYSCALL(sys_setdomainname,sys32_setdomainname_wrapper)
-        .long  SYSCALL(sys_newuname,sys32_newuname_wrapper)
+        .long  SYSCALL(s390x_newuname,sys32_newuname_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* modify_ldt for i386 */
         .long  SYSCALL(sys_adjtimex,sys32_adjtimex_wrapper)
         .long  SYSCALL(sys_mprotect,sys32_mprotect_wrapper) /* 125 */
@@ -544,7 +507,7 @@
         .long  SYSCALL(sys_fchdir,sys32_fchdir_wrapper)
         .long  SYSCALL(sys_bdflush,sys32_bdflush_wrapper)
         .long  SYSCALL(sys_sysfs,sys32_sysfs_wrapper)           /* 135 */
-        .long  SYSCALL(sys_personality,sys32_personality_wrapper)
+        .long  SYSCALL(s390x_personality,sys32_personality_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* for afs_syscall */
         .long  SYSCALL(sys_ni_syscall,sys32_setfsuid16_wrapper) /* old setfsuid16 syscall */
         .long  SYSCALL(sys_ni_syscall,sys32_setfsgid16_wrapper) /* old setfsgid16 syscall */
@@ -557,7 +520,7 @@
         .long  SYSCALL(sys_writev,sys32_writev_wrapper)
         .long  SYSCALL(sys_getsid,sys32_getsid_wrapper)
         .long  SYSCALL(sys_fdatasync,sys32_fdatasync_wrapper)
-        .long  SYSCALL(sys_sysctl,sys_ni_syscall)
+        .long  SYSCALL(sys_sysctl,sys32_sysctl_wrapper)
         .long  SYSCALL(sys_mlock,sys32_mlock_wrapper)           /* 150 */
         .long  SYSCALL(sys_munlock,sys32_munlock_wrapper)
         .long  SYSCALL(sys_mlockall,sys32_mlockall_wrapper)
@@ -599,7 +562,7 @@
         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* streams1 */
         .long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* streams2 */
         .long  SYSCALL(sys_vfork_glue,sys_vfork_glue) /* 190 */
-        .long  SYSCALL(sys_getrlimit,sys32_old_getrlimit_wrapper)
+        .long  SYSCALL(sys_getrlimit,sys32_getrlimit_wrapper)
 	.long  SYSCALL(sys_mmap2,sys32_mmap2_wrapper)
 	.long  SYSCALL(sys_ni_syscall,sys32_truncate64_wrapper)
         .long  SYSCALL(sys_ni_syscall,sys32_ftruncate64_wrapper)
@@ -630,13 +593,27 @@
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
 	.long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
 	.long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 222 - reserved for posix_acl */
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 223 - reserved for posix_acl */
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for posix_acl */
-        .rept  255-224
-	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
+	.long  SYSCALL(sys_readahead,sys32_readahead)
+	.long  SYSCALL(sys_ni_syscall,sys32_sendfile64)
+	.long  SYSCALL(sys_setxattr,sys32_setxattr_wrapper)
+	.long  SYSCALL(sys_lsetxattr,sys32_lsetxattr_wrapper)	/* 225 */
+	.long  SYSCALL(sys_fsetxattr,sys32_fsetxattr_wrapper)
+	.long  SYSCALL(sys_getxattr,sys32_getxattr_wrapper)
+	.long  SYSCALL(sys_lgetxattr,sys32_lgetxattr_wrapper)
+	.long  SYSCALL(sys_fgetxattr,sys32_fgetxattr_wrapper)
+	.long  SYSCALL(sys_listxattr,sys32_listxattr_wrapper)	/* 230 */
+	.long  SYSCALL(sys_llistxattr,sys32_llistxattr_wrapper)
+	.long  SYSCALL(sys_flistxattr,sys32_flistxattr_wrapper)
+	.long  SYSCALL(sys_removexattr,sys32_removexattr_wrapper)
+	.long  SYSCALL(sys_lremovexattr,sys32_lremovexattr_wrapper)
+	.long  SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper)
 	.long  SYSCALL(sys_gettid,sys_gettid)
 	.long  SYSCALL(sys_tkill,sys_tkill)
+	.long  SYSCALL(sys_futex,sys32_futex_wrapper)
+	.long  SYSCALL(sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
+	.long  SYSCALL(sys_sched_getaffinity,sys32_sched_getaffinity_wrapper)
+        .rept  255-240
+	.long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
 	.endr
 
 /*
@@ -659,51 +636,106 @@
  * for LPSW?).
  */
         tm      __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
-        jz      pgm_sv                   # skip if not
+        jnz     pgm_per                  # got per exception -> special case
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+	llgh    %r8,__LC_PGM_INT_CODE
+        sll     %r8,3
+	GET_THREAD_INFO
+        larl    %r1,pgm_check_table
+        lg      %r1,0(%r8,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+	larl	%r14,sysc_return
+        br      %r1			 # branch to interrupt-handler
+
+#
+# handle per exception
+#
+pgm_per:
         tm      __LC_PGM_OLD_PSW,0x40    # test if per event recording is on
-        jnz     pgm_sv                   # skip if it is
+        jnz     pgm_per_std              # ok, normal per event from user space
 # ok its one of the special cases, now we need to find out which one
         clc     __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
         je      pgm_svcper
 # no interesting special case, ignore PER event
 	lpswe   __LC_PGM_OLD_PSW
+
+#
+# Normal per exception
+#
+pgm_per_std:
+	SAVE_ALL __LC_PGM_OLD_PSW,1
+	GET_THREAD_INFO
+	lghi    %r4,0x7f
+	lgf     %r3,__LC_PGM_ILC	 # load program interruption code
+        nr      %r4,%r3			 # clear per-event-bit and ilc
+        je      pgm_per_only		 # only per of per+check ?
+        sll     %r4,3
+        larl    %r1,pgm_check_table
+        lg      %r1,0(%r4,%r1)		 # load address of handler routine
+        la      %r2,SP_PTREGS(%r15)	 # address of register-save area
+        basr    %r14,%r1		 # branch to interrupt-handler
+pgm_per_only:
+        la      %r2,SP_PTREGS(15)	 # address of register-save area
+        larl    %r14,sysc_return	 # load adr. of system return
+        jg      handle_per_exception
+
+#
 # it was a single stepped SVC that is causing all the trouble
+#
 pgm_svcper:
 	SAVE_ALL __LC_SVC_OLD_PSW,1
-        mvc     SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information
-        j       pgm_system_call          # now do the svc
+	llgh    %r8,__LC_SVC_INT_CODE # get svc number from lowcore
+        GET_THREAD_INFO           # load pointer to task_struct to R9
+	stosm   48(%r15),0x03     # reenable interrupts
+	larl    %r7,sys_call_table
+        sll     %r8,3
+        tm      SP_PSW+3(%r15),0x01  # are we running in 31 bit mode ?
+        jo      pgm_svcper_noemu
+	la      %r7,4(%r8)        # use 31 bit emulation system calls
+pgm_svcper_noemu:
+        lgf     %r8,0(%r8,%r7)    # load address of system call routine
+	tm	__TI_flags+3(%r9),_TIF_SYSCALL_TRACE
+        jo      pgm_tracesys
+        basr    %r14,%r8          # call sys_xxxx
+        stg     %r2,SP_R2(%r15)   # store return value (change R2 on stack)
+                                  # ATTENTION: check sys_execve_glue before
+                                  # changing anything here !!
+
 pgm_svcret:
+	tm	__TI_flags+3(%r9),_TIF_SIGPENDING
+	jo	pgm_svcper_nosig
+        la      %r2,SP_PTREGS(%r15) # load pt_regs
+        sgr     %r3,%r3             # clear *oldset
+	brasl	%r14,do_signal
+	
+pgm_svcper_nosig:
 	lhi     %r0,__LC_PGM_OLD_PSW     # set trap indication back to pgm_chk
 	st      %r0,SP_TRAP(%r15)
-        llgh    %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack
-        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-	j       pgm_no_sv
-pgm_sv:
-	SAVE_ALL __LC_PGM_OLD_PSW,1
-        mvi     SP_PGM_OLD_ILC(%r15),1   # mark PGM_OLD_ILC as invalid
-        llgh    %r7,__LC_PGM_ILC         # load instruction length
-	GET_CURRENT
-pgm_no_sv:
-        llgh    %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-	lghi    %r3,0x7f
-        nr      %r3,%r8           # clear per-event-bit & move to r3
-        je      pgm_dn            # none of Martins exceptions occurred bypass
-        sll     %r3,3
-        larl    %r1,pgm_check_table
-        lg      %r1,0(%r3,%r1)    # load address of handler routine
-        srl     %r3,3
-        la      %r2,SP_PTREGS(%r15) # address of register-save area
-        chi     %r3,0x4           # protection-exception ?
-        jne     pgm_go            # if not,
-        lg      %r5,SP_PSW+8(15)  # load psw addr
-        slgr    %r5,%r7           # substract ilc from psw
-        stg     %r5,SP_PSW+8(15)  # store corrected psw addr
-pgm_go: basr    %r14,%r1          # branch to interrupt-handler
-pgm_dn: nill    %r8,0x80          # check for per exception
-        je      sysc_return
         la      %r2,SP_PTREGS(15) # address of register-save area
         larl    %r14,sysc_return  # load adr. of system return
         jg      handle_per_exception
+#
+# call trace before and after sys_call
+#
+pgm_tracesys:
+	lghi    %r0,-ENOSYS
+	stg     %r0,SP_R2(%r15)     # give sysc_trace an -ENOSYS retval
+        brasl   %r14,syscall_trace
+	lg      %r2,SP_R2(%r15)
+	cghi	%r2,256
+	jnl     pgm_svc_go
+	sllg    %r2,%r2,3           # strace wants to change the syscall
+	lgf	%r8,0(%r2,%r7)
+pgm_svc_go:
+	lmg     %r3,%r6,SP_R3(%r15)
+	lg      %r2,SP_ORIG_R2(%r15)
+        basr    %r14,%r8            # call sys_xxx
+        stg     %r2,SP_R2(%r15)     # store return value
+	tm	__TI_flags+7(%r9),_TIF_SYSCALL_TRACE
+        jno     pgm_svcret
+	larl	%r14,pgm_svcret     # return point is sysc_return
+	jg	syscall_trace
 
 /*
  * IO interrupt handler routine
@@ -711,7 +743,7 @@
         .globl io_int_handler
 io_int_handler:
         SAVE_ALL __LC_IO_OLD_PSW,0
-        GET_CURRENT                    # load pointer to task_struct to R9
+        GET_THREAD_INFO                # load pointer to task_struct to R9
         la      %r2,SP_PTREGS(%r15)    # address of register-save area
 	llgh    %r3,__LC_SUBCHANNEL_NR # load subchannel number
         llgf    %r4,__LC_IO_INT_PARM   # load interuption parm
@@ -722,43 +754,38 @@
 #
 # check, if bottom-half has to be done
 #
-	lgf     %r1,processor(%r9)    # get cpu number from task struture
+        lgf     %r1,__TI_cpu(%r9)
 	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
+	icm     %r0,15,0(%r1)          # test irq_stat[#cpu].__softirq_pending
         jnz     io_handle_bottom_half
 io_return_bh:	
-
-        tm      SP_PSW+1(%r15),0x01    # returning to user ?
-        jno     io_leave               # no-> skip resched & signal
-        stosm   48(%r15),0x03          # reenable interrupts
-#
-# check, if reschedule is needed
-#
-#error	lg      %r0,need_resched(%r9)  # get need_resched from task_struct
-	ltgr    %r0,%r0
-        jnz     io_reschedule
-#error        icm     %r0,15,sigpending(%r9) # get sigpending from task_struct
-        jnz     io_signal_return
+	tm	__TI_flags+7(%r9),_TIF_WORK_MASK
+	jnz	io_work                # there is work to do (signals etc.)
 io_leave:
         stnsm   48(%r15),0xfc          # disable I/O and ext. interrupts
         RESTORE_ALL 0
 
 #
-# call do_softirq and return from syscall, if interrupt-level
-# is zero
+# call do_softirq
 #
 io_handle_bottom_half:        
 	larl    %r14,io_return_bh
-        jg      do_softirq          # return point is io_return_bh
+        jg      do_softirq             # return point is io_return_bh
 
 #
-# call schedule with io_return as return-address
+# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
+# _TIF_NEED_RESCHED is on. Find out which one.
 #
-io_reschedule:        
-	larl    %r14,io_return
-        jg      schedule            # call scheduler, return to io_return
+io_work:
+        tm      SP_PSW+1(%r15),0x01    # returning to user ?
+        jno     io_leave               # no-> skip resched & signal
+        stosm   48(%r15),0x03          # reenable interrupts
+	tm	__TI_flags+7(%r9),_TIF_NEED_RESCHED
+	jo	io_reschedule
+	# add a test for TIF_NOTIFY_RESUME here when it is used.
+	# _TIF_SIGPENDING is the only flag left
 
 #
 # call do_signal before return
@@ -769,33 +796,40 @@
 	larl    %r14,io_leave
         jg      do_signal           # return point is io_leave
 
+#
+# call schedule with io_return as return-address
+#
+io_reschedule:        
+	larl    %r14,io_return
+        jg      schedule            # call scheduler, return to io_return
+
 /*
  * External interrupt handler routine
  */
         .globl  ext_int_handler
 ext_int_handler:
         SAVE_ALL __LC_EXT_OLD_PSW,0
-        GET_CURRENT                    # load pointer to task_struct to R9
-        la      %r2,SP_PTREGS(%r15)    # address of register-save area
-        llgh    %r3,__LC_EXT_INT_CODE  # error code
-        lgr     %r1,%r3                # calculate index = code & 0xff
-	nill    %r1,0xff
-        sll     %r1,3
-        larl    %r4,ext_int_hash
-        lg      %r4,0(%r1,%r4)         # get first list entry for hash value
-        ltgr    %r4,%r4                # == NULL ?
-        jz      io_return              # yes, nothing to do, exit
+        GET_THREAD_INFO                # load pointer to task_struct to R9
+	llgh	%r6,__LC_EXT_INT_CODE  # get interruption code
+	lgr	%r1,%r6		       # calculate index = code & 0xff
+	nill	%r1,0xff
+	sll	%r1,3
+	larl	%r7,ext_int_hash
+	lg	%r7,0(%r1,%r7)	       # get first list entry for hash value
+	ltgr	%r7,%r7		       # == NULL ?
+	jz	io_return	       # yes, nothing to do, exit
 ext_int_loop:
-        ch      %r3,16(%r4)            # compare external interrupt code
-        je      ext_int_found
-        lg      %r4,0(%r4)             # next list entry
-	ltgr    %r4,%r4
-        jnz     ext_int_loop
-        j       io_return
-ext_int_found:
-        lg      %r4,8(%r4)             # get handler address
-        larl    %r14,io_return
-        br      %r4                    # branch to ext call handler
+	ch	%r6,16(%r7)	       # compare external interrupt code
+	jne	ext_int_next
+	lg	%r1,8(%r7)	       # get handler address
+	la	%r2,SP_PTREGS(%r15)    # address of register-save area
+	lgr	%r3,%r6		       # interruption code
+	basr	%r14,%r1	       # call handler
+ext_int_next:
+	lg	%r7,0(%r7)	       # next list entry
+	ltgr	%r7,%r7
+	jnz	ext_int_loop
+	j	io_return
 
 /*
  * Machine check handler routines
@@ -841,3 +875,4 @@
  */
                .align 4
 .Lc_ac:        .long  0,0,1
+.Lc256:        .quad  256
diff -Nru a/arch/s390x/kernel/exec32.c b/arch/s390x/kernel/exec32.c
--- a/arch/s390x/kernel/exec32.c	Sat Jun  8 22:31:35 2002
+++ b/arch/s390x/kernel/exec32.c	Sat Jun  8 22:31:35 2002
@@ -20,6 +20,7 @@
 #include <linux/pagemap.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
+#include <linux/binfmts.h>
 #define __NO_VERSION__
 #include <linux/module.h>
 
diff -Nru a/arch/s390x/kernel/exec_domain32.c b/arch/s390x/kernel/exec_domain32.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/s390x/kernel/exec_domain32.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,30 @@
+/*
+ * Support for 32-bit Linux for S390 personality.
+ *
+ * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Author(s): Gerhard Tonn (ton@de.ibm.com)
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/personality.h>
+#include <linux/sched.h>
+
+struct exec_domain s390_exec_domain;
+
+static int __init
+s390_init (void)
+{
+	s390_exec_domain.name = "Linux/s390";
+	s390_exec_domain.handler = NULL;
+	s390_exec_domain.pers_low = PER_LINUX32;
+	s390_exec_domain.pers_high = PER_LINUX32;
+	s390_exec_domain.signal_map = default_exec_domain.signal_map;
+	s390_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
+	register_exec_domain(&s390_exec_domain);
+	return 0;
+}
+
+__initcall(s390_init);
diff -Nru a/arch/s390x/kernel/head.S b/arch/s390x/kernel/head.S
--- a/arch/s390x/kernel/head.S	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/head.S	Sat Jun  8 22:31:36 2002
@@ -326,7 +326,7 @@
         bnz   .Lrdcont
         st    %r2,INITRD_START+4-PARMAREA(%r12)# no ramdisk found, null it
 .Lrdcont:
-	l     %r2,INITRD_START-PARMAREA(%r12)
+	l     %r2,INITRD_START+4-PARMAREA(%r12)
 	clc   0(3,%r2),.L_hdr		       # skip HDRx and EOFx 
 	bz    .Lagain2
 	clc   0(3,%r2),.L_eof
@@ -613,7 +613,7 @@
 #
 # Setup stack
 #
-	larl  %r15,init_task_union
+	larl  %r15,init_thread_union
         aghi  %r15,16384                # init_task_union + 16384
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
diff -Nru a/arch/s390x/kernel/init_task.c b/arch/s390x/kernel/init_task.c
--- a/arch/s390x/kernel/init_task.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/init_task.c	Sat Jun  8 22:31:37 2002
@@ -13,21 +13,26 @@
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
-static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
 static struct files_struct init_files = INIT_FILES;
 static struct signal_struct init_signals = INIT_SIGNALS;
 struct mm_struct init_mm = INIT_MM(init_mm);
 
 /*
- * Initial task structure.
+ * Initial thread structure.
  *
- * We need to make sure that this is 16384-byte aligned due to the
- * way process stacks are handled. This is done by making sure
- * the linker maps this in the .text segment right after head.S,
- * and making head.S ensure the proper alignment.
+ * We need to make sure that this is 8192-byte aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union 
+	__attribute__((__section__(".data.init_task"))) =
+		{ INIT_THREAD_INFO(init_task) };
+
+/*
+ * Initial task structure.
  *
- * The things we do for performance..
+ * All other task structs will be allocated on slabs in fork.c
  */
-union task_union init_task_union __attribute__((aligned(16384))) = 
-  { INIT_TASK(init_task_union.task) };
+struct task_struct init_task = INIT_TASK(init_task);
+
diff -Nru a/arch/s390x/kernel/ioctl32.c b/arch/s390x/kernel/ioctl32.c
--- a/arch/s390x/kernel/ioctl32.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/ioctl32.c	Sat Jun  8 22:31:37 2002
@@ -24,10 +24,17 @@
 #include <linux/route.h>
 #include <linux/ext2_fs.h>
 #include <linux/hdreg.h>
+#include <linux/if_bonding.h>
+#include <linux/loop.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+#include <linux/elevator.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/dasd.h>
+#include <asm/tape390.h>
 #include <asm/sockios.h>
+#include <asm/ioctls.h>
 
 #include "linux32.h"
 
@@ -198,6 +205,58 @@
 	return err;
 }
 
+static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq ifr;
+	mm_segment_t old_fs;
+	int err, len;
+	u32 data;
+	
+	if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32)))
+		return -EFAULT;
+	ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL);
+	if (!ifr.ifr_data)
+		return -EAGAIN;
+
+	switch (cmd) {
+	case SIOCBONDENSLAVE:
+	case SIOCBONDRELEASE:
+	case SIOCBONDSETHWADDR:
+	case SIOCBONDCHANGEACTIVE:
+		len = IFNAMSIZ * sizeof(char);
+		break;
+	case SIOCBONDSLAVEINFOQUERY:
+		len = sizeof(struct ifslave);
+		break;
+	case SIOCBONDINFOQUERY:
+		len = sizeof(struct ifbond);
+		break;
+	default:
+		err = -EINVAL;
+		goto out;
+	};
+
+	__get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data));
+	if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		len = copy_to_user((char *)A(data), ifr.ifr_data, len);
+		if (len)
+			err = -EFAULT;
+	}
+
+out:
+	free_page((unsigned long)ifr.ifr_data);
+	return err;
+}
+
 static inline int dev_ifsioc(unsigned int fd, unsigned int cmd,
 			     unsigned long arg)
 {
@@ -320,6 +379,375 @@
 	return sys_ioctl(fd, cmd, arg);
 }
 
+
+struct loop_info32 {
+	int			lo_number;      /* ioctl r/o */
+	__kernel_dev_t32	lo_device;      /* ioctl r/o */
+	unsigned int		lo_inode;       /* ioctl r/o */
+	__kernel_dev_t32	lo_rdevice;     /* ioctl r/o */
+	int			lo_offset;
+	int			lo_encrypt_type;
+	int			lo_encrypt_key_size;    /* ioctl w/o */
+	int			lo_flags;       /* ioctl r/o */
+	char			lo_name[LO_NAME_SIZE];
+	unsigned char		lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+	unsigned int		lo_init[2];
+	char			reserved[4];
+};
+
+static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct loop_info l;
+	int err = -EINVAL;
+
+	switch(cmd) {
+	case LOOP_SET_STATUS:
+		err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+		err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+		err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+		err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+		err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset,
+					   8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+		if (err) {
+			err = -EFAULT;
+		} else {
+			set_fs (KERNEL_DS);
+			err = sys_ioctl (fd, cmd, (unsigned long)&l);
+			set_fs (old_fs);
+		}
+		break;
+	case LOOP_GET_STATUS:
+		set_fs (KERNEL_DS);
+		err = sys_ioctl (fd, cmd, (unsigned long)&l);
+		set_fs (old_fs);
+		if (!err) {
+			err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number);
+			err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device);
+			err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode);
+			err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice);
+			err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset,
+					   (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
+			if (err)
+				err = -EFAULT;
+		}
+		break;
+	default: {
+		static int count = 0;
+		if (++count <= 20)
+			printk("%s: Unknown loop ioctl cmd, fd(%d) "
+			       "cmd(%08x) arg(%08lx)\n",
+			       __FUNCTION__, fd, cmd, arg);
+	}
+	}
+	return err;
+}
+
+
+struct blkpg_ioctl_arg32 {
+	int op;
+	int flags;
+	int datalen;
+	u32 data;
+};
+                                
+static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg)
+{
+	struct blkpg_ioctl_arg a;
+	struct blkpg_partition p;
+	int err;
+	mm_segment_t old_fs = get_fs();
+	
+	err = get_user(a.op, &arg->op);
+	err |= __get_user(a.flags, &arg->flags);
+	err |= __get_user(a.datalen, &arg->datalen);
+	err |= __get_user((long)a.data, &arg->data);
+	if (err) return err;
+	switch (a.op) {
+	case BLKPG_ADD_PARTITION:
+	case BLKPG_DEL_PARTITION:
+		if (a.datalen < sizeof(struct blkpg_partition))
+			return -EINVAL;
+                if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+			return -EFAULT;
+		a.data = &p;
+		set_fs (KERNEL_DS);
+		err = sys_ioctl(fd, cmd, (unsigned long)&a);
+		set_fs (old_fs);
+	default:
+		return -EINVAL;
+	}                                        
+	return err;
+}
+
+
+typedef struct ica_z90_status_t {
+  int totalcount;
+  int leedslitecount;
+  int leeds2count;
+  int requestqWaitCount;
+  int pendingqWaitCount;
+  int totalOpenCount;
+  int cryptoDomain;
+  unsigned char status[64];
+  unsigned char qdepth[64];
+} ica_z90_status;
+
+typedef struct _ica_rsa_modexpo {
+  char         *inputdata;
+  unsigned int  inputdatalength;
+  char         *outputdata;
+  unsigned int  outputdatalength;
+  char         *b_key;
+  char         *n_modulus;
+} ica_rsa_modexpo_t;
+
+typedef struct _ica_rsa_modexpo_32 {
+  u32          inputdata;
+  u32          inputdatalength;
+  u32          outputdata;
+  u32          outputdatalength;
+  u32          b_key;
+  u32          n_modulus;
+} ica_rsa_modexpo_32_t;
+
+typedef struct _ica_rsa_modexpo_crt {
+  char         *inputdata;
+  unsigned int  inputdatalength;
+  char         *outputdata;
+  unsigned int  outputdatalength;
+  char         *bp_key;
+  char         *bq_key;
+  char         *np_prime;
+  char         *nq_prime;
+  char         *u_mult_inv;
+} ica_rsa_modexpo_crt_t;
+
+typedef struct _ica_rsa_modexpo_crt_32 {
+  u32          inputdata;
+  u32          inputdatalength;
+  u32          outputdata;
+  u32          outputdatalength;
+  u32          bp_key;
+  u32          bq_key;
+  u32          np_prime;
+  u32          nq_prime;
+  u32          u_mult_inv;
+} ica_rsa_modexpo_crt_32_t;
+
+#define ICA_IOCTL_MAGIC 'z'
+#define ICARSAMODEXPO   _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x05, 0)
+#define ICARSACRT       _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x06, 0) 
+#define ICARSAMODMULT   _IOC(_IOC_READ|_IOC_WRITE, ICA_IOCTL_MAGIC, 0x07, 0)
+#define ICAZ90STATUS    _IOC(_IOC_READ, ICA_IOCTL_MAGIC, 0x10, sizeof(ica_z90_status))
+#define ICAZ90QUIESCE   _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x11, 0)
+#define ICAZ90HARDRESET _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x12, 0)
+#define ICAZ90HARDERROR _IOC(_IOC_NONE, ICA_IOCTL_MAGIC, 0x13, 0)
+
+static int do_rsa_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err = 0;
+	ica_rsa_modexpo_t rsa;
+	ica_rsa_modexpo_32_t *rsa32 = (ica_rsa_modexpo_32_t *)arg;
+	u32 inputdata, outputdata, b_key, n_modulus;
+
+	memset (&rsa, 0, sizeof(rsa));
+
+	err |= __get_user (inputdata, &rsa32->inputdata);
+	err |= __get_user (rsa.inputdatalength, &rsa32->inputdatalength);
+	err |= __get_user (outputdata, &rsa32->outputdata);
+	err |= __get_user (rsa.outputdatalength, &rsa32->outputdatalength);
+	err |= __get_user (b_key, &rsa32->b_key);
+	err |= __get_user (n_modulus, &rsa32->n_modulus);
+	if (err)
+		return -EFAULT;
+
+	rsa.inputdata = (char *)kmalloc(rsa.inputdatalength, GFP_KERNEL);
+	if (!rsa.inputdata) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.inputdata, (char *)(u64)(inputdata & 0x7fffffff), 
+			   rsa.inputdatalength)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.outputdata = (char *)kmalloc(rsa.outputdatalength, GFP_KERNEL);
+	if (!rsa.outputdata) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+
+	rsa.b_key = (char *)kmalloc(rsa.inputdatalength, GFP_KERNEL);
+	if (!rsa.b_key) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.b_key, (char *)(u64)(b_key & 0x7fffffff), 
+			   rsa.inputdatalength)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.n_modulus = (char *)kmalloc(rsa.inputdatalength, GFP_KERNEL);
+	if (!rsa.n_modulus) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.n_modulus, (char *)(u64)(n_modulus & 0x7fffffff), 
+			   rsa.inputdatalength)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&rsa);
+	set_fs(old_fs);
+	if (err < 0)
+		goto cleanup;
+
+	if (copy_to_user((char *)(u64)(outputdata & 0x7fffffff), rsa.outputdata,
+			 rsa.outputdatalength))
+		err = -EFAULT;
+
+cleanup:
+	if (rsa.inputdata)
+		kfree(rsa.inputdata);
+	if (rsa.outputdata)
+		kfree(rsa.outputdata);
+	if (rsa.b_key)
+		kfree(rsa.b_key);
+	if (rsa.n_modulus)
+		kfree(rsa.n_modulus);
+	
+	return err;
+}
+
+static int do_rsa_crt_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	int err = 0;
+	ica_rsa_modexpo_crt_t rsa;
+	ica_rsa_modexpo_crt_32_t *rsa32 = (ica_rsa_modexpo_crt_32_t *)arg;
+	u32 inputdata, outputdata, bp_key, bq_key, np_prime, nq_prime, u_mult_inv;
+
+	memset (&rsa, 0, sizeof(rsa));
+
+	err |= __get_user (inputdata, &rsa32->inputdata);
+	err |= __get_user (rsa.inputdatalength, &rsa32->inputdatalength);
+	err |= __get_user (outputdata, &rsa32->outputdata);
+	err |= __get_user (rsa.outputdatalength, &rsa32->outputdatalength);
+	err |= __get_user (bp_key, &rsa32->bp_key);
+	err |= __get_user (bq_key, &rsa32->bq_key);
+	err |= __get_user (np_prime, &rsa32->np_prime);
+	err |= __get_user (nq_prime, &rsa32->nq_prime);
+	err |= __get_user (u_mult_inv, &rsa32->u_mult_inv);
+	if (err)
+		return -EFAULT;
+
+	rsa.inputdata = (char *)kmalloc(rsa.inputdatalength, GFP_KERNEL);
+	if (!rsa.inputdata) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.inputdata, (char *)(u64)(inputdata & 0x7fffffff), 
+			   rsa.inputdatalength)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.outputdata = (char *)kmalloc(rsa.outputdatalength, GFP_KERNEL);
+	if (!rsa.outputdata) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+
+	rsa.bp_key = (char *)kmalloc(rsa.inputdatalength/2 + 8, GFP_KERNEL);
+	if (!rsa.bp_key) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.bp_key, (char *)(u64)(bp_key & 0x7fffffff), 
+			   rsa.inputdatalength/2 + 8)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.bq_key = (char *)kmalloc(rsa.inputdatalength/2, GFP_KERNEL);
+	if (!rsa.bq_key) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.bq_key, (char *)(u64)(bq_key & 0x7fffffff), 
+			   rsa.inputdatalength/2)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.np_prime = (char *)kmalloc(rsa.inputdatalength/2 + 8, GFP_KERNEL);
+	if (!rsa.np_prime) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.np_prime, (char *)(u64)(np_prime & 0x7fffffff), 
+			   rsa.inputdatalength/2 + 8)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.nq_prime = (char *)kmalloc(rsa.inputdatalength/2, GFP_KERNEL);
+	if (!rsa.nq_prime) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.nq_prime, (char *)(u64)(nq_prime & 0x7fffffff), 
+			   rsa.inputdatalength/2)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	rsa.u_mult_inv = (char *)kmalloc(rsa.inputdatalength/2 + 8, GFP_KERNEL);
+	if (!rsa.u_mult_inv) {
+		err = -ENOMEM;
+		goto cleanup;
+	}
+	if (copy_from_user(rsa.u_mult_inv, (char *)(u64)(u_mult_inv & 0x7fffffff), 
+			   rsa.inputdatalength/2 + 8)) {
+		err = -EFAULT;
+		goto cleanup;
+	}
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&rsa);
+	set_fs(old_fs);
+	if (err < 0)
+		goto cleanup;
+
+	if (copy_to_user((char *)(u64)(outputdata & 0x7fffffff), rsa.outputdata,
+			 rsa.outputdatalength))
+		err = -EFAULT;
+
+cleanup:
+	if (rsa.inputdata)
+		kfree(rsa.inputdata);
+	if (rsa.outputdata)
+		kfree(rsa.outputdata);
+	if (rsa.bp_key)
+		kfree(rsa.bp_key);
+	if (rsa.bq_key)
+		kfree(rsa.bq_key);
+	if (rsa.np_prime)
+		kfree(rsa.np_prime);
+	if (rsa.nq_prime)
+		kfree(rsa.nq_prime);
+	if (rsa.u_mult_inv)
+		kfree(rsa.u_mult_inv);
+	
+	return err;
+}
+
 static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t old_fs = get_fs();
@@ -360,7 +788,21 @@
 	IOCTL32_DEFAULT(BIODASDINFO),
 	IOCTL32_DEFAULT(BIODASDFMT),
 
+	IOCTL32_DEFAULT(TAPE390_DISPLAY),
+
+	IOCTL32_DEFAULT(BLKROSET),
+	IOCTL32_DEFAULT(BLKROGET),
 	IOCTL32_DEFAULT(BLKRRPART),
+	IOCTL32_DEFAULT(BLKFLSBUF),
+	IOCTL32_DEFAULT(BLKRASET),
+	IOCTL32_DEFAULT(BLKFRASET),
+	IOCTL32_DEFAULT(BLKSECTSET),
+	IOCTL32_DEFAULT(BLKSSZGET),
+	IOCTL32_DEFAULT(BLKBSZGET),
+	IOCTL32_DEFAULT(BLKGETSIZE64),
+
+	IOCTL32_DEFAULT(BLKELVGET),
+	IOCTL32_DEFAULT(BLKELVSET),
 
 	IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl),
 
@@ -455,6 +897,9 @@
 
 	IOCTL32_DEFAULT(SIOCGSTAMP),
 
+	IOCTL32_DEFAULT(LOOP_SET_FD),
+	IOCTL32_DEFAULT(LOOP_CLR_FD),
+
 	IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32),
 	IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf),
 	IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc),
@@ -499,7 +944,22 @@
 	IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl),
 	IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl),
 
-	IOCTL32_HANDLER(BLKGETSIZE, w_long)
+	IOCTL32_HANDLER(LOOP_SET_STATUS, loop_status),
+	IOCTL32_HANDLER(LOOP_GET_STATUS, loop_status),
+
+	IOCTL32_HANDLER(ICARSAMODEXPO, do_rsa_ioctl),
+	IOCTL32_HANDLER(ICARSACRT, do_rsa_crt_ioctl),
+	IOCTL32_HANDLER(ICARSAMODMULT, do_rsa_ioctl),
+	IOCTL32_DEFAULT(ICAZ90STATUS),
+	IOCTL32_DEFAULT(ICAZ90QUIESCE),
+	IOCTL32_DEFAULT(ICAZ90HARDRESET),
+	IOCTL32_DEFAULT(ICAZ90HARDERROR),
+
+	IOCTL32_HANDLER(BLKRAGET, w_long),
+	IOCTL32_HANDLER(BLKGETSIZE, w_long),
+	IOCTL32_HANDLER(BLKFRAGET, w_long),
+	IOCTL32_HANDLER(BLKSECTGET, w_long),
+	IOCTL32_HANDLER(BLKPG, blkpg_ioctl_trans)
 
 };
 
diff -Nru a/arch/s390x/kernel/irq.c b/arch/s390x/kernel/irq.c
--- a/arch/s390x/kernel/irq.c	Sat Jun  8 22:31:52 2002
+++ b/arch/s390x/kernel/irq.c	Sat Jun  8 22:31:52 2002
@@ -63,7 +63,6 @@
 int show_interrupts(struct seq_file *p, void *v)
 {
 	int i, j;
-	struct irqaction * action;
 
 	seq_puts(p, "           ");
 
@@ -77,37 +76,13 @@
 		if (ioinfo[i] == INVALID_STORAGE_AREA)
 			continue;
 
-		action = ioinfo[i]->irq_desc.action;
-		
-  		if (!action)
-			continue;
-
 		seq_printf(p, "%3d: ",i);
-#ifndef CONFIG_SMP
-		seq_printf(p, "%10u ", kstat_irqs(i));
-#else
-		for (j=0; j<smp_num_cpus; j++)
-			seq_printf( p, "%10u ",
-			              kstat.irqs[cpu_logical_map(j)][i]);
-#endif
-		seq_printf(p, " %14s", ioinfo[i]->irq_desc.handler->typename);
-		seq_printf(p, "  %s", action->name);
-
-		for (action=action->next; action; action = action->next)
-		{
-			seq_printf(p, ", %s", action->name);
-
-		} /* endfor */
+		seq_printf(p, "  %s", ioinfo[i]->irq_desc.name);
 
 		seq_putc(p, '\n');
 	
 	} /* endfor */
 
-	seq_printf(p, "NMI: %10u\n", nmi_counter);
-#ifdef CONFIG_SMP
-	seq_printf(p, "IPI: %10u\n", atomic_read(&ipi_count));
-#endif
-
 	return 0;
 }
 
@@ -134,10 +109,10 @@
  */
 #define check_smp_invalidate(cpu)
 
+extern void show_stack(unsigned long* esp);
+
 static void show(char * str)
 {
-	int i;
-	unsigned long *stack;
 	int cpu = smp_processor_id();
 
 	printk("\n%s, CPU %d:\n", str, cpu);
@@ -145,13 +120,7 @@
 	       atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
 	printk("bh:   %d [%d]\n",
 	       atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
-	stack = (unsigned long *) &str;
-	for (i = 40; i ; i--) {
-		unsigned long x = *++stack;
-		if (x > (unsigned long) &init_task_union && x < (unsigned long) &vsprintf) {
-			printk("<[%08lx]> ", x);
-		}
-	}
+	show_stack(NULL);
 }
 
 #define MAXCOUNT 100000000
diff -Nru a/arch/s390x/kernel/linux32.c b/arch/s390x/kernel/linux32.c
--- a/arch/s390x/kernel/linux32.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/linux32.c	Sat Jun  8 22:31:36 2002
@@ -56,6 +56,7 @@
 #include <linux/in.h>
 #include <linux/icmpv6.h>
 #include <linux/sysctl.h>
+#include <linux/binfmts.h>
 
 #include <asm/types.h>
 #include <asm/ipc.h>
@@ -63,6 +64,7 @@
 #include <asm/semaphore.h>
 
 #include <net/scm.h>
+#include <net/sock.h>
 
 #include "linux32.h"
 
@@ -288,6 +290,21 @@
 
 struct msgbuf32 { s32 mtype; char mtext[1]; };
 
+struct ipc64_perm_ds32
+{
+        __kernel_key_t          key;
+        __kernel_uid32_t        uid;
+        __kernel_gid32_t        gid;
+        __kernel_uid32_t        cuid;
+        __kernel_gid32_t        cgid;
+        __kernel_mode_t32       mode;
+        unsigned short          __pad1;
+        unsigned short          seq;
+        unsigned short          __pad2;
+        unsigned int            __unused1;
+        unsigned int            __unused2;
+};
+
 struct ipc_perm32
 {
 	key_t    	  key;
@@ -311,7 +328,7 @@
 };
 
 struct semid64_ds32 {
-	struct ipc64_perm sem_perm;		  /* this structure is the same on sparc32 and sparc64 */
+	struct ipc64_perm_ds32 sem_perm;
 	unsigned int	  __pad1;
 	__kernel_time_t32 sem_otime;
 	unsigned int	  __pad2;
@@ -339,7 +356,7 @@
 };
 
 struct msqid64_ds32 {
-	struct ipc64_perm msg_perm;
+	struct ipc64_perm_ds32 msg_perm;
 	unsigned int   __pad1;
 	__kernel_time_t32 msg_stime;
 	unsigned int   __pad2;
@@ -368,19 +385,19 @@
 };
 
 struct shmid64_ds32 {
-	struct ipc64_perm	shm_perm;
-	unsigned int		__pad1;
+	struct ipc64_perm_ds32	shm_perm;
+	__kernel_size_t32	shm_segsz;
 	__kernel_time_t32	shm_atime;
-	unsigned int		__pad2;
+	unsigned int		__unused1;
 	__kernel_time_t32	shm_dtime;
-	unsigned int		__pad3;
+	unsigned int		__unused2;
 	__kernel_time_t32	shm_ctime;
-	__kernel_size_t32	shm_segsz;
+	unsigned int		__unused3;
 	__kernel_pid_t32	shm_cpid;
 	__kernel_pid_t32	shm_lpid;
 	unsigned int		shm_nattch;
-	unsigned int		__unused1;
-	unsigned int		__unused2;
+	unsigned int		__unused4;
+	unsigned int		__unused5;
 };
 
                                                         
@@ -489,13 +506,21 @@
 
 static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
 {
-	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+	struct msgbuf *p = kmalloc (second + sizeof (struct msgbuf), GFP_USER);
 	struct msgbuf32 *up = (struct msgbuf32 *)uptr;
 	mm_segment_t old_fs;
 	int err;
 
 	if (!p)
 		return -ENOMEM;
+
+	if (second > MSGMAX || first < 0 || second < 0)
+		return -EINVAL;
+
+	err = -EFAULT;
+	if (!uptr)
+		goto out;
+
 	err = get_user (p->mtype, &up->mtype);
 	err |= __copy_from_user (p->mtext, &up->mtext, second);
 	if (err)
@@ -517,6 +542,9 @@
 	mm_segment_t old_fs;
 	int err;
 
+	if (first < 0 || second < 0)
+		return -EINVAL;
+
 	if (!version) {
 		struct ipc_kludge_32 *uipck = (struct ipc_kludge_32 *)uptr;
 		struct ipc_kludge_32 ipck;
@@ -531,12 +559,12 @@
 		msgtyp = ipck.msgtyp;
 	}
 	err = -ENOMEM;
-	p = kmalloc (second + sizeof (struct msgbuf) + 4, GFP_USER);
+	p = kmalloc (second + sizeof (struct msgbuf), GFP_USER);
 	if (!p)
 		goto out;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	err = sys_msgrcv (first, p, second + 4, msgtyp, third);
+	err = sys_msgrcv (first, p, second, msgtyp, third);
 	set_fs (old_fs);
 	if (err < 0)
 		goto free_then_out;
@@ -864,27 +892,39 @@
 {
 	switch (cmd) {
 	case F_GETLK:
-	case F_SETLK:
-	case F_SETLKW:
 		{
 			struct flock f;
 			mm_segment_t old_fs;
 			long ret;
 			
-			if(get_flock(&f, (struct flock32 *)arg))
+			if(get_flock(&f, (struct flock32 *)A(arg)))
 				return -EFAULT;
 			old_fs = get_fs(); set_fs (KERNEL_DS);
 			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 			set_fs (old_fs);
 			if (ret) return ret;
 			if (f.l_start >= 0x7fffffffUL ||
-			    f.l_len >= 0x7fffffffUL ||
 			    f.l_start + f.l_len >= 0x7fffffffUL)
 				return -EOVERFLOW;
-			if(put_flock(&f, (struct flock32 *)arg))
+			if(put_flock(&f, (struct flock32 *)A(arg)))
 				return -EFAULT;
 			return 0;
 		}
+	case F_SETLK:
+	case F_SETLKW:
+		{
+			struct flock f;
+			mm_segment_t old_fs;
+			long ret;
+			
+			if(get_flock(&f, (struct flock32 *)A(arg)))
+				return -EFAULT;
+			old_fs = get_fs(); set_fs (KERNEL_DS);
+			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
+			set_fs (old_fs);
+			if (ret) return ret;
+			return 0;
+		}
 	default:
 		return sys_fcntl(fd, cmd, (unsigned long)arg);
 	}
@@ -1332,7 +1372,7 @@
 
 	timeout = MAX_SCHEDULE_TIMEOUT;
 	if (tvp) {
-		time_t sec, usec;
+		int sec, usec;
 
 		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
 		    || (ret = __get_user(sec, &tvp->tv_sec))
@@ -1384,7 +1424,7 @@
 	ret = do_select(n, &fds, &timeout);
 
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
+		int sec = 0, usec = 0;
 		if (timeout) {
 			sec = timeout / HZ;
 			usec = timeout % HZ;
@@ -2002,15 +2042,17 @@
 	return ret;
 }
 
-#define RLIM_INFINITY32	0x7fffffff
-#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
+#define RLIM_OLD_INFINITY32	0x7fffffff
+#define RLIM_INFINITY32		0xffffffff
+#define RESOURCE32_OLD(x)	((x > RLIM_OLD_INFINITY32) ? RLIM_OLD_INFINITY32 : x)
+#define RESOURCE32(x) 		((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
 
 struct rlimit32 {
 	u32	rlim_cur;
 	u32	rlim_max;
 };
 
-extern asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit *rlim);
+extern asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit *rlim);
 
 asmlinkage int sys32_old_getrlimit(unsigned int resource, struct rlimit32 *rlim)
 {
@@ -2019,7 +2061,23 @@
 	mm_segment_t old_fs = get_fs ();
 	
 	set_fs (KERNEL_DS);
-	ret = sys_old_getrlimit(resource, &r);
+	ret = sys_getrlimit(resource, &r);
+	set_fs (old_fs);
+	if (!ret) {
+		ret = put_user (RESOURCE32_OLD(r.rlim_cur), &rlim->rlim_cur);
+		ret |= __put_user (RESOURCE32_OLD(r.rlim_max), &rlim->rlim_max);
+	}
+	return ret;
+}
+
+asmlinkage int sys32_getrlimit(unsigned int resource, struct rlimit32 *rlim)
+{
+	struct rlimit r;
+	int ret;
+	mm_segment_t old_fs = get_fs ();
+	
+	set_fs (KERNEL_DS);
+	ret = sys_getrlimit(resource, &r);
 	set_fs (old_fs);
 	if (!ret) {
 		ret = put_user (RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
@@ -2463,6 +2521,7 @@
 	kmsg->msg_control = (void *) orig_cmsg_uptr;
 }
 
+#if 0
 asmlinkage int sys32_sendmsg(int fd, struct msghdr32 *user_msg, unsigned user_flags)
 {
 	struct socket *sock;
@@ -2588,6 +2647,196 @@
 		return err;
 	return len;
 }
+#endif
+
+/*
+ *	BSD sendmsg interface
+ */
+
+int sys32_sendmsg(int fd, struct msghdr32 *msg, unsigned flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];	/* 20 is size of ipv6_pktinfo */
+	unsigned char *ctl_buf = ctl;
+	struct msghdr msg_sys;
+	int err, ctl_len, iov_size, total_len;
+	
+	err = -EFAULT;
+	if (msghdr_from_user32_to_kern(&msg_sys, msg))
+		goto out; 
+
+	sock = sockfd_lookup(fd, &err);
+	if (!sock) 
+		goto out;
+
+	/* do not move before msg_sys is valid */
+	err = -EINVAL;
+	if (msg_sys.msg_iovlen > UIO_MAXIOV)
+		goto out_put;
+
+	/* Check whether to allocate the iovec area*/
+	err = -ENOMEM;
+	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec32);
+	if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+		iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+		if (!iov)
+			goto out_put;
+	}
+
+	/* This will also move the address data into kernel space */
+	err = verify_iovec32(&msg_sys, iov, address, VERIFY_READ);
+	if (err < 0) 
+		goto out_freeiov;
+	total_len = err;
+
+	err = -ENOBUFS;
+
+	if (msg_sys.msg_controllen > INT_MAX)
+		goto out_freeiov;
+	ctl_len = msg_sys.msg_controllen; 
+	if (ctl_len) 
+	{
+		if (ctl_len > sizeof(ctl))
+		{
+			ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL);
+			if (ctl_buf == NULL) 
+				goto out_freeiov;
+		}
+		else if (ctl_len < sizeof(struct cmsghdr))
+		{
+			/* to get same error message as on 31 bit native */
+			err = EOPNOTSUPP;
+			goto out_freeiov;
+		}
+		err = -EFAULT;
+		if (cmsghdr_from_user32_to_kern(&msg_sys, ctl_buf, ctl_len))
+			goto out_freectl;
+//		msg_sys.msg_control = ctl_buf;
+	}
+	msg_sys.msg_flags = flags;
+
+	if (sock->file->f_flags & O_NONBLOCK)
+		msg_sys.msg_flags |= MSG_DONTWAIT;
+	err = sock_sendmsg(sock, &msg_sys, total_len);
+
+out_freectl:
+	if (ctl_buf != ctl)    
+		sock_kfree_s(sock->sk, ctl_buf, ctl_len);
+out_freeiov:
+	if (iov != iovstack)
+		sock_kfree_s(sock->sk, iov, iov_size);
+out_put:
+	sockfd_put(sock);
+out:       
+	return err;
+}
+
+/*
+ *	BSD recvmsg interface
+ */
+
+int
+sys32_recvmsg (int fd, struct msghdr32 *msg, unsigned int flags)
+{
+	struct socket *sock;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov=iovstack;
+	struct msghdr msg_sys;
+	unsigned long cmsg_ptr;
+	int err, iov_size, total_len, len;
+
+	/* kernel mode address */
+	char addr[MAX_SOCK_ADDR];
+
+	/* user mode address pointers */
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	struct scm_cookie scm;
+	
+	err=-EFAULT;
+	if (msghdr_from_user32_to_kern(&msg_sys, msg))
+		goto out;
+
+	sock = sockfd_lookup(fd, &err);
+	if (!sock)
+		goto out;
+
+	err = -EINVAL;
+	if (msg_sys.msg_iovlen > UIO_MAXIOV)
+		goto out_put;
+	
+	/* Check whether to allocate the iovec area*/
+	err = -ENOMEM;
+	iov_size = msg_sys.msg_iovlen * sizeof(struct iovec);
+	if (msg_sys.msg_iovlen > UIO_FASTIOV) {
+		iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL);
+		if (!iov)
+			goto out_put;
+	}
+
+	/*
+	 *	Save the user-mode address (verify_iovec will change the
+	 *	kernel msghdr to use the kernel address space)
+	 */
+	 
+	uaddr = msg_sys.msg_name;
+	uaddr_len = &msg->msg_namelen;
+	err = verify_iovec32(&msg_sys, iov, addr, VERIFY_WRITE);
+	if (err < 0)
+		goto out_freeiov;
+	total_len=err;
+
+	cmsg_ptr = (unsigned long)msg_sys.msg_control;
+	msg_sys.msg_flags = 0;
+	
+	if (sock->file->f_flags & O_NONBLOCK)
+		flags |= MSG_DONTWAIT;
+	memset(&scm, 0, sizeof(scm));
+	err = sock->ops->recvmsg(sock, &msg_sys, total_len,
+				 flags, &scm);
+	if (err < 0)
+		goto out_freeiov;
+	len = err;
+
+	if (uaddr != NULL && 
+	/* in order to get same error message as on native 31 bit */
+		msg_sys.msg_namelen > 0) {
+		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
+		if (err < 0)
+			goto out_freeiov;
+	}
+	if(!msg_sys.msg_control) {
+		if(sock->passcred || scm.fp)
+			msg_sys.msg_flags |= MSG_CTRUNC;
+		if(scm.fp)
+			__scm_destroy(&scm);
+	} else {
+		/* If recvmsg processing itself placed some
+		 * control messages into user space, it's is
+		 * using 64-bit CMSG processing, so we need
+		 * to fix it up before we tack on more stuff.
+		 */
+		if((unsigned long) msg_sys.msg_control != cmsg_ptr)
+			cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr);
+		/* Wheee... */
+		if(sock->passcred)
+			put_cmsg32(&msg_sys,
+				SOL_SOCKET, SCM_CREDENTIALS,
+				sizeof(scm.creds), &scm.creds);
+		if(scm.fp != NULL)
+			scm_detach_fds32(&msg_sys, &scm);
+	}
+
+out_freeiov:
+	if (iov != iovstack)
+		sock_kfree_s(sock->sk, iov, iov_size);
+out_put:
+	sockfd_put(sock);
+out:
+	return err;
+}
 
 extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
 				     char *optval, int optlen);
@@ -3520,7 +3769,7 @@
  */
 static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
 {
-	return copy_to_user(res32, kres, sizeof(*res32));
+	return copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0;
 }
 
 /*
@@ -3751,6 +4000,12 @@
 	return sys_pwrite(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
 }
 
+extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
+
+asmlinkage ssize_t32 sys32_readahead(int fd, u32 offhi, u32 offlo, s32 count)
+{
+	return sys_readahead(fd, ((loff_t)AA(offhi) << 32) | AA(offlo), count);
+}
 
 extern asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
 
@@ -3773,6 +4028,29 @@
 	return ret;
 }
 
+extern asmlinkage ssize_t sys_sendfile64(int out_fd, int in_fd, 
+					 loff_t *offset, size_t count);
+
+asmlinkage int sys32_sendfile64(int out_fd, int in_fd, 
+				__kernel_loff_t32 *offset, s32 count)
+{
+	mm_segment_t old_fs = get_fs();
+	int ret;
+	loff_t lof;
+	
+	if (offset && get_user(lof, offset))
+		return -EFAULT;
+		
+	set_fs(KERNEL_DS);
+	ret = sys_sendfile64(out_fd, in_fd, offset ? &lof : NULL, count);
+	set_fs(old_fs);
+	
+	if (offset && put_user(lof, offset))
+		return -EFAULT;
+		
+	return ret;
+}
+
 /* Handle adjtimex compatability. */
 
 struct timex32 {
@@ -4195,3 +4473,52 @@
 	return ret;
 }
 
+extern asmlinkage int sys_sched_setaffinity(pid_t pid, unsigned int len,
+					    unsigned long *user_mask_ptr);
+
+asmlinkage int sys32_sched_setaffinity(__kernel_pid_t32 pid, unsigned int len,
+				       u32 *user_mask_ptr)
+{
+	unsigned long kernel_mask;
+	mm_segment_t old_fs;
+	int ret;
+
+	if (get_user(kernel_mask, user_mask_ptr))
+		return -EFAULT;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_sched_setaffinity(pid,
+				    /* XXX Nice api... */
+				    sizeof(kernel_mask),
+				    &kernel_mask);
+	set_fs(old_fs);
+
+	return ret;
+}
+
+extern asmlinkage int sys_sched_getaffinity(pid_t pid, unsigned int len,
+					    unsigned long *user_mask_ptr);
+
+asmlinkage int sys32_sched_getaffinity(__kernel_pid_t32 pid, unsigned int len,
+				       u32 *user_mask_ptr)
+{
+	unsigned long kernel_mask;
+	mm_segment_t old_fs;
+	int ret;
+
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_sched_getaffinity(pid,
+				    /* XXX Nice api... */
+				    sizeof(kernel_mask),
+				    &kernel_mask);
+	set_fs(old_fs);
+
+	if (ret == 0) {
+		if (put_user(kernel_mask, user_mask_ptr))
+			ret = -EFAULT;
+	}
+
+	return ret;
+}
diff -Nru a/arch/s390x/kernel/process.c b/arch/s390x/kernel/process.c
--- a/arch/s390x/kernel/process.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/process.c	Sat Jun  8 22:31:36 2002
@@ -47,198 +47,75 @@
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 /*
- * The idle loop on a S390...
+ * Return saved PC of a blocked thread. used in kernel/sched
+ * resume in entry.S does not create a new stack frame, it
+ * just stores the registers %r6-%r15 to the frame given by
+ * schedule. We want to return the address of the caller of
+ * schedule, so we have to walk the backchain one time to
+ * find the frame schedule() store its return address.
  */
-
-static psw_t wait_psw;
-
-int cpu_idle(void *unused)
+unsigned long thread_saved_pc(struct task_struct *tsk)
 {
-	/* endless idle loop with no priority at all */
-        init_idle();
-	current->nice = 20;
-	wait_psw.mask = _WAIT_PSW_MASK;
-	wait_psw.addr = (unsigned long) &&idle_wakeup;
-	while(1) {
-                if (need_resched()) {
-                        schedule();
-                        check_pgt_cache();
-                        continue;
-                }
-
-		/* load wait psw */
-		asm volatile (
-                        "lpswe %0"
-                        : : "m" (wait_psw) );
-idle_wakeup:
-	}
+	unsigned long bc;
+
+	bc = *((unsigned long *) tsk->thread.ksp);
+	return *((unsigned long *) (bc+112));
 }
 
 /*
-  As all the register will only be made displayable to the root
-  user ( via printk ) or checking if the uid of the user is 0 from
-  the /proc filesystem please god this will be secure enough DJB.
-  The lines are given one at a time so as not to chew stack space in
-  printk on a crash & also for the proc filesystem when you get
-  0 returned you know you've got all the lines
+ * The idle loop on a S390...
  */
 
-static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs)
+void default_idle(void)
 {
-	int linelen=0;
-	int regno,chaincnt;
-	u64 backchain,prev_backchain,endchain;
-	u64 ksp = 0;
-	char *mode = "???";
-
-	enum
-	{
-		sp_linefeed,
-		sp_psw,
-		sp_ksp,
-		sp_gprs,
-		sp_gprs1,
-		sp_gprs2,
-		sp_gprs3,
-		sp_gprs4,
-		sp_gprs5,
-		sp_gprs6,
-		sp_gprs7,
-		sp_gprs8,
-		sp_acrs,
-		sp_acrs1,
-		sp_acrs2,
-		sp_acrs3,
-		sp_acrs4,
-		sp_kern_backchain,
-		sp_kern_backchain1
-	};
-
-	if (task)
-		ksp = task->thread.ksp;
-	if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE))
-		ksp = regs->gprs[15];
-
-	if (regs)
-		mode = (regs->psw.mask & PSW_PROBLEM_STATE)?
-		       "User" : "Kernel";
-
-	switch(line)
-	{
-	case sp_linefeed: 
-		linelen=sprintf(buff,"\n");
-		break;
-	case sp_psw:
-		if(regs)
-			linelen=sprintf(buff, "%s PSW:    %016lx %016lx    %s\n", mode,
-				(unsigned long) regs->psw.mask,
-				(unsigned long) regs->psw.addr,
-				print_tainted());
-		else
-			linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n");
-		break;
-	case sp_ksp:
-		linelen=sprintf(&buff[linelen],
-				"task: %016lx ksp: %016lx pt_regs: %016lx\n",
-				(addr_t)task, (addr_t)ksp, (addr_t)regs);
-		break;
-	case sp_gprs:
-		if(regs)
-			linelen=sprintf(buff, "%s GPRS:\n", mode);
-		break;
-	case sp_gprs1 ... sp_gprs8:
-		if(regs)
-		{
-			regno=(line-sp_gprs1)*2;
-			linelen = sprintf(buff,"%016lx  %016lx\n",
-					  regs->gprs[regno],
-					  regs->gprs[regno+1]);
-		}
-		break;
-	case sp_acrs:
-		if(regs)
-			linelen=sprintf(buff, "%s ACRS:\n", mode);
-		break;	
-        case sp_acrs1 ... sp_acrs4:
-		if(regs)
-		{
-			regno=(line-sp_acrs1)*4;
-			linelen=sprintf(buff,"%08x  %08x  %08x  %08x\n",
-					regs->acrs[regno],
-					regs->acrs[regno+1],
-					regs->acrs[regno+2],
-					regs->acrs[regno+3]);
-		}
-		break;
-	case sp_kern_backchain:
-		if (regs && (regs->psw.mask & PSW_PROBLEM_STATE))
-			break;
-		if (ksp)
-			linelen=sprintf(buff, "Kernel BackChain          CallChain\n");
-		break;
-	default:
-		if (ksp)
-		{
-			
-			backchain=ksp&PSW_ADDR_MASK;
-			endchain=((backchain&(-THREAD_SIZE))+THREAD_SIZE);
-			prev_backchain=backchain-1;
-			line-=sp_kern_backchain1;
-			for(chaincnt=0;;chaincnt++)
-			{
-				if((backchain==0)||(backchain>=endchain)
-				   ||(chaincnt>=8)||(prev_backchain>=backchain))
-					break;
-				if(chaincnt==line)
-				{
-					linelen+=sprintf(&buff[linelen],"       %016lx   [<%016lx>]\n",
-							 backchain,
-							 *(u64 *)(backchain+112)&PSW_ADDR_MASK);
-					break;
-				}
-				prev_backchain=backchain;
-				backchain=(*((u64 *)backchain))&PSW_ADDR_MASK;
-			}
-		}
-	}
-	return(linelen);
-}
+	psw_t wait_psw;
+	unsigned long reg;
 
-void show_regs(struct pt_regs *regs)
-{
-	char buff[80];
-	int i, line;
-
-        printk("CPU:    %d\n",smp_processor_id());
-        printk("Process %s (pid: %d, stackpage=%016lX)\n",
-                current->comm, current->pid, 4096+(addr_t)current);
-	
-	for (line = 0; sprintf_regs(line, buff, current, regs); line++)
-		printk(buff);
-
-	if (regs->psw.mask & PSW_PROBLEM_STATE)
-	{
-		printk("User Code:\n");
-		memset(buff, 0, 20);
-		copy_from_user(buff,
-			       (char *) (regs->psw.addr & PSW_ADDR_MASK), 20);
-		for (i = 0; i < 20; i++)
-			printk("%02x ", buff[i]);
-		printk("\n");
-	}
+        if (need_resched()) {
+                schedule();
+                return;
+        }
+
+	/* 
+	 * Wait for external, I/O or machine check interrupt and
+	 * switch of machine check bit after the wait has ended.
+	 */
+	wait_psw.mask = _WAIT_PSW_MASK;
+	asm volatile (
+		"    larl  %0,0f\n"
+		"    stg   %0,8(%1)\n"
+		"    lpswe 0(%1)\n"
+		"0:  larl  %0,1f\n"
+		"    stg   %0,8(%1)\n"
+		"    ni    1(%1),0xf9\n"
+		"    lpswe 0(%1)\n"
+		"1:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+int cpu_idle(void)
+{
+	for (;;)
+		default_idle();
+	return 0;
 }
 
-char *task_show_regs(struct task_struct *task, char *buffer)
+extern void show_registers(struct pt_regs *regs);
+extern void show_trace(unsigned long *sp);
+
+void show_regs(struct pt_regs *regs)
 {
-	int line, len;
+	struct task_struct *tsk = current;
 
-	for (line = 0; ; line++)
-	{
-		len = sprintf_regs(line, buffer, task, NULL);
-		if (!len) break;
-		buffer += len;
-	}
-	return buffer;
+        printk("CPU:    %d    %s\n", tsk->thread_info->cpu, print_tainted());
+        printk("Process %s (pid: %d, task: %016lx, ksp: %016lx)\n",
+	       current->comm, current->pid, (unsigned long) tsk,
+	       tsk->thread.ksp);
+
+	show_registers(regs);
+	/* Show stack backtrace if pt_regs is from kernel mode */
+	if (!(regs->psw.mask & PSW_PROBLEM_STATE))
+		show_trace((unsigned long *) regs->gprs[15]);
 }
 
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
@@ -279,7 +156,7 @@
 {
 
         current->used_math = 0;
-        current->flags &= ~PF_USEDFPU;
+	clear_tsk_thread_flag(current, TIF_USEDFPU);
 }
 
 void release_thread(struct task_struct *dead_task)
@@ -300,16 +177,11 @@
             unsigned long gprs[10];    /* gprs 6 -15                       */
             unsigned long fprs[2];     /* fpr 4 and 6                      */
             unsigned long empty[2];
-#if CONFIG_REMOTE_DEBUG
-	    struct gdb_pt_regs childregs;
-#else
             struct pt_regs childregs;
-#endif
           } *frame;
 
-        frame = (struct stack_frame *) (4*PAGE_SIZE + (unsigned long) p) -1;
-        frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
-        p->thread.regs = &frame->childregs;
+        frame = ((struct stack_frame *)
+		 (THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
         p->thread.ksp = (unsigned long) frame;
         frame->childregs = *regs;
         frame->childregs.gprs[15] = new_stackp;
@@ -319,8 +191,7 @@
         frame->gprs[8] = (unsigned long) &ret_from_fork;
 
         /* fake return stack for resume(), don't go back to schedule */
-        frame->gprs[9]  = (unsigned long) frame;
-	frame->childregs.old_ilc = -1; /* We are not single stepping an svc */
+        frame->gprs[9] = (unsigned long) frame;
         /* save fprs, if used in last task */
 	save_fp_regs(&p->thread.fp_regs);
         p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
diff -Nru a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c
--- a/arch/s390x/kernel/ptrace.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/ptrace.c	Sat Jun  8 22:31:36 2002
@@ -38,10 +38,16 @@
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_S390_SUPPORT
+#include "linux32.h"
+#else
+#define parent_31bit 0
+#endif
+
 
 void FixPerRegisters(struct task_struct *task)
 {
-	struct pt_regs *regs = task->thread.regs;
+	struct pt_regs *regs = __KSTK_PTREGS(task);
 	per_struct *per_info=
 			(per_struct *)&task->thread.per_info;
 
@@ -135,48 +141,180 @@
 	return retval;
 }
 
+#ifdef CONFIG_S390_SUPPORT
+
+typedef struct
+{
+	__u32 cr[3];
+} per_cr_words32  __attribute__((packed));
+
+typedef struct
+{
+	__u16          perc_atmid;          /* 0x096 */
+	__u32          address;             /* 0x098 */
+	__u8           access_id;           /* 0x0a1 */
+} per_lowcore_words32  __attribute__((packed));
+
+typedef struct
+{
+	union {
+		per_cr_words32   words;
+	} control_regs  __attribute__((packed));
+	/*
+	 * Use these flags instead of setting em_instruction_fetch
+	 * directly they are used so that single stepping can be
+	 * switched on & off while not affecting other tracing
+	 */
+	unsigned  single_step       : 1;
+	unsigned  instruction_fetch : 1;
+	unsigned                    : 30;
+	/*
+	 * These addresses are copied into cr10 & cr11 if single
+	 * stepping is switched off
+	 */
+	__u32     starting_addr;
+	__u32     ending_addr;
+	union {
+		per_lowcore_words32 words;
+	} lowcore; 
+} per_struct32 __attribute__((packed));
+
+struct user_regs_struct32
+{
+	_psw_t32 psw;
+	u32 gprs[NUM_GPRS];
+	u32 acrs[NUM_ACRS];
+	u32 orig_gpr2;
+	s390_fp_regs fp_regs;
+	/*
+	 * These per registers are in here so that gdb can modify them
+	 * itself as there is no "official" ptrace interface for hardware
+	 * watchpoints. This is the way intel does it.
+	 */
+	per_struct32 per_info;
+	u32  ieee_instruction_pointer; 
+	/* Used to give failing instruction back to user for ieee exceptions */
+};
+
+struct user32 {
+                                  /* We start with the registers, to mimic the way that "memory" is returned
+                                   from the ptrace(3,...) function.  */
+  struct user_regs_struct32 regs; /* Where the registers are actually stored */
+                                  /* The rest of this junk is to help gdb figure out what goes where */
+  u32 u_tsize;	                  /* Text segment size (pages). */
+  u32 u_dsize;	                  /* Data segment size (pages). */
+  u32 u_ssize;	                  /* Stack segment size (pages). */
+  u32 start_code;                 /* Starting virtual address of text. */
+  u32 start_stack;	          /* Starting virtual address of stack area.
+				   This is actually the bottom of the stack,
+				   the top of the stack is always found in the
+				   esp register.  */
+  s32 signal;     		  /* Signal that caused the core dump. */
+  u32 u_ar0;                      /* Used by gdb to help find the values for */
+				  /* the registers. */
+  u32 magic;		          /* To uniquely identify a core file */
+  char u_comm[32];		  /* User command that was responsible */
+};
+
+
+#define PT32_PSWMASK  0x0
+#define PT32_PSWADDR  0x04
+#define PT32_GPR0     0x08
+#define PT32_GPR15    0x44
+#define PT32_ACR0     0x48
+#define PT32_ACR15    0x84
+#define PT32_ORIGGPR2 0x88
+#define PT32_FPC      0x90
+#define PT32_FPR0_HI  0x98
+#define PT32_FPR15_LO 0x114
+#define PT32_CR_9     0x118
+#define PT32_CR_11    0x120
+#define PT32_IEEE_IP  0x13C
+#define PT32_LASTOFF  PT32_IEEE_IP
+#define PT32_ENDREGS  0x140-1
+#define U32OFFSETOF(member) offsetof(struct user32,regs.member)
+#define U64OFFSETOF(member) offsetof(struct user,regs.member)
+#define U6432DIFF(member) (U64OFFSETOF(member) - U32OFFSETOF(member))
+#define PT_SINGLE_STEP   (PT_CR_11+8)
+#define PT32_SINGLE_STEP (PT32_CR_11+4)
+
+#endif /* CONFIG_S390_SUPPORT */
+
 int copy_user(struct task_struct *task,saddr_t useraddr, addr_t copyaddr,
               int len, int tofromuser, int writingtouser)
 {
 	int copylen=0,copymax;
 	addr_t  realuseraddr;
 	saddr_t enduseraddr;
-	
 	unsigned long mask;
-
 #ifdef CONFIG_S390_SUPPORT
-	if (current->thread.flags & S390_FLAG_31BIT) {
-	/* adjust user offsets to 64 bit structure */
-		if (useraddr < PT_PSWADDR / 2)
-			useraddr = 2 * useraddr;
-		else if(useraddr < PT_ACR0 / 2)
-			useraddr = 2 * useraddr + sizeof(addr_t) / 2;
-		else if(useraddr < PT_ACR0 / 2 + (PT_ORIGGPR2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2;
-		else if(useraddr < PT_ACR0 / 2 + (sizeof(struct user_regs_struct) - sizeof(addr_t) / 2 - PT_ACR0))
-			useraddr = useraddr + PT_ACR0 / 2 + sizeof(addr_t) / 2; 
-        }
-#endif  
-    
+	int     parent_31bit=current->thread.flags & S390_FLAG_31BIT;
+	int     skip;
+#endif
 	enduseraddr=useraddr+len;
-
-	if (useraddr < 0 || enduseraddr > sizeof(struct user)||
-	   (useraddr < PT_ENDREGS && (useraddr&3))||
-	   (enduseraddr < PT_ENDREGS && (enduseraddr&3)))
+	if ((useraddr<0||useraddr&3||enduseraddr&3)||
+#ifdef CONFIG_S390_SUPPORT
+	    (parent_31bit && enduseraddr > sizeof(struct user32)) ||
+#endif
+	    enduseraddr > sizeof(struct user))
 		return (-EIO);
+
+#ifdef CONFIG_S390_SUPPORT
+	if(parent_31bit)
+	{
+		if(useraddr != PT32_PSWMASK)
+		{
+			if (useraddr == PT32_PSWADDR)
+				useraddr = PT_PSWADDR+4;
+			else if(useraddr <= PT32_GPR15)
+				useraddr = ((useraddr-PT32_GPR0)*2) + PT_GPR0+4;
+			else if(useraddr <= PT32_ACR15)
+				useraddr += PT_ACR0-PT32_ACR0;
+			else if(useraddr == PT32_ORIGGPR2)
+				useraddr = PT_ORIGGPR2+4;
+			else if(useraddr <= PT32_FPR15_LO)
+				useraddr += PT_FPR0-PT32_FPR0_HI;
+			else if(useraddr <= PT32_CR_11)
+				useraddr = ((useraddr-PT32_CR_9)*2) + PT_CR_9+4;
+			else if(useraddr ==  PT32_SINGLE_STEP)
+				useraddr = PT_SINGLE_STEP; 
+			else if(useraddr <= U32OFFSETOF(per_info.ending_addr))	
+				useraddr = (((useraddr-U32OFFSETOF(per_info.starting_addr)))*2) + 
+					U64OFFSETOF(per_info.starting_addr)+4;
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.perc_atmid))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.perc_atmid);
+			else if( useraddr == U32OFFSETOF(per_info.lowcore.words.address))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.address)+4;
+			else if(useraddr == U32OFFSETOF(per_info.lowcore.words.access_id))
+				useraddr = U64OFFSETOF(per_info.lowcore.words.access_id);
+			else if(useraddr == PT32_IEEE_IP)
+				useraddr = PT_IEEE_IP+4;
+		}
+	}
+#endif /* CONFIG_S390_SUPPORT */
+
 	while(len>0)
 	{
+#ifdef CONFIG_S390_SUPPORT
+		skip=0;
+#endif
 		mask=PSW_ADDR_MASK;
 		if(useraddr<PT_FPC)
 		{
-			realuseraddr=(addr_t)&(((u8 *)task->thread.regs)[useraddr]);
-			if(useraddr<PT_PSWMASK)
-			{
-				copymax=PT_PSWMASK;
-			}
-			else if(useraddr<(PT_PSWMASK+8))
+			realuseraddr=((addr_t) __KSTK_PTREGS(task)) + useraddr;
+			if(useraddr<(PT_PSWMASK+8))
 			{
-				copymax=(PT_PSWMASK+8);
+				if(parent_31bit)
+				{
+					copymax=PT_PSWMASK+4;
+#ifdef CONFIG_S390_SUPPORT
+					skip=8;
+#endif
+				}
+				else
+				{
+					copymax=PT_PSWMASK+8;
+				}
 				if(writingtouser)
 					mask=PSW_MASK_DEBUGCHANGE;
 			}
@@ -184,10 +322,25 @@
 			{
 				copymax=PT_PSWADDR+8;
 				mask=PSW_ADDR_DEBUGCHANGE;
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit)
+					skip=4;
+#endif
+
 			}
 			else
-				copymax=PT_FPC;
-			
+			{
+#ifdef CONFIG_S390_SUPPORT
+				if(parent_31bit && useraddr <= PT_GPR15+4)
+				{
+					copymax=useraddr+4;
+					if(useraddr<PT_GPR15+4)
+						skip=4;
+				}
+				else
+#endif
+					copymax=PT_FPC;
+			}
 		}
 		else if(useraddr<(PT_FPR15+sizeof(freg_t)))
 		{
@@ -196,7 +349,33 @@
 		}
 		else if(useraddr<sizeof(struct user_regs_struct))
 		{
-			copymax=sizeof(struct user_regs_struct);
+#ifdef CONFIG_S390_SUPPORT
+			if( parent_31bit && useraddr <= PT_IEEE_IP+4)
+			{
+				switch(useraddr)
+				{
+				case PT_CR_11+4:
+				case U64OFFSETOF(per_info.ending_addr)+4:
+				case U64OFFSETOF(per_info.lowcore.words.address)+4:
+					copymax=useraddr+4;
+					break;
+				case  PT_SINGLE_STEP:
+				case  U64OFFSETOF(per_info.lowcore.words.perc_atmid):
+					/* We copy 2 bytes in excess for the atmid member this also gets around */
+					/* alignment for this member in 32 bit */
+					skip=8;
+					copymax=useraddr+4;
+					break;
+				default: 
+					copymax=useraddr+4;
+					skip=4;
+				}
+			}
+			else
+#endif
+			{
+				copymax=sizeof(struct user_regs_struct);
+			}
 			realuseraddr=(addr_t)&(((u8 *)&task->thread.per_info)[useraddr-PT_CR_9]);
 		}
 		else 
@@ -210,7 +389,11 @@
 			return (-EIO);
 		copyaddr+=copylen;
 		len-=copylen;
-		useraddr+=copylen;
+		useraddr+=copylen
+#if CONFIG_S390_SUPPORT
+			+skip
+#endif
+			;
 	}
 	FixPerRegisters(task);
 	return(0);
@@ -227,149 +410,6 @@
 	clear_single_step(child);
 }
 
-asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
-{
-	struct task_struct *child;
-	int ret = -EPERM;
-	unsigned long flags;
-	unsigned long tmp;
-	int copied;
-	ptrace_area   parea; 
-
-	lock_kernel();
-	if (request == PTRACE_TRACEME) 
-	{
-		/* are we already being traced? */
-		if (current->ptrace & PT_PTRACED)
-			goto out;
-		/* set the ptrace bit in the process flags. */
-		current->ptrace |= PT_PTRACED;
-		ret = 0;
-		goto out;
-	}
-	ret = -ESRCH;
-	read_lock(&tasklist_lock);
-	child = find_task_by_pid(pid);
-	read_unlock(&tasklist_lock);
-	if (!child)
-		goto out;
-	ret = -EPERM;
-	if (pid == 1)		/* you may not mess with init */
-		goto out;
-	if (request == PTRACE_ATTACH) 
-	{
-		ret = ptrace_attach(child);
-		goto out;
-	}
-	ret = -ESRCH;
-	// printk("child=%lX child->flags=%lX",child,child->flags);
-	/* I added child!=current line so we can get the */
-	/* ieee_instruction_pointer from the user structure DJB */
-	if(child!=current)
-	{
-		if (!(child->ptrace & PT_PTRACED))
-			goto out;
-		if (child->state != TASK_STOPPED) 
-		{
-			if (request != PTRACE_KILL)
-				goto out;
-		}
-		if (child->p_pptr != current)
-			goto out;
-	}
-	switch (request) 
-	{
-		/* If I and D space are separate, these will need to be fixed. */
-	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
-	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
-		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(unsigned long *) data);
-		goto out;
-
-		/* read the word at location addr in the USER area. */
-	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(unsigned long),1,0);
-		break;
-
-		/* If I and D space are separate, this will have to be fixed. */
-	case PTRACE_POKETEXT: /* write the word at location addr. */
-	case PTRACE_POKEDATA:
-		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-			goto out;
-		ret = -EIO;
-		goto out;
-		break;
-
-	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(unsigned long),0,1);
-		break;
-
-	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
-	case PTRACE_CONT: 	 /* restart after signal. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
-		else
-			child->ptrace &= ~PT_TRACESYS;
-		child->exit_code = data;
-		/* make sure the single step bit is not set. */
-		clear_single_step(child);
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-/*
- * make the child exit.  Best I can do is send it a sigkill. 
- * perhaps it should be put in the status that it wants to 
- * exit.
- */
-	case PTRACE_KILL:
-		ret = 0;
-		if (child->state == TASK_ZOMBIE) /* already dead */
-			break;
-		child->exit_code = SIGKILL;
-		clear_single_step(child);
-		wake_up_process(child);
-		/* make sure the single step bit is not set. */
-		break;
-
-	case PTRACE_SINGLESTEP:  /* set the trap flag. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~PT_TRACESYS;
-		child->exit_code = data;
-		set_single_step(child);
-		/* give it a chance to run. */
-		wake_up_process(child);
-		ret = 0;
-		break;
-
-	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = ptrace_detach(child, data);
-		break;
-
-	case PTRACE_PEEKUSR_AREA:
-	case PTRACE_POKEUSR_AREA:
-		if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
-		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		break;
-	default:
-		ret = -EIO;
-		break;
-	}
- out:
-	unlock_kernel();
-	return ret;
-}
-
 typedef struct
 {
 __u32	len;
@@ -377,15 +417,20 @@
 __u32	process_addr;
 } ptrace_area_emu31;
 
-asmlinkage int sys32_ptrace(long request, long pid, long addr, s32 data)
+
+asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
 {
 	struct task_struct *child;
 	int ret = -EPERM;
-	unsigned long flags;
-	u32 tmp;
 	int copied;
-	ptrace_area   parea; 
-
+#ifdef CONFIG_S390_SUPPORT
+	int           parent_31bit;
+	int           sizeof_parent_long;
+	u8            *dataptr;
+#else
+#define sizeof_parent_long 8
+#define dataptr (u8 *)&data
+#endif
 	lock_kernel();
 	if (request == PTRACE_TRACEME) 
 	{
@@ -400,16 +445,18 @@
 	ret = -ESRCH;
 	read_lock(&tasklist_lock);
 	child = find_task_by_pid(pid);
+	if (child)
+		get_task_struct(child);
 	read_unlock(&tasklist_lock);
 	if (!child)
 		goto out;
 	ret = -EPERM;
 	if (pid == 1)		/* you may not mess with init */
-		goto out;
+		goto out_tsk;
 	if (request == PTRACE_ATTACH) 
 	{
 		ret = ptrace_attach(child);
-		goto out;
+		goto out_tsk;
 	}
 	ret = -ESRCH;
 	// printk("child=%lX child->flags=%lX",child,child->flags);
@@ -418,44 +465,51 @@
 	if(child!=current)
 	{
 		if (!(child->ptrace & PT_PTRACED))
-			goto out;
+			goto out_tsk;
 		if (child->state != TASK_STOPPED) 
 		{
 			if (request != PTRACE_KILL)
-				goto out;
+				goto out_tsk;
 		}
-		if (child->p_pptr != current)
-			goto out;
+		if (child->parent != current)
+			goto out_tsk;
 	}
+#ifdef CONFIG_S390_SUPPORT
+	parent_31bit=(current->thread.flags & S390_FLAG_31BIT);
+	sizeof_parent_long=(parent_31bit ? 4:8);
+	dataptr=&(((u8 *)&data)[parent_31bit ? 4:0]);
+#endif
 	switch (request) 
 	{
 		/* If I and D space are separate, these will need to be fixed. */
 	case PTRACE_PEEKTEXT: /* read word at location addr. */ 
 	case PTRACE_PEEKDATA: 
-		copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+	{
+		u8 tmp[8];
+		copied = access_process_vm(child, addr, tmp, sizeof_parent_long, 0);
 		ret = -EIO;
-		if (copied != sizeof(tmp))
-			goto out;
-		ret = put_user(tmp,(u32 *)(unsigned long)data);
-		goto out;
-
+		if (copied != sizeof_parent_long)
+			break;
+		ret = copy_to_user((void *)data,tmp,sizeof_parent_long);
+		break;
+	
+	}
 		/* read the word at location addr in the USER area. */
 	case PTRACE_PEEKUSR:
-		ret=copy_user(child,addr,data,sizeof(u32),1,0);
+		ret=copy_user(child,addr,data,sizeof_parent_long,1,0);
 		break;
 
 		/* If I and D space are separate, this will have to be fixed. */
 	case PTRACE_POKETEXT: /* write the word at location addr. */
 	case PTRACE_POKEDATA:
 		ret = 0;
-		if (access_process_vm(child, addr, &data, sizeof(data), 1) == sizeof(data))
-			goto out;
+		if (access_process_vm(child, addr,dataptr, sizeof_parent_long, 1) == sizeof_parent_long)
+			break;
 		ret = -EIO;
-		goto out;
 		break;
 
 	case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
-		ret=copy_user(child,addr,(addr_t)&data,sizeof(u32),0,1);
+		ret=copy_user(child,addr,(addr_t)dataptr,sizeof_parent_long,0,1);
 		break;
 
 	case PTRACE_SYSCALL: 	/* continue and stop at next (return from) syscall */
@@ -464,9 +518,9 @@
 		if ((unsigned long) data >= _NSIG)
 			break;
 		if (request == PTRACE_SYSCALL)
-			child->ptrace |= PT_TRACESYS;
+			set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		else
-			child->ptrace &= ~PT_TRACESYS;
+			clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		/* make sure the single step bit is not set. */
 		clear_single_step(child);
@@ -493,7 +547,7 @@
 		ret = -EIO;
 		if ((unsigned long) data >= _NSIG)
 			break;
-		child->ptrace &= ~PT_TRACESYS;
+		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		child->exit_code = data;
 		set_single_step(child);
 		/* give it a chance to run. */
@@ -502,52 +556,56 @@
 		break;
 
 	case PTRACE_DETACH:  /* detach a process that was attached. */
-		ret = -EIO;
-		if ((unsigned long) data >= _NSIG)
-			break;
-		child->ptrace &= ~(PT_PTRACED|PT_TRACESYS);
-		child->exit_code = data;
-		write_lock_irqsave(&tasklist_lock, flags);
-		REMOVE_LINKS(child);
-		child->p_pptr = child->p_opptr;
-		SET_LINKS(child);
-		write_unlock_irqrestore(&tasklist_lock, flags);
-		/* make sure the single step bit is not set. */
-		clear_single_step(child);
-		wake_up_process(child);
-		ret = 0;
+		ret = ptrace_detach(child, data);
 		break;
+
 	case PTRACE_PEEKUSR_AREA:
 	case PTRACE_POKEUSR_AREA:
+		if(parent_31bit)
 		{
-		ptrace_area_emu31 * parea31 = (void *)addr;
-		if (!access_ok(VERIFY_READ, parea31, sizeof(*parea31)))
-			return(-EFAULT);
-		ret = __get_user(parea.len, &parea31->len);
-		ret |= __get_user(parea.kernel_addr, &parea31->kernel_addr);
-		ret |= __get_user(parea.process_addr, &parea31->process_addr);
-		if(ret==0)  
-		   ret=copy_user(child,parea.kernel_addr,parea.process_addr,
-				 parea.len,1,(request==PTRACE_POKEUSR_AREA));
-		break;
+			ptrace_area_emu31   parea; 
+			if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
 		}
+		else
+		{
+			ptrace_area   parea; 
+			if((ret=copy_from_user(&parea,(void *)addr,sizeof(parea)))==0)  
+				ret=copy_user(child,parea.kernel_addr,parea.process_addr,
+					      parea.len,1,(request==PTRACE_POKEUSR_AREA));
+		}
+		break;
+	case PTRACE_SETOPTIONS: {
+		if (data & PTRACE_O_TRACESYSGOOD)
+			child->ptrace |= PT_TRACESYSGOOD;
+		else
+			child->ptrace &= ~PT_TRACESYSGOOD;
+		ret = 0;
+		break;
+	}
 	default:
 		ret = -EIO;
 		break;
 	}
+ out_tsk:
+	put_task_struct(child);
  out:
 	unlock_kernel();
 	return ret;
 }
 
+
+
 asmlinkage void syscall_trace(void)
 {
-	lock_kernel();
-	if ((current->ptrace & (PT_PTRACED|PT_TRACESYS))
-	    != (PT_PTRACED|PT_TRACESYS))
-		goto out;
-	current->exit_code = SIGTRAP;
-	set_current_state(TASK_STOPPED);
+	if (!test_thread_flag(TIF_SYSCALL_TRACE))
+		return;
+	if (!(current->ptrace & PT_PTRACED))
+		return;
+	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+					? 0x80 : 0);
+	current->state = TASK_STOPPED;
 	notify_parent(current, SIGCHLD);
 	schedule();
 	/*
@@ -559,6 +617,4 @@
 		send_sig(current->exit_code, current, 1);
 		current->exit_code = 0;
 	}
- out:
-	unlock_kernel();
 }
diff -Nru a/arch/s390x/kernel/reipl.S b/arch/s390x/kernel/reipl.S
--- a/arch/s390x/kernel/reipl.S	Sat Jun  8 22:31:52 2002
+++ b/arch/s390x/kernel/reipl.S	Sat Jun  8 22:31:52 2002
@@ -21,8 +21,10 @@
 	        oi      .Lschib+5-.Lpg0(%r13),0x84 
 .Lecs:  	xi      .Lschib+27-.Lpg0(%r13),0x01 
         	msch    .Lschib-.Lpg0(%r13) 
-		ssch	.Liplorb-.Lpg0(%r13)           
-		jz	.L001   
+	        lghi    %r0,5
+.Lssch:		ssch	.Liplorb-.Lpg0(%r13)           
+		jz	.L001
+		brct    %r0,.Lssch   
 		bas	%r14,.Ldisab-.Lpg0(%r13)
 .L001:		mvc	__LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)	
 .Ltpi:		lpswe	.Lwaitpsw-.Lpg0(%r13)          
diff -Nru a/arch/s390x/kernel/s390_ext.c b/arch/s390x/kernel/s390_ext.c
--- a/arch/s390x/kernel/s390_ext.c	Sat Jun  8 22:31:36 2002
+++ b/arch/s390x/kernel/s390_ext.c	Sat Jun  8 22:31:36 2002
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <linux/errno.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
@@ -21,34 +22,31 @@
  * 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;
         int index;
 
-        index = code & 0xff;
-        p = ext_int_hash[index];
-        while (p != NULL) {
-                if (p->code == code)
-                        return -EBUSY;
-                p = p->next;
-        }
-        if (code == 0x1004) /* time_init is done before kmalloc works :-/ */
-                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);
+	p = (ext_int_info_t *) kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
                 return -ENOMEM;
         p->code = code;
         p->handler = handler;
+        index = code & 0xff;
+        p->next = ext_int_hash[index];
+        ext_int_hash[index] = p;
+        return 0;
+}
+
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *p) {
+        int index;
+
+        if (p == NULL)
+                return -EINVAL;
+        p->code = code;
+        p->handler = handler;
+        index = code & 0xff;
         p->next = ext_int_hash[index];
         ext_int_hash[index] = p;
         return 0;
@@ -73,9 +71,31 @@
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
-                kfree(p);
+	kfree(p);
         return 0;
+}
+
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *p) {
+	ext_int_info_t *q;
+	int index;
+
+	if (p == NULL || p->code != code || p->handler != handler)
+		return -EINVAL;
+	index = code & 0xff;
+	q = ext_int_hash[index];
+	if (p != q) {
+		while (q != NULL) {
+			if (q->next == p)
+				break;
+			q = q->next;
+		}
+		if (q == NULL)
+			return -ENOENT;
+		q->next = p->next;
+	} else
+		ext_int_hash[index] = p->next;
+	return 0;
 }
 
 EXPORT_SYMBOL(register_external_interrupt);
diff -Nru a/arch/s390x/kernel/s390_ksyms.c b/arch/s390x/kernel/s390_ksyms.c
--- a/arch/s390x/kernel/s390_ksyms.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/s390_ksyms.c	Sat Jun  8 22:31:37 2002
@@ -7,10 +7,12 @@
 #include <linux/highuid.h>
 #include <linux/module.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
 #include <asm/checksum.h>
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
+#include <asm/softirq.h>
 #if CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
@@ -21,8 +23,9 @@
 EXPORT_SYMBOL_NOVERS(_oi_bitmap);
 EXPORT_SYMBOL_NOVERS(_ni_bitmap);
 EXPORT_SYMBOL_NOVERS(_zb_findmap);
-EXPORT_SYMBOL_NOVERS(__copy_from_user_fixup);
-EXPORT_SYMBOL_NOVERS(__copy_to_user_fixup);
+EXPORT_SYMBOL_NOVERS(__copy_from_user_asm);
+EXPORT_SYMBOL_NOVERS(__copy_to_user_asm);
+EXPORT_SYMBOL_NOVERS(__clear_user_asm);
 
 /*
  * semaphore ops
@@ -30,7 +33,6 @@
 EXPORT_SYMBOL(__up);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
-EXPORT_SYMBOL(__down_trylock);
 
 /*
  * string functions
@@ -38,6 +40,7 @@
 EXPORT_SYMBOL_NOVERS(memcmp);
 EXPORT_SYMBOL_NOVERS(memset);
 EXPORT_SYMBOL_NOVERS(memmove);
+EXPORT_SYMBOL_NOVERS(memscan);
 EXPORT_SYMBOL_NOVERS(strlen);
 EXPORT_SYMBOL_NOVERS(strchr);
 EXPORT_SYMBOL_NOVERS(strcmp);
@@ -47,7 +50,6 @@
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strstr);
-EXPORT_SYMBOL_NOVERS(strsep);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
 /*
@@ -67,4 +69,3 @@
 EXPORT_SYMBOL(console_mode);
 EXPORT_SYMBOL(console_device);
 EXPORT_SYMBOL_NOVERS(do_call_softirq);
-
diff -Nru a/arch/s390x/kernel/semaphore.c b/arch/s390x/kernel/semaphore.c
--- a/arch/s390x/kernel/semaphore.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/semaphore.c	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,5 @@
 /*
- *  linux/arch/S390/kernel/semaphore.c
+ *  linux/arch/s390x/kernel/semaphore.c
  *
  *  S390 version
  *    Copyright (C) 1998-2000 IBM Corporation
@@ -10,151 +10,97 @@
  *
  */
 #include <linux/sched.h>
+#include <linux/errno.h>
 
 #include <asm/semaphore.h>
 
 /*
- * Semaphores are implemented using a two-way counter:
- * The "count" variable is decremented for each process
- * that tries to acquire the semaphore, while the "sleeping"
- * variable is a count of such acquires.
- *
- * Notably, the inline "up()" and "down()" functions can
- * efficiently test if they need to do any extra work (up
- * needs to do something only if count was negative before
- * the increment operation.
- *
- * "sleeping" and the contention routine ordering is
- * protected by the semaphore spinlock.
- *
- * Note that these functions are only called when there is
- * contention on the lock, and as such all this is the
- * "non-critical" part of the whole semaphore business. The
- * critical part is the inline stuff in <asm/semaphore.h>
- * where we want to avoid any extra jumps and calls.
+ * Atomically update sem->count. Equivalent to:
+ *   old_val = sem->count.counter;
+ *   new_val = ((old_val >= 0) ? old_val : 0) + incr;
+ *   sem->count.counter = new_val;
+ *   return old_val;
  */
+static inline int __sem_update_count(struct semaphore *sem, int incr)
+{
+	int old_val, new_val;
+
+        __asm__ __volatile__("   l     %0,0(%3)\n"
+                             "0: ltr   %1,%0\n"
+			     "   jhe   1f\n"
+			     "   lhi   %1,0\n"
+			     "1: ar    %1,%4\n"
+                             "   cs    %0,%1,0(%3)\n"
+                             "   jl    0b\n"
+                             : "=&d" (old_val), "=&d" (new_val),
+			       "+m" (sem->count)
+			     : "a" (&sem->count), "d" (incr) : "cc" );
+	return old_val;
+}
 
 /*
- * Logic:
- *  - only on a boundary condition do we need to care. When we go
- *    from a negative count to a non-negative, we wake people up.
- *  - when we go from a non-negative count to a negative do we
- *    (a) synchronize with the "sleeper" count and (b) make sure
- *    that we're on the wakeup list before we synchronize so that
- *    we cannot lose wakeup events.
+ * The inline function up() incremented count but the result
+ * was <= 0. This indicates that some process is waiting on
+ * the semaphore. The semaphore is free and we'll wake the
+ * first sleeping process, so we set count to 1 unless some
+ * other cpu has called up in the meantime in which case
+ * we just increment count by 1.
  */
-
 void __up(struct semaphore *sem)
 {
+	__sem_update_count(sem, 1);
 	wake_up(&sem->wait);
 }
 
-static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED;
-
+/*
+ * The inline function down() decremented count and the result
+ * was < 0. The wait loop will atomically test and update the
+ * semaphore counter following the rules:
+ *   count > 0: decrement count, wake up queue and exit.
+ *   count <= 0: set count to -1, go to sleep.
+ */
 void __down(struct semaphore * sem)
 {
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+
 	tsk->state = TASK_UNINTERRUPTIBLE;
 	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers++;
-	for (;;) {
-		int sleepers = sem->sleepers;
-
-		/*
-		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock.
-		 */
-		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-			sem->sleepers = 0;
-			break;
-		}
-		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
-
+	while (__sem_update_count(sem, -1) <= 0) {
 		schedule();
 		tsk->state = TASK_UNINTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
 	remove_wait_queue(&sem->wait, &wait);
 	tsk->state = TASK_RUNNING;
 	wake_up(&sem->wait);
 }
 
+/*
+ * Same as __down() with an additional test for signals.
+ * If a signal is pending the count is updated as follows:
+ *   count > 0: wake up queue and exit.
+ *   count <= 0: set count to 0, wake up queue and exit.
+ */
 int __down_interruptible(struct semaphore * sem)
 {
 	int retval = 0;
 	struct task_struct *tsk = current;
 	DECLARE_WAITQUEUE(wait, tsk);
+
 	tsk->state = TASK_INTERRUPTIBLE;
 	add_wait_queue_exclusive(&sem->wait, &wait);
-
-	spin_lock_irq(&semaphore_lock);
-	sem->sleepers ++;
-	for (;;) {
-		int sleepers = sem->sleepers;
-
-		/*
-		 * With signals pending, this turns into
-		 * the trylock failure case - we won't be
-		 * sleeping, and we* can't get the lock as
-		 * it has contention. Just correct the count
-		 * and exit.
-		 */
+	while (__sem_update_count(sem, -1) <= 0) {
 		if (signal_pending(current)) {
+			__sem_update_count(sem, 0);
 			retval = -EINTR;
-			sem->sleepers = 0;
-			atomic_add(sleepers, &sem->count);
-			break;
-		}
-
-		/*
-		 * Add "everybody else" into it. They aren't
-		 * playing, because we own the spinlock. The
-		 * "-1" is because we're still hoping to get
-		 * the lock.
-		 */
-		if (!atomic_add_negative(sleepers - 1, &sem->count)) {
-			sem->sleepers = 0;
 			break;
 		}
-		sem->sleepers = 1;	/* us - see -1 above */
-		spin_unlock_irq(&semaphore_lock);
-
 		schedule();
 		tsk->state = TASK_INTERRUPTIBLE;
-		spin_lock_irq(&semaphore_lock);
 	}
-	spin_unlock_irq(&semaphore_lock);
-	tsk->state = TASK_RUNNING;
 	remove_wait_queue(&sem->wait, &wait);
+	tsk->state = TASK_RUNNING;
 	wake_up(&sem->wait);
 	return retval;
 }
 
-/*
- * Trylock failed - make sure we correct for
- * having decremented the count.
- */
-int __down_trylock(struct semaphore * sem)
-{
-        unsigned long flags;
-	int sleepers;
-
-	spin_lock_irqsave(&semaphore_lock, flags);
-	sleepers = sem->sleepers + 1;
-	sem->sleepers = 0;
-
-	/*
-	 * Add "everybody else" and us into it. They aren't
-	 * playing, because we own the spinlock.
-	 */
-	if (!atomic_add_negative(sleepers, &sem->count))
-		wake_up(&sem->wait);
-
-	spin_unlock_irqrestore(&semaphore_lock, flags);
-	return 1;
-}
diff -Nru a/arch/s390x/kernel/setup.c b/arch/s390x/kernel/setup.c
--- a/arch/s390x/kernel/setup.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/setup.c	Sat Jun  8 22:31:37 2002
@@ -48,7 +48,7 @@
 unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
-struct { unsigned long addr, size, type; } memory_chunk[16];
+struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
 #define CHUNK_READ_WRITE 0
 #define CHUNK_READ_ONLY 1
 __u16 boot_cpu_addr;
@@ -99,7 +99,7 @@
         /*
          * Force FPU initialization:
          */
-        current->flags &= ~PF_USEDFPU;
+        clear_thread_flag(TIF_USEDFPU);
         current->used_math = 0;
 
         /* Setup active_mm for idle_task  */
@@ -165,15 +165,15 @@
 static int __init conmode_setup(char *str)
 {
 #if defined(CONFIG_HWC_CONSOLE)
-	if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+	if (strncmp(str, "hwc", 4) == 0)
                 SET_CONSOLE_HWC;
 #endif
 #if defined(CONFIG_TN3215_CONSOLE)
-	if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3215", 5) == 0)
 		SET_CONSOLE_3215;
 #endif
 #if defined(CONFIG_TN3270_CONSOLE)
-	if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+	if (strncmp(str, "3270", 5) == 0)
 		SET_CONSOLE_3270;
 #endif
         return 1;
@@ -233,31 +233,63 @@
 	}
 }
 
+#ifdef CONFIG_SMP
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
+void (*_machine_restart)(char *command) = machine_restart_smp;
+void (*_machine_halt)(void) = machine_halt_smp;
+void (*_machine_power_off)(void) = machine_power_off_smp;
+#else
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
-#ifndef CONFIG_SMP
-void machine_restart(char * __unused)
+static void do_machine_restart_nonsmp(char * __unused)
 {
 	reipl(S390_lowcore.ipl_device);
 }
 
-void machine_halt(void)
+static void do_machine_halt_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
                 cpcmd(vmhalt_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
 
-void machine_power_off(void)
+static void do_machine_power_off_nonsmp(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
         signal_processor(smp_processor_id(), sigp_stop_and_store_status);
 }
+
+void (*_machine_restart)(char *command) = do_machine_restart_nonsmp;
+void (*_machine_halt)(void) = do_machine_halt_nonsmp;
+void (*_machine_power_off)(void) = do_machine_power_off_nonsmp;
 #endif
 
 /*
+ * Reboot, halt and power_off stubs. They just call _machine_restart,
+ * _machine_halt or _machine_power_off. 
+ */
+
+void machine_restart(char *command)
+{
+	_machine_restart(command);
+}
+
+void machine_halt(void)
+{
+	_machine_halt();
+}
+
+void machine_power_off(void)
+{
+	_machine_power_off();
+}
+
+/*
  * Setup function called from init/main.c just after the banner
  * was printed.
  */
@@ -283,8 +315,8 @@
          * print what head.S has found out about the machine 
          */
 	printk((MACHINE_IS_VM) ?
-	       "We are running under VM\n" :
-	       "We are running native\n");
+	       "We are running under VM (64 bit mode)\n" :
+	       "We are running native (64 bit mode)\n");
 
         ROOT_DEV = to_kdev_t(0x0100);
         memory_start = (unsigned long) &_end;    /* fixit if use $CODELO etc*/
@@ -425,9 +457,10 @@
 	lowcore->io_new_psw.mask = _IO_PSW_MASK;
 	lowcore->io_new_psw.addr = (addr_t) &io_int_handler;
 	lowcore->ipl_device = S390_lowcore.ipl_device;
-	lowcore->kernel_stack = ((__u32) &init_task_union) + 16384;
+	lowcore->kernel_stack = ((__u64) &init_thread_union) + 16384;
 	lowcore->async_stack = (__u64)
 		__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
+	lowcore->jiffy_timer = -1LL;
 	set_prefix((__u32)(__u64) lowcore);
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
@@ -474,17 +507,18 @@
 static int show_cpuinfo(struct seq_file *m, void *v)
 {
         struct cpuinfo_S390 *cpuinfo;
-	unsigned n = v;
+	unsigned long n = (unsigned long) v - 1;
 
-	if (!n--) {
+	if (!n) {
 		seq_printf(m, "vendor_id       : IBM/S390\n"
 				"# processors    : %i\n"
 				"bogomips per cpu: %lu.%02lu\n",
 				smp_num_cpus, loops_per_jiffy/(500000/HZ),
 				(loops_per_jiffy/(5000/HZ))%100);
-	} else if (cpu_online_map & (1 << n)) {
-		cpuinfo = &safe_get_cpu_lowcore(n).cpu_data;
-		seq_printf(m, "processor %i: "
+	}
+	if (cpu_online_map & (1 << n)) {
+		cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
+		seq_printf(m, "processor %li: "
 				"version = %02X,  "
 				"identification = %06X,  "
 				"machine = %04X\n",
@@ -497,7 +531,7 @@
 
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
-	return *pos <= NR_CPUS ? (void)(*pos+1) : NULL;
+	return *pos <= NR_CPUS ? (void *)((unsigned long) *pos + 1) : NULL;
 }
 static void *c_next(struct seq_file *m, void *v, loff_t *pos)
 {
diff -Nru a/arch/s390x/kernel/signal.c b/arch/s390x/kernel/signal.c
--- a/arch/s390x/kernel/signal.c	Sat Jun  8 22:31:35 2002
+++ b/arch/s390x/kernel/signal.c	Sat Jun  8 22:31:35 2002
@@ -24,7 +24,9 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/tty.h>
 #include <linux/personality.h>
+#include <linux/binfmts.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
@@ -267,10 +269,10 @@
 
 static inline int map_signal(int sig)
 {
-	if (current->exec_domain
-	    && current->exec_domain->signal_invmap
+	if (current_thread_info()->exec_domain
+	    && current_thread_info()->exec_domain->signal_invmap
 	    && sig < 32)
-		return current->exec_domain->signal_invmap[sig];
+		return current_thread_info()->exec_domain->signal_invmap[sig];
 	else
 		return sig;
 }
@@ -301,6 +303,10 @@
 			goto give_sigsegv;
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -335,7 +341,7 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.uc_flags);
 	err |= __put_user(0, &frame->uc.uc_link);
-	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user((void*)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
 	err |= __put_user(sas_ss_flags(regs->gprs[15]),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
@@ -354,6 +360,10 @@
 	                          (u16 *)(frame->retcode));
 	}
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (addr_t *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -430,6 +440,7 @@
 int do_signal(struct pt_regs *regs, sigset_t *oldset)
 {
 	siginfo_t info;
+	int signr;
 
 	/*
 	 * We want the common case to go fast, which
diff -Nru a/arch/s390x/kernel/signal32.c b/arch/s390x/kernel/signal32.c
--- a/arch/s390x/kernel/signal32.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/signal32.c	Sat Jun  8 22:31:37 2002
@@ -23,14 +23,16 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/stddef.h>
+#include <linux/tty.h>
 #include <linux/personality.h>
+#include <linux/binfmts.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include "linux32.h"
 
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
-#define _USER_PSW_MASK32 0x0701C00080000000
+#define _USER_PSW_MASK32 0x0705C00080000000
 
 typedef struct 
 {
@@ -85,7 +87,8 @@
 			err |= __put_user(from->si_status, &to->si_status);
 			break;
 		case __SI_FAULT >> 16:
-			err |= __put_user(from->si_addr, &to->si_addr);
+			err |= __put_user((unsigned long) from->si_addr,
+					  &to->si_addr);
 			break;
 		case __SI_POLL >> 16:
 		case __SI_TIMER >> 16:
@@ -262,7 +265,7 @@
 	if (uss) {
 		if (!access_ok(VERIFY_READ, uss, sizeof(*uss)))
 			return -EFAULT;
-		err |= __get_user(kss.ss_sp, &uss->ss_sp);
+		err |= __get_user((unsigned long) kss.ss_sp, &uss->ss_sp);
 		err |= __get_user(kss.ss_size, &uss->ss_size);
 		err |= __get_user(kss.ss_flags, &uss->ss_flags);
 		if (err)
@@ -276,7 +279,7 @@
 	if (!ret && uoss) {
 		if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)))
 			return -EFAULT;
-		err |= __put_user(koss.ss_sp, &uoss->ss_sp);
+		err |= __put_user((unsigned long) koss.ss_sp, &uoss->ss_sp);
 		err |= __put_user(koss.ss_size, &uoss->ss_size);
 		err |= __put_user(koss.ss_flags, &uoss->ss_flags);
 		if (err)
@@ -369,6 +372,7 @@
 	rt_sigframe32 *frame = (rt_sigframe32 *)regs->gprs[15];
 	sigset_t set;
 	stack_t st;
+	__u32 ss_sp;
 	int err;
 	mm_segment_t old_fs = get_fs();
 
@@ -386,8 +390,8 @@
 	if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
 		goto badframe;
 
-	err = __get_user(st.ss_sp, &frame->uc.uc_stack.ss_sp);
-	st.ss_sp = (void *) A((unsigned long)st.ss_sp);
+	err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
+	st.ss_sp = (void *) A((unsigned long)ss_sp);
 	err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size);
 	err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags);
 	if (err)
@@ -440,10 +444,10 @@
 
 static inline int map_signal(int sig)
 {
-	if (current->exec_domain
-	    && current->exec_domain->signal_invmap
+	if (current_thread_info()->exec_domain
+	    && current_thread_info()->exec_domain->signal_invmap
 	    && sig < 32)
-		return current->exec_domain->signal_invmap[sig];
+		return current_thread_info()->exec_domain->signal_invmap[sig];
         else
 		return sig;
 }
@@ -460,7 +464,7 @@
 
 	if (save_sigregs32(regs, &frame->sregs))
 		goto give_sigsegv;
-	if (__put_user(&frame->sregs, &frame->sc.sregs))
+	if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
 		goto give_sigsegv;
 
 	/* Set up to return from userspace.  If provided, use a stub
@@ -474,6 +478,10 @@
 			goto give_sigsegv;
         }
 
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (unsigned int *) frame))
+		goto give_sigsegv;
+
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
 	regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
@@ -526,6 +534,10 @@
 		err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
 		                  (u16 *)(frame->retcode));
 	}
+
+	/* Set up backchain. */
+	if (__put_user(regs->gprs[15], (unsigned int *) frame))
+		goto give_sigsegv;
 
 	/* Set up registers for signal handler */
 	regs->gprs[15] = (addr_t)frame;
diff -Nru a/arch/s390x/kernel/smp.c b/arch/s390x/kernel/smp.c
--- a/arch/s390x/kernel/smp.c	Sat Jun  8 22:31:49 2002
+++ b/arch/s390x/kernel/smp.c	Sat Jun  8 22:31:49 2002
@@ -49,16 +49,15 @@
 static int       max_cpus = NR_CPUS;	  /* Setup configured maximum number of CPUs to activate	*/
 int              smp_num_cpus;
 struct _lowcore *lowcore_ptr[NR_CPUS];
-unsigned int     prof_multiplier[NR_CPUS];
-unsigned int     prof_old_multiplier[NR_CPUS];
-unsigned int     prof_counter[NR_CPUS];
 cycles_t         cacheflush_time=0;
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 static atomic_t  smp_commenced = ATOMIC_INIT(0);
 
 spinlock_t       kernel_flag __cacheline_aligned_in_smp = SPIN_LOCK_UNLOCKED;
 
-unsigned long	 cpu_online_map;
+volatile unsigned long phys_cpu_present_map;
+volatile unsigned long cpu_online_map;
+unsigned long    cache_decay_ticks = 0;
 
 /*
  *      Setup routine for controlling SMP activation
@@ -179,58 +178,123 @@
 	return 0;
 }
 
+static inline void do_send_stop(void)
+{
+        u32 dummy;
+        int i, rc;
+
+        /* stop all processors */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i)
+			continue;
+		do {
+			rc = signal_processor_ps(&dummy, 0, i, sigp_stop);
+		} while (rc == sigp_busy);
+        }
+}
+
+static inline void do_store_status(void)
+{
+        unsigned long low_core_addr;
+        u32 dummy;
+        int i, rc;
+
+        /* store status of all processors in their lowcores (real 0) */
+        for (i =  0; i < smp_num_cpus; i++) {
+                if (smp_processor_id() == i) 
+			continue;
+		low_core_addr = (unsigned long)get_cpu_lowcore(i);
+		do {
+			rc = signal_processor_ps(&dummy, low_core_addr, i,
+						 sigp_store_status_at_address);
+		} while(rc == sigp_busy);
+	}
+}
+
+/*
+ * this function sends a 'stop' sigp to all other CPUs in the system.
+ * it goes straight through.
+ */
+void smp_send_stop(void)
+{
+	/* write magic number to zero page (absolute 0) */
+	get_cpu_lowcore(smp_processor_id())->panic_magic = __PANIC_MAGIC;
+
+	/* stop other processors. */
+	do_send_stop();
+
+	/* store status of other processors. */
+	do_store_status();
+}
 
 /*
- * Various special callbacks
+ * Reboot, halt and power_off routines for SMP.
  */
+static volatile unsigned long cpu_restart_map;
 
-void do_machine_restart(void)
+static void do_machine_restart(void * __unused)
 {
-        smp_send_stop();
-	reipl(S390_lowcore.ipl_device);
+	clear_bit(smp_processor_id(), &cpu_restart_map);
+	if (smp_processor_id() == 0) {
+		/* Wait for all other cpus to enter do_machine_restart. */
+		while (cpu_restart_map != 0);
+		/* Store status of other cpus. */
+		do_store_status();
+		/*
+		 * Finally call reipl. Because we waited for all other
+		 * cpus to enter this function we know that they do
+		 * not hold any s390irq-locks (the cpus have been
+		 * interrupted by an external interrupt and s390irq
+		 * locks are always held disabled).
+		 */
+		reipl(S390_lowcore.ipl_device);
+	}
+	signal_processor(smp_processor_id(), sigp_stop);
 }
 
-void machine_restart(char * __unused) 
+void machine_restart_smp(char * __unused) 
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_restart);
-                for (;;);
-        } else
-                do_machine_restart();
+	cpu_restart_map = cpu_online_map;
+        smp_call_function(do_machine_restart, NULL, 0, 0);
+	do_machine_restart(NULL);
 }
 
-void do_machine_halt(void)
+static void do_machine_halt(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
-                cpcmd(vmhalt_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
+			cpcmd(vmhalt_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_halt(void)
+void machine_halt_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_halt);
-                for (;;);
-        } else
-                do_machine_halt();
+        smp_call_function(do_machine_halt, NULL, 0, 0);
+	do_machine_halt(NULL);
 }
 
-void do_machine_power_off(void)
+static void do_machine_power_off(void * __unused)
 {
-        smp_send_stop();
-        if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
-                cpcmd(vmpoff_cmd, NULL, 0);
-        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
+	if (smp_processor_id() == 0) {
+		smp_send_stop();
+		if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
+			cpcmd(vmpoff_cmd, NULL, 0);
+		signal_processor(smp_processor_id(),
+				 sigp_stop_and_store_status);
+	}
+	for (;;)
+		enabled_wait();
 }
 
-void machine_power_off(void)
+void machine_power_off_smp(void)
 {
-        if (smp_processor_id() != 0) {
-                smp_ext_bitcall(0, ec_power_off);
-                for (;;);
-        } else
-                do_machine_power_off();
+        smp_call_function(do_machine_power_off, NULL, 0, 0);
+	do_machine_power_off(NULL);
 }
 
 /*
@@ -247,17 +311,9 @@
          *
          * For the ec_schedule signal we have to do nothing. All the work
          * is done automatically when we return from the interrupt.
-	 * For the ec_restart, ec_halt and ec_power_off we call the
-         * appropriate routine.
          */
 	bits = xchg(&S390_lowcore.ext_call_fast, 0);
 
-        if (test_bit(ec_restart, &bits))
-		do_machine_restart();
-        if (test_bit(ec_halt, &bits))
-		do_machine_halt();
-        if (test_bit(ec_power_off, &bits))
-		do_machine_power_off();
         if (test_bit(ec_call_function, &bits))
 		do_call_function();
 }
@@ -273,7 +329,7 @@
         /*
          * Set signaling bit in lowcore of target cpu and kick it
          */
-	set_bit(sig, &(get_cpu_lowcore(cpu).ext_call_fast));
+	set_bit(sig, &(get_cpu_lowcore(cpu)->ext_call_fast));
         ccode = signal_processor(cpu, sigp_external_call);
         return ccode;
 }
@@ -284,7 +340,6 @@
  */
 static void smp_ext_bitcall_others(ec_bit_sig sig)
 {
-        sigp_ccode ccode;
         int i;
 
         for (i = 0; i < smp_num_cpus; i++) {
@@ -293,55 +348,9 @@
                 /*
                  * Set signaling bit in lowcore of target cpu and kick it
                  */
-		set_bit(sig, &(get_cpu_lowcore(i).ext_call_fast));
-                ccode = signal_processor(i, sigp_external_call);
-        }
-}
-
-/*
- * this function sends a 'stop' sigp to all other CPUs in the system.
- * it goes straight through.
- */
-
-void smp_send_stop(void)
-{
-        int i;
-        u32 dummy;
-        unsigned long low_core_addr;
-
-        /* write magic number to zero page (absolute 0) */
-
-        get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC;
-
-        /* stop all processors */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   0,
-                                   i,
-                                   sigp_stop);
-                        } while(ccode == sigp_busy);
-                }
-        }
-
-        /* store status of all processors in their lowcores (real 0) */
-
-        for (i =  0; i < smp_num_cpus; i++) {
-                if (smp_processor_id() != i) {
-                        int ccode;
-                        low_core_addr = (unsigned long)&get_cpu_lowcore(i);
-                        do {
-                                ccode = signal_processor_ps(
-                                   &dummy,
-                                   low_core_addr,
-                                   i,
-                                   sigp_store_status_at_address);
-                        } while(ccode == sigp_busy);
-                }
+		set_bit(sig, &(get_cpu_lowcore(i)->ext_call_fast));
+                while (signal_processor(i, sigp_external_call) == sigp_busy)
+			udelay(10);
         }
 }
 
@@ -433,8 +442,10 @@
 {
         int curr_cpu;
 
-        current->processor = 0;
+        current_thread_info()->cpu = 0;
         smp_num_cpus = 1;
+	phys_cpu_present_map = 1;
+        cpu_online_map = 1;
         for (curr_cpu = 0;
              curr_cpu <= 65535 && smp_num_cpus < max_cpus; curr_cpu++) {
                 if ((__u16) curr_cpu == boot_cpu_addr)
@@ -443,6 +454,7 @@
                 if (signal_processor(smp_num_cpus, sigp_sense) ==
                     sigp_not_operational)
                         continue;
+		set_bit(smp_num_cpus, &phys_cpu_present_map);
                 smp_num_cpus++;
         }
         printk("Detected %d CPU's\n",(int) smp_num_cpus);
@@ -453,20 +465,22 @@
 /*
  *      Activate a secondary processor.
  */
-extern void init_100hz_timer(void);
+extern void init_cpu_timer(void);
 extern int pfault_init(void);
 
 int __init start_secondary(void *cpuvoid)
 {
         /* Setup the cpu */
         cpu_init();
+	/* Mark this cpu as online. */
+	set_bit(smp_processor_id(), &cpu_online_map);
         /* Print info about this processor */
-        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id())->cpu_data);
         /* Wait for completion of smp startup */
         while (!atomic_read(&smp_commenced))
                 /* nothing */ ;
-        /* init per CPU 100 hz timer */
-        init_100hz_timer();
+        /* init per CPU timer */
+        init_cpu_timer();
 #ifdef CONFIG_PFAULT
 	/* Enable pfault pseudo page faults on this cpu. */
 	pfault_init();
@@ -475,15 +489,6 @@
         return cpu_idle(NULL);
 }
 
-/*
- * The restart interrupt handler jumps to start_secondary directly
- * without the detour over initialize_secondary. We defined it here
- * so that the linker doesn't complain.
- */
-void __init initialize_secondary(void)
-{
-}
-
 static struct task_struct * __init fork_by_hand(void)
 {
        struct pt_regs regs;
@@ -508,16 +513,13 @@
          * We remove it from the pidhash and the runqueue
          * once we got the process:
          */
-        idle->processor = cpu;
-	idle->cpus_runnable = 1 << cpu; /* we schedule the first task manually */
+	init_idle(idle, cpu);
 
-        del_from_runqueue(idle);
         unhash_process(idle);
-        init_tasks[cpu] = idle;
 
-        cpu_lowcore=&get_cpu_lowcore(cpu);
+        cpu_lowcore = get_cpu_lowcore(cpu);
 	cpu_lowcore->save_area[15] = idle->thread.ksp;
-	cpu_lowcore->kernel_stack = (idle->thread.ksp | 16383) + 1;
+	cpu_lowcore->kernel_stack = (__u64) idle->thread_info + 16384;
         __asm__ __volatile__("la    1,%0\n\t"
 			     "stctg 0,15,0(1)\n\t"
 			     "la    1,%1\n\t"
@@ -528,8 +530,6 @@
 
         eieio();
         signal_processor(cpu,sigp_restart);
-	/* Mark this cpu as online. */
-	set_bit(cpu, &cpu_online_map);
 }
 
 /*
@@ -556,7 +556,6 @@
 
 void __init smp_boot_cpus(void)
 {
-        struct _lowcore *curr_lowcore;
 	unsigned long async_stack;
         sigp_ccode   ccode;
         int i;
@@ -569,55 +568,37 @@
         
         /*
          *      Initialize the logical to physical CPU number mapping
-         *      and the per-CPU profiling counter/multiplier
          */
-        
-        for (i = 0; i < NR_CPUS; i++) {
-                prof_counter[i] = 1;
-                prof_old_multiplier[i] = 1;
-                prof_multiplier[i] = 1;
-        }
+        print_cpu_info(&safe_get_cpu_lowcore(0)->cpu_data);
 
-        print_cpu_info(&safe_get_cpu_lowcore(0).cpu_data);
-
-        for(i = 0; i < smp_num_cpus; i++)
-        {
-                curr_lowcore = (struct _lowcore *)
+        for(i = 0; i < smp_num_cpus; i++) {
+                lowcore_ptr[i] = (struct _lowcore *)
                                     __get_free_pages(GFP_KERNEL|GFP_DMA, 1);
-                if (curr_lowcore == NULL) {
-                        printk("smp_boot_cpus failed to allocate prefix memory\n");
-                        break;
-                }
 		async_stack = __get_free_pages(GFP_KERNEL,2);
-		if (async_stack == 0) {
-			printk("smp_boot_cpus failed to allocate asyncronous"
-			       " interrupt stack\n");
-			free_page((unsigned long) curr_lowcore);
-			break;
-		}
-                lowcore_ptr[i] = curr_lowcore;
-                memcpy(curr_lowcore, &S390_lowcore, sizeof(struct _lowcore));
-		curr_lowcore->async_stack = async_stack + (4 * PAGE_SIZE);
+		if (lowcore_ptr[i] == NULL || async_stack == 0ULL)
+			panic("smp_boot_cpus failed to allocate memory\n");
+                memcpy(lowcore_ptr[i], &S390_lowcore, sizeof(struct _lowcore));
+		lowcore_ptr[i]->async_stack = async_stack + (4 * PAGE_SIZE);
                 /*
                  * Most of the parameters are set up when the cpu is
                  * started up.
                  */
-                if (smp_processor_id() == i)
-                        set_prefix((u32)(u64)curr_lowcore);
-                else {
-                        ccode = signal_processor_p((u64)(curr_lowcore),
-                                                   i, sigp_set_prefix);
-                        if(ccode) {
-                                /* if this gets troublesome I'll have to do
-                                 * something about it. */
-                                printk("ccode %d for cpu %d  returned when "
-                                       "setting prefix in smp_boot_cpus not good.\n",
-                                       (int) ccode, (int) i);
-                        }
-                        else
-                                do_boot_cpu(i);
-                }
+                if (smp_processor_id() == i) {
+                        set_prefix((u32)(u64) lowcore_ptr[i]);
+			continue;
+		}
+		ccode = signal_processor_p((u64) lowcore_ptr[i],
+					   i, sigp_set_prefix);
+		if(ccode)
+			panic("sigp_set_prefix failed for cpu %d "
+			      "with condition code %d\n",
+			      (int) i, (int) ccode);
+		do_boot_cpu(i);
         }
+	/*
+	 * Now wait until all of the cpus are online.
+	 */
+	while (phys_cpu_present_map != cpu_online_map);
 }
 
 /*
@@ -631,58 +612,9 @@
         return 0;
 }
 
-/*
- * Local timer interrupt handler. It does both profiling and
- * process statistics/rescheduling.
- *
- * We do profiling in every local tick, statistics/rescheduling
- * happen only every 'profiling multiplier' ticks. The default
- * multiplier is 1 and it can be changed by writing the new multiplier
- * value into /proc/profile.
- */
-
-void smp_local_timer_interrupt(struct pt_regs * regs)
-{
-	int user = (user_mode(regs) != 0);
-        int cpu = smp_processor_id();
-
-        /*
-         * The profiling function is SMP safe. (nothing can mess
-         * around with "current", and the profiling counters are
-         * updated with atomic operations). This is especially
-         * useful with a profiling multiplier != 1
-         */
-        if (!user_mode(regs))
-                s390_do_profile(regs->psw.addr);
-
-        if (!--prof_counter[cpu]) {
-
-                /*
-                 * The multiplier may have changed since the last time we got
-                 * to this point as a result of the user writing to
-                 * /proc/profile.  In this case we need to adjust the APIC
-                 * timer accordingly.
-                 *
-                 * Interrupts are already masked off at this point.
-                 */
-                prof_counter[cpu] = prof_multiplier[cpu];
-                if (prof_counter[cpu] != prof_old_multiplier[cpu]) {
-                  prof_old_multiplier[cpu] = prof_counter[cpu];
-                }
-
-                /*
-                 * After doing the above, we need to make like
-                 * a normal interrupt - otherwise timer interrupts
-                 * ignore the global interrupt lock, which is the
-                 * WrongThing (tm) to do.
-                 */
-
-		update_process_times(user);
-        }
-}
-
 EXPORT_SYMBOL(lowcore_ptr);
 EXPORT_SYMBOL(kernel_flag);
 EXPORT_SYMBOL(smp_ctl_set_bit);
 EXPORT_SYMBOL(smp_ctl_clear_bit);
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
diff -Nru a/arch/s390x/kernel/sys_s390.c b/arch/s390x/kernel/sys_s390.c
--- a/arch/s390x/kernel/sys_s390.c	Sat Jun  8 22:31:52 2002
+++ b/arch/s390x/kernel/sys_s390.c	Sat Jun  8 22:31:52 2002
@@ -24,6 +24,7 @@
 #include <linux/mman.h>
 #include <linux/file.h>
 #include <linux/utsname.h>
+#include <linux/personality.h>
 
 #include <asm/uaccess.h>
 #include <asm/ipc.h>
@@ -203,3 +204,30 @@
 	return -ERESTARTNOHAND;
 }
 
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
+asmlinkage int s390x_newuname(struct new_utsname * name)
+{
+	int ret = sys_newuname(name);
+
+	if (current->personality == PER_LINUX32 && !ret) {
+		ret = copy_to_user(name->machine, "s390\0\0\0\0", 8);
+		if (ret) ret = -EFAULT;
+	}
+	return ret;
+}
+
+extern asmlinkage long sys_personality(unsigned long);
+
+asmlinkage int s390x_personality(unsigned long personality)
+{
+	int ret;
+
+	if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+		personality = PER_LINUX32;
+	ret = sys_personality(personality);
+	if (ret == PER_LINUX32)
+		ret = PER_LINUX;
+
+	return ret;
+}
diff -Nru a/arch/s390x/kernel/time.c b/arch/s390x/kernel/time.c
--- a/arch/s390x/kernel/time.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/time.c	Sat Jun  8 22:31:37 2002
@@ -33,65 +33,34 @@
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 
-
 /* change this if you have some constant time drift */
-#define USECS_PER_JIFFY ((signed long)1000000/HZ)
-#define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12)
+#define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
+#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
 #define TICK_SIZE tick
 
-static uint64_t init_timer_cc, last_timer_cc;
+static ext_int_info_t ext_int_info_timer;
+static uint64_t init_timer_cc;
 
 extern rwlock_t xtime_lock;
 extern unsigned long wall_jiffies;
 
-void tod_to_timeval(uint64_t todval, struct timeval *xtime)
+void tod_to_timeval(__u64 todval, struct timeval *xtime)
 {
-#if 0
-        const int high_bit = 0x80000000L;
-        const int c_f4240 = 0xf4240L;
-        const int c_7a120 = 0x7a120;
-	/* We have to divide the 64 bit value todval by 4096
-	 * (because the 2^12 bit is the one that changes every 
-         * microsecond) and then split it into seconds and
-         * microseconds. A value of max (2^52-1) divided by
-         * the value 0xF4240 can yield a max result of approx
-         * (2^32.068). Thats to big to fit into a signed int
-	 *   ... hacking time!
-         */
-	asm volatile ("L     2,%1\n\t"
-		      "LR    3,2\n\t"
-		      "SRL   2,12\n\t"
-		      "SLL   3,20\n\t"
-		      "L     4,%O1+4(%R1)\n\t"
-		      "SRL   4,12\n\t"
-		      "OR    3,4\n\t"  /* now R2/R3 contain (todval >> 12) */
-		      "SR    4,4\n\t"
-		      "CL    2,%2\n\t"
-		      "JL    .+12\n\t"
-		      "S     2,%2\n\t"
-		      "L     4,%3\n\t"
-                      "D     2,%4\n\t"
-		      "OR    3,4\n\t"
-		      "ST    2,%O0+4(%R0)\n\t"
-		      "ST    3,%0"
-		      : "=m" (*xtime) : "m" (todval),
-		        "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
-		      : "cc", "memory", "2", "3", "4" );
-#else
-    todval >>= 12;
-    xtime->tv_sec = todval / 1000000;
-    xtime->tv_usec = todval % 1000000;
-#endif
+        todval >>= 12;
+        xtime->tv_sec = todval / 1000000;
+        xtime->tv_usec = todval % 1000000;
 }
 
-unsigned long do_gettimeoffset(void) 
+static inline unsigned long do_gettimeoffset(void) 
 {
-	__u64 timer_cc;
+	__u64 now;
 
-	asm volatile ("STCK %0" : "=m" (timer_cc));
-        /* We require the offset from the previous interrupt */
-        return ((unsigned long)((timer_cc - last_timer_cc)>>12));
+	asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
+        now = (now - init_timer_cc) >> 12;
+	/* We require the offset from the latest update of xtime */
+	now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
+	return (unsigned long) now;
 }
 
 /*
@@ -101,15 +70,10 @@
 {
 	unsigned long flags;
 	unsigned long usec, sec;
-	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);
 	sec = xtime.tv_sec;
-	usec += xtime.tv_usec;
+	usec = xtime.tv_usec + do_gettimeoffset();
 	read_unlock_irqrestore(&xtime_lock, flags);
 
 	while (usec >= 1000000) {
@@ -155,51 +119,31 @@
 extern __u16 boot_cpu_addr;
 #endif
 
-void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
+static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
 {
 	int cpu = smp_processor_id();
 
 	irq_enter(cpu, 0);
 
-        /*
-         * reset timer to 10ms minus time already elapsed
-         * since timer-interrupt pending
-         */
+	/*
+	 * set clock comparator for next tick
+	 */
+        S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
+        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
+
 #ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
 		write_lock(&xtime_lock);
-		last_timer_cc = S390_lowcore.jiffy_timer_cc;
-	}
-#else
-        last_timer_cc = S390_lowcore.jiffy_timer_cc;
-#endif
-        /* set clock comparator */
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
 
-/*
- * In the SMP case we use the local timer interrupt to do the
- * profiling, except when we simulate SMP mode on a uniprocessor
- * system, in that case we have to call the local interrupt handler.
- */
-#ifdef CONFIG_SMP
-        /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
-           but only do the rest for the boot CPU */
-        smp_local_timer_interrupt(regs);
-#else
-        if (!user_mode(regs))
-                s390_do_profile(regs->psw.addr);
-#endif
+	update_process_times(user_mode(regs));
 
-#ifdef CONFIG_SMP
-	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
-#endif
-	{
+	if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
 		do_timer(regs);
-#ifdef CONFIG_SMP
 		write_unlock(&xtime_lock);
-#endif
 	}
+#else
+	do_timer(regs);
+#endif
 
 	irq_exit(cpu, 0);
 }
@@ -207,19 +151,17 @@
 /*
  * Start the clock comparator on the current CPU
  */
-static unsigned long cr0 __attribute__ ((aligned (8)));
-
-void init_100hz_timer(void)
+void init_cpu_timer(void)
 {
+	unsigned long cr0;
+
         /* allow clock comparator timer interrupt */
         asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
         cr0 |= 0x800;
         asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
-        /* set clock comparator */
-        /* read the TOD clock */
-        asm volatile ("STCK %0" : "=m" (S390_lowcore.jiffy_timer_cc));
-        S390_lowcore.jiffy_timer_cc += CLK_TICKS_PER_JIFFY;
-        asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer_cc));
+	S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
+	S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
+	asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
 }
 
 /*
@@ -228,12 +170,14 @@
  */
 void __init time_init(void)
 {
+        __u64 set_time_cc;
 	int cc;
 
         /* kick the TOD clock */
-        asm volatile ("STCK %1\n\t"
+        asm volatile ("STCK 0(%1)\n\t"
                       "IPM  %0\n\t"
-                      "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
+                      "SRL  %0,28" : "=r" (cc) : "a" (&init_timer_cc) 
+				   : "memory", "cc");
         switch (cc) {
         case 0: /* clock in set state: all is fine */
                 break;
@@ -247,12 +191,17 @@
                 printk("time_init: TOD clock stopped/non-operational\n");
                 break;
         }
+
+	/* set xtime */
+        set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
+                      (0x3c26700LL*1000000*4096);
+        tod_to_timeval(set_time_cc, &xtime);
+
         /* request the 0x1004 external interrupt */
-        if (register_external_interrupt(0x1004, do_timer_interrupt) != 0)
-                panic("Couldn't request external interrupts 0x1004");
-        init_100hz_timer();
-        init_timer_cc = S390_lowcore.jiffy_timer_cc;
-        init_timer_cc -= 0x8126d60e46000000LL -
-                         (0x3c26700LL*1000000*4096);
-        tod_to_timeval(init_timer_cc, &xtime);
+        if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
+					      &ext_int_info_timer) != 0)
+                panic("Couldn't request external interrupt 0x1004");
+
+        /* init CPU timer */
+        init_cpu_timer();
 }
diff -Nru a/arch/s390x/kernel/traps.c b/arch/s390x/kernel/traps.c
--- a/arch/s390x/kernel/traps.c	Sat Jun  8 22:31:51 2002
+++ b/arch/s390x/kernel/traps.c	Sat Jun  8 22:31:51 2002
@@ -26,6 +26,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/module.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -51,13 +52,214 @@
 #endif
 #endif
 
-extern pgm_check_handler_t do_page_fault;
+extern pgm_check_handler_t do_protection_exception;
+extern pgm_check_handler_t do_segment_exception;
+extern pgm_check_handler_t do_region_exception;
+extern pgm_check_handler_t do_page_exception;
 #ifdef CONFIG_PFAULT
 extern int pfault_init(void);
 extern void pfault_fini(void);
 extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+static ext_int_info_t ext_int_pfault;
 #endif
 
+int kstack_depth_to_print = 20;
+
+/*
+ * If the address is either in the .text section of the
+ * kernel, or in the vmalloc'ed module regions, it *may* 
+ * be the address of a calling routine
+ */
+extern char _stext, _etext;
+
+#ifdef CONFIG_MODULES
+
+extern struct module *module_list;
+extern struct module kernel_module;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	int retval = 0;
+	struct module *mod;
+
+	if (addr >= (unsigned long) &_stext &&
+	    addr <= (unsigned long) &_etext)
+		return 1;
+
+	for (mod = module_list; mod != &kernel_module; mod = mod->next) {
+		/* mod_bound tests for addr being inside the vmalloc'ed
+		 * module area. Of course it'd be better to test only
+		 * for the .text subset... */
+		if (mod_bound(addr, 0, mod)) {
+			retval = 1;
+			break;
+		}
+	}
+
+	return retval;
+}
+
+#else
+
+static inline int kernel_text_address(unsigned long addr)
+{
+	return (addr >= (unsigned long) &_stext &&
+		addr <= (unsigned long) &_etext);
+}
+
+#endif
+
+void show_trace(unsigned long * stack)
+{
+	unsigned long backchain, low_addr, high_addr, ret_addr;
+	int i;
+
+	if (!stack)
+		stack = (unsigned long*)&stack;
+
+	printk("Call Trace: ");
+	low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
+	high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
+	/* Skip the first frame (biased stack) */
+	backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
+	/* Print up to 8 lines */
+	for (i = 0; i < 8; i++) {
+		if (backchain < low_addr || backchain >= high_addr)
+			break;
+		ret_addr = *((unsigned long *) (backchain+112)) & PSW_ADDR_MASK;
+		if (!kernel_text_address(ret_addr))
+			break;
+		if (i && ((i % 3) == 0))
+			printk("\n   ");
+		printk("[<%016lx>] ", ret_addr);
+		low_addr = backchain;
+		backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
+	}
+	printk("\n");
+}
+
+void show_trace_task(struct task_struct *tsk)
+{
+	/*
+	 * We can't print the backtrace of a running process. It is
+	 * unreliable at best and can cause kernel oopses.
+	 */
+	if (tsk->state == TASK_RUNNING)
+		return;
+	show_trace((unsigned long *) tsk->thread.ksp);
+}
+
+void show_stack(unsigned long *sp)
+{
+	unsigned long *stack;
+	int i;
+
+	// debugging aid: "show_stack(NULL);" prints the
+	// back trace for this cpu.
+
+	if (sp == NULL)
+		sp = (unsigned long*) &sp;
+
+	stack = sp;
+	for (i = 0; i < kstack_depth_to_print; i++) {
+		if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
+			break;
+		if (i && ((i % 4) == 0))
+			printk("\n       ");
+		printk("%016lx ", *stack++);
+	}
+	printk("\n");
+	show_trace(sp);
+}
+
+void show_registers(struct pt_regs *regs)
+{
+	mm_segment_t old_fs;
+	char *mode;
+	int i;
+
+	mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
+	printk("%s PSW : %016lx %016lx\n",
+	       mode, (unsigned long) regs->psw.mask,
+	       (unsigned long) regs->psw.addr);
+	printk("%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
+	       regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
+	printk("           %016lx %016lx %016lx %016lx\n",
+	       regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
+	printk("           %016lx %016lx %016lx %016lx\n",
+	       regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
+	printk("           %016lx %016lx %016lx %016lx\n",
+	       regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
+	printk("%s ACRS: %08x %08x %08x %08x\n", mode,
+	       regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
+	printk("           %08x %08x %08x %08x\n",
+	       regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
+
+	/*
+	 * Print the first 20 byte of the instruction stream at the
+	 * time of the fault.
+	 */
+	old_fs = get_fs();
+	if (regs->psw.mask & PSW_PROBLEM_STATE)
+		set_fs(USER_DS);
+	else
+		set_fs(KERNEL_DS);
+	printk("%s Code: ", mode);
+	for (i = 0; i < 20; i++) {
+		unsigned char c;
+		if (__get_user(c, (char *)(regs->psw.addr + i))) {
+			printk(" Bad PSW.");
+			break;
+		}
+		printk("%02x ", c);
+	}
+	set_fs(old_fs);
+
+	printk("\n");
+}	
+
+/* This is called from fs/proc/array.c */
+char *task_show_regs(struct task_struct *task, char *buf)
+{
+	struct pt_regs *regs;
+
+	regs = __KSTK_PTREGS(task);
+	buf += sprintf(buf, "task: %016lx, ksp: %016lx\n",
+		       (unsigned long) task, task->thread.ksp);
+	buf += sprintf(buf, "User PSW : %016lx %016lx\n",
+		       (unsigned long) regs->psw.mask, 
+		       (unsigned long) regs->psw.addr);
+	buf += sprintf(buf, "User GPRS: %016lx %016lx %016lx %016lx\n",
+		       regs->gprs[0], regs->gprs[1],
+		       regs->gprs[2], regs->gprs[3]);
+	buf += sprintf(buf, "           %016lx %016lx %016lx %016lx\n",
+		       regs->gprs[4], regs->gprs[5], 
+		       regs->gprs[6], regs->gprs[7]);
+	buf += sprintf(buf, "           %016lx %016lx %016lx %016lx\n",
+		       regs->gprs[8], regs->gprs[9],
+		       regs->gprs[10], regs->gprs[11]);
+	buf += sprintf(buf, "           %016lx %016lx %016lx %016lx\n",
+		       regs->gprs[12], regs->gprs[13],
+		       regs->gprs[14], regs->gprs[15]);
+	buf += sprintf(buf, "User ACRS: %08x %08x %08x %08x\n",
+		       regs->acrs[0], regs->acrs[1],
+		       regs->acrs[2], regs->acrs[3]);
+	buf += sprintf(buf, "           %08x %08x %08x %08x\n",
+		       regs->acrs[4], regs->acrs[5],
+		       regs->acrs[6], regs->acrs[7]);
+	buf += sprintf(buf, "           %08x %08x %08x %08x\n",
+		       regs->acrs[8], regs->acrs[9],
+		       regs->acrs[10], regs->acrs[11]);
+	buf += sprintf(buf, "           %08x %08x %08x %08x\n",
+		       regs->acrs[12], regs->acrs[13],
+		       regs->acrs[14], regs->acrs[15]);
+	return buf;
+}
+
 spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char * str, struct pt_regs * regs, long err)
@@ -72,23 +274,6 @@
         do_exit(SIGSEGV);
 }
 
-#define DO_ERROR(signr, str, name) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-	do_trap(interruption_code, signr, str, regs, NULL); \
-}
-
-#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
-{ \
-        siginfo_t info; \
-        info.si_signo = signr; \
-        info.si_errno = 0; \
-        info.si_code = sicode; \
-        info.si_addr = (void *)siaddr; \
-        do_trap(interruption_code, signr, str, regs, &info); \
-}
-
 static void inline do_trap(long interruption_code, int signr, char *str,
                            struct pt_regs *regs, siginfo_t *info)
 {
@@ -101,7 +286,7 @@
 
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 struct task_struct *tsk = current;
-                tsk->thread.trap_no = interruption_code;
+                tsk->thread.trap_no = interruption_code & 0xffff;
 		if (info)
 			force_sig_info(signr, info, tsk);
 		else
@@ -128,6 +313,11 @@
         }
 }
 
+static inline void *get_check_address(struct pt_regs *regs)
+{
+	return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
+}
+
 int do_debugger_trap(struct pt_regs *regs,int signal)
 {
 	if(regs->psw.mask&PSW_PROBLEM_STATE)
@@ -142,7 +332,7 @@
 #if CONFIG_REMOTE_DEBUG
 		if(gdb_stub_initialised)
 		{
-			gdb_stub_handle_exception((gdb_pt_regs *)regs,signal);
+			gdb_stub_handle_exception(regs, signal);
 			return 0;
 		}
 #endif
@@ -151,15 +341,70 @@
 	return 0;
 }
 
+#define DO_ERROR(signr, str, name) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+	do_trap(interruption_code, signr, str, regs, NULL); \
+}
+
+#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
+asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+{ \
+        siginfo_t info; \
+        info.si_signo = signr; \
+        info.si_errno = 0; \
+        info.si_code = sicode; \
+        info.si_addr = (void *)siaddr; \
+        do_trap(interruption_code, signr, str, regs, &info); \
+}
+
 DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
-DO_ERROR(SIGILL,  "privileged operation", privileged_op)
-DO_ERROR(SIGILL,  "execute exception", execute_exception)
-DO_ERROR(SIGSEGV, "addressing exception", addressing_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)
-DO_ERROR(SIGILL,  "specification exception", specification_exception);
+
+DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
+	      BUS_ADRERR, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
+	      FPE_INTDIV, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
+	      ILL_PRVOPC, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "specification exception", specification_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
+	      ILL_ILLOPN, get_check_address(regs))
+
+static inline void
+do_fp_trap(struct pt_regs *regs, void *location,
+           int fpc, long interruption_code)
+{
+	siginfo_t si;
+
+	si.si_signo = SIGFPE;
+	si.si_errno = 0;
+	si.si_addr = location;
+	si.si_code = 0;
+	/* FPC[2] is Data Exception Code */
+	if ((fpc & 0x00000300) == 0) {
+		/* bits 6 and 7 of DXC are 0 iff IEEE exception */
+		if (fpc & 0x8000) /* invalid fp operation */
+			si.si_code = FPE_FLTINV;
+		else if (fpc & 0x4000) /* div by 0 */
+			si.si_code = FPE_FLTDIV;
+		else if (fpc & 0x2000) /* overflow */
+			si.si_code = FPE_FLTOVF;
+		else if (fpc & 0x1000) /* underflow */
+			si.si_code = FPE_FLTUND;
+		else if (fpc & 0x0800) /* inexact */
+			si.si_code = FPE_FLTRES;
+	}
+	current->thread.ieee_instruction_pointer = (addr_t) location;
+	do_trap(interruption_code, SIGFPE,
+		"floating point exception", regs, &si);
+}
 
 asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 {
@@ -167,7 +412,7 @@
 	__u16 *location;
 	int do_sig = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -192,15 +437,15 @@
 	else
 		do_sig = 1;
 	if (do_sig)
-		do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
+		do_trap(interruption_code, SIGILL,
+			"illegal operation", regs, NULL);
 }
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
 {
 	__u16 *location;
-	int do_sig = 0;
 
-	location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
+	location = (__u16 *) get_check_address(regs);
 
 	/*
 	 * We got all needed information from the lowcore and can
@@ -211,17 +456,19 @@
 
 	__asm__ volatile ("stfpc %0\n\t" 
 			  : "=m" (current->thread.fp_regs.fpc));
-	/* Same code should work when we implement fpu emulation */
-	/* provided we call data exception from the fpu emulator */
-	if(current->thread.fp_regs.fpc&FPC_DXC_MASK)
-	{
-		current->thread.ieee_instruction_pointer=(addr_t)location;
-		force_sig(SIGFPE, current);
+
+	if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
+		do_fp_trap(regs, location,
+                           current->thread.fp_regs.fpc, interruption_code);
+        else {
+		siginfo_t info;
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLOPN;
+		info.si_addr = location;
+		do_trap(interruption_code, SIGILL, 
+			"data exception", regs, &info);
 	}
-	else
-		do_sig = 1;
-        if (do_sig)
-                do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
 }
 
 
@@ -237,6 +484,7 @@
         pgm_check_table[1] = &illegal_op;
         pgm_check_table[2] = &privileged_op;
         pgm_check_table[3] = &execute_exception;
+        pgm_check_table[4] = &do_protection_exception;
         pgm_check_table[5] = &addressing_exception;
         pgm_check_table[6] = &specification_exception;
         pgm_check_table[7] = &data_exception;
@@ -244,24 +492,25 @@
         pgm_check_table[0x12] = &translation_exception;
         pgm_check_table[0x13] = &special_op_exception;
         pgm_check_table[0x15] = &operand_exception;
-        pgm_check_table[4] = &do_page_fault;
-        pgm_check_table[0x10] = &do_page_fault;
-        pgm_check_table[0x11] = &do_page_fault;
+        pgm_check_table[0x10] = &do_segment_exception;
+        pgm_check_table[0x11] = &do_page_exception;
         pgm_check_table[0x1C] = &privileged_op;
         pgm_check_table[0x38] = &addressing_exception;
-        pgm_check_table[0x3B] = &do_page_fault;
+        pgm_check_table[0x3B] = &do_region_exception;
 #ifdef CONFIG_PFAULT
 	if (MACHINE_IS_VM) {
 		/* request the 0x2603 external interrupt */
-		if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+		if (register_early_external_interrupt(0x2603, pfault_interrupt,
+						      &ext_int_pfault) != 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);
+			unregister_early_external_interrupt(0x2603,
+							    pfault_interrupt,
+							    &ext_int_pfault);
 		}
 	}
 #endif
diff -Nru a/arch/s390x/kernel/wrapper32.S b/arch/s390x/kernel/wrapper32.S
--- a/arch/s390x/kernel/wrapper32.S	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/kernel/wrapper32.S	Sat Jun  8 22:31:37 2002
@@ -120,8 +120,8 @@
 	lgfr	%r2,%r2			# long
 	lgfr	%r3,%r3			# long
 	llgtr	%r4,%r4			# long
-	lgfr	%r5,%r5			# long
-	jg	sys32_ptrace		# branch to system call
+	llgfr	%r5,%r5			# long
+	jg	sys_ptrace		# branch to system call
 
 	.globl  sys32_alarm_wrapper 
 sys32_alarm_wrapper:
@@ -311,6 +311,12 @@
 	llgtr	%r3,%r3			# struct rlimit_emu31 *
 	jg	sys32_old_getrlimit	# branch to system call
 
+	.globl  sys32_getrlimit_wrapper 
+sys32_getrlimit_wrapper:
+	llgfr	%r2,%r2			# unsigned int
+	llgtr	%r3,%r3			# struct rlimit_emu31 *
+	jg	sys32_getrlimit		# branch to system call
+
 	.globl  sys32_mmap2_wrapper 
 sys32_mmap2_wrapper:
 	llgtr	%r2,%r2			# struct mmap_arg_struct_emu31 *
@@ -537,7 +543,7 @@
 	.globl  sys32_newuname_wrapper 
 sys32_newuname_wrapper:
 	llgtr	%r2,%r2			# struct new_utsname *
-	jg	sys_newuname		# branch to system call
+	jg	s390x_newuname		# branch to system call
 
 	.globl  sys32_adjtimex_wrapper 
 sys32_adjtimex_wrapper:
@@ -614,7 +620,7 @@
 	.globl  sys32_personality_wrapper 
 sys32_personality_wrapper:
 	llgfr	%r2,%r2			# unsigned long
-	jg	sys_personality		# branch to system call
+	jg	s390x_personality	# branch to system call
 
 	.globl  sys32_setfsuid16_wrapper 
 sys32_setfsuid16_wrapper:
@@ -1085,9 +1091,130 @@
 	llgfr	%r4,%r4			# long
 	jg	sys32_lstat64		# branch to system call
 
+	.globl	sys32_stime_wrapper
+sys32_stime_wrapper:
+	llgtr	%r2,%r2			# int *
+	jg	sys_stime		# branch to system call
+
+	.globl  sys32_sysctl_wrapper
+sys32_sysctl_wrapper:
+	llgtr   %r2,%r2                 # struct __sysctl_args32 *
+	jg      sys32_sysctl
+
 	.globl	sys32_fstat64_wrapper
 sys32_fstat64_wrapper:
 	llgfr	%r2,%r2			# unsigned long
 	llgtr	%r3,%r3			# struct stat64 *
 	llgfr	%r4,%r4			# long
 	jg	sys32_fstat64		# branch to system call
+
+	.globl  sys32_futex_wrapper 
+sys32_futex_wrapper:
+	llgtr	%r2,%r2			# void *
+	lgfr	%r3,%r3			# int
+	jg	sys_futex		# branch to system call
+
+	.globl	sys32_setxattr_wrapper
+sys32_setxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	lgfr	%r6,%r6			# int
+	jg	sys_setxattr
+
+	.globl	sys32_lsetxattr_wrapper
+sys32_lsetxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	lgfr	%r6,%r6			# int
+	jg	sys_lsetxattr
+
+	.globl	sys32_fsetxattr_wrapper
+sys32_fsetxattr_wrapper:
+	lgfr	%r2,%r2			# int
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	lgfr	%r6,%r6			# int
+	jg	sys_fsetxattr
+
+	.globl	sys32_getxattr_wrapper
+sys32_getxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	jg	sys_getxattr
+
+	.globl	sys32_lgetxattr_wrapper
+sys32_lgetxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	jg	sys_lgetxattr
+
+	.globl	sys32_fgetxattr_wrapper
+sys32_fgetxattr_wrapper:
+	lgfr	%r2,%r2			# int
+	llgtr	%r3,%r3			# char *
+	llgtr	%r4,%r4			# void *
+	llgfr	%r5,%r5			# size_t
+	jg	sys_fgetxattr
+
+	.globl	sys32_listxattr_wrapper
+sys32_listxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgfr	%r4,%r4			# size_t
+	jg	sys_listxattr
+
+	.globl	sys32_llistxattr_wrapper
+sys32_llistxattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	llgfr	%r4,%r4			# size_t
+	jg	sys_llistxattr
+
+	.globl	sys32_flistxattr_wrapper
+sys32_flistxattr_wrapper:
+	lgfr	%r2,%r2			# int
+	llgtr	%r3,%r3			# char *
+	llgfr	%r4,%r4			# size_t
+	jg	sys_flistxattr
+
+	.globl	sys32_removexattr_wrapper
+sys32_removexattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	jg	sys_removexattr
+
+	.globl	sys32_lremovexattr_wrapper
+sys32_lremovexattr_wrapper:
+	llgtr	%r2,%r2			# char *
+	llgtr	%r3,%r3			# char *
+	jg	sys_lremovexattr
+
+	.globl	sys32_fremovexattr_wrapper
+sys32_fremovexattr_wrapper:
+	lgfr	%r2,%r2			# int
+	llgtr	%r3,%r3			# char *
+	jg	sys_fremovexattr
+
+	.globl	sys32_sched_setaffinity_wrapper
+sys32_sched_setaffinity_wrapper:
+	lgfr	%r2,%r2			# int
+	llgfr	%r3,%r3			# unsigned int
+	llgtr	%r4,%r4			# unsigned long *
+	jg	sys32_sched_setaffinity
+
+	.globl	sys32_sched_getaffinity_wrapper
+sys32_sched_getaffinity_wrapper:
+	lgfr	%r2,%r2			# int
+	llgfr	%r3,%r3			# unsigned int
+	llgtr	%r4,%r4			# unsigned long *
+	jg	sys32_sched_getaffinity
+
diff -Nru a/arch/s390x/lib/uaccess.S b/arch/s390x/lib/uaccess.S
--- a/arch/s390x/lib/uaccess.S	Sat Jun  8 22:31:51 2002
+++ b/arch/s390x/lib/uaccess.S	Sat Jun  8 22:31:51 2002
@@ -6,40 +6,73 @@
  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  *
- *  These functions have a non-standard call interface
+ *  These functions have standard call interface
  */
 
 #include <asm/lowcore.h>
 
         .text
         .align 4
-        .globl __copy_from_user_fixup
-__copy_from_user_fixup:
-        lg    1,__LC_PGM_OLD_PSW+8
-0:      lghi  3,-4096
-        ng    3,__LC_TRANS_EXC_ADDR
-        sgr   3,4
-        bm    4(1)
-1:      mvcle 2,4,0
-        b     4(1)
+        .globl __copy_from_user_asm
+__copy_from_user_asm:
+	lgr	%r5,%r3
+	sacf	512
+0:	mvcle	%r2,%r4,0
+	jo	0b
+1:	sacf	0
+	lgr	%r2,%r5
+	br	%r14
+2:	lghi	%r3,-4096
+        ng	%r3,__LC_TRANS_EXC_ADDR
+        sgr	%r3,%r4
+        jm	1b
+	j	0b
         .section __ex_table,"a"
-        .align 8
-	.quad 1b,0b
+        .align	8
+	.quad	0b,2b
         .previous
 
         .align 4
         .text
-        .globl __copy_to_user_fixup
-__copy_to_user_fixup:
-        lg    1,__LC_PGM_OLD_PSW+8
-0:      lghi  5,-4096
-        ng    5,__LC_TRANS_EXC_ADDR
-        sgr   5,4
-        bm    4(1)
-1:      mvcle 4,2,0
-        b     4(1)
+        .globl __copy_to_user_asm
+__copy_to_user_asm:
+	lgr	%r5,%r3
+	sacf	512
+0:	mvcle	%r4,%r2,0
+	jo	0b
+1:	sacf	0
+	lgr	%r2,%r3
+	br	%r14
+2:      lghi	%r5,-4096
+        ng	%r5,__LC_TRANS_EXC_ADDR
+        sgr	%r5,%r4
+	jm	1b
+	j	0b
         .section __ex_table,"a"
-        .align 8
-        .quad 1b,0b
+        .align	8
+        .quad	0b,2b
         .previous
 
+        .align 4
+        .text
+        .globl __clear_user_asm
+__clear_user_asm:
+	lgr	%r4,%r2
+	lgr	%r5,%r3
+	sgr	%r2,%r2
+	sgr	%r3,%r3
+	sacf	512
+0:	mvcle	%r4,%r2,0
+	jo	0b
+1:	sacf	0
+	lgr	%r2,%r5
+	br	%r14
+2:      lghi	%r5,-4096
+        ng	%r5,__LC_TRANS_EXC_ADDR
+        sgr	%r5,%r4
+	jm	1b
+	j	0b
+        .section __ex_table,"a"
+        .align	8
+        .quad	0b,2b
+        .previous
diff -Nru a/arch/s390x/mm/extable.c b/arch/s390x/mm/extable.c
--- a/arch/s390x/mm/extable.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/mm/extable.c	Sat Jun  8 22:31:37 2002
@@ -43,13 +43,13 @@
 search_exception_table(unsigned long addr)
 {
 	unsigned long ret = 0;
-	unsigned long flags;
 
 #ifndef CONFIG_MODULES
 	/* There is only the kernel to search.  */
 	ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
 	return ret;
 #else
+	unsigned long flags;
 	/* The kernel is the last "module" -- no need to treat it special.  */
 	struct module *mp;
 
diff -Nru a/arch/s390x/mm/fault.c b/arch/s390x/mm/fault.c
--- a/arch/s390x/mm/fault.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/mm/fault.c	Sat Jun  8 22:31:37 2002
@@ -35,7 +35,6 @@
 #endif
 
 extern void die(const char *,struct pt_regs *,long);
-static void force_sigsegv(struct task_struct *tsk, int code, void *address);
 
 extern spinlock_t timerlist_lock;
 
@@ -65,26 +64,96 @@
 }
 
 /*
+ * Check which address space is addressed by the access
+ * register in S390_lowcore.exc_access_id.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static int __check_access_register(struct pt_regs *regs, int error_code)
+{
+	int areg = S390_lowcore.exc_access_id;
+
+	if (areg == 0)
+		/* Access via access register 0 -> kernel address */
+		return 0;
+	if (regs && areg < NUM_ACRS && regs->acrs[areg] <= 1)
+		/*
+		 * access register contains 0 -> kernel address,
+		 * access register contains 1 -> user space address
+		 */
+		return regs->acrs[areg];
+
+	/* Something unhealthy was done with the access registers... */
+	die("page fault via unknown access register", regs, error_code);
+	do_exit(SIGKILL);
+	return 0;
+}
+
+/*
+ * Check which address space the address belongs to.
+ * Returns 1 for user space and 0 for kernel space.
+ */
+static inline int check_user_space(struct pt_regs *regs, int error_code)
+{
+	/*
+	 * The lowest two bits of S390_lowcore.trans_exc_code indicate
+	 * which paging table was used:
+	 *   0: Primary Segment Table Descriptor
+	 *   1: STD determined via access register
+	 *   2: Secondary Segment Table Descriptor
+	 *   3: Home Segment Table Descriptor
+	 */
+	int descriptor = S390_lowcore.trans_exc_code & 3;
+	if (descriptor == 1)
+		return __check_access_register(regs, error_code);
+	return descriptor >> 1;
+}
+		
+/*
+ * Send SIGSEGV to task.  This is an external routine
+ * to keep the stack usage of do_page_fault small.
+ */
+static void force_sigsegv(struct pt_regs *regs, unsigned long error_code,
+			  int si_code, unsigned long address)
+{
+	struct siginfo si;
+
+#if defined(CONFIG_SYSCTL) || defined(CONFIG_PROCESS_DEBUG)
+#if defined(CONFIG_SYSCTL)
+	if (sysctl_userprocess_debug)
+#endif
+	{
+		printk("User process fault: interruption code 0x%lX\n",
+		       error_code);
+		printk("failing address: %lX\n", address);
+		show_regs(regs);
+	}
+#endif
+	si.si_signo = SIGSEGV;
+	si.si_code = si_code;
+	si.si_addr = (void *) address;
+	force_sig_info(SIGSEGV, &si, current);
+}
+
+/*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  *
  * error_code:
- *             ****0004       Protection           ->  Write-Protection  (suprression)
- *             ****0010       Segment translation  ->  Not present       (nullification)
- *             ****0011       Page translation     ->  Not present       (nullification)
- *             ****003B       Region third exception ->  Not present       (nullification)
+ *   04       Protection           ->  Write-Protection  (suprression)
+ *   10       Segment translation  ->  Not present       (nullification)
+ *   11       Page translation     ->  Not present       (nullification)
+ *   3b       Region third trans.  ->  Not present       (nullification)
  */
-asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
+extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
 {
         struct task_struct *tsk;
         struct mm_struct *mm;
         struct vm_area_struct * vma;
         unsigned long address;
+	int user_address;
         unsigned long fixup;
-        int write;
 	int si_code = SEGV_MAPERR;
-	int kernel_address = 0;
 
         tsk = current;
         mm = tsk->mm;
@@ -94,13 +163,13 @@
 	 * as a special case because the translation exception code 
 	 * field is not guaranteed to contain valid data in this case.
 	 */
-	if ((error_code & 0xff) == 4 && !(S390_lowcore.trans_exc_code & 4)) {
+	if (error_code == 4 && !(S390_lowcore.trans_exc_code & 4)) {
 
 		/* Low-address protection hit in kernel mode means 
 		   NULL pointer write access in kernel mode.  */
  		if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
 			address = 0;
-			kernel_address = 1;
+			user_address = 0;
 			goto no_context;
 		}
 
@@ -114,52 +183,15 @@
          * more specific the segment and page table portion of 
          * the address 
          */
-
-        address = S390_lowcore.trans_exc_code&-4096L;
-
+        address = S390_lowcore.trans_exc_code & -4096L;
+	user_address = check_user_space(regs, error_code);
 
 	/*
-	 * Check which address space the address belongs to
+	 * Verify that the fault happened in user space, that
+	 * we are not in an interrupt and that there is a 
+	 * user context.
 	 */
-	switch (S390_lowcore.trans_exc_code & 3)
-	{
-	case 0: /* Primary Segment Table Descriptor */
-		kernel_address = 1;
-		goto no_context;
-
-	case 1: /* STD determined via access register */
-		if (S390_lowcore.exc_access_id == 0)
-		{
-			kernel_address = 1;
-			goto no_context;
-		}
-		if (regs && S390_lowcore.exc_access_id < NUM_ACRS)
-		{
-			if (regs->acrs[S390_lowcore.exc_access_id] == 0)
-			{
-				kernel_address = 1;
-				goto no_context;
-			}
-			if (regs->acrs[S390_lowcore.exc_access_id] == 1)
-			{
-				/* user space address */
-				break;
-			}
-		}
-		die("page fault via unknown access register", regs, error_code);
-        	do_exit(SIGKILL);
-		break;
-
-	case 2: /* Secondary Segment Table Descriptor */
-	case 3: /* Home Segment Table Descriptor */
-		/* user space address */
-		break;
-	}
-
-	/*
-	 * Check whether we have a user MM in the first place.
-	 */
-        if (in_interrupt() || !mm || !(regs->psw.mask & _PSW_IO_MASK_BIT))
+        if (user_address == 0 || in_interrupt() || !mm)
                 goto no_context;
 
 	/*
@@ -167,7 +199,6 @@
 	 * task's user address space, so we can switch on the
 	 * interrupts again and then search the VMAs
 	 */
-
 	__sti();
 
         down_read(&mm->mmap_sem);
@@ -186,31 +217,23 @@
  * we can handle it..
  */
 good_area:
-        write = 0;
 	si_code = SEGV_ACCERR;
+	if (error_code != 4) {
+		/* page not present, check vm flags */
+		if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
+			goto bad_area;
+	} else {
+		if (!(vma->vm_flags & VM_WRITE))
+			goto bad_area;
+	}
 
-        switch (error_code & 0xFF) {
-                case 0x04:                                /* write, present*/
-                        write = 1;
-                        break;
-                case 0x10:                                   /* not present*/
-                case 0x11:                                   /* not present*/
-                case 0x3B:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
-                                goto bad_area;
-                        break;
-                default:
-                       printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
-                       goto bad_area;
-        }
-
- survive:
+survive:
 	/*
 	 * If for any reason at all we couldn't handle the fault,
 	 * make sure we exit gracefully rather than endlessly redo
 	 * the fault.
 	 */
-	switch (handle_mm_fault(mm, vma, address, write)) {
+	switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
 	case 1:
 		tsk->min_flt++;
 		break;
@@ -237,22 +260,7 @@
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
-#ifndef CONFIG_SYSCTL
-#ifdef CONFIG_PROCESS_DEBUG
-                printk("User process fault: interruption code 0x%lX\n",error_code);
-                printk("failing address: %lX\n",address);
-		show_regs(regs);
-#endif
-#else
-		if (sysctl_userprocess_debug) {
-			printk("User process fault: interruption code 0x%lX\n",
-			       error_code);
-			printk("failing address: %lX\n", address);
-			show_regs(regs);
-		}
-#endif
-
-		force_sigsegv(tsk, si_code, (void *)address);
+		force_sigsegv(regs, error_code, si_code, address);
                 return;
 	}
 
@@ -267,8 +275,7 @@
  * Oops. The kernel tried to access some bad page. We'll have to
  * terminate things with extreme prejudice.
  */
-
-        if (kernel_address)
+        if (user_address == 0)
                 printk(KERN_ALERT "Unable to handle kernel pointer dereference"
         	       " at virtual kernel address %016lx\n", address);
         else
@@ -286,9 +293,7 @@
 out_of_memory:
 	up_read(&mm->mmap_sem);
 	if (tsk->pid == 1) {
-		tsk->policy |= SCHED_YIELD;
-		schedule();
-		down_read(&mm->mmap_sem);
+		yield();
 		goto survive;
 	}
 	printk("VM: killing process %s\n", tsk->comm);
@@ -312,19 +317,26 @@
 		goto no_context;
 }
 
-/*
- * Send SIGSEGV to task.  This is an external routine
- * to keep the stack usage of do_page_fault small.
- */
-static void force_sigsegv(struct task_struct *tsk, int code, void *address)
+void do_protection_exception(struct pt_regs *regs, unsigned long error_code)
 {
-	struct siginfo si;
-	si.si_signo = SIGSEGV;
-	si.si_code = code;
-	si.si_addr = address;
-	force_sig_info(SIGSEGV, &si, tsk);
+	regs->psw.addr -= (error_code >> 16);
+	do_exception(regs, 4);
 }
 
+void do_segment_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x10);
+}
+
+void do_page_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x11);
+}
+
+void do_region_exception(struct pt_regs *regs, unsigned long error_code)
+{
+	do_exception(regs, 0x3b);
+}
 
 #ifdef CONFIG_PFAULT
 /*
diff -Nru a/arch/s390x/mm/init.c b/arch/s390x/mm/init.c
--- a/arch/s390x/mm/init.c	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/mm/init.c	Sat Jun  8 22:31:37 2002
@@ -36,34 +36,13 @@
 #include <asm/dma.h>
 #include <asm/lowcore.h>
 #include <asm/tlb.h>
+#include <asm/tlbflush.h>
 
 mmu_gather_t mmu_gathers[NR_CPUS];
 
 pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
 char  empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
 
-int do_check_pgt_cache(int low, int high)
-{
-        int freed = 0;
-        if(pgtable_cache_size > high) {
-                do {
-                        if(pgd_quicklist) {
-				free_pgd_slow(get_pgd_fast());
-				freed += 4;
-			}
-                        if(pmd_quicklist) {
-				pmd_free_slow(pmd_alloc_one_fast(NULL, 0));
-				freed += 4;
-			}
-                        if(pte_quicklist) {
-				pte_free_slow(pte_alloc_one_fast(NULL, 0));
-				freed += 1;
-			}
-                } while(pgtable_cache_size > low);
-        }
-        return freed;
-}
-
 void show_mem(void)
 {
         int i, total = 0,reserved = 0;
@@ -86,7 +65,6 @@
         printk("%d reserved pages\n",reserved);
         printk("%d pages shared\n",shared);
         printk("%d pages swap cached\n",cached);
-        printk("%ld pages in page table cache\n",pgtable_cache_size);
 }
 
 /* References to section boundaries */
@@ -158,10 +136,10 @@
                         }          
                         
                         pt_dir = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
-                        pmd_populate(&init_mm, pm_dir, pt_dir);
+                        pmd_populate_kernel(&init_mm, pm_dir, pt_dir);
 	
                         for (k = 0 ; k < PTRS_PER_PTE ; k++,pt_dir++) {
-                                pte = mk_pte_phys(pfn, PAGE_KERNEL);
+                                pte = pfn_pte(pfn, PAGE_KERNEL);
                                 if (pfn >= max_low_pfn) {
                                         pte_clear(&pte); 
                                         continue;
diff -Nru a/arch/s390x/mm/ioremap.c b/arch/s390x/mm/ioremap.c
--- a/arch/s390x/mm/ioremap.c	Sat Jun  8 22:31:43 2002
+++ b/arch/s390x/mm/ioremap.c	Sat Jun  8 22:31:43 2002
@@ -16,6 +16,8 @@
 #include <linux/vmalloc.h>
 #include <asm/io.h>
 #include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
 
 static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
         unsigned long phys_addr, unsigned long flags)
@@ -55,7 +57,7 @@
 	if (address >= end)
 		BUG();
 	do {
-		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		pte_t * pte = pte_alloc_kernel(&init_mm, pmd, address);
 		if (!pte)
 			return -ENOMEM;
 		remap_area_pte(pte, address, end - address, address + phys_addr, flags);
diff -Nru a/arch/s390x/vmlinux-shared.lds b/arch/s390x/vmlinux-shared.lds
--- a/arch/s390x/vmlinux-shared.lds	Sat Jun  8 22:31:51 2002
+++ b/arch/s390x/vmlinux-shared.lds	Sat Jun  8 22:31:51 2002
@@ -14,6 +14,9 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x0700
+
+  _etext = .;			/* End of text section */
+
   .rodata : { *(.rodata) }
   .kstrtab : { *(.kstrtab) }
 
@@ -26,13 +29,9 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
-  __start___kallsyms = .;       /* All kernel symbols */
-  __kallsyms : { *(__kallsyms) }
-  __stop___kallsyms = .;
-
   . = ALIGN(1048576);		/* VM shared segments are 1MB aligned */
 
-  _etext = .;			/* End of text section */
+  _eshared = .;			/* End of shareable data */
 
   .data : {			/* Data */
 	*(.data)
@@ -48,9 +47,7 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-
+  . = ALIGN(256);
   __setup_start = .;
   .setup.init : { *(.setup.init) }
   __setup_end = .;
@@ -65,6 +62,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(256);
+  __per_cpu_start = .;
+  .date.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -Nru a/arch/s390x/vmlinux.lds b/arch/s390x/vmlinux.lds
--- a/arch/s390x/vmlinux.lds	Sat Jun  8 22:31:37 2002
+++ b/arch/s390x/vmlinux.lds	Sat Jun  8 22:31:37 2002
@@ -14,6 +14,9 @@
 	*(.fixup)
 	*(.gnu.warning)
 	} = 0x0700
+
+  _etext = .;			/* End of text section */
+
   .rodata : { *(.rodata) *(.rodata.*) }
   .kstrtab : { *(.kstrtab) }
 
@@ -26,12 +29,6 @@
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
 
-  __start___kallsyms = .;       /* All kernel symbols */
-  __kallsyms : { *(__kallsyms) }
-  __stop___kallsyms = .;
-
-  _etext = .;			/* End of text section */
-
   .data : {			/* Data */
 	*(.data)
 	CONSTRUCTORS
@@ -46,9 +43,7 @@
   __init_begin = .;
   .text.init : { *(.text.init) }
   .data.init : { *(.data.init) }
-  . = ALIGN(4096);
-  __init_end = .;
-
+  . = ALIGN(256);
   __setup_start = .;
   .setup.init : { *(.setup.init) }
   __setup_end = .;
@@ -63,6 +58,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(256);
+  __per_cpu_start = .;
+  .date.percpu  : { *(.data.percpu) }
+  __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
 
diff -Nru a/arch/sh/boot/Makefile b/arch/sh/boot/Makefile
--- a/arch/sh/boot/Makefile	Sat Jun  8 22:31:35 2002
+++ b/arch/sh/boot/Makefile	Sat Jun  8 22:31:35 2002
@@ -10,19 +10,19 @@
 
 SYSTEM  =$(TOPDIR)/vmlinux
 
-Image:	$(CONFIGURE) $(SYSTEM)
+Image:	$(SYSTEM)
 	$(OBJCOPY) $(SYSTEM) Image
 
-zImage: $(CONFIGURE) compressed/vmlinux
+zImage: compressed/vmlinux
 	$(OBJCOPY) compressed/vmlinux zImage
 
 compressed/vmlinux: $(TOPDIR)/vmlinux
 	$(MAKE) -C compressed vmlinux
 
-install: $(CONFIGURE) Image
+install: Image
 	sh -x ./install.sh $(KERNELRELEASE) Image $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
-zinstall: $(CONFIGURE) zImage
+zinstall: zImage
 	sh -x ./install.sh $(KERNELRELEASE) zImage $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
 dep:
diff -Nru a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
--- a/arch/sparc/kernel/devices.c	Sat Jun  8 22:31:52 2002
+++ b/arch/sparc/kernel/devices.c	Sat Jun  8 22:31:52 2002
@@ -22,8 +22,8 @@
 extern void clock_stop_probe(void); /* tadpole.c */
 extern void sun4c_probe_memerr_reg(void);
 
-unsigned long __init
-device_scan(unsigned long mem_start)
+void __init
+device_scan(void)
 {
 	char node_str[128];
 	int thismid;
@@ -37,46 +37,45 @@
 		int scan;
 		scan = prom_getchild(prom_root_node);
 		/* One can look it up in PROM instead */
-		/* prom_printf("root child is %08lx\n", (unsigned long) scan); */
-		while((scan = prom_getsibling(scan)) != 0) {
-			prom_getstring(scan, "device_type", node_str, sizeof(node_str));
-			if(strcmp(node_str, "cpu") == 0) {
+		while ((scan = prom_getsibling(scan)) != 0) {
+			prom_getstring(scan, "device_type",
+				       node_str, sizeof(node_str));
+			if (strcmp(node_str, "cpu") == 0) {
 				linux_cpus[linux_num_cpus].prom_node = scan;
-				prom_getproperty(scan, "mid", (char *) &thismid, sizeof(thismid));
+				prom_getproperty(scan, "mid",
+						 (char *) &thismid, sizeof(thismid));
 				linux_cpus[linux_num_cpus].mid = thismid;
-				/* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid); */
-				printk("Found CPU %d <node=%08lx,mid=%d>\n", linux_num_cpus, (unsigned long) scan, thismid);
+				printk("Found CPU %d <node=%08lx,mid=%d>\n",
+				       linux_num_cpus, (unsigned long) scan, thismid);
 				linux_num_cpus++;
 			}
 		}
-		if(linux_num_cpus == 0) {
-			if (sparc_cpu_model == sun4d) {
-				scan = prom_getchild(prom_root_node);
-				for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
-				     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
-					int node = prom_getchild(scan);
-
-					prom_getstring(node, "device_type", node_str, sizeof(node_str));
-					if (strcmp(node_str, "cpu") == 0) {
-						prom_getproperty(node, "cpu-id", (char *) &thismid, sizeof(thismid));
-						linux_cpus[linux_num_cpus].prom_node = node;
-						linux_cpus[linux_num_cpus].mid = thismid;
-						/* prom_printf("Found CPU %d <node=%08lx,mid=%d>\n", 
-							       linux_num_cpus, (unsigned long) node, thismid); */
-						printk("Found CPU %d <node=%08lx,mid=%d>\n", 
-						       linux_num_cpus, (unsigned long) node, thismid);
-						linux_num_cpus++;
-					}
+		if (linux_num_cpus == 0 && sparc_cpu_model == sun4d) {
+			scan = prom_getchild(prom_root_node);
+			for (scan = prom_searchsiblings(scan, "cpu-unit"); scan;
+			     scan = prom_searchsiblings(prom_getsibling(scan), "cpu-unit")) {
+				int node = prom_getchild(scan);
+
+				prom_getstring(node, "device_type",
+					       node_str, sizeof(node_str));
+				if (strcmp(node_str, "cpu") == 0) {
+					prom_getproperty(node, "cpu-id",
+							 (char *) &thismid, sizeof(thismid));
+					linux_cpus[linux_num_cpus].prom_node = node;
+					linux_cpus[linux_num_cpus].mid = thismid;
+					printk("Found CPU %d <node=%08lx,mid=%d>\n", 
+					       linux_num_cpus, (unsigned long) node, thismid);
+					linux_num_cpus++;
 				}
 			}
 		}
-		if(linux_num_cpus == 0) {
+		if (linux_num_cpus == 0) {
 			printk("No CPU nodes found, cannot continue.\n");
 			/* Probably a sun4e, Sun is trying to trick us ;-) */
 			halt();
 		}
 		printk("Found %d CPU prom device tree node(s).\n", linux_num_cpus);
-	};
+	}
 
 	cpu_probe();
 #ifdef CONFIG_SUN_AUXIO
@@ -92,5 +91,5 @@
 	if (ARCH_SUN4C_SUN4)
 		sun4c_probe_memerr_reg();
 
-	return mem_start;
+	return;
 }
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Sat Jun  8 22:31:36 2002
+++ b/arch/sparc/mm/sun4c.c	Sat Jun  8 22:31:36 2002
@@ -35,6 +35,7 @@
 #include <asm/mmu_context.h>
 #include <asm/sun4paddr.h>
 #include <asm/highmem.h>
+#include <asm/btfixup.h>
 
 /* Because of our dynamic kernel TLB miss strategy, and how
  * our DVMA mapping allocation works, you _MUST_:
@@ -63,25 +64,17 @@
 
 #define SUN4C_KERNEL_BUCKETS 32
 
-#ifndef MAX
-#define MAX(a,b) ((a)<(b)?(b):(a))
-#endif
-#ifndef MIN
-#define MIN(a,b) ((a)<(b)?(a):(b))
-#endif
-
 /* Flushing the cache. */
 struct sun4c_vac_props sun4c_vacinfo;
 unsigned long sun4c_kernel_faults;
 
 /* Invalidate every sun4c cache line tag. */
-void sun4c_flush_all(void)
+static void __init sun4c_flush_all(void)
 {
 	unsigned long begin, end;
 
 	if (sun4c_vacinfo.on)
-		panic("SUN4C: AIEEE, trying to invalidate vac while"
-                      " it is on.");
+		panic("SUN4C: AIEEE, trying to invalidate vac while it is on.");
 
 	/* Clear 'valid' bit in all cache line tags */
 	begin = AC_CACHETAGS;
@@ -93,7 +86,7 @@
 	}
 }
 
-static __inline__ void sun4c_flush_context_hw(void)
+static void sun4c_flush_context_hw(void)
 {
 	unsigned long end = SUN4C_VAC_SIZE;
 
@@ -122,8 +115,17 @@
 	}
 }
 
+/* File local boot time fixups. */
+BTFIXUPDEF_CALL(void, sun4c_flush_page, unsigned long)
+BTFIXUPDEF_CALL(void, sun4c_flush_segment, unsigned long)
+BTFIXUPDEF_CALL(void, sun4c_flush_context, void)
+
+#define sun4c_flush_page(addr) BTFIXUP_CALL(sun4c_flush_page)(addr)
+#define sun4c_flush_segment(addr) BTFIXUP_CALL(sun4c_flush_segment)(addr)
+#define sun4c_flush_context() BTFIXUP_CALL(sun4c_flush_context)()
+
 /* Must be called minimally with interrupts disabled. */
-static __inline__ void sun4c_flush_page_hw(unsigned long addr)
+static void sun4c_flush_page_hw(unsigned long addr)
 {
 	addr &= PAGE_MASK;
 	if ((int)sun4c_get_pte(addr) < 0)
@@ -195,48 +197,6 @@
 	}
 }
 
-/* Bolix one page from the virtual cache. */
-static void sun4c_flush_page(unsigned long addr)
-{
-	addr &= PAGE_MASK;
-
-	if ((sun4c_get_pte(addr) & (_SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_VALID)) !=
-	    _SUN4C_PAGE_VALID)
-		return;
-
-	if (sun4c_vacinfo.do_hwflushes) {
-		__asm__ __volatile__("sta %%g0, [%0] %1;nop;nop;nop;\n\t" : :
-				     "r" (addr), "i" (ASI_HWFLUSHPAGE));
-	} else {
-		unsigned long left = PAGE_SIZE;
-		unsigned long lsize = sun4c_vacinfo.linesize;
-
-		__asm__ __volatile__("add	%2, %2, %%g1\n\t"
-				     "add	%2, %%g1, %%g2\n\t"
-				     "add	%2, %%g2, %%g3\n\t"
-				     "add	%2, %%g3, %%g4\n\t"
-				     "add	%2, %%g4, %%g5\n\t"
-				     "add	%2, %%g5, %%o4\n\t"
-				     "add	%2, %%o4, %%o5\n"
-				     "1:\n\t"
-				     "subcc	%1, %%o5, %1\n\t"
-				     "sta	%%g0, [%0] %6\n\t"
-				     "sta	%%g0, [%0 + %2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g1] %6\n\t"
-				     "sta	%%g0, [%0 + %%g2] %6\n\t"
-				     "sta	%%g0, [%0 + %%g3] %6\n\t"
-				     "sta	%%g0, [%0 + %%g4] %6\n\t"
-				     "sta	%%g0, [%0 + %%g5] %6\n\t"
-				     "sta	%%g0, [%0 + %%o4] %6\n\t"
-				     "bg	1b\n\t"
-				     " add	%0, %%o5, %0\n\t"
-				     : "=&r" (addr), "=&r" (left), "=&r" (lsize)
-				     : "0" (addr), "1" (left), "2" (lsize),
-				       "i" (ASI_FLUSHPG)
-				     : "g1", "g2", "g3", "g4", "g5", "o4", "o5", "cc");
-	}
-}
-
 /* Don't inline the software version as it eats too many cache lines if expanded. */
 static void sun4c_flush_page_sw(unsigned long addr)
 {
@@ -387,7 +347,8 @@
 			 prom_getintdefault(prom_root_node, "vac_hwflush", 0);
 
 		if (sun4c_vacinfo.num_bytes != 65536) {
-			prom_printf("WEIRD Sun4C VAC cache size, tell davem");
+			prom_printf("WEIRD Sun4C VAC cache size, "
+				    "tell sparclinux@vger.kernel.org");
 			prom_halt();
 		}
 	}
@@ -427,7 +388,7 @@
 		*daddr = *iaddr;	\
 	} while (0)
 
-static void patch_kernel_fault_handler(void)
+static void __init patch_kernel_fault_handler(void)
 {
 	unsigned long *iaddr, *daddr;
 
@@ -459,10 +420,6 @@
 		case 16:
 			PATCH_INSN(num_context_patch1_16,
 				   num_context_patch1);
-#if 0
-			PATCH_INSN(num_context_patch2_16,
-				   num_context_patch2);
-#endif
 			break;
 		default:
 			prom_printf("Unhandled number of contexts: %d\n",
@@ -867,33 +824,7 @@
 #define sun4c_user_unmap(__entry) \
 	sun4c_put_segmap((__entry)->vaddr, invalid_segment)
 
-static void sun4c_demap_context_hw(struct sun4c_mmu_ring *crp, unsigned char ctx)
-{
-	struct sun4c_mmu_entry *head = &crp->ringhd;
-	unsigned long flags;
-
-	save_and_cli(flags);
-	if (head->next != head) {
-		struct sun4c_mmu_entry *entry = head->next;
-		int savectx = sun4c_get_context();
-
-		flush_user_windows();
-		sun4c_set_context(ctx);
-		sun4c_flush_context_hw();
-		do {
-			struct sun4c_mmu_entry *next = entry->next;
-
-			sun4c_user_unmap(entry);
-			free_user_entry(ctx, entry);
-
-			entry = next;
-		} while (entry != head);
-		sun4c_set_context(savectx);
-	}
-	restore_flags(flags);
-}
-
-static void sun4c_demap_context_sw(struct sun4c_mmu_ring *crp, unsigned char ctx)
+static void sun4c_demap_context(struct sun4c_mmu_ring *crp, unsigned char ctx)
 {
 	struct sun4c_mmu_entry *head = &crp->ringhd;
 	unsigned long flags;
@@ -905,7 +836,7 @@
 
 		flush_user_windows();
 		sun4c_set_context(ctx);
-		sun4c_flush_context_sw();
+		sun4c_flush_context();
 		do {
 			struct sun4c_mmu_entry *next = entry->next;
 
@@ -919,8 +850,8 @@
 	restore_flags(flags);
 }
 
-static int sun4c_user_taken_entries = 0;  /* This is how much we have.             */
-static int max_user_taken_entries = 0;    /* This limits us and prevents deadlock. */
+static int sun4c_user_taken_entries;  /* This is how much we have.             */
+static int max_user_taken_entries;    /* This limits us and prevents deadlock. */
 
 static struct sun4c_mmu_entry *sun4c_kernel_strategy(void)
 {
@@ -934,10 +865,7 @@
 
 	/* Else free one up. */
 	this_entry = sun4c_kernel_ring.ringhd.prev;
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(this_entry->vaddr);
-	else
-		sun4c_flush_segment_sw(this_entry->vaddr);
+	sun4c_flush_segment(this_entry->vaddr);
 	sun4c_kernel_unmap(this_entry);
 	free_kernel_entry(this_entry, &sun4c_kernel_ring);
 	this_entry = sun4c_kfree_ring.ringhd.next;
@@ -976,10 +904,7 @@
 	savectx = sun4c_get_context();
 	flush_user_windows();
 	sun4c_set_context(ctx);
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(entry->vaddr);
-	else
-		sun4c_flush_segment_sw(entry->vaddr);
+	sun4c_flush_segment(entry->vaddr);
 	sun4c_user_unmap(entry);
 	remove_ring(sun4c_context_ring + ctx, entry);
 	remove_lru(entry);
@@ -1068,10 +993,7 @@
 	entry = &mmu_entry_pool[pseg];
 
 	flush_user_windows();
-	if (sun4c_vacinfo.do_hwflushes)
-		sun4c_flush_segment_hw(addr);
-	else
-		sun4c_flush_segment_sw(addr);
+	sun4c_flush_segment(addr);
 	sun4c_kernel_unmap(entry);
 	add_ring(&sun4c_ufree_ring, entry);
 	max_user_taken_entries++;
@@ -1126,17 +1048,10 @@
 	/* We are changing the virtual color of the page(s)
 	 * so we must flush the cache to guarentee consistancy.
 	 */
-	if (sun4c_vacinfo.do_hwflushes) {
-		sun4c_flush_page_hw(pages);
-#ifndef CONFIG_SUN4	
-		sun4c_flush_page_hw(pages + PAGE_SIZE);
-#endif
-	} else {
-		sun4c_flush_page_sw(pages);
+	sun4c_flush_page(pages);
 #ifndef CONFIG_SUN4	
-		sun4c_flush_page_sw(pages + PAGE_SIZE);
+	sun4c_flush_page(pages + PAGE_SIZE);
 #endif
-	}
 
 	sun4c_put_pte(addr, BUCKET_PTE(pages));
 #ifndef CONFIG_SUN4	
@@ -1145,32 +1060,7 @@
 	return (struct task_struct *) addr;
 }
 
-static void sun4c_free_task_struct_hw(struct task_struct *tsk)
-{
-	unsigned long tsaddr = (unsigned long) tsk;
-	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
-	int entry = BUCKET_NUM(tsaddr);
-
-	if (atomic_dec_and_test(&(tsk)->thread.refcount)) {
-		/* We are deleting a mapping, so the flush here is mandatory. */
-		sun4c_flush_page_hw(tsaddr);
-#ifndef CONFIG_SUN4	
-		sun4c_flush_page_hw(tsaddr + PAGE_SIZE);
-#endif
-		sun4c_put_pte(tsaddr, 0);
-#ifndef CONFIG_SUN4	
-		sun4c_put_pte(tsaddr + PAGE_SIZE, 0);
-#endif
-		sun4c_bucket[entry] = BUCKET_EMPTY;
-		if (entry < sun4c_lowbucket_avail)
-			sun4c_lowbucket_avail = entry;
-
-		free_pages(pages, TASK_STRUCT_ORDER);
-		garbage_collect(entry);
-	}
-}
-
-static void sun4c_free_task_struct_sw(struct task_struct *tsk)
+static void sun4c_free_task_struct(struct task_struct *tsk)
 {
 	unsigned long tsaddr = (unsigned long) tsk;
 	unsigned long pages = BUCKET_PTE_PAGE(sun4c_get_pte(tsaddr));
@@ -1178,9 +1068,9 @@
 
 	if (atomic_dec_and_test(&(tsk)->thread.refcount)) {
 		/* We are deleting a mapping, so the flush here is mandatory. */
-		sun4c_flush_page_sw(tsaddr);
+		sun4c_flush_page(tsaddr);
 #ifndef CONFIG_SUN4	
-		sun4c_flush_page_sw(tsaddr + PAGE_SIZE);
+		sun4c_flush_page(tsaddr + PAGE_SIZE);
 #endif
 		sun4c_put_pte(tsaddr, 0);
 #ifndef CONFIG_SUN4	
@@ -1452,131 +1342,7 @@
 	}
 }
 
-static void sun4c_flush_cache_mm_hw(struct mm_struct *mm)
-{
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		flush_user_windows();
-		if (sun4c_context_ring[new_ctx].num_entries) {
-			struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-			unsigned long flags;
-
-			save_and_cli(flags);
-			if (head->next != head) {
-				struct sun4c_mmu_entry *entry = head->next;
-				int savectx = sun4c_get_context();
-
-				sun4c_set_context(new_ctx);
-				sun4c_flush_context_hw();
-				do {
-					struct sun4c_mmu_entry *next = entry->next;
-
-					sun4c_user_unmap(entry);
-					free_user_entry(new_ctx, entry);
-
-					entry = next;
-				} while (entry != head);
-				sun4c_set_context(savectx);
-			}
-			restore_flags(flags);
-		}
-	}
-}
-
-static void sun4c_flush_cache_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-	
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		struct sun4c_mmu_entry *entry;
-		unsigned long flags;
-
-		flush_user_windows();
-
-		save_and_cli(flags);
-
-		/* All user segmap chains are ordered on entry->vaddr. */
-		for (entry = head->next;
-		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		     entry = entry->next)
-			;
-
-		/* Tracing various job mixtures showed that this conditional
-		 * only passes ~35% of the time for most worse case situations,
-		 * therefore we avoid all of this gross overhead ~65% of the time.
-		 */
-		if ((entry != head) && (entry->vaddr < end)) {
-			int octx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-
-			/* At this point, always, (start >= entry->vaddr) and
-			 * (entry->vaddr < end), once the latter condition
-			 * ceases to hold, or we hit the end of the list, we
-			 * exit the loop.  The ordering of all user allocated
-			 * segmaps makes this all work out so beautifully.
-			 */
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-				unsigned long realend;
-
-				/* "realstart" is always >= entry->vaddr */
-				realend = entry->vaddr + SUN4C_REAL_PGDIR_SIZE;
-				if (end < realend)
-					realend = end;
-				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
-					unsigned long page = entry->vaddr;
-					while (page < realend) {
-						sun4c_flush_page_hw(page);
-						page += PAGE_SIZE;
-					}
-				} else {
-					sun4c_flush_segment_hw(entry->vaddr);
-					sun4c_user_unmap(entry);
-					free_user_entry(new_ctx, entry);
-				}
-				entry = next;
-			} while ((entry != head) && (entry->vaddr < end));
-			sun4c_set_context(octx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_cache_page_hw(struct vm_area_struct *vma, unsigned long page)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-
-	/* Sun4c has no separate I/D caches so cannot optimize for non
-	 * text page flushes.
-	 */
-	if (new_ctx != NO_CONTEXT) {
-		int octx = sun4c_get_context();
-		unsigned long flags;
-
-		flush_user_windows();
-		save_and_cli(flags);
-		sun4c_set_context(new_ctx);
-		sun4c_flush_page_hw(page);
-		sun4c_set_context(octx);
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_page_to_ram_hw(unsigned long page)
-{
-	unsigned long flags;
-
-	save_and_cli(flags);
-	sun4c_flush_page_hw(page);
-	restore_flags(flags);
-}
-
-static void sun4c_flush_cache_mm_sw(struct mm_struct *mm)
+static void sun4c_flush_cache_mm(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
@@ -1593,7 +1359,7 @@
 				int savectx = sun4c_get_context();
 
 				sun4c_set_context(new_ctx);
-				sun4c_flush_context_sw();
+				sun4c_flush_context();
 				do {
 					struct sun4c_mmu_entry *next = entry->next;
 
@@ -1653,11 +1419,11 @@
 				if ((realend - entry->vaddr) <= (PAGE_SIZE << 3)) {
 					unsigned long page = entry->vaddr;
 					while (page < realend) {
-						sun4c_flush_page_sw(page);
+						sun4c_flush_page(page);
 						page += PAGE_SIZE;
 					}
 				} else {
-					sun4c_flush_segment_sw(entry->vaddr);
+					sun4c_flush_segment(entry->vaddr);
 					sun4c_user_unmap(entry);
 					free_user_entry(new_ctx, entry);
 				}
@@ -1669,7 +1435,7 @@
 	}
 }
 
-static void sun4c_flush_cache_page_sw(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_cache_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
@@ -1684,18 +1450,18 @@
 		flush_user_windows();
 		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
-		sun4c_flush_page_sw(page);
+		sun4c_flush_page(page);
 		sun4c_set_context(octx);
 		restore_flags(flags);
 	}
 }
 
-static void sun4c_flush_page_to_ram_sw(unsigned long page)
+static void sun4c_flush_page_to_ram(unsigned long page)
 {
 	unsigned long flags;
 
 	save_and_cli(flags);
-	sun4c_flush_page_sw(page);
+	sun4c_flush_page(page);
 	restore_flags(flags);
 }
 
@@ -1723,10 +1489,7 @@
 	flush_user_windows();
 	while (sun4c_kernel_ring.num_entries) {
 		next_entry = this_entry->next;
-		if (sun4c_vacinfo.do_hwflushes)
-			sun4c_flush_segment_hw(this_entry->vaddr);
-		else
-			sun4c_flush_segment_sw(this_entry->vaddr);
+		sun4c_flush_segment(this_entry->vaddr);
 		for (ctx = 0; ctx < num_contexts; ctx++) {
 			sun4c_set_context(ctx);
 			sun4c_put_segmap(this_entry->vaddr, invalid_segment);
@@ -1738,7 +1501,7 @@
 	restore_flags(flags);
 }
 
-static void sun4c_flush_tlb_mm_hw(struct mm_struct *mm)
+static void sun4c_flush_tlb_mm(struct mm_struct *mm)
 {
 	int new_ctx = mm->context;
 
@@ -1752,91 +1515,7 @@
 			int savectx = sun4c_get_context();
 
 			sun4c_set_context(new_ctx);
-			sun4c_flush_context_hw();
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
-
-				entry = next;
-			} while (entry != head);
-			sun4c_set_context(savectx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_range_hw(struct vm_area_struct *vma, unsigned long start, unsigned long end)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		struct sun4c_mmu_entry *entry;
-		unsigned long flags;
-
-		save_and_cli(flags);
-		/* See commentary in sun4c_flush_cache_range_*(). */
-		for (entry = head->next;
-		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
-		     entry = entry->next)
-			;
-
-		if ((entry != head) && (entry->vaddr < end)) {
-			int octx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-			do {
-				struct sun4c_mmu_entry *next = entry->next;
-
-				sun4c_flush_segment_hw(entry->vaddr);
-				sun4c_user_unmap(entry);
-				free_user_entry(new_ctx, entry);
-
-				entry = next;
-			} while ((entry != head) && (entry->vaddr < end));
-			sun4c_set_context(octx);
-		}
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_page_hw(struct vm_area_struct *vma, unsigned long page)
-{
-	struct mm_struct *mm = vma->vm_mm;
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		int savectx = sun4c_get_context();
-		unsigned long flags;
-
-		save_and_cli(flags);
-		sun4c_set_context(new_ctx);
-		page &= PAGE_MASK;
-		sun4c_flush_page_hw(page);
-		sun4c_put_pte(page, 0);
-		sun4c_set_context(savectx);
-		restore_flags(flags);
-	}
-}
-
-static void sun4c_flush_tlb_mm_sw(struct mm_struct *mm)
-{
-	int new_ctx = mm->context;
-
-	if (new_ctx != NO_CONTEXT) {
-		struct sun4c_mmu_entry *head = &sun4c_context_ring[new_ctx].ringhd;
-		unsigned long flags;
-
-		save_and_cli(flags);
-		if (head->next != head) {
-			struct sun4c_mmu_entry *entry = head->next;
-			int savectx = sun4c_get_context();
-
-			sun4c_set_context(new_ctx);
-			sun4c_flush_context_sw();
+			sun4c_flush_context();
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
 
@@ -1862,7 +1541,7 @@
 		unsigned long flags;
 
 		save_and_cli(flags);
-		/* See commentary in sun4c_flush_cache_range_*(). */
+		/* See commentary in sun4c_flush_cache_range(). */
 		for (entry = head->next;
 		     (entry != head) && ((entry->vaddr+SUN4C_REAL_PGDIR_SIZE) < start);
 		     entry = entry->next)
@@ -1875,7 +1554,7 @@
 			do {
 				struct sun4c_mmu_entry *next = entry->next;
 
-				sun4c_flush_segment_sw(entry->vaddr);
+				sun4c_flush_segment(entry->vaddr);
 				sun4c_user_unmap(entry);
 				free_user_entry(new_ctx, entry);
 
@@ -1887,7 +1566,7 @@
 	}
 }
 
-static void sun4c_flush_tlb_page_sw(struct vm_area_struct *vma, unsigned long page)
+static void sun4c_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	int new_ctx = mm->context;
@@ -1899,7 +1578,7 @@
 		save_and_cli(flags);
 		sun4c_set_context(new_ctx);
 		page &= PAGE_MASK;
-		sun4c_flush_page_sw(page);
+		sun4c_flush_page(page);
 		sun4c_put_pte(page, 0);
 		sun4c_set_context(savectx);
 		restore_flags(flags);
@@ -1923,7 +1602,7 @@
 	sun4c_put_pte(virt_addr, 0);
 }
 
-static void sun4c_alloc_context_hw(struct mm_struct *old_mm, struct mm_struct *mm)
+static void sun4c_alloc_context(struct mm_struct *old_mm, struct mm_struct *mm)
 {
 	struct ctx_list *ctxp;
 
@@ -1943,19 +1622,19 @@
 	ctxp->ctx_mm->context = NO_CONTEXT;
 	ctxp->ctx_mm = mm;
 	mm->context = ctxp->ctx_number;
-	sun4c_demap_context_hw(&sun4c_context_ring[ctxp->ctx_number],
+	sun4c_demap_context(&sun4c_context_ring[ctxp->ctx_number],
 			       ctxp->ctx_number);
 }
 
 /* Switch the current MM context. */
-static void sun4c_switch_mm_hw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
+static void sun4c_switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
 {
 	struct ctx_list *ctx;
 	int dirty = 0;
 
 	if (mm->context == NO_CONTEXT) {
 		dirty = 1;
-		sun4c_alloc_context_hw(old_mm, mm);
+		sun4c_alloc_context(old_mm, mm);
 	} else {
 		/* Update the LRU ring of contexts. */
 		ctx = ctx_list_pool + mm->context;
@@ -1966,69 +1645,12 @@
 		sun4c_set_context(mm->context);
 }
 
-static void sun4c_destroy_context_hw(struct mm_struct *mm)
+static void sun4c_destroy_context(struct mm_struct *mm)
 {
 	struct ctx_list *ctx_old;
 
 	if (mm->context != NO_CONTEXT) {
-		sun4c_demap_context_hw(&sun4c_context_ring[mm->context], mm->context);
-		ctx_old = ctx_list_pool + mm->context;
-		remove_from_ctx_list(ctx_old);
-		add_to_free_ctxlist(ctx_old);
-		mm->context = NO_CONTEXT;
-	}
-}
-
-static void sun4c_alloc_context_sw(struct mm_struct *old_mm, struct mm_struct *mm)
-{
-	struct ctx_list *ctxp;
-
-	ctxp = ctx_free.next;
-	if (ctxp != &ctx_free) {
-		remove_from_ctx_list(ctxp);
-		add_to_used_ctxlist(ctxp);
-		mm->context = ctxp->ctx_number;
-		ctxp->ctx_mm = mm;
-		return;
-	}
-	ctxp = ctx_used.next;
-	if(ctxp->ctx_mm == old_mm)
-		ctxp = ctxp->next;
-	remove_from_ctx_list(ctxp);
-	add_to_used_ctxlist(ctxp);
-	ctxp->ctx_mm->context = NO_CONTEXT;
-	ctxp->ctx_mm = mm;
-	mm->context = ctxp->ctx_number;
-	sun4c_demap_context_sw(&sun4c_context_ring[ctxp->ctx_number],
-			       ctxp->ctx_number);
-}
-
-/* Switch the current MM context. */
-static void sun4c_switch_mm_sw(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk, int cpu)
-{
-	struct ctx_list *ctx;
-	int dirty = 0;
-
-	if (mm->context == NO_CONTEXT) {
-		dirty = 1;
-		sun4c_alloc_context_sw(old_mm, mm);
-	} else {
-		/* Update the LRU ring of contexts. */
-		ctx = ctx_list_pool + mm->context;
-		remove_from_ctx_list(ctx);
-		add_to_used_ctxlist(ctx);
-	}
-
-	if (dirty || old_mm != mm)
-		sun4c_set_context(mm->context);
-}
-
-static void sun4c_destroy_context_sw(struct mm_struct *mm)
-{
-	struct ctx_list *ctx_old;
-
-	if (mm->context != NO_CONTEXT) {
-		sun4c_demap_context_sw(&sun4c_context_ring[mm->context], mm->context);
+		sun4c_demap_context(&sun4c_context_ring[mm->context], mm->context);
 		ctx_old = ctx_list_pool + mm->context;
 		remove_from_ctx_list(ctx_old);
 		add_to_free_ctxlist(ctx_old);
@@ -2095,7 +1717,7 @@
 
 static void sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
 {
-	*pmdp = (PGD_TABLE | (unsigned long) ptep);
+	*pmdp = __pmd(PGD_TABLE | (unsigned long) ptep);
 }
 
 static int sun4c_pte_present(pte_t pte)
@@ -2178,10 +1800,7 @@
 	return (pmd_val(pmd) & PAGE_MASK);
 }
 
-static unsigned long sun4c_pgd_page(pgd_t pgd)
-{
-	return 0;
-}
+static unsigned long sun4c_pgd_page(pgd_t pgd) { return 0; }
 
 /* to find an entry in a page-table-directory */
 static inline pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
@@ -2275,9 +1894,7 @@
 	return NULL;
 }
 
-static void sun4c_free_pmd_fast(pmd_t * pmd)
-{
-}
+static void sun4c_free_pmd_fast(pmd_t * pmd) { }
 
 static int sun4c_check_pgt_cache(int low, int high)
 {
@@ -2470,37 +2087,31 @@
 		    _SUN4C_PAGE_IO | _SUN4C_PAGE_NOCACHE;
 	
 	/* Functions */
-#ifndef CONFIG_SMP
 	BTFIXUPSET_CALL(___xchg32, ___xchg32_sun4c, BTFIXUPCALL_NORM);
-#endif
 	BTFIXUPSET_CALL(do_check_pgt_cache, sun4c_check_pgt_cache, BTFIXUPCALL_NORM);
 	
 	BTFIXUPSET_CALL(flush_cache_all, sun4c_flush_cache_all, BTFIXUPCALL_NORM);
 
 	if (sun4c_vacinfo.do_hwflushes) {
-		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_hw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_hw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_hw, BTFIXUPCALL_NORM);
 	} else {
-		BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm_sw, BTFIXUPCALL_NORM);
-		BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_page, sun4c_flush_page_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_segment, sun4c_flush_segment_sw, BTFIXUPCALL_NORM);
+		BTFIXUPSET_CALL(sun4c_flush_context, sun4c_flush_context_sw, BTFIXUPCALL_NORM);
 	}
 
+	BTFIXUPSET_CALL(flush_tlb_mm, sun4c_flush_tlb_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_mm, sun4c_flush_cache_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(destroy_context, sun4c_destroy_context, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(switch_mm, sun4c_switch_mm, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_page, sun4c_flush_cache_page, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_tlb_page, sun4c_flush_tlb_page, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_tlb_range, sun4c_flush_tlb_range, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(flush_cache_range, sun4c_flush_cache_range, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(free_task_struct, sun4c_free_task_struct, BTFIXUPCALL_NORM);
+	BTFIXUPSET_CALL(__flush_page_to_ram, sun4c_flush_page_to_ram, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(flush_tlb_all, sun4c_flush_tlb_all, BTFIXUPCALL_NORM);
 
 	BTFIXUPSET_CALL(flush_sig_insns, sun4c_flush_sig_insns, BTFIXUPCALL_NOP);
diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
--- a/arch/sparc64/kernel/Makefile	Sat Jun  8 22:31:36 2002
+++ b/arch/sparc64/kernel/Makefile	Sat Jun  8 22:31:36 2002
@@ -31,11 +31,6 @@
   endif
 endif
 
-#
-# This is just to get the dependencies...
-#
-binfmt_elf32.o: $(TOPDIR)/fs/binfmt_elf.c
-
 ifneq ($(NEW_GCC),y)
   CMODEL_CFLAG := -mmedlow
 else
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Sat Jun  8 22:31:51 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Sat Jun  8 22:31:51 2002
@@ -2879,16 +2879,19 @@
 	bprm.sh_bang = 0;
 	bprm.loader = 0;
 	bprm.exec = 0;
-	if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) {
-		allow_write_access(file);
-		fput(file);
-		return bprm.argc;
-	}
-	if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) {
-		allow_write_access(file);
-		fput(file);
-		return bprm.envc;
-	}
+
+	bprm.mm = mm_alloc();
+	retval = -ENOMEM;
+	if (!bprm.mm) 
+		goto out_file;
+
+	bprm.argc = count32(argv, bprm.p / sizeof(u32));
+	if ((retval = bprm.argc) < 0)
+		goto out_mm;
+
+	bprm.envc = count32(envp, bprm.p / sizeof(u32));
+	if ((retval = bprm.envc) < 0)
+		goto out_mm;
 
 	retval = prepare_binprm(&bprm);
 	if (retval < 0)
@@ -2914,14 +2917,20 @@
 
 out:
 	/* Something went wrong, return the inode and free the argument pages*/
-	allow_write_access(bprm.file);
-	if (bprm.file)
-		fput(bprm.file);
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		struct page * page = bprm.page[i];
+		if (page)
+			__free_page(page);
+	}
 
-	for (i=0 ; i<MAX_ARG_PAGES ; i++)
-		if (bprm.page[i])
-			__free_page(bprm.page[i]);
+out_mm:
+	mmdrop(bprm.mm);
 
+out_file:
+	if (bprm.file) {
+		allow_write_access(bprm.file);
+		fput(bprm.file);
+	}
 	return retval;
 }
 
diff -Nru a/arch/sparc64/mm/generic.c b/arch/sparc64/mm/generic.c
--- a/arch/sparc64/mm/generic.c	Sat Jun  8 22:31:37 2002
+++ b/arch/sparc64/mm/generic.c	Sat Jun  8 22:31:37 2002
@@ -17,20 +17,10 @@
 
 static inline void forget_pte(pte_t page)
 {
-	if (pte_none(page))
-		return;
-	if (pte_present(page)) {
-		unsigned long pfn = pte_pfn(page);
-		struct page *ptpage;
-		if (!pfn_valid(pfn))
-			return;
-		ptpage = pfn_to_page(page);
-		if (PageReserved(ptpage))
-			return;
-		page_cache_release(ptpage);
-		return;
+	if (!pte_none(page)) {
+		printk("forget_pte: old mapping existed!\n");
+		BUG();
 	}
-	swap_free(pte_to_swp_entry(page));
 }
 
 /* Remap IO memory, the same way as remap_page_range(), but use
diff -Nru a/arch/sparc64/solaris/Makefile b/arch/sparc64/solaris/Makefile
--- a/arch/sparc64/solaris/Makefile	Sat Jun  8 22:31:35 2002
+++ b/arch/sparc64/solaris/Makefile	Sat Jun  8 22:31:35 2002
@@ -4,10 +4,6 @@
 
 EXTRA_AFLAGS := -ansi
 
-ifeq ($(CONFIG_SOLARIS_EMUL),m)
-  EXTRA_AFLAGS += $(CFLAGS_MODULE) # FIXME
-endif
-
 solaris-objs := entry64.o fs.o misc.o signal.o systbl.o socket.o \
 		ioctl.o ipc.o socksys.o timod.o
 
diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
--- a/arch/sparc64/solaris/timod.c	Sat Jun  8 22:31:37 2002
+++ b/arch/sparc64/solaris/timod.c	Sat Jun  8 22:31:37 2002
@@ -820,14 +820,18 @@
 	if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
 		SOLD("generating udi");
 		udi.PRIM_type = T_UNITDATA_IND;
-		get_user(udi.SRC_length, ctl_len);
+		if (get_user(udi.SRC_length, ctl_len))
+			return -EFAULT;
 		udi.SRC_offset = sizeof(udi);
 		udi.OPT_length = udi.OPT_offset = 0;
-		copy_to_user(ctl_buf, &udi, sizeof(udi));
-		put_user(sizeof(udi)+udi.SRC_length, ctl_len);
+		if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
+		    put_user(sizeof(udi)+udi.SRC_length, ctl_len))
+			return -EFAULT;
 		SOLD("udi done");
-	} else
-		put_user(0, ctl_len);
+	} else {
+		if (put_user(0, ctl_len))
+			return -EFAULT;
+	}
 	put_user(error, data_len);
 	SOLD("done");
 	return 0;
diff -Nru a/arch/x86_64/boot/Makefile b/arch/x86_64/boot/Makefile
--- a/arch/x86_64/boot/Makefile	Sat Jun  8 22:31:37 2002
+++ b/arch/x86_64/boot/Makefile	Sat Jun  8 22:31:37 2002
@@ -31,11 +31,11 @@
 		$(TOPDIR)/include/linux/autoconf.h \
 		$(TOPDIR)/include/asm/boot.h
 
-zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
+zImage: bootsect setup compressed/vmlinux tools/build
 	$(OBJCOPY) compressed/vmlinux compressed/vmlinux.out
 	tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
 
-bzImage: $(CONFIGURE) bbootsect bsetup compressed/bvmlinux tools/build
+bzImage: bbootsect bsetup compressed/bvmlinux tools/build
 	$(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out
 	tools/build -b bbootsect bsetup compressed/bvmlinux.out $(ROOT_DEV) > bzImage
 
@@ -51,14 +51,14 @@
 zdisk: $(BOOTIMAGE)
 	dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0
 
-zlilo: $(CONFIGURE) $(BOOTIMAGE)
+zlilo: $(BOOTIMAGE)
 	if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi
 	if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi
 	cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz
 	cp $(TOPDIR)/System.map $(INSTALL_PATH)/
 	if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
 
-install: $(CONFIGURE) $(BOOTIMAGE)
+install: $(BOOTIMAGE)
 	sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map "$(INSTALL_PATH)"
 
 tools/build: tools/build.c
diff -Nru a/drivers/acpi/Config.in b/drivers/acpi/Config.in
--- a/drivers/acpi/Config.in	Sat Jun  8 22:31:52 2002
+++ b/drivers/acpi/Config.in	Sat Jun  8 22:31:52 2002
@@ -23,7 +23,7 @@
       if [ "$CONFIG_PCI" = "y" ]; then
         define_bool CONFIG_ACPI_PCI		y
       fi
-      define_bool CONFIG_ACPI_SLEEP		y
+      define_bool CONFIG_ACPI_SLEEP		$CONFIG_SOFTWARE_SUSPEND
       define_bool CONFIG_ACPI_SYSTEM		y
       tristate     '  AC Adapter'	CONFIG_ACPI_AC
       tristate     '  Battery'		CONFIG_ACPI_BATTERY
diff -Nru a/drivers/acpi/system.c b/drivers/acpi/system.c
--- a/drivers/acpi/system.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/acpi/system.c	Sat Jun  8 22:31:51 2002
@@ -260,37 +260,23 @@
 	u32			state)
 {
 	acpi_status		status = AE_ERROR;
-#if 0
 	unsigned long		flags = 0;
 
-	/* this is very broken, so don't do anything until it's fixed */
 	save_flags(flags);
 	
 	switch (state)
 	{
 	case ACPI_STATE_S1:
-		/* do nothing */
+		barrier();
+		status = acpi_enter_sleep_state(state);
 		break;
 
 	case ACPI_STATE_S2:
 	case ACPI_STATE_S3:
-		save_processor_context();
-		/* TODO: this is horribly broken, fix it */
-		/* TODO: inline this function in acpi_suspend,or something. */
+		do_suspend_lowlevel(0);
 		break;
 	}
-
-	barrier();
-	status = acpi_enter_sleep_state(state);
-
-acpi_sleep_done:
-
-	restore_processor_context();
-	fix_processor_context();
-
 	restore_flags(flags);
-#endif
-	printk("ACPI: ACPI-based suspend currently broken, aborting\n");
 
 	return status;
 }
@@ -311,6 +297,8 @@
 	if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5)
 		return AE_ERROR;
 
+	freeze_processes();		/* device_suspend needs processes to be stopped */
+
 	/* do we have a wakeup address for S2 and S3? */
 	if (state == ACPI_STATE_S2 || state == ACPI_STATE_S3) {
 		if (!acpi_wakeup_address)
@@ -343,6 +331,7 @@
 
 	/* reset firmware waking vector */
 	acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0);
+	thaw_processes();
 
 	return status;
 }
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Sat Jun  8 22:31:35 2002
+++ b/drivers/atm/Makefile	Sat Jun  8 22:31:35 2002
@@ -56,6 +56,8 @@
 
 fore_200e-objs	:= fore200e.o $(FORE200E_FW_OBJS)
 
+host-progs := fore200e_mkfirm
+
 include $(TOPDIR)/Rules.make
 
 
@@ -79,9 +81,6 @@
 	  echo 'FORE200E_FW_UP_TO_DATE += $@'; \
 	  echo 'endif' \
 	) >.$@.fw
-
-fore200e_mkfirm: fore200e_mkfirm.c
-	$(HOSTCC) $(HOSTCFLAGS) $< -o $@
 
 # deal with the various suffixes of the binary firmware images
 %.bin %.bin1 %.bin2: %.data
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/base/base.h	Sat Jun  8 22:31:37 2002
@@ -18,5 +18,5 @@
 
 extern int device_bus_link(struct device * dev);
 
-extern int driver_bind(struct device_driver * drv);
-extern void driver_unbind(struct device_driver * drv);
+extern int driver_attach(struct device_driver * drv);
+extern void driver_detach(struct device_driver * drv);
diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c
--- a/drivers/base/bus.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/base/bus.c	Sat Jun  8 22:31:36 2002
@@ -167,12 +167,13 @@
 
 int bus_register(struct bus_type * bus)
 {
-	spin_lock(&device_lock);
 	rwlock_init(&bus->lock);
 	INIT_LIST_HEAD(&bus->devices);
 	INIT_LIST_HEAD(&bus->drivers);
-	list_add_tail(&bus->node,&bus_driver_list);
 	atomic_set(&bus->refcount,2);
+
+	spin_lock(&device_lock);
+	list_add_tail(&bus->node,&bus_driver_list);
 	spin_unlock(&device_lock);
 
 	pr_debug("bus type '%s' registered\n",bus->name);
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/base/core.c	Sat Jun  8 22:31:35 2002
@@ -5,6 +5,8 @@
  *		 2002 Open Source Development Lab
  */
 
+#define DEBUG 0
+
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -29,7 +31,7 @@
  * @dev:	device 
  * @drv:	driver
  *
- * We're here because the bus's bind callback returned success for this 
+ * We're here because the bus's match callback returned success for this 
  * pair. We call the driver's probe callback to verify they're really a
  * match made in heaven.
  *
@@ -65,62 +67,75 @@
 }
 
 /**
- * bind_device - try to associated device with a driver
+ * device_attach - try to associated device with a driver
  * @drv:	current driver to try
  * @data:	device in disguise
  *
  * This function is used as a callback to bus_for_each_drv.
- * It calls the bus's ::bind callback to check if the driver supports
+ * It calls the bus's match callback to check if the driver supports
  * the device. If so, it calls the found_match() function above to 
  * take care of all the details.
  */
-static int do_device_bind(struct device_driver * drv, void * data)
+static int do_device_attach(struct device_driver * drv, void * data)
 {
 	struct device * dev = (struct device *)data;
 	int error = 0;
 
 	if (!dev->driver) {
-		if (drv->bus->bind && drv->bus->bind(dev,drv))
+		if (drv->bus->match && drv->bus->match(dev,drv))
 			error = found_match(dev,drv);
 	}
 	return error;
 }
 
-static int device_bind(struct device * dev)
+static int device_attach(struct device * dev)
 {
 	int error = 0;
 	if (dev->bus)
-		error = bus_for_each_drv(dev->bus,dev,do_device_bind);
+		error = bus_for_each_drv(dev->bus,dev,do_device_attach);
 	return error;
 }
 
-static void device_unbind(struct device * dev)
+static void device_detach(struct device * dev)
 {
-	/* unbind from driver */
-	if (dev->driver && dev->driver->remove)
-		dev->driver->remove(dev);
+	struct device_driver * drv; 
+
+	if (dev->driver) {
+		lock_device(dev);
+		drv = dev->driver;
+		dev->driver = NULL;
+		unlock_device(dev);
+
+		write_lock(&drv->lock);
+		list_del_init(&dev->driver_list);
+		write_unlock(&drv->lock);
+
+		/* detach from driver */
+		if (drv->remove)
+			drv->remove(dev);
+		put_driver(drv);
+	}
 }
 
-static int do_driver_bind(struct device * dev, void * data)
+static int do_driver_attach(struct device * dev, void * data)
 {
 	struct device_driver * drv = (struct device_driver *)data;
 	int error = 0;
 
 	if (!dev->driver) {
-		if (dev->bus->bind && dev->bus->bind(dev,drv))
+		if (dev->bus->match && dev->bus->match(dev,drv))
 			error = found_match(dev,drv);
 	}
 	return error;
 }
 
-int driver_bind(struct device_driver * drv)
+int driver_attach(struct device_driver * drv)
 {
-	return bus_for_each_dev(drv->bus,drv,do_driver_bind);
+	return bus_for_each_dev(drv->bus,drv,do_driver_attach);
 }
 
-static int do_driver_unbind(struct device * dev, void * data)
+static int do_driver_detach(struct device * dev, struct device_driver * drv)
 {
-	struct device_driver * drv = (struct device_driver *)data;
 	lock_device(dev);
 	if (dev->driver == drv) {
 		dev->driver = NULL;
@@ -132,9 +147,34 @@
 	return 0;
 }
 
-void driver_unbind(struct device_driver * drv)
+void driver_detach(struct device_driver * drv)
 {
-	driver_for_each_dev(drv,drv,do_driver_unbind);
+	struct device * next;
+	struct device * dev = NULL;
+	struct list_head * node;
+	int error = 0;
+
+	write_lock(&drv->lock);
+	node = drv->devices.next;
+	while (node != &drv->devices) {
+		next = list_entry(node,struct device,driver_list);
+		get_device(next);
+		list_del_init(&next->driver_list);
+		write_unlock(&drv->lock);
+
+		if (dev)
+			put_device(dev);
+		dev = next;
+		if ((error = do_driver_detach(dev,drv))) {
+			put_device(dev);
+			break;
+		}
+		write_lock(&drv->lock);
+		node = drv->devices.next;
+	}
+	write_unlock(&drv->lock);
+	if (dev)
+		put_device(dev);
 }
 
 /**
@@ -156,13 +196,13 @@
 	if (!dev || !strlen(dev->bus_id))
 		return -EINVAL;
 
-	spin_lock(&device_lock);
 	INIT_LIST_HEAD(&dev->node);
 	INIT_LIST_HEAD(&dev->children);
 	INIT_LIST_HEAD(&dev->g_list);
 	spin_lock_init(&dev->lock);
 	atomic_set(&dev->refcount,2);
 
+	spin_lock(&device_lock);
 	if (dev != &device_root) {
 		if (!dev->parent)
 			dev->parent = &device_root;
@@ -178,8 +218,8 @@
 	}
 	spin_unlock(&device_lock);
 
-	DBG("DEV: registering device: ID = '%s', name = %s\n",
-	    dev->bus_id, dev->name);
+	pr_debug("DEV: registering device: ID = '%s', name = %s\n",
+		 dev->bus_id, dev->name);
 
 	if ((error = device_make_dir(dev)))
 		goto register_done;
@@ -187,7 +227,7 @@
 	bus_add_device(dev);
 
 	/* bind to driver */
-	device_bind(dev);
+	device_attach(dev);
 
 	/* notify platform of device entry */
 	if (platform_notify)
@@ -212,8 +252,8 @@
 	list_del_init(&dev->g_list);
 	spin_unlock(&device_lock);
 
-	DBG("DEV: Unregistering device. ID = '%s', name = '%s'\n",
-	    dev->bus_id,dev->name);
+	pr_debug("DEV: Unregistering device. ID = '%s', name = '%s'\n",
+		 dev->bus_id,dev->name);
 
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
@@ -221,7 +261,7 @@
 	if (platform_notify_remove)
 		platform_notify_remove(dev);
 
-	device_unbind(dev);
+	device_detach(dev);
 	bus_remove_device(dev);
 
 	/* remove the driverfs directory */
diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c
--- a/drivers/base/driver.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/base/driver.c	Sat Jun  8 22:31:52 2002
@@ -3,6 +3,8 @@
  *
  */
 
+#define DEBUG 0
+
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/errno.h>
@@ -67,40 +69,52 @@
 	get_bus(drv->bus);
 	atomic_set(&drv->refcount,2);
 	rwlock_init(&drv->lock);
+	INIT_LIST_HEAD(&drv->devices);
 	write_lock(&drv->bus->lock);
 	list_add(&drv->bus_list,&drv->bus->drivers);
 	write_unlock(&drv->bus->lock);
 	driver_make_dir(drv);
-	driver_bind(drv);
+	driver_attach(drv);
 	put_driver(drv);
 	return 0;
 }
 
+static void __remove_driver(struct device_driver * drv)
+{
+	pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
+	driver_detach(drv);
+	driverfs_remove_dir(&drv->dir);
+	if (drv->release)
+		drv->release(drv);
+	put_bus(drv->bus);
+}
+
+void remove_driver(struct device_driver * drv)
+{
+	write_lock(&drv->bus->lock);
+	atomic_set(&drv->refcount,0);
+	list_del_init(&drv->bus_list);
+	write_unlock(&drv->bus->lock);
+	__remove_driver(drv);
+}
+
 /**
  * put_driver - decrement driver's refcount and clean up if necessary
  * @drv:	driver in question
  */
 void put_driver(struct device_driver * drv)
 {
-	if (!atomic_dec_and_lock(&drv->refcount,&device_lock))
-		return;
-	spin_unlock(&device_lock);
-
-	if (drv->bus) {
-		pr_debug("Unregistering driver '%s' from bus '%s'\n",drv->name,drv->bus->name);
-
-		driver_unbind(drv);
-		write_lock(&drv->bus->lock);
-		list_del_init(&drv->bus_list);
+	write_lock(&drv->bus->lock);
+	if (!atomic_dec_and_test(&drv->refcount)) {
 		write_unlock(&drv->bus->lock);
-
-		driverfs_remove_dir(&drv->dir);
-		put_bus(drv->bus);
+		return;
 	}
-	if (drv->release)
-		drv->release(drv);
+	list_del_init(&drv->bus_list);
+	write_unlock(&drv->bus->lock);
+	__remove_driver(drv);
 }
 
 EXPORT_SYMBOL(driver_for_each_dev);
 EXPORT_SYMBOL(driver_register);
 EXPORT_SYMBOL(put_driver);
+EXPORT_SYMBOL(remove_driver);
diff -Nru a/drivers/base/sys.c b/drivers/base/sys.c
--- a/drivers/base/sys.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/base/sys.c	Sat Jun  8 22:31:35 2002
@@ -44,6 +44,6 @@
        return device_register(&system_bus);
 }
 
-subsys_initcall(sys_bus_init);
+postcore_initcall(sys_bus_init);
 EXPORT_SYMBOL(register_sys_device);
 EXPORT_SYMBOL(unregister_sys_device);
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/block/ll_rw_blk.c	Sat Jun  8 22:31:36 2002
@@ -507,7 +507,6 @@
 	"REQ_STARTED",
 	"REQ_DONTPREP",
 	"REQ_QUEUED",
-	"REQ_DRIVE_ACB",
 	"REQ_PC",
 	"REQ_BLOCK_PC",
 	"REQ_SENSE",
@@ -821,7 +820,7 @@
 	/*
 	 * not plugged
 	 */
-	if (!__test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+	if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
 		return;
 
 	if (test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags))
@@ -893,6 +892,20 @@
  **/
 void blk_stop_queue(request_queue_t *q)
 {
+	unsigned long flags;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+
+	/*
+	 * remove from the plugged list, queue must not be called.
+	 */
+	if (test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
+		spin_lock(&blk_plug_lock);
+		list_del(&q->plug_list);
+		spin_unlock(&blk_plug_lock);
+	}
+
+	spin_unlock_irqrestore(q->queue_lock, flags);
 	set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
 }
 
@@ -904,45 +917,36 @@
  *   are currently stopped are ignored. This is equivalent to the older
  *   tq_disk task queue run.
  **/
+#define blk_plug_entry(entry) list_entry((entry), request_queue_t, plug_list)
 void blk_run_queues(void)
 {
-	struct list_head *n, *tmp, local_plug_list;
-	unsigned long flags;
+	struct list_head local_plug_list;
 
 	INIT_LIST_HEAD(&local_plug_list);
 
+	spin_lock_irq(&blk_plug_lock);
+
 	/*
 	 * this will happen fairly often
 	 */
-	spin_lock_irqsave(&blk_plug_lock, flags);
 	if (list_empty(&blk_plug_list)) {
-		spin_unlock_irqrestore(&blk_plug_lock, flags);
+		spin_unlock_irq(&blk_plug_lock);
 		return;
 	}
 
 	list_splice(&blk_plug_list, &local_plug_list);
 	INIT_LIST_HEAD(&blk_plug_list);
-	spin_unlock_irqrestore(&blk_plug_lock, flags);
-
-	/*
-	 * local_plug_list is now a private copy we can traverse lockless
-	 */
-	list_for_each_safe(n, tmp, &local_plug_list) {
-		request_queue_t *q = list_entry(n, request_queue_t, plug_list);
-
-		if (!test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) {
-			list_del(&q->plug_list);
-			generic_unplug_device(q);
-		}
-	}
-
-	/*
-	 * add any remaining queue back to plug list
-	 */
-	if (!list_empty(&local_plug_list)) {
-		spin_lock_irqsave(&blk_plug_lock, flags);
-		list_splice(&local_plug_list, &blk_plug_list);
-		spin_unlock_irqrestore(&blk_plug_lock, flags);
+	spin_unlock_irq(&blk_plug_lock);
+	
+	while (!list_empty(&local_plug_list)) {
+		request_queue_t *q = blk_plug_entry(local_plug_list.next);
+
+		BUG_ON(test_bit(QUEUE_FLAG_STOPPED, &q->queue_flags));
+
+		spin_lock_irq(q->queue_lock);
+		list_del(&q->plug_list);
+		__generic_unplug_device(q);
+		spin_unlock_irq(q->queue_lock);
 	}
 }
 
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/block/rd.c	Sat Jun  8 22:31:51 2002
@@ -144,6 +144,7 @@
 {
 	struct address_space * mapping;
 	unsigned long index;
+	unsigned int vec_offset;
 	int offset, size, err;
 
 	err = 0;
@@ -152,6 +153,7 @@
 	index = sector >> (PAGE_CACHE_SHIFT - 9);
 	offset = (sector << 9) & ~PAGE_CACHE_MASK;
 	size = vec->bv_len;
+	vec_offset = vec->bv_offset;
 
 	do {
 		int count;
@@ -186,13 +188,14 @@
 		if (rw == READ) {
 			src = kmap(page);
 			src += offset;
-			dst = kmap(vec->bv_page) + vec->bv_offset;
+			dst = kmap(vec->bv_page) + vec_offset;
 		} else {
 			dst = kmap(page);
 			dst += offset;
-			src = kmap(vec->bv_page) + vec->bv_offset;
+			src = kmap(vec->bv_page) + vec_offset;
 		}
 		offset = 0;
+		vec_offset += count;
 
 		memcpy(dst, src, count);
 
diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
--- a/drivers/bluetooth/hci_vhci.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/bluetooth/hci_vhci.c	Sat Jun  8 22:31:52 2002
@@ -139,7 +139,10 @@
 	if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
 		return -ENOMEM;
 	
-	copy_from_user(skb_put(skb, count), buf, count); 
+	if (copy_from_user(skb_put(skb, count), buf, count)) {
+		kfree_skb(skb);
+		return -EFAULT;
+	}
 
 	skb->dev = (void *) &hci_vhci->hdev;
 	skb->pkt_type = *((__u8 *) skb->data);
@@ -170,7 +173,8 @@
 	char *ptr = buf;
 
 	len = MIN(skb->len, len); 
-	copy_to_user(ptr, skb->data, len); 
+	if (copy_to_user(ptr, skb->data, len))
+		return -EFAULT;
 	total += len;
 
 	hci_vhci->hdev.stat.byte_tx += len;
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
--- a/drivers/cdrom/cdu31a.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/cdrom/cdu31a.c	Sat Jun  8 22:31:36 2002
@@ -2619,13 +2619,14 @@
 						retval = -EIO;
 						goto exit_read_audio;
 					}
-				} else {
-					copy_to_user((char *) (ra->buf +
+				} else if (copy_to_user((char *)(ra->buf +
 							       (CD_FRAMESIZE_RAW
 								* cframe)),
-						     (char *)
-						     readahead_buffer,
-						     CD_FRAMESIZE_RAW);
+							(char *)
+							       readahead_buffer,
+							CD_FRAMESIZE_RAW)) {
+					retval = -EFAULT;
+					goto exit_read_audio;
 				}
 			} else {
 				printk
@@ -2635,12 +2636,12 @@
 				retval = -EIO;
 				goto exit_read_audio;
 			}
-		} else {
-			copy_to_user((char *) (ra->buf +
-					       (CD_FRAMESIZE_RAW *
-						cframe)),
-				     (char *) readahead_buffer,
-				     CD_FRAMESIZE_RAW);
+		} else if (copy_to_user((char *)(ra->buf + (CD_FRAMESIZE_RAW *
+							    cframe)),
+					(char *)readahead_buffer,
+					CD_FRAMESIZE_RAW)) {
+			retval = -EFAULT;
+			goto exit_read_audio;
 		}
 
 		cframe++;
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/cdrom/optcd.c	Sat Jun  8 22:31:36 2002
@@ -1445,10 +1445,8 @@
 	int status;
 	struct cdrom_msf msf;
 
-	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
-	if (status)
-		return status;
-	copy_from_user(&msf, (void *) arg, sizeof msf);
+	if (copy_from_user(&msf, (void *) arg, sizeof msf))
+		return -EFAULT;
 
 	bin2bcd(&msf);
 	status = exec_long_cmd(COMPLAY, &msf);
@@ -1469,10 +1467,8 @@
 	struct cdrom_ti ti;
 	struct cdrom_msf msf;
 
-	status = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
-	if (status)
-		return status;
-	copy_from_user(&ti, (void *) arg, sizeof ti);
+	if (copy_from_user(&ti, (void *) arg, sizeof ti))
+		return -EFAULT;
 
 	if (ti.cdti_trk0 < disk_info.first
 	    || ti.cdti_trk0 > disk_info.last
@@ -1514,15 +1510,10 @@
 	int status;
 	struct cdrom_tochdr tochdr;
 
-	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof tochdr);
-	if (status)
-		return status;
-
 	tochdr.cdth_trk0 = disk_info.first;
 	tochdr.cdth_trk1 = disk_info.last;
 
-	copy_to_user((void *) arg, &tochdr, sizeof tochdr);
-	return 0;
+	return copy_to_user((void *)arg, &tochdr, sizeof tochdr) ? -EFAULT : 0;
 }
 
 
@@ -1532,10 +1523,8 @@
 	struct cdrom_tocentry entry;
 	struct cdrom_subchnl *tocptr;
 
-	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
-	if (status)
-		return status;
-	copy_from_user(&entry, (void *) arg, sizeof entry);
+	if (copy_from_user(&entry, (void *) arg, sizeof entry))
+		return -EFAULT;
 
 	if (entry.cdte_track == CDROM_LEADOUT)
 		tocptr = &toc[disk_info.last + 1];
@@ -1557,8 +1546,7 @@
 	else if (entry.cdte_format != CDROM_MSF)
 		return -EINVAL;
 
-	copy_to_user((void *) arg, &entry, sizeof entry);
-	return 0;
+	return copy_to_user((void *)arg, &entry, sizeof entry) ? -EFAULT : 0;
 }
 
 
@@ -1568,10 +1556,8 @@
 	struct cdrom_volctrl volctrl;
 	struct cdrom_msf msf;
 
-	status = verify_area(VERIFY_READ, (void *) arg, sizeof volctrl);
-	if (status)
-		return status;
-	copy_from_user(&volctrl, (char *) arg, sizeof volctrl);
+	if (copy_from_user(&volctrl, (char *) arg, sizeof volctrl))
+		return -EFAULT;
 
 	msf.cdmsf_min0 = 0x10;
 	msf.cdmsf_sec0 = 0x32;
@@ -1594,10 +1580,8 @@
 	int status;
 	struct cdrom_subchnl subchnl;
 
-	status = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl);
-	if (status)
-		return status;
-	copy_from_user(&subchnl, (void *) arg, sizeof subchnl);
+	if (copy_from_user(&subchnl, (void *) arg, sizeof subchnl))
+		return -EFAULT;
 
 	if (subchnl.cdsc_format != CDROM_LBA
 	    && subchnl.cdsc_format != CDROM_MSF)
@@ -1609,7 +1593,8 @@
 		return -EIO;
 	}
 
-	copy_to_user((void *) arg, &subchnl, sizeof subchnl);
+	if (copy_to_user((void *)arg, &subchnl, sizeof subchnl))
+		return -EFAULT;
 	return 0;
 }
 
@@ -1620,10 +1605,8 @@
 	struct cdrom_msf msf;
 	char buf[CD_FRAMESIZE_RAWER];
 
-	status = verify_area(VERIFY_WRITE, (void *) arg, blocksize);
-	if (status)
-		return status;
-	copy_from_user(&msf, (void *) arg, sizeof msf);
+	if (copy_from_user(&msf, (void *) arg, sizeof msf))
+		return -EFAULT;
 
 	bin2bcd(&msf);
 	msf.cdmsf_min1 = 0;
@@ -1637,8 +1620,7 @@
 		return -EIO;
 	fetch_data(buf, blocksize);
 
-	copy_to_user((void *) arg, &buf, blocksize);
-	return 0;
+	return copy_to_user((void *)arg, &buf, blocksize) ? -EFAULT : 0;
 }
 
 
@@ -1647,10 +1629,8 @@
 	int status;
 	struct cdrom_msf msf;
 
-	status = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
-	if (status)
-		return status;
-	copy_from_user(&msf, (void *) arg, sizeof msf);
+	if (copy_from_user(&msf, (void *)arg, sizeof msf))
+		return -EFAULT;
 
 	bin2bcd(&msf);
 	status = exec_seek_cmd(COMSEEK, &msf);
@@ -1669,10 +1649,8 @@
 	int status;
 	struct cdrom_multisession ms;
 
-	status = verify_area(VERIFY_WRITE, (void*) arg, sizeof ms);
-	if (status)
-		return status;
-	copy_from_user(&ms, (void*) arg, sizeof ms);
+	if (copy_from_user(&ms, (void*) arg, sizeof ms))
+		return -EFAULT;
 
 	ms.addr.msf.minute = disk_info.last_session.minute;
 	ms.addr.msf.second = disk_info.last_session.second;
@@ -1686,8 +1664,8 @@
 
 	ms.xa_flag = disk_info.xa;
 
-  	copy_to_user((void*) arg, &ms,
-		sizeof(struct cdrom_multisession));
+  	if (copy_to_user((void *)arg, &ms, sizeof(struct cdrom_multisession)))
+		return -EFAULT;
 
 #if DEBUG_MULTIS
  	if (ms.addr_format == CDROM_MSF)
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/cdrom/sbpcd.c	Sat Jun  8 22:31:36 2002
@@ -4255,9 +4255,9 @@
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
 #endif /* SAFE_MIXED */ 
 		if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL);
-		i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
-		if (i) RETURN_UP(i);
-		copy_from_user(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio));
+		if (copy_from_user(&read_audio, (void *)arg,
+				   sizeof(struct cdrom_read_audio)))
+			RETURN_UP(-EFAULT);
 		if (read_audio.nframes < 0 || read_audio.nframes>D_S[d].sbp_audsiz) RETURN_UP(-EINVAL);
 		i=verify_area(VERIFY_WRITE, read_audio.buf,
 			      read_audio.nframes*CD_FRAMESIZE_RAW);
@@ -4454,9 +4454,10 @@
 				msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i);
 				continue;
 			}
-			copy_to_user((u_char *) read_audio.buf,
-				    (u_char *) D_S[d].aud_buf,
-				    read_audio.nframes*CD_FRAMESIZE_RAW);
+			if (copy_to_user((u_char *)read_audio.buf,
+					 (u_char *) D_S[d].aud_buf,
+					 read_audio.nframes * CD_FRAMESIZE_RAW))
+				RETURN_UP(-EFAULT);
 			msg(DBG_AUD,"read_audio: copy_to_user done.\n");
 			break;
 		}
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/cdrom/sjcd.c	Sat Jun  8 22:31:51 2002
@@ -795,16 +795,12 @@
 
 	case CDROMPLAYTRKIND:{
 			struct cdrom_ti ti;
-			int s;
+			int s = -EFAULT;
 #if defined( SJCD_TRACE )
 			printk("SJCD: ioctl: playtrkind\n");
 #endif
-			if ((s =
-			     verify_area(VERIFY_READ, (void *) arg,
-					 sizeof(ti))) == 0) {
-				copy_from_user(&ti, (void *) arg,
-					       sizeof(ti));
-
+			if (!copy_from_user(&ti, (void *) arg, sizeof(ti))) {
+				s = 0;
 				if (ti.cdti_trk0 < sjcd_first_track_no)
 					return (-EINVAL);
 				if (ti.cdti_trk1 > sjcd_last_track_no)
@@ -879,19 +875,15 @@
 
 	case CDROMREADTOCHDR:{
 			struct cdrom_tochdr toc_header;
-			int s;
 #if defined (SJCD_TRACE )
 			printk("SJCD: ioctl: readtocheader\n");
 #endif
-			if ((s =
-			     verify_area(VERIFY_WRITE, (void *) arg,
-					 sizeof(toc_header))) == 0) {
-				toc_header.cdth_trk0 = sjcd_first_track_no;
-				toc_header.cdth_trk1 = sjcd_last_track_no;
-				copy_to_user((void *) arg, &toc_header,
-					     sizeof(toc_header));
-			}
-			return (s);
+			toc_header.cdth_trk0 = sjcd_first_track_no;
+			toc_header.cdth_trk1 = sjcd_last_track_no;
+			if (copy_to_user((void *)arg, &toc_header,
+					 sizeof(toc_header)))
+				return -EFAULT;
+			return 0;
 		}
 
 	case CDROMREADTOCENTRY:{
@@ -942,8 +934,9 @@
 				default:
 					return (-EINVAL);
 				}
-				copy_to_user((void *) arg, &toc_entry,
-					     sizeof(toc_entry));
+				if (copy_to_user((void *) arg, &toc_entry,
+						 sizeof(toc_entry)))
+					s = -EFAULT;
 			}
 			return (s);
 		}
@@ -998,8 +991,9 @@
 				default:
 					return (-EINVAL);
 				}
-				copy_to_user((void *) arg, &subchnl,
-					     sizeof(subchnl));
+				if (copy_to_user((void *) arg, &subchnl,
+					         sizeof(subchnl)))
+					s = -EFAULT;
 			}
 			return (s);
 		}
@@ -1041,16 +1035,13 @@
 
 #if defined( SJCD_GATHER_STAT )
 	case 0xABCD:{
-			int s;
 #if defined( SJCD_TRACE )
 			printk("SJCD: ioctl: statistic\n");
 #endif
-			if ((s =
-			     verify_area(VERIFY_WRITE, (void *) arg,
-					 sizeof(statistic))) == 0)
-				copy_to_user((void *) arg, &statistic,
-					     sizeof(statistic));
-			return (s);
+			if (copy_to_user((void *)arg, &statistic,
+					 sizeof(statistic)))
+				return -EFAULT;
+			return 0;
 		}
 #endif
 
diff -Nru a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
--- a/drivers/cdrom/sonycd535.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/cdrom/sonycd535.c	Sat Jun  8 22:31:37 2002
@@ -1022,11 +1022,8 @@
 	if (!sony_toc_read) {
 		return -EIO;
 	}
-	err = verify_area(VERIFY_WRITE /* and read */ , (char *)arg, sizeof schi);
-	if (err)
-		return err;
-
-	copy_from_user(&schi, (char *)arg, sizeof schi);
+	if (copy_from_user(&schi, (char *)arg, sizeof schi))
+		return -EFAULT;
 
 	switch (sony_audio_status) {
 	case CDROM_AUDIO_PLAY:
@@ -1041,7 +1038,8 @@
 
 	case CDROM_AUDIO_NO_STATUS:
 		schi.cdsc_audiostatus = sony_audio_status;
-		copy_to_user((char *)arg, &schi, sizeof schi);
+		if (copy_to_user((char *)arg, &schi, sizeof schi))
+			return -EFAULT;
 		return 0;
 		break;
 
@@ -1068,8 +1066,7 @@
 		schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf);
 		schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf);
 	}
-	copy_to_user((char *)arg, &schi, sizeof schi);
-	return 0;
+	return copy_to_user((char *)arg, &schi, sizeof schi) ? -EFAULT : 0;
 }
 
 
@@ -1218,12 +1215,10 @@
 			if (!sony_toc_read)
 				return -EIO;
 			hdr = (struct cdrom_tochdr *)arg;
-			err = verify_area(VERIFY_WRITE, hdr, sizeof *hdr);
-			if (err)
-				return err;
 			loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num);
 			loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num);
-			copy_to_user(hdr, &loc_hdr, sizeof *hdr);
+			if (copy_to_user(hdr, &loc_hdr, sizeof *hdr))
+				return -EFAULT;
 		}
 		return 0;
 		break;
@@ -1240,11 +1235,9 @@
 				return -EIO;
 			}
 			entry = (struct cdrom_tocentry *)arg;
-			err = verify_area(VERIFY_WRITE /* and read */ , entry, sizeof *entry);
-			if (err)
-				return err;
 
-			copy_from_user(&loc_entry, entry, sizeof loc_entry);
+			if (copy_from_user(&loc_entry, entry, sizeof loc_entry))
+				return -EFAULT;
 
 			/* Lead out is handled separately since it is special. */
 			if (loc_entry.cdte_track == CDROM_LEADOUT) {
@@ -1268,7 +1261,8 @@
 				loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1));
 				loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2));
 			}
-			copy_to_user(entry, &loc_entry, sizeof *entry);
+			if (copy_to_user(entry, &loc_entry, sizeof *entry))
+				return -EFAULT;
 		}
 		return 0;
 		break;
@@ -1281,11 +1275,9 @@
 			sony_get_toc();
 			if (!sony_toc_read)
 				return -EIO;
-			err = verify_area(VERIFY_READ, (char *)arg, sizeof ti);
-			if (err)
-				return err;
 
-			copy_from_user(&ti, (char *)arg, sizeof ti);
+			if (copy_from_user(&ti, (char *)arg, sizeof ti))
+				return -EFAULT;
 			if ((ti.cdti_trk0 < sony_toc->first_track_num)
 				|| (sony_toc->last_track_num < ti.cdti_trk0)
 				|| (ti.cdti_trk1 < ti.cdti_trk0)) {
@@ -1352,11 +1344,9 @@
 		{
 			struct cdrom_volctrl volctrl;
 
-			err = verify_area(VERIFY_READ, (char *)arg, sizeof volctrl);
-			if (err)
-				return err;
-
-			copy_from_user(&volctrl, (char *)arg, sizeof volctrl);
+			if (copy_from_user(&volctrl, (char *)arg,
+					   sizeof volctrl))
+				return -EFAULT;
 			cmd_buff[0] = SONY535_SET_VOLUME;
 			cmd_buff[1] = volctrl.channel0;
 			cmd_buff[2] = volctrl.channel1;
diff -Nru a/drivers/char/Makefile b/drivers/char/Makefile
--- a/drivers/char/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/char/Makefile	Sat Jun  8 22:31:37 2002
@@ -214,17 +214,12 @@
 obj-$(CONFIG_DRM) += drm/
 obj-$(CONFIG_PCMCIA) += pcmcia/
 
-include $(TOPDIR)/Rules.make
-
-fastdep:
+host-progs := conmakehash
 
-conmakehash: conmakehash.c
-	$(HOSTCC) $(HOSTCFLAGS) -o conmakehash conmakehash.c
+include $(TOPDIR)/Rules.make
 
 consolemap_deftbl.c: $(FONTMAPFILE) conmakehash
-	./conmakehash $(FONTMAPFILE) > consolemap_deftbl.c
-
-consolemap_deftbl.o: consolemap_deftbl.c $(TOPDIR)/include/linux/types.h
+	./conmakehash $< > $@
 
 .DELETE_ON_ERROR:
 
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
--- a/drivers/char/drm/i810_dma.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/char/drm/i810_dma.c	Sat Jun  8 22:31:37 2002
@@ -1209,7 +1209,8 @@
 
 	data.offset = dev_priv->overlay_offset;
 	data.physical = dev_priv->overlay_physical;
-	copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
+	if (copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data)))
+		return -EFAULT;
 	return 0;
 }
 
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/hotplug/ibmphp_core.c	Sat Jun  8 22:31:43 2002
@@ -44,7 +44,7 @@
 #define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev)
 #define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt)
 
-#define DRIVER_VERSION	"0.2"
+#define DRIVER_VERSION	"0.3"
 #define DRIVER_DESC	"IBM Hot Plug PCI Controller Driver"
 
 int ibmphp_debug;
@@ -106,7 +106,7 @@
 	return rc;
 }
 
-static int get_max_slots (void)
+static int __init get_max_slots (void)
 {
 	struct list_head * tmp;
 	int slot_count = 0;
@@ -528,7 +528,7 @@
  * function. It will also power off empty slots that are powered on since BIOS
  * leaves those on, albeit disconnected
  ******************************************************************************/
-static int init_ops (void)
+static int __init init_ops (void)
 {
 	struct slot *slot_cur;
 	int retval;
diff -Nru a/drivers/hotplug/ibmphp_ebda.c b/drivers/hotplug/ibmphp_ebda.c
--- a/drivers/hotplug/ibmphp_ebda.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/hotplug/ibmphp_ebda.c	Sat Jun  8 22:31:36 2002
@@ -34,6 +34,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
 /*
@@ -76,7 +77,7 @@
 	return slot;
 }
 
-static struct ebda_hpc_list *alloc_ebda_hpc_list (void)
+static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void)
 {
 	struct ebda_hpc_list *list;
 
@@ -127,7 +128,7 @@
 	kfree (controller);
 }
 
-static struct ebda_rsrc_list *alloc_ebda_rsrc_list (void)
+static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void)
 {
 	struct ebda_rsrc_list *list;
 
@@ -149,7 +150,7 @@
 	return resource;
 }
 
-static void print_bus_info (void)
+static void __init print_bus_info (void)
 {
 	struct bus_info *ptr;
 	struct list_head *ptr1;
@@ -184,7 +185,7 @@
 	}
 }
 
-static void print_ebda_hpc (void)
+static void __init print_ebda_hpc (void)
 {
 	struct controller *hpc_ptr;
 	struct list_head *ptr1;
@@ -228,7 +229,7 @@
 	}
 }
 
-int ibmphp_access_ebda (void)
+int __init ibmphp_access_ebda (void)
 {
 	u8 format, num_ctlrs, rio_complete, hs_complete;
 	u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base;
@@ -387,7 +388,7 @@
  * each hpc from physical address to a list of hot plug controllers based on
  * hpc descriptors.
  */
-static int ebda_rsrc_controller (void)
+static int __init ebda_rsrc_controller (void)
 {
 	u16 addr, addr_slot, addr_bus;
 	u8 ctlr_id, temp, bus_index;
@@ -649,7 +650,7 @@
  * map info (bus, devfun, start addr, end addr..) of i/o, memory,
  * pfm from the physical addr to a list of resource.
  */
-static int ebda_rsrc_rsrc (void)
+static int __init ebda_rsrc_rsrc (void)
 {
 	u16 addr;
 	short rsrc;
@@ -717,7 +718,7 @@
 /*
  * map info of scalability details and rio details from physical address
  */
-static int ebda_rio_table(void)
+static int __init ebda_rio_table(void)
 {
 	u16 offset;
 	u8 i;
diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c
--- a/drivers/hotplug/ibmphp_hpc.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/hotplug/ibmphp_hpc.c	Sat Jun  8 22:31:36 2002
@@ -3,7 +3,7 @@
  *
  * Written By: Jyoti Shah, IBM Corporation
  *
- * Copyright (c) 2001,2001 IBM Corp.
+ * Copyright (c) 2001-2002 IBM Corp.
  *
  * All rights reserved.
  *
@@ -27,17 +27,14 @@
  *
  */
 
-//#include <linux/delay.h>
 #include <linux/wait.h>
 #include <linux/time.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
-#define POLL_NO		0x01
-#define POLL_YES	0x00
-
 static int to_debug = FALSE;
 #define debug_polling(fmt, arg...)	do { if (to_debug) debug (fmt, arg); } while (0)
 
@@ -98,19 +95,15 @@
 // if bits 20,22,25,26,27,29,30 are OFF return TRUE
 #define HPC_I2CSTATUS_CHECK(s)	((u8)((s & 0x00000A76) ? FALSE : TRUE))
 
-// return code 0:poll slots, 1-POLL_LATCH_CNT:poll latch register
-#define INCREMENT_POLLCNT(i)	((i < POLL_LATCH_CNT) ? i++ : (i=0))
 //----------------------------------------------------------------------------
 // global variables
 //----------------------------------------------------------------------------
 static int ibmphp_shutdown;
 static int tid_poll;
-static int stop_polling;		// 2 values: poll, don't poll
 static struct semaphore sem_hpcaccess;	// lock access to HPC
 static struct semaphore semOperations;	// lock all operations and
 					// access to data structures
 static struct semaphore sem_exit;	// make sure polling thread goes away
-static struct semaphore sem_poll;	// make sure poll is idle 
 //----------------------------------------------------------------------------
 // local function prototypes
 //----------------------------------------------------------------------------
@@ -134,15 +127,13 @@
 *
 * Action:  initialize semaphores and variables
 *---------------------------------------------------------------------*/
-void ibmphp_hpc_initvars (void)
+void __init ibmphp_hpc_initvars (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
 
 	init_MUTEX (&sem_hpcaccess);
 	init_MUTEX (&semOperations);
 	init_MUTEX_LOCKED (&sem_exit);
-	init_MUTEX_LOCKED (&sem_poll);
-	stop_polling = POLL_YES;
 	to_debug = FALSE;
 	ibmphp_shutdown = FALSE;
 	tid_poll = 0;
@@ -710,11 +701,6 @@
 void ibmphp_lock_operations (void)
 {
 	down (&semOperations);
-	stop_polling = POLL_NO;
-	to_debug = TRUE;
-
-	/* waiting for polling to actually stop */
-	down (&sem_poll);
 }
 
 /*----------------------------------------------------------------------
@@ -723,8 +709,6 @@
 void ibmphp_unlock_operations (void)
 {
 	debug ("%s - Entry\n", __FUNCTION__);
-	stop_polling = POLL_YES;
-	to_debug = FALSE;
 	up (&semOperations);
 	debug ("%s - Exit\n", __FUNCTION__);
 }
@@ -732,34 +716,30 @@
 /*----------------------------------------------------------------------
 * Name:    poll_hpc()
 *---------------------------------------------------------------------*/
+#define POLL_LATCH_REGISTER	0
+#define POLL_SLOTS		1
+#define POLL_SLEEP		2
 static void poll_hpc (void)
 {
-	struct slot myslot, *pslot = NULL;
+	struct slot myslot;
+	struct slot *pslot = NULL;
 	struct list_head *pslotlist;
 	int rc;
+	int poll_state = POLL_LATCH_REGISTER;
 	u8 oldlatchlow = 0x00;
 	u8 curlatchlow = 0x00;
-	int pollcnt = 0;
+	int poll_count = 0;
 	u8 ctrl_count = 0x00;
 
-	debug ("poll_hpc - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	while (!ibmphp_shutdown) {
-		if (stop_polling) {
-			debug ("poll_hpc - stop_polling\n");
-			up (&sem_poll); 
-			/* to prevent deadlock */
-			if (ibmphp_shutdown)
-				break;
-			/* to make the thread sleep */
-			down (&semOperations);
-			up (&semOperations);
-			debug ("poll_hpc - after stop_polling sleep\n");
-		} else {
-			if (pollcnt) {
-				// only poll the latch register
-				oldlatchlow = curlatchlow;
+		/* try to get the lock to do some kind of harware access */
+		down (&semOperations);
 
+		switch (poll_state) {
+			case POLL_LATCH_REGISTER:
+				oldlatchlow = curlatchlow;
 				ctrl_count = 0x00;
 				list_for_each (pslotlist, &ibmphp_slot_head) {
 					if (ctrl_count >= ibmphp_get_total_controllers())
@@ -773,14 +753,16 @@
 										  &curlatchlow);
 							if (oldlatchlow != curlatchlow)
 								process_changeinlatch (oldlatchlow,
-											curlatchlow, pslot->ctrl);
+										       curlatchlow,
+										       pslot->ctrl);
 						}
 					}
 				}
-			} else {
+				poll_state = POLL_SLOTS;
+				break;
+
+			case POLL_SLOTS:
 				list_for_each (pslotlist, &ibmphp_slot_head) {
-					if (stop_polling)
-						break;
 					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
 					// make a copy of the old status
 					memcpy ((void *) &myslot, (void *) pslot,
@@ -791,31 +773,45 @@
 						process_changeinstatus (pslot, &myslot);
 				}
 
-				if (!stop_polling) {
-					ctrl_count = 0x00;
-					list_for_each (pslotlist, &ibmphp_slot_head) {
-						if (ctrl_count >= ibmphp_get_total_controllers())
-							break;
-						pslot =
-						    list_entry (pslotlist, struct slot,
-								ibm_slot_list);
-						if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
-							ctrl_count++;
-							if (READ_SLOT_LATCH (pslot->ctrl))
-								rc = ibmphp_hpc_readslot (pslot,
-											  READ_SLOTLATCHLOWREG,
-											  &curlatchlow);
-						}
+				ctrl_count = 0x00;
+				list_for_each (pslotlist, &ibmphp_slot_head) {
+					if (ctrl_count >= ibmphp_get_total_controllers())
+						break;
+					pslot = list_entry (pslotlist, struct slot, ibm_slot_list);
+					if (pslot->ctrl->ctlr_relative_id == ctrl_count) {
+						ctrl_count++;
+						if (READ_SLOT_LATCH (pslot->ctrl))
+							rc = ibmphp_hpc_readslot (pslot,
+										  READ_SLOTLATCHLOWREG,
+										  &curlatchlow);
 					}
 				}
-			}
-			INCREMENT_POLLCNT (pollcnt);
-			long_delay (POLL_INTERVAL_SEC * HZ);	// snooze
+				++poll_count;
+				if (poll_count >= POLL_LATCH_CNT) {
+					poll_count = 0;
+					poll_state = POLL_SLEEP;
+				}
+				break;
+
+			case POLL_SLEEP:
+				/* don't sleep with a lock on the hardware */
+				up (&semOperations);
+				long_delay (POLL_INTERVAL_SEC * HZ);
+				down (&semOperations);
+				poll_state = POLL_LATCH_REGISTER;
+				break;
 		}
+
+		/* give up the harware semaphore */
+		up (&semOperations);
+
+		/* sleep for a short time just for good measure */
+		set_current_state (TASK_INTERRUPTIBLE);
+		schedule_timeout (HZ/10);
 	}
-	up (&sem_poll);
+
 	up (&sem_exit);
-	debug ("poll_hpc - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 
@@ -1049,19 +1045,19 @@
 *
 * Action:  start polling thread
 *---------------------------------------------------------------------*/
-int ibmphp_hpc_start_poll_thread (void)
+int __init ibmphp_hpc_start_poll_thread (void)
 {
 	int rc = 0;
 
-	debug ("ibmphp_hpc_start_poll_thread - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	tid_poll = kernel_thread (hpc_poll_thread, 0, 0);
 	if (tid_poll < 0) {
-		err ("ibmphp_hpc_start_poll_thread - Error, thread not started\n");
+		err ("%s - Error, thread not started\n", __FUNCTION__);
 		rc = -1;
 	}
 
-	debug ("ibmphp_hpc_start_poll_thread - Exit tid_poll[%d] rc[%d]\n", tid_poll, rc);
+	debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc);
 	return rc;
 }
 
@@ -1070,9 +1066,9 @@
 *
 * Action:  stop polling thread and cleanup
 *---------------------------------------------------------------------*/
-void ibmphp_hpc_stop_poll_thread (void)
+void __exit ibmphp_hpc_stop_poll_thread (void)
 {
-	debug ("ibmphp_hpc_stop_poll_thread - Entry\n");
+	debug ("%s - Entry\n", __FUNCTION__);
 
 	ibmphp_shutdown = TRUE;
 	ibmphp_lock_operations ();
@@ -1083,10 +1079,9 @@
 	// cleanup
 	free_hpc_access ();
 	ibmphp_unlock_operations ();
-	up (&sem_poll);
 	up (&sem_exit);
 
-	debug ("ibmphp_hpc_stop_poll_thread - Exit\n");
+	debug ("%s - Exit\n", __FUNCTION__);
 }
 
 /*----------------------------------------------------------------------
diff -Nru a/drivers/hotplug/ibmphp_res.c b/drivers/hotplug/ibmphp_res.c
--- a/drivers/hotplug/ibmphp_res.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/hotplug/ibmphp_res.c	Sat Jun  8 22:31:37 2002
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/list.h>
+#include <linux/init.h>
 #include "ibmphp.h"
 
 static int flags = 0;		/* for testing */
@@ -45,7 +46,7 @@
 
 static LIST_HEAD(gbuses);
 
-static struct bus_node * alloc_error_bus (struct ebda_pci_rsrc * curr)
+static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr)
 {
 	struct bus_node * newbus;
 
@@ -61,7 +62,7 @@
 	return newbus;
 }
 
-static struct resource_node * alloc_resources (struct ebda_pci_rsrc * curr)
+static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr)
 {
 	struct resource_node *rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL);
 	if (!rs) {
@@ -77,7 +78,7 @@
 	return rs;
 }
 
-static int alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
+static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus)
 {
 	struct bus_node * newbus;
 	struct range_node *newrange;
@@ -184,7 +185,7 @@
  * Input: ptr to the head of the resource list from EBDA
  * Output: 0, -1 or error codes
  ***************************************************************************/
-int ibmphp_rsrc_init (void)
+int __init ibmphp_rsrc_init (void)
 {
 	struct ebda_pci_rsrc *curr;
 	struct range_node *newrange = NULL;
@@ -1650,7 +1651,7 @@
  * a new Mem node
  * This routine is called right after initialization
  *******************************************************************************/
-static int once_over (void)
+static int __init once_over (void)
 {
 	struct resource_node *pfmem_cur;
 	struct resource_node *pfmem_prev;
@@ -1871,7 +1872,7 @@
  *	 behind them All these are TO DO.
  *	 Also need to add more error checkings... (from fnc returns etc)
  */
-static int update_bridge_ranges (struct bus_node **bus)
+static int __init update_bridge_ranges (struct bus_node **bus)
 {
 	u8 sec_busno, device, function, busno, hdr_type, start_io_address, end_io_address;
 	u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address;
@@ -1885,7 +1886,7 @@
 	bus_cur = *bus;
 	busno = bus_cur->busno;
 
-	debug ("inside update_bridge_ranges \n");
+	debug ("inside %s \n", __FUNCTION__);
 	debug ("bus_cur->busno = %x\n", bus_cur->busno);
 
 	for (device = 0; device < 32; device++) {
diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c
--- a/drivers/hotplug/pci_hotplug_core.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/hotplug/pci_hotplug_core.c	Sat Jun  8 22:31:37 2002
@@ -36,6 +36,7 @@
 #include <linux/slab.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
+#include <linux/namei.h>
 #include <linux/pci.h>
 #include <asm/uaccess.h>
 #include "pci_hotplug.h"
@@ -290,7 +291,7 @@
 
 static struct super_operations pcihpfs_ops = {
 	statfs:		simple_statfs,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 };
 
 static int pcihpfs_fill_super(struct super_block *sb, void *data, int silent)
diff -Nru a/drivers/ide/Config.help b/drivers/ide/Config.help
--- a/drivers/ide/Config.help	Sat Jun  8 22:31:52 2002
+++ b/drivers/ide/Config.help	Sat Jun  8 22:31:52 2002
@@ -409,13 +409,14 @@
   the chip to optimum performance.
 
 CONFIG_BLK_DEV_PIIX_TRY133
-  The ICH2, ICH2-M, ICH3, ICH3-M, ICH3-S and CICH chips can support
-  UDMA133 in hardware, even though the specifications of the chips
-  say otherwise. By enabling this option, you allow the driver to
-  enable the UDMA133 mode on these chips.
+  The ICH2, ICH2-M, ICH3, ICH3-M, ICH3-S, ICH-4 and CICH chips can
+  support UDMA133 in hardware, even though the specifications of
+  the chips say otherwise. By enabling this option, you allow the
+  driver to enable the UDMA133 mode on these chips. Note that if
+  it doesn't work, your data gets lost, you're on your own, don't
+  expect any help. 
 
-  If you want to stay on the safe side, say N here.
-  If you prefer maximum performance, say Y here.
+  Say N here, unless you really know what are you doing.
 
 CONFIG_BLK_DEV_PDC202XX
   Promise Ultra33 or PDC20246
diff -Nru a/drivers/ide/Config.in b/drivers/ide/Config.in
--- a/drivers/ide/Config.in	Sat Jun  8 22:31:52 2002
+++ b/drivers/ide/Config.in	Sat Jun  8 22:31:52 2002
@@ -53,7 +53,7 @@
       dep_bool '    HPT366 chipset support' CONFIG_BLK_DEV_HPT366 $CONFIG_BLK_DEV_IDEDMA_PCI
       dep_bool '    Intel and Efar (SMsC) chipset support' CONFIG_BLK_DEV_PIIX $CONFIG_BLK_DEV_IDEDMA_PCI
       if [ "$CONFIG_BLK_DEV_PIIX" = "y" ]; then
-         dep_bool '      Use UDMA133 even on ICH2, ICH3 and CICH chips (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TRY133 $CONFIG_EXPERIMENTAL
+         dep_bool '      Allow undocumented UDMA133 on ICH chips (EXPERIMENTAL)' CONFIG_BLK_DEV_PIIX_TRY133 $CONFIG_EXPERIMENTAL
       fi
       if [ "$CONFIG_MIPS_ITE8172" = "y" -o "$CONFIG_MIPS_IVR" = "y" ]; then
          dep_mbool '    IT8172 IDE support' CONFIG_BLK_DEV_IT8172 $CONFIG_BLK_DEV_IDEDMA_PCI
diff -Nru a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c
--- a/drivers/ide/ali14xx.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/ali14xx.c	Sat Jun  8 22:31:37 2002
@@ -13,7 +13,7 @@
  * I think the code should be pretty understandable,
  * but I'll be happy to (try to) answer questions.
  *
- * The critical part is in the setupDrive function.  The initRegisters
+ * The critical part is in the ali14xx_tune_drive function.  The init_registers
  * function doesn't seem to be necessary, but the DOS driver does it, so
  * I threw it in.
  *
@@ -37,12 +37,6 @@
 
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/ioport.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
 #include <linux/ide.h>
 #include <linux/init.h>
 
@@ -52,12 +46,14 @@
 
 /* port addresses for auto-detection */
 #define ALI_NUM_PORTS 4
-static int ports[ALI_NUM_PORTS] __initdata = {0x074, 0x0f4, 0x034, 0x0e4};
+static int ports[ALI_NUM_PORTS] __initdata = { 0x074, 0x0f4, 0x034, 0x0e4 };
 
 /* register initialization data */
-typedef struct { byte reg, data; } RegInitializer;
+struct reg_initializer {
+	u8 reg, data; 
+};
 
-static RegInitializer initData[] __initdata = {
+static struct reg_initializer init_data[] __initdata = {
 	{0x01, 0x0f}, {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x00},
 	{0x05, 0x00}, {0x06, 0x00}, {0x07, 0x2b}, {0x0a, 0x0f},
 	{0x25, 0x00}, {0x26, 0x00}, {0x27, 0x00}, {0x28, 0x00},
@@ -68,37 +64,37 @@
 };
 
 /* timing parameter registers for each drive */
-static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = {
-	{0x03, 0x26, 0x04, 0x27},     /* drive 0 */
-	{0x05, 0x28, 0x06, 0x29},     /* drive 1 */
-	{0x2b, 0x30, 0x2c, 0x31},     /* drive 2 */
-	{0x2d, 0x32, 0x2e, 0x33},     /* drive 3 */
+static struct {
+	u8 reg1, reg2, reg3, reg4;
+} reg_tab[4] = {
+	{ 0x03, 0x26, 0x04, 0x27 },	/* drive 0 */
+	{ 0x05, 0x28, 0x06, 0x29 },	/* drive 1 */
+	{ 0x2b, 0x30, 0x2c, 0x31 },	/* drive 2 */
+	{ 0x2d, 0x32, 0x2e, 0x33 },	/* drive 3 */
 };
 
-static int basePort;	/* base port address */
-static int regPort;	/* port for register number */
-static int dataPort;	/* port for register data */
-static byte regOn;	/* output to base port to access registers */
-static byte regOff;	/* output to base port to close registers */
-
-/*------------------------------------------------------------------------*/
+static int base_port;	/* base port address */
+static int reg_port;	/* port for register number */
+static int data_port;	/* port for register data */
+static u8 reg_on;	/* output to base port to access registers */
+static u8 reg_off;	/* output to base port to close registers */
 
 /*
  * Read a controller register.
  */
-static inline byte inReg (byte reg)
+static inline u8 in_reg(u8 reg)
 {
-	outb_p(reg, regPort);
-	return inb(dataPort);
+	outb_p(reg, reg_port);
+	return inb(data_port);
 }
 
 /*
  * Write a controller register.
  */
-static void outReg (byte data, byte reg)
+static inline void out_reg(u8 data, u8 reg)
 {
-	outb_p(reg, regPort);
-	outb_p(data, dataPort);
+	outb_p(reg, reg_port);
+	outb_p(data, data_port);
 }
 
 /*
@@ -108,7 +104,7 @@
  */
 static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
 {
-	int driveNum;
+	int drive_num;
 	int time1, time2;
 	u8 param1, param2, param3, param4;
 	unsigned long flags;
@@ -117,7 +113,7 @@
 	if (pio == 255)
 		pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO);
 	else
-		pio = XFER_PIO_0 + min_t(byte, pio, 4);
+		pio = XFER_PIO_0 + min_t(u8, pio, 4);
 
 	t = ata_timing_data(pio);
 
@@ -130,50 +126,50 @@
 		param3 += 8;
 		param4 += 8;
 	}
-	printk("%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
+	printk(KERN_DEBUG "%s: PIO mode%d, t1=%dns, t2=%dns, cycles = %d+%d, %d+%d\n",
 		drive->name, pio - XFER_PIO_0, time1, time2, param1, param2, param3, param4);
 
 	/* stuff timing parameters into controller registers */
-	driveNum = (drive->channel->index << 1) + drive->select.b.unit;
+	drive_num = (drive->channel->index << 1) + drive->select.b.unit;
 	save_flags(flags);	/* all CPUs */
 	cli();			/* all CPUs */
-	outb_p(regOn, basePort);
-	outReg(param1, regTab[driveNum].reg1);
-	outReg(param2, regTab[driveNum].reg2);
-	outReg(param3, regTab[driveNum].reg3);
-	outReg(param4, regTab[driveNum].reg4);
-	outb_p(regOff, basePort);
+	outb_p(reg_on, base_port);
+	out_reg(param1, reg_tab[drive_num].reg1);
+	out_reg(param2, reg_tab[drive_num].reg2);
+	out_reg(param3, reg_tab[drive_num].reg3);
+	out_reg(param4, reg_tab[drive_num].reg4);
+	outb_p(reg_off, base_port);
 	restore_flags(flags);	/* all CPUs */
 }
 
 /*
  * Auto-detect the IDE controller port.
  */
-static int __init findPort (void)
+static int __init find_port(void)
 {
 	int i;
-	byte t;
 	unsigned long flags;
 
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
-	for (i = 0; i < ALI_NUM_PORTS; ++i) {
-		basePort = ports[i];
-		regOff = inb(basePort);
-		for (regOn = 0x30; regOn <= 0x33; ++regOn) {
-			outb_p(regOn, basePort);
-			if (inb(basePort) == regOn) {
-				regPort = basePort + 4;
-				dataPort = basePort + 8;
-				t = inReg(0) & 0xf0;
-				outb_p(regOff, basePort);
+	for (i = 0; i < ALI_NUM_PORTS; i++) {
+		base_port = ports[i];
+		reg_off = inb(base_port);
+		for (reg_on = 0x30; reg_on <= 0x33; reg_on++) {
+			outb_p(reg_on, base_port);
+			if (inb(base_port) == reg_on) {
+				u8 t;
+				reg_port = base_port + 4;
+				data_port = base_port + 8;
+				t = in_reg(0) & 0xf0;
+				outb_p(reg_off, base_port);
 				__restore_flags(flags);	/* local CPU only */
 				if (t != 0x50)
 					return 0;
-				return 1;  /* success */
+				return 1;	/* success */
 			}
 		}
-		outb_p(regOff, basePort);
+		outb_p(reg_off, base_port);
 	}
 	__restore_flags(flags);	/* local CPU only */
 	return 0;
@@ -182,32 +178,34 @@
 /*
  * Initialize controller registers with default values.
  */
-static int __init initRegisters (void) {
-	RegInitializer *p;
-	byte t;
+static int __init init_registers(void)
+{
+	struct reg_initializer *p;
 	unsigned long flags;
+	u8 t;
 
 	__save_flags(flags);	/* local CPU only */
 	__cli();		/* local CPU only */
-	outb_p(regOn, basePort);
-	for (p = initData; p->reg != 0; ++p)
-		outReg(p->data, p->reg);
-	outb_p(0x01, regPort);
-	t = inb(regPort) & 0x01;
-	outb_p(regOff, basePort);
+	outb_p(reg_on, base_port);
+	for (p = init_data; p->reg != 0; ++p)
+		out_reg(p->data, p->reg);
+	outb_p(0x01, reg_port);
+	t = inb(reg_port) & 0x01;
+	outb_p(reg_off, base_port);
 	__restore_flags(flags);	/* local CPU only */
 	return t;
 }
 
-void __init init_ali14xx (void)
+void __init init_ali14xx(void)
 {
 	/* auto-detect IDE controller port */
-	if (!findPort()) {
-		printk("\nali14xx: not found");
+	if (!find_port()) {
+		printk(KERN_ERR "ali14xx: not found\n");
 		return;
 	}
 
-	printk("\nali14xx: base= 0x%03x, regOn = 0x%02x", basePort, regOn);
+	printk(KERN_DEBUG "ali14xx: base=%#03x, reg_on=%#02x\n",
+		base_port, reg_on);
 	ide_hwifs[0].chipset = ide_ali14xx;
 	ide_hwifs[1].chipset = ide_ali14xx;
 	ide_hwifs[0].tuneproc = &ali14xx_tune_drive;
@@ -216,8 +214,8 @@
 	ide_hwifs[1].unit = ATA_SECONDARY;
 
 	/* initialize controller registers */
-	if (!initRegisters()) {
-		printk("\nali14xx: Chip initialization failed");
+	if (!init_registers()) {
+		printk(KERN_ERR "ali14xx: Chip initialization failed\n");
 		return;
 	}
 }
diff -Nru a/drivers/ide/device.c b/drivers/ide/device.c
--- a/drivers/ide/device.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/device.c	Sat Jun  8 22:31:37 2002
@@ -159,4 +159,18 @@
 	OUT_BYTE(rf->high_cylinder, ch->io_ports[IDE_HCYL_OFFSET]);
 }
 
+/*
+ * Output a complete register file.
+ */
+void ata_in_regfile(struct ata_device *drive, struct hd_drive_task_hdr *rf)
+{
+	struct ata_channel *ch = drive->channel;
+
+	rf->sector_count = IN_BYTE(ch->io_ports[IDE_NSECTOR_OFFSET]);
+	rf->sector_number = IN_BYTE(ch->io_ports[IDE_SECTOR_OFFSET]);
+	rf->low_cylinder = IN_BYTE(ch->io_ports[IDE_LCYL_OFFSET]);
+	rf->high_cylinder = IN_BYTE(ch->io_ports[IDE_HCYL_OFFSET]);
+}
+
+
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/ide/hpt34x.c b/drivers/ide/hpt34x.c
--- a/drivers/ide/hpt34x.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/ide/hpt34x.c	Sat Jun  8 22:31:36 2002
@@ -253,7 +253,7 @@
 	unsigned int count;
 	u8 cmd;
 
-	if (!(count = udma_new_table(ch, rq)))
+	if (!(count = udma_new_table(drive, rq)))
 		return 1;	/* try PIO instead of DMA */
 
 	if (rq_data_dir(rq) == READ)
diff -Nru a/drivers/ide/icside.c b/drivers/ide/icside.c
--- a/drivers/ide/icside.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/ide/icside.c	Sat Jun  8 22:31:35 2002
@@ -275,12 +275,13 @@
 #define NR_ENTRIES 256
 #define TABLE_SIZE (NR_ENTRIES * 8)
 
-static int ide_build_sglist(struct ata_channel *ch, struct request *rq)
+static int ide_build_sglist(struct ata_device *drive, struct request *rq)
 {
+	struct ata_channel *ch = drive->channel;
 	struct scatterlist *sg = ch->sg_table;
 	int nents;
 
-	if (rq->flags & REQ_DRIVE_ACB) {
+	if (rq->flags & REQ_SPECIAL) {
 		struct ata_taskfile *args = rq->special;
 
 		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
@@ -294,7 +295,7 @@
 		sg->length = rq->nr_sectors * SECTOR_SIZE;
 		nents = 1;
 	} else {
-		nents = blk_rq_map_sg(rq->q, rq, sg);
+		nents = blk_rq_map_sg(&drive->queue, rq, sg);
 
 		if (rq->q && nents > rq->nr_phys_segments)
 			printk("icside: received %d segments, build %d\n",
@@ -390,7 +391,7 @@
 		udma_tcq_enable(drive, 0);
 #endif
 	}
-	
+
 	/*
 	 * We don't need any bouncing.  Yes, this looks the
 	 * wrong way around, but it is correct.
@@ -491,7 +492,7 @@
 	 */
 	BUG_ON(dma_channel_active(ch->hw.dma));
 
-	count = ch->sg_nents = ide_build_sglist(ch, rq);
+	count = ch->sg_nents = ide_build_sglist(drive, rq);
 	if (!count)
 		return 1;
 
@@ -517,33 +518,6 @@
 	return 0;
 }
 
-static int icside_dma_read(struct ata_device *drive, struct request *rq)
-{
-	struct ata_channel *ch = drive->channel;
-	unsigned int cmd;
-
-	if (icside_dma_common(drive, rq, DMA_MODE_READ))
-		return 1;
-
-	if (drive->type != ATA_DISK)
-		return 0;
-
-	ide_set_handler(drive, icside_dmaintr, WAIT_CMD, NULL);
-
-	if ((rq->flags & REQ_DRIVE_ACB) && drive->addressing == 1) {
-		struct ata_taskfile *args = rq->special;
-		cmd = args->taskfile.command;
-	} else if (drive->addressing) {
-		cmd = WIN_READDMA_EXT;
-	} else {
-		cmd = WIN_READDMA;
-	}
-
-	OUT_BYTE(cmd, IDE_COMMAND_REG);
-	enable_dma(ch->hw.dma);
-	return 0;
-}
-
 static int icside_dma_init(struct ata_device *drive, struct request *rq)
 {
 	struct ata_channel *ch = drive->channel;
@@ -557,13 +531,13 @@
 
 	ide_set_handler(drive, icside_dmaintr, WAIT_CMD, NULL);
 
-	if ((rq->flags & REQ_DRIVE_ACB) && drive->addressing == 1) {
+	if ((rq->flags & REQ_SPECIAL) && drive->addressing == 1) {
 		struct ata_taskfile *args = rq->special;
-		cmd = args->taskfile.command;
+		cmd = args->cmd;
 	} else if (drive->addressing) {
-		cmd = WIN_WRITEDMA_EXT;
+		cmd = rq_data_dir(rq) == WRITE ? WIN_WRITEDMA_EXT : WIN_READDMA_EXT;
 	} else {
-		cmd = WIN_WRITEDMA;
+		cmd = rq_data_dir(rq) == WRITE ? WIN_WRITEDMA : WIN_READDMA;
 	}
 	OUT_BYTE(cmd, IDE_COMMAND_REG);
 
@@ -586,7 +560,7 @@
 {
 	printk(KERN_ERR "ATA: %s: UDMA timeout occured:", drive->name);
 	ata_status(drive, 0, 0);
-	ide_dump_status(drive, NULL, "UDMA timeout", drive->status);
+	ata_dump(drive, NULL, "UDMA timeout");
 }
 
 static void icside_irq_lost(struct ata_device *drive)
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/ide-cd.c	Sat Jun  8 22:31:37 2002
@@ -614,7 +614,7 @@
 			return 0;
 		} else if (!pc->quiet) {
 			/* Otherwise, print an error. */
-			ide_dump_status(drive, rq, "packet command error", drive->status);
+			ata_dump(drive, rq, "packet command error");
 		}
 
 		/* Set the error flag and complete the request.
@@ -662,13 +662,13 @@
 			   sense_key == DATA_PROTECT) {
 			/* No point in retrying after an illegal
 			   request or data protect error.*/
-			ide_dump_status(drive, rq, "command error", drive->status);
+			ata_dump(drive, rq, "command error");
 			cdrom_end_request(drive, rq,  0);
 		} else if (sense_key == MEDIUM_ERROR) {
 			/* No point in re-trying a zillion times on a bad
 			 * sector.  The error is not correctable at all.
 			 */
-			ide_dump_status(drive, rq, "media error (bad sector)", drive->status);
+			ata_dump(drive, rq, "media error (bad sector)");
 			cdrom_end_request(drive, rq, 0);
 		} else if ((err & ~ABRT_ERR) != 0) {
 			/* Go to the default handler
@@ -2477,8 +2477,8 @@
 	devinfo->dev = mk_kdev(drive->channel->major, minor);
 	devinfo->ops = &ide_cdrom_dops;
 	devinfo->mask = 0;
-	*(int *)&devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
-	*(int *)&devinfo->capacity = nslots;
+	devinfo->speed = CDROM_STATE_FLAGS (drive)->current_speed;
+	devinfo->capacity = nslots;
 	devinfo->handle = (void *) drive;
 	strcpy(devinfo->name, drive->name);
 
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/ide/ide-disk.c	Sat Jun  8 22:31:35 2002
@@ -90,7 +90,224 @@
 	return 0;	/* lba_capacity value may be bad */
 }
 
-static u8 get_command(struct ata_device *drive, int cmd)
+/*
+ * Handler for command with PIO data-in phase
+ */
+static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
+{
+	char *buf = NULL;
+	unsigned long flags;
+
+	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
+		if (drive->status & (ERR_STAT|DRQ_STAT))
+			return ata_error(drive, rq, __FUNCTION__);
+
+		if (!(drive->status & BUSY_STAT)) {
+#if 0
+			printk("task_in_intr to Soon wait for next interrupt\n");
+#endif
+			ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
+
+			return ide_started;
+		}
+	}
+	buf = ide_map_rq(rq, &flags);
+#if 0
+	printk("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
+#endif
+
+	ata_read(drive, buf, SECTOR_WORDS);
+	ide_unmap_rq(rq, buf, &flags);
+
+	/* First segment of the request is complete. note that this does not
+	 * necessarily mean that the entire request is done!! this is only true
+	 * if ide_end_request() returns 0.
+	 */
+
+	if (--rq->current_nr_sectors <= 0) {
+#if 0
+		printk("Request Ended stat: %02x\n", drive->status);
+#endif
+		if (!ide_end_request(drive, rq, 1))
+			return ide_stopped;
+	}
+
+	/* still data left to transfer */
+	ide_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Handler for command with PIO data-out phase
+ */
+static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
+{
+	char *buf = NULL;
+	unsigned long flags;
+
+	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
+		return ata_error(drive, rq, __FUNCTION__);
+
+	if (!rq->current_nr_sectors)
+		if (!ide_end_request(drive, rq, 1))
+			return ide_stopped;
+
+	if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
+		buf = ide_map_rq(rq, &flags);
+#if 0
+		printk("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
+#endif
+
+		ata_write(drive, buf, SECTOR_WORDS);
+		ide_unmap_rq(rq, buf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors--;
+	}
+
+	ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Handler for command with Read Multiple
+ */
+static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
+{
+	char *buf = NULL;
+	unsigned int msect, nsect;
+	unsigned long flags;
+
+	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
+		if (drive->status & (ERR_STAT|DRQ_STAT))
+			return ata_error(drive, rq, __FUNCTION__);
+
+		/* no data yet, so wait for another interrupt */
+		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+		return ide_started;
+	}
+
+	/* (ks/hs): Fixed Multi-Sector transfer */
+	msect = drive->mult_count;
+
+	do {
+		nsect = rq->current_nr_sectors;
+		if (nsect > msect)
+			nsect = msect;
+
+		buf = ide_map_rq(rq, &flags);
+
+#if 0
+		printk("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
+			buf, nsect, rq->current_nr_sectors);
+#endif
+		ata_read(drive, buf, nsect * SECTOR_WORDS);
+		ide_unmap_rq(rq, buf, &flags);
+		rq->errors = 0;
+		rq->current_nr_sectors -= nsect;
+		msect -= nsect;
+		if (!rq->current_nr_sectors) {
+			if (!ide_end_request(drive, rq, 1))
+				return ide_stopped;
+		}
+	} while (msect);
+
+
+	/*
+	 * more data left
+	 */
+	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+
+	return ide_started;
+}
+
+static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
+{
+	int ok;
+	int mcount = drive->mult_count;
+	ide_startstop_t startstop;
+
+
+	/*
+	 * FIXME: the drive->status checks here seem to be messy.
+	 *
+	 * (ks/hs): Handle last IRQ on multi-sector transfer,
+	 * occurs after all data was sent in this chunk
+	 */
+
+	ok = ata_status(drive, DATA_READY, BAD_R_STAT);
+
+	if (!ok || !rq->nr_sectors) {
+		if (drive->status & (ERR_STAT | DRQ_STAT)) {
+			startstop = ata_error(drive, rq, __FUNCTION__);
+
+			return startstop;
+		}
+	}
+
+	if (!rq->nr_sectors) {
+		__ide_end_request(drive, rq, 1, rq->hard_nr_sectors);
+		rq->bio = NULL;
+
+		return ide_stopped;
+	}
+
+	if (!ok) {
+		/* no data yet, so wait for another interrupt */
+		if (!drive->channel->handler)
+			ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
+		return ide_started;
+	}
+
+	do {
+		char *buffer;
+		int nsect = rq->current_nr_sectors;
+		unsigned long flags;
+
+		if (nsect > mcount)
+			nsect = mcount;
+		mcount -= nsect;
+
+		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
+		rq->sector += nsect;
+		rq->nr_sectors -= nsect;
+		rq->current_nr_sectors -= nsect;
+
+		/* Do we move to the next bio after this? */
+		if (!rq->current_nr_sectors) {
+			/* remember to fix this up /jens */
+			struct bio *bio = rq->bio->bi_next;
+
+			/* end early if we ran out of requests */
+			if (!bio) {
+				mcount = 0;
+			} else {
+				rq->bio = bio;
+				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+			}
+		}
+
+		/*
+		 * Ok, we're all setup for the interrupt re-entering us on the
+		 * last transfer.
+		 */
+		ata_write(drive, buffer, nsect * SECTOR_WORDS);
+		bio_kunmap_irq(buffer, &flags);
+	} while (mcount);
+
+	rq->errors = 0;
+	if (!drive->channel->handler)
+		ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
+
+	return ide_started;
+}
+
+/*
+ * Decode with physical ATA command to use and setup associated data.
+ */
+static u8 get_command(struct ata_device *drive, struct ata_taskfile *ar, int cmd)
 {
 	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;
 
@@ -100,45 +317,63 @@
 
 	if (lba48bit) {
 		if (cmd == READ) {
-			if (drive->using_tcq)
+			ar->command_type = IDE_DRIVE_TASK_IN;
+			if (drive->using_tcq) {
 				return WIN_READDMA_QUEUED_EXT;
-			if (drive->using_dma)
+			} else if (drive->using_dma) {
 				return WIN_READDMA_EXT;
-			else if (drive->mult_count)
+			} else if (drive->mult_count) {
+				ar->handler = task_mulin_intr;
 				return WIN_MULTREAD_EXT;
-			else
+			} else {
+				ar->handler = task_in_intr;
 				return WIN_READ_EXT;
+			}
 		} else if (cmd == WRITE) {
-			if (drive->using_tcq)
+			ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
+			if (drive->using_tcq) {
 				return WIN_WRITEDMA_QUEUED_EXT;
-			if (drive->using_dma)
+			} else if (drive->using_dma) {
 				return WIN_WRITEDMA_EXT;
-			else if (drive->mult_count)
+			} else if (drive->mult_count) {
+				ar->handler = task_mulout_intr;
 				return WIN_MULTWRITE_EXT;
-			else
+			} else {
+				ar->handler = task_out_intr;
 				return WIN_WRITE_EXT;
+			}
 		}
 	} else {
 		if (cmd == READ) {
-			if (drive->using_tcq)
+			ar->command_type = IDE_DRIVE_TASK_IN;
+			if (drive->using_tcq) {
 				return WIN_READDMA_QUEUED;
-			if (drive->using_dma)
+			} else if (drive->using_dma) {
 				return WIN_READDMA;
-			else if (drive->mult_count)
+			} else if (drive->mult_count) {
+				ar->handler = task_in_intr;
 				return WIN_MULTREAD;
-			else
+			} else {
+				ar->handler = task_in_intr;
 				return WIN_READ;
+			}
 		} else if (cmd == WRITE) {
-			if (drive->using_tcq)
+			ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
+			if (drive->using_tcq) {
 				return WIN_WRITEDMA_QUEUED;
-			if (drive->using_dma)
+			} else if (drive->using_dma) {
 				return WIN_WRITEDMA;
-			else if (drive->mult_count)
+			} else if (drive->mult_count) {
+				ar->handler = task_mulout_intr;
 				return WIN_MULTWRITE;
-			else
+			} else {
+				ar->handler = task_out_intr;
 				return WIN_WRITE;
+			}
 		}
 	}
+
+	/* not reached! */
 	return WIN_NOP;
 }
 
@@ -170,7 +405,7 @@
 
 	args.taskfile.device_head = head;
 	args.taskfile.device_head |= drive->select.all;
-	args.cmd =  get_command(drive, rq_data_dir(rq));
+	args.cmd = get_command(drive, &args, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -181,7 +416,6 @@
 	printk("buffer=%p\n", rq->buffer);
 #endif
 
-	ide_cmd_type_parser(&args);
 	rq->special = &args;
 
 	return ata_taskfile(drive, &args, rq);
@@ -211,7 +445,7 @@
 
 	args.taskfile.device_head = ((block >> 8) & 0x0f);
 	args.taskfile.device_head |= drive->select.all;
-	args.cmd = get_command(drive, rq_data_dir(rq));
+	args.cmd = get_command(drive, &args, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -222,7 +456,6 @@
 	printk("buffer=%p\n", rq->buffer);
 #endif
 
-	ide_cmd_type_parser(&args);
 	rq->special = &args;
 
 	return ata_taskfile(drive, &args, rq);
@@ -264,7 +497,7 @@
 	args.hobfile.high_cylinder = (block >>= 8);	/* hi  lba */
 	args.hobfile.device_head = drive->select.all;
 
-	args.cmd = get_command(drive, rq_data_dir(rq));
+	args.cmd = get_command(drive, &args, rq_data_dir(rq));
 
 #ifdef DEBUG
 	printk("%s: %sing: ", drive->name,
@@ -275,7 +508,6 @@
 	printk("buffer=%p\n",rq->buffer);
 #endif
 
-	ide_cmd_type_parser(&args);
 	rq->special = &args;
 
 	return ata_taskfile(drive, &args, rq);
@@ -349,23 +581,21 @@
 {
 	MOD_INC_USE_COUNT;
 	if (drive->removable && drive->usage == 1) {
-		struct ata_taskfile args;
-
 		check_disk_change(inode->i_rdev);
 
-		memset(&args, 0, sizeof(args));
-
-		args.cmd = WIN_DOORLOCK;
-		ide_cmd_type_parser(&args);
-
 		/*
 		 * Ignore the return code from door_lock, since the open() has
 		 * already succeeded once, and the door_lock is irrelevant at this
 		 * time.
 		 */
+		if (drive->doorlocking) {
+			struct ata_taskfile args;
 
-		if (drive->doorlocking && ide_raw_taskfile(drive, &args))
-			drive->doorlocking = 0;
+			memset(&args, 0, sizeof(args));
+			args.cmd = WIN_DOORLOCK;
+			if (ide_raw_taskfile(drive, &args))
+				drive->doorlocking = 0;
+		}
 	}
 	return 0;
 }
@@ -380,27 +610,23 @@
 		args.cmd = WIN_FLUSH_CACHE_EXT;
 	else
 		args.cmd = WIN_FLUSH_CACHE;
-
-	ide_cmd_type_parser(&args);
-
 	return ide_raw_taskfile(drive, &args);
 }
 
 static void idedisk_release(struct inode *inode, struct file *filp, struct ata_device *drive)
 {
 	if (drive->removable && !drive->usage) {
-		struct ata_taskfile args;
-
 		/* XXX I don't think this is up to the lowlevel drivers..  --hch */
 		invalidate_bdev(inode->i_bdev, 0);
 
-		memset(&args, 0, sizeof(args));
-		args.cmd = WIN_DOORUNLOCK;
-		ide_cmd_type_parser(&args);
-
-		if (drive->doorlocking &&
-		    ide_raw_taskfile(drive, &args))
-			drive->doorlocking = 0;
+		if (drive->doorlocking) {
+			struct ata_taskfile args;
+
+			memset(&args, 0, sizeof(args));
+			args.cmd = WIN_DOORUNLOCK;
+			if (ide_raw_taskfile(drive, &args))
+				drive->doorlocking = 0;
+		}
 	}
 	if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
 		if (idedisk_flushcache(drive))
@@ -445,8 +671,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.sector_count = arg;
 	args.cmd = WIN_SETMULT;
-	ide_cmd_type_parser(&args);
-
 	if (!ide_raw_taskfile(drive, &args)) {
 		/* all went well track this setting as valid */
 		drive->mult_count = arg;
@@ -476,7 +700,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature	= (arg) ? SETFEATURES_EN_WCACHE : SETFEATURES_DIS_WCACHE;
 	args.cmd = WIN_SETFEATURES;
-	ide_cmd_type_parser(&args);
 	ide_raw_taskfile(drive, &args);
 
 	drive->wcache = arg;
@@ -490,8 +713,6 @@
 
 	memset(&args, 0, sizeof(args));
 	args.cmd = WIN_STANDBYNOW1;
-	ide_cmd_type_parser(&args);
-
 	return ide_raw_taskfile(drive, &args);
 }
 
@@ -503,7 +724,6 @@
 	args.taskfile.feature = (arg)?SETFEATURES_EN_AAM:SETFEATURES_DIS_AAM;
 	args.taskfile.sector_count = arg;
 	args.cmd = WIN_SETFEATURES;
-	ide_cmd_type_parser(&args);
 	ide_raw_taskfile(drive, &args);
 
 	drive->acoustic = arg;
@@ -623,9 +843,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.device_head = 0x40;
 	args.cmd = WIN_READ_NATIVE_MAX;
-	args.handler = task_no_data_intr;
-
-	/* submit command request */
 	ide_raw_taskfile(drive, &args);
 
 	/* if OK, compute maximum address value */
@@ -651,9 +868,6 @@
 
 	args.taskfile.device_head = 0x40;
 	args.cmd = WIN_READ_NATIVE_MAX_EXT;
-	args.handler = task_no_data_intr;
-
-        /* submit command request */
         ide_raw_taskfile(drive, &args);
 
 	/* if OK, compute maximum address value */
@@ -692,9 +906,8 @@
 
 	args.taskfile.device_head = ((addr_req >> 24) & 0x0f) | 0x40;
 	args.cmd = WIN_SET_MAX;
-	args.handler = task_no_data_intr;
-	/* submit command request */
 	ide_raw_taskfile(drive, &args);
+
 	/* if OK, read new maximum address value */
 	if (!(drive->status & ERR_STAT)) {
 		addr_set = ((args.taskfile.device_head & 0x0f) << 24)
@@ -724,12 +937,10 @@
 	args.hobfile.sector_number = (addr_req >>= 8);
 	args.hobfile.low_cylinder = (addr_req >>= 8);
 	args.hobfile.high_cylinder = (addr_req >>= 8);
-
 	args.hobfile.device_head = 0x40;
 
-        args.handler = task_no_data_intr;
-	/* submit command request */
 	ide_raw_taskfile(drive, &args);
+
 	/* if OK, compute maximum address value */
 	if (!(drive->status & ERR_STAT)) {
 		u32 high = (args.hobfile.high_cylinder << 16) |
@@ -858,7 +1069,9 @@
                         }
 #else
 			printk("%s: setmax_ext LBA %llu, native  %llu\n",
-				drive->name, set_max_ext, capacity_2);
+				drive->name,
+			       (long long) set_max_ext,
+			       (long long) capacity_2);
 #endif
 		}
 		drive->bios_cyl	= drive->cyl;
diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
--- a/drivers/ide/ide-floppy.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/ide/ide-floppy.c	Sat Jun  8 22:31:36 2002
@@ -66,7 +66,7 @@
  * Ver 0.94  Oct 27 00   Tidied up to remove strstr(Clik) everywhere
  * Ver 0.95  Nov  7 00   Brought across to kernel 2.4
  * Ver 0.96  Jan  7 01   Actually in line with release version of 2.4.0
- *                       including set_bit patch from Rusty Russel
+ *                       including set_bit patch from Rusty Russell
  * Ver 0.97  Jul 22 01   Merge 0.91-0.96 onto 0.9.sv for ac series
  * Ver 0.97.sv Aug 3 01  Backported from 2.4.7-ac3
  * Ver 0.98  Oct 26 01   Split idefloppy_transfer_pc into two pieces to
@@ -308,8 +308,6 @@
 #define	IDEFLOPPY_IOCTL_FORMAT_START		0x4602
 #define IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS	0x4603
 
-#define IDEFLOPPY_RQ			(REQ_SPECIAL)
-
 /*
  *	Error codes which are returned in rq->errors to the higher part
  *	of the driver.
@@ -633,7 +631,7 @@
 	if (!rq)
 		return 0;
 
-	if (!(rq->flags & IDEFLOPPY_RQ)) {
+	if (!(rq->flags & REQ_SPECIAL)) {
 		ide_end_request(drive, rq, uptodate);
 		return 0;
 	}
@@ -717,7 +715,7 @@
 		struct atapi_packet_command *pc, struct request *rq)
 {
 	memset(rq, 0, sizeof(*rq));
-	rq->flags = IDEFLOPPY_RQ;
+	rq->flags = REQ_SPECIAL;
 	/* FIXME: --mdcki */
 	rq->buffer = (char *) pc;
 	(void) ide_do_drive_cmd (drive, rq, ide_preempt);
@@ -1251,7 +1249,7 @@
 		}
 		pc = idefloppy_next_pc_storage(drive);
 		idefloppy_create_rw_cmd (floppy, pc, rq, block);
-	} else if (rq->flags & IDEFLOPPY_RQ) {
+	} else if (rq->flags & REQ_SPECIAL) {
 		/* FIXME: --mdcki */
 		pc = (struct atapi_packet_command *) rq->buffer;
 	} else {
@@ -1274,7 +1272,7 @@
 	memset(&rq, 0, sizeof(rq));
 	/* FIXME: --mdcki */
 	rq.buffer = (char *) pc;
-	rq.flags = IDEFLOPPY_RQ;
+	rq.flags = REQ_SPECIAL;
 
 	return ide_do_drive_cmd(drive, &rq, ide_wait);
 }
diff -Nru a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c
--- a/drivers/ide/ide-pci.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/ide/ide-pci.c	Sat Jun  8 22:31:52 2002
@@ -451,7 +451,7 @@
 		if (d->init_chipset)
 			d->init_chipset(dev);
 #ifdef __sparc__
-		printk(KERN_INFO "ATA: 100%% native mode on irq\n", __irq_itoa(pciirq));
+		printk(KERN_INFO "ATA: 100%% native mode on irq %s\n", __irq_itoa(pciirq));
 #else
 		printk(KERN_INFO "ATA: 100%% native mode on irq %d\n", pciirq);
 #endif
diff -Nru a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c
--- a/drivers/ide/ide-pmac.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/ide/ide-pmac.c	Sat Jun  8 22:31:51 2002
@@ -1126,7 +1126,7 @@
 		udelay(1);
 
 	/* Build sglist */
-	if (rq->flags & REQ_DRIVE_ACB) {
+	if (rq->flags & REQ_SPECIAL) {
 		pmac_ide[ix].sg_nents = i = pmac_raw_build_sglist(ix, rq);
 	} else {
 		pmac_ide[ix].sg_nents = i = pmac_ide_build_sglist(ix, rq);
@@ -1437,10 +1437,11 @@
 	if (drive->type != ATA_DISK)
 		return 0;
 	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, NULL);
-	if ((rq->flags & REQ_DRIVE_ACB) &&
+	if ((rq->flags & REQ_SPECIAL) &&
 		(drive->addressing == 1)) {
 		struct ata_taskfile *args = rq->special;
-		OUT_BYTE(args->taskfile.command, IDE_COMMAND_REG);
+		/* FIXME: this is never reached */
+		OUT_BYTE(args->cmd, IDE_COMMAND_REG);
 	} else if (drive->addressing) {
 		OUT_BYTE(reading ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 	} else {
diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
--- a/drivers/ide/ide-taskfile.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/ide/ide-taskfile.c	Sat Jun  8 22:31:43 2002
@@ -42,24 +42,6 @@
 #endif
 
 /*
- * for now, taskfile requests are special :/
- */
-static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
-{
-	if (rq->bio)
-		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
-	else
-		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
-}
-
-static inline void ide_unmap_rq(struct request *rq, char *to,
-				unsigned long *flags)
-{
-	if (rq->bio)
-		bio_kunmap_irq(to, flags);
-}
-
-/*
  * Data transfer functions for polled IO.
  */
 
@@ -194,129 +176,16 @@
 	return 1;	/* drive ready: *might* be interrupting */
 }
 
-/*
- * Polling wait until the drive is ready.
- *
- * Stuff the first sector(s) by implicitly calling the handler driectly
- * therafter.
- */
-void ata_poll_drive_ready(struct ata_device *drive)
-{
-	int i;
-
-	if (drive_is_ready(drive))
-		return;
-
-	/* FIXME: Replace hard-coded 100, what about error handling?
-	 */
-	for (i = 0; i < 100; ++i) {
-		if (drive_is_ready(drive))
-			break;
-	}
-}
-
-static ide_startstop_t pre_task_mulout_intr(struct ata_device *drive, struct request *rq)
-{
-	struct ata_taskfile *args = rq->special;
-	ide_startstop_t startstop;
-
-	if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ))
-		return startstop;
-
-	ata_poll_drive_ready(drive);
-
-	return args->handler(drive, rq);
-}
-
-static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request *rq)
-{
-	int ok;
-	int mcount = drive->mult_count;
-	ide_startstop_t startstop;
-
-
-	/*
-	 * FIXME: the drive->status checks here seem to be messy.
-	 *
-	 * (ks/hs): Handle last IRQ on multi-sector transfer,
-	 * occurs after all data was sent in this chunk
-	 */
-
-	ok = ata_status(drive, DATA_READY, BAD_R_STAT);
-
-	if (!ok || !rq->nr_sectors) {
-		if (drive->status & (ERR_STAT | DRQ_STAT)) {
-			startstop = ata_error(drive, rq, __FUNCTION__);
-
-			return startstop;
-		}
-	}
-
-	if (!rq->nr_sectors) {
-		__ide_end_request(drive, rq, 1, rq->hard_nr_sectors);
-		rq->bio = NULL;
-
-		return ide_stopped;
-	}
-
-	if (!ok) {
-		/* no data yet, so wait for another interrupt */
-		if (!drive->channel->handler)
-			ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-
-		return ide_started;
-	}
-
-	do {
-		char *buffer;
-		int nsect = rq->current_nr_sectors;
-		unsigned long flags;
-
-		if (nsect > mcount)
-			nsect = mcount;
-		mcount -= nsect;
-
-		buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq);
-		rq->sector += nsect;
-		rq->nr_sectors -= nsect;
-		rq->current_nr_sectors -= nsect;
-
-		/* Do we move to the next bio after this? */
-		if (!rq->current_nr_sectors) {
-			/* remember to fix this up /jens */
-			struct bio *bio = rq->bio->bi_next;
-
-			/* end early if we ran out of requests */
-			if (!bio) {
-				mcount = 0;
-			} else {
-				rq->bio = bio;
-				rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9;
-			}
-		}
-
-		/*
-		 * Ok, we're all setup for the interrupt re-entering us on the
-		 * last transfer.
-		 */
-		ata_write(drive, buffer, nsect * SECTOR_WORDS);
-		bio_kunmap_irq(buffer, &flags);
-	} while (mcount);
-
-	rq->errors = 0;
-	if (!drive->channel->handler)
-		ide_set_handler(drive, task_mulout_intr, WAIT_CMD, NULL);
-
-	return ide_started;
-}
-
 ide_startstop_t ata_taskfile(struct ata_device *drive,
 		struct ata_taskfile *ar, struct request *rq)
 {
 	struct hd_driveid *id = drive->id;
 
-	/* (ks/hs): Moved to start, do not use for multiple out commands */
-	if (ar->handler != task_mulout_intr) {
+	/* (ks/hs): Moved to start, do not use for multiple out commands.
+	 * FIXME: why not?! */
+	if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
+	      ar->cmd == WIN_MULTWRITE ||
+	      ar->cmd == WIN_MULTWRITE_EXT)) {
 		ata_irq_enable(drive, 1);
 		ata_mask(drive);
 	}
@@ -324,14 +193,12 @@
 	if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) &&
 	    (drive->addressing == 1))
 		ata_out_regfile(drive, &ar->hobfile);
-
 	ata_out_regfile(drive, &ar->taskfile);
 
-	{
-		u8 HIHI = (drive->addressing) ? 0xE0 : 0xEF;
-		OUT_BYTE((ar->taskfile.device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
-	}
-	if (ar->handler != NULL) {
+	OUT_BYTE((ar->taskfile.device_head & (drive->addressing ? 0xE0 : 0xEF)) | drive->select.all,
+			IDE_SELECT_REG);
+
+	if (ar->handler) {
 
 		/* This is apparently supposed to reset the wait timeout for
 		 * the interrupt to accur.
@@ -340,34 +207,90 @@
 		ide_set_handler(drive, ar->handler, WAIT_CMD, NULL);
 		OUT_BYTE(ar->cmd, IDE_COMMAND_REG);
 
-		/*
-		 * Warning check for race between handler and prehandler for
-		 * writing first block of data.  however since we are well
+		/* FIXME: Warning check for race between handler and prehandler
+		 * for writing first block of data.  however since we are well
 		 * inside the boundaries of the seek, we should be okay.
+		 *
+		 * FIXME: Replace the switch by using a proper command_type.
 		 */
 
-		if (ar->prehandler != NULL)
-			return ar->prehandler(drive, rq);
+		if (ar->cmd == CFA_WRITE_SECT_WO_ERASE ||
+		    ar->cmd == WIN_WRITE ||
+		    ar->cmd == WIN_WRITE_EXT ||
+		    ar->cmd == WIN_WRITE_VERIFY ||
+		    ar->cmd == WIN_WRITE_BUFFER ||
+		    ar->cmd == WIN_DOWNLOAD_MICROCODE ||
+		    ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
+		    ar->cmd == WIN_MULTWRITE ||
+		    ar->cmd == WIN_MULTWRITE_EXT) {
+			ide_startstop_t startstop;
+
+			if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
+				printk(KERN_ERR "%s: no DRQ after issuing %s\n",
+						drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
+				return startstop;
+			}
+
+			/* FIXME: This doesn't make the slightest sense.
+			 * (ks/hs): Fixed Multi Write
+			 */
+			if (!(ar->cmd == CFA_WRITE_MULTI_WO_ERASE ||
+			      ar->cmd == WIN_MULTWRITE ||
+			      ar->cmd == WIN_MULTWRITE_EXT)) {
+				unsigned long flags;
+				char *buf = ide_map_rq(rq, &flags);
+
+				/* For Write_sectors we need to stuff the first sector */
+				ata_write(drive, buf, SECTOR_WORDS);
+
+				rq->current_nr_sectors--;
+				ide_unmap_rq(rq, buf, &flags);
+
+				return ide_started;
+			} else {
+				int i;
+
+				/* Polling wait until the drive is ready.
+				 *
+				 * Stuff the first sector(s) by calling the
+				 * handler driectly therafter.
+				 *
+				 * FIXME: Replace hard-coded 100, what about
+				 * error handling?
+				 */
+
+				for (i = 0; i < 100; ++i) {
+					if (drive_is_ready(drive))
+						break;
+				}
+				if (!drive_is_ready(drive)) {
+					printk(KERN_ERR "DISASTER WAITING TO HAPPEN!\n");
+				}
+				return ar->handler(drive, rq);
+			}
+		}
 	} else {
 		/*
 		 * FIXME: This is a gross hack, need to unify tcq dma proc and
 		 * regular dma proc. It should now be easier.
+		 *
+		 * FIXME: Handle the alternateives by a command type.
 		 */
 
 		if (!drive->using_dma)
 			return ide_started;
 
 		/* for dma commands we don't set the handler */
-		if (ar->cmd == WIN_WRITEDMA
-		      || ar->cmd == WIN_WRITEDMA_EXT
-		      || ar->cmd == WIN_READDMA
-		      || ar->cmd == WIN_READDMA_EXT)
+		if (ar->cmd == WIN_WRITEDMA ||
+		    ar->cmd == WIN_WRITEDMA_EXT ||
+		    ar->cmd == WIN_READDMA ||
+		    ar->cmd == WIN_READDMA_EXT)
 			return !udma_init(drive, rq);
 #ifdef CONFIG_BLK_DEV_IDE_TCQ
-		else if (ar->cmd == WIN_WRITEDMA_QUEUED
-		      || ar->cmd == WIN_WRITEDMA_QUEUED_EXT
-		      || ar->cmd == WIN_READDMA_QUEUED
-		      || ar->cmd == WIN_READDMA_QUEUED_EXT)
+		else if (ar->cmd == WIN_WRITEDMA_QUEUED ||
+			 ar->cmd == WIN_WRITEDMA_QUEUED_EXT ||
+			 ar->cmd == WIN_READDMA_QUEUED ||
+			 ar->cmd == WIN_READDMA_QUEUED_EXT)
 			return udma_tcq_taskfile(drive, rq);
 #endif
 		else {
@@ -380,363 +303,6 @@
 }
 
 /*
- * This is invoked on completion of a WIN_RESTORE (recalibrate) cmd.
- */
-ide_startstop_t recal_intr(struct ata_device *drive, struct request *rq)
-{
-	if (!ata_status(drive, READY_STAT, BAD_STAT))
-		return ata_error(drive, rq, __FUNCTION__);
-
-	return ide_stopped;
-}
-
-/*
- * Handler for commands without a data phase
- */
-ide_startstop_t task_no_data_intr(struct ata_device *drive, struct request *rq)
-{
-	struct ata_taskfile *ar = rq->special;
-
-	ide__sti();	/* local CPU only */
-
-	if (!ata_status(drive, READY_STAT, BAD_STAT)) {
-		/* Keep quiet for NOP because it is expected to fail. */
-		if (ar && ar->cmd != WIN_NOP)
-			return ata_error(drive, rq, __FUNCTION__);
-	}
-
-	if (ar)
-		ide_end_drive_cmd(drive, rq);
-
-	return ide_stopped;
-}
-
-/*
- * Handler for command with PIO data-in phase
- */
-static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq)
-{
-	char *buf = NULL;
-	unsigned long flags;
-
-	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT|DRQ_STAT))
-			return ata_error(drive, rq, __FUNCTION__);
-
-		if (!(drive->status & BUSY_STAT)) {
-			DTF("task_in_intr to Soon wait for next interrupt\n");
-			ide_set_handler(drive, task_in_intr, WAIT_CMD, NULL);
-
-			return ide_started;
-		}
-	}
-	DTF("stat: %02x\n", drive->status);
-	buf = ide_map_rq(rq, &flags);
-	DTF("Read: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
-
-	ata_read(drive, buf, SECTOR_WORDS);
-	ide_unmap_rq(rq, buf, &flags);
-
-	/* First segment of the request is complete. note that this does not
-	 * necessarily mean that the entire request is done!! this is only true
-	 * if ide_end_request() returns 0.
-	 */
-
-	if (--rq->current_nr_sectors <= 0) {
-		DTF("Request Ended stat: %02x\n", drive->status);
-		if (!ide_end_request(drive, rq, 1))
-			return ide_stopped;
-	}
-
-	/* still data left to transfer */
-	ide_set_handler(drive, task_in_intr,  WAIT_CMD, NULL);
-
-	return ide_started;
-}
-
-static ide_startstop_t pre_task_out_intr(struct ata_device *drive, struct request *rq)
-{
-	struct ata_taskfile *args = rq->special;
-	ide_startstop_t startstop;
-
-	if (ide_wait_stat(&startstop, drive, rq, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
-		printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, drive->mult_count ? "MULTWRITE" : "WRITE");
-		return startstop;
-	}
-
-	/* (ks/hs): Fixed Multi Write */
-	if ((args->cmd != WIN_MULTWRITE) &&
-	    (args->cmd != WIN_MULTWRITE_EXT)) {
-		unsigned long flags;
-		char *buf = ide_map_rq(rq, &flags);
-		/* For Write_sectors we need to stuff the first sector */
-		ata_write(drive, buf, SECTOR_WORDS);
-		rq->current_nr_sectors--;
-		ide_unmap_rq(rq, buf, &flags);
-	} else {
-		ata_poll_drive_ready(drive);
-		return args->handler(drive, rq);
-	}
-	return ide_started;
-}
-
-/*
- * Handler for command with PIO data-out phase
- */
-static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *rq)
-{
-	char *buf = NULL;
-	unsigned long flags;
-
-	if (!ata_status(drive, DRIVE_READY, drive->bad_wstat))
-		return ata_error(drive, rq, __FUNCTION__);
-
-	if (!rq->current_nr_sectors)
-		if (!ide_end_request(drive, rq, 1))
-			return ide_stopped;
-
-	if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) {
-		buf = ide_map_rq(rq, &flags);
-		DTF("write: %p, rq->current_nr_sectors: %d\n", buf, (int) rq->current_nr_sectors);
-
-		ata_write(drive, buf, SECTOR_WORDS);
-		ide_unmap_rq(rq, buf, &flags);
-		rq->errors = 0;
-		rq->current_nr_sectors--;
-	}
-
-	ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL);
-
-	return ide_started;
-}
-
-/*
- * Handler for command with Read Multiple
- */
-static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request *rq)
-{
-	char *buf = NULL;
-	unsigned int msect, nsect;
-	unsigned long flags;
-
-	if (!ata_status(drive, DATA_READY, BAD_R_STAT)) {
-		if (drive->status & (ERR_STAT|DRQ_STAT))
-			return ata_error(drive, rq, __FUNCTION__);
-
-		/* no data yet, so wait for another interrupt */
-		ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
-		return ide_started;
-	}
-
-	/* (ks/hs): Fixed Multi-Sector transfer */
-	msect = drive->mult_count;
-
-	do {
-		nsect = rq->current_nr_sectors;
-		if (nsect > msect)
-			nsect = msect;
-
-		buf = ide_map_rq(rq, &flags);
-
-		DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %d\n",
-			buf, nsect, rq->current_nr_sectors);
-		ata_read(drive, buf, nsect * SECTOR_WORDS);
-		ide_unmap_rq(rq, buf, &flags);
-		rq->errors = 0;
-		rq->current_nr_sectors -= nsect;
-		msect -= nsect;
-		if (!rq->current_nr_sectors) {
-			if (!ide_end_request(drive, rq, 1))
-				return ide_stopped;
-		}
-	} while (msect);
-
-
-	/*
-	 * more data left
-	 */
-	ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
-
-	return ide_started;
-}
-
-/* Called to figure out the type of command being called.
- */
-void ide_cmd_type_parser(struct ata_taskfile *ar)
-{
-	struct hd_drive_task_hdr *taskfile = &ar->taskfile;
-
-	ar->prehandler = NULL;
-	ar->handler = NULL;
-
-	switch (ar->cmd) {
-		case WIN_IDENTIFY:
-		case WIN_PIDENTIFY:
-		case CFA_TRANSLATE_SECTOR:
-		case WIN_READ:
-		case WIN_READ_EXT:
-		case WIN_READ_BUFFER:
-			ar->handler = task_in_intr;
-			ar->command_type = IDE_DRIVE_TASK_IN;
-			return;
-
-		case CFA_WRITE_SECT_WO_ERASE:
-		case WIN_WRITE:
-		case WIN_WRITE_EXT:
-		case WIN_WRITE_VERIFY:
-		case WIN_WRITE_BUFFER:
-		case WIN_DOWNLOAD_MICROCODE:
-			ar->prehandler = pre_task_out_intr;
-			ar->handler = task_out_intr;
-			ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
-			return;
-
-		case WIN_MULTREAD:
-		case WIN_MULTREAD_EXT:
-			ar->handler = task_mulin_intr;
-			ar->command_type = IDE_DRIVE_TASK_IN;
-			return;
-
-		case CFA_WRITE_MULTI_WO_ERASE:
-		case WIN_MULTWRITE:
-		case WIN_MULTWRITE_EXT:
-			ar->prehandler = pre_task_mulout_intr;
-			ar->handler = task_mulout_intr;
-			ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
-			return;
-
-		case WIN_SECURITY_DISABLE:
-		case WIN_SECURITY_ERASE_UNIT:
-		case WIN_SECURITY_SET_PASS:
-		case WIN_SECURITY_UNLOCK:
-			ar->handler = task_out_intr;
-			ar->command_type = IDE_DRIVE_TASK_OUT;
-			return;
-
-		case WIN_SMART:
-			if (taskfile->feature == SMART_WRITE_LOG_SECTOR)
-				ar->prehandler = pre_task_out_intr;
-
-			ar->taskfile.low_cylinder = SMART_LCYL_PASS;
-			ar->taskfile.high_cylinder = SMART_HCYL_PASS;
-
-			switch(ar->taskfile.feature) {
-				case SMART_READ_VALUES:
-				case SMART_READ_THRESHOLDS:
-				case SMART_READ_LOG_SECTOR:
-					ar->handler = task_in_intr;
-					ar->command_type = IDE_DRIVE_TASK_IN;
-					return;
-
-				case SMART_WRITE_LOG_SECTOR:
-					ar->handler = task_out_intr;
-					ar->command_type = IDE_DRIVE_TASK_OUT;
-					return;
-
-				default:
-					ar->handler = task_no_data_intr;
-					ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-					return;
-
-			}
-#ifdef CONFIG_BLK_DEV_IDEDMA
-		case WIN_READDMA:
-		case WIN_IDENTIFY_DMA:
-		case WIN_READDMA_QUEUED:
-		case WIN_READDMA_EXT:
-		case WIN_READDMA_QUEUED_EXT:
-			ar->command_type = IDE_DRIVE_TASK_IN;
-			return;
-
-		case WIN_WRITEDMA:
-		case WIN_WRITEDMA_QUEUED:
-		case WIN_WRITEDMA_EXT:
-		case WIN_WRITEDMA_QUEUED_EXT:
-			ar->command_type = IDE_DRIVE_TASK_RAW_WRITE;
-			return;
-
-#endif
-		case WIN_SETFEATURES:
-			ar->handler = task_no_data_intr;
-			switch (ar->taskfile.feature) {
-				case SETFEATURES_XFER:
-					ar->command_type = IDE_DRIVE_TASK_SET_XFER;
-					return;
-				case SETFEATURES_DIS_DEFECT:
-				case SETFEATURES_EN_APM:
-				case SETFEATURES_DIS_MSN:
-				case SETFEATURES_EN_RI:
-				case SETFEATURES_EN_SI:
-				case SETFEATURES_DIS_RPOD:
-				case SETFEATURES_DIS_WCACHE:
-				case SETFEATURES_EN_DEFECT:
-				case SETFEATURES_DIS_APM:
-				case SETFEATURES_EN_MSN:
-				case SETFEATURES_EN_RLA:
-				case SETFEATURES_PREFETCH:
-				case SETFEATURES_EN_RPOD:
-				case SETFEATURES_DIS_RI:
-				case SETFEATURES_DIS_SI:
-				default:
-					ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-					return;
-			}
-
-		case WIN_SPECIFY:
-			ar->handler = task_no_data_intr;
-			ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-			return;
-
-		case WIN_RESTORE:
-			ar->handler = recal_intr;
-			ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-			return;
-
-		case WIN_DIAGNOSE:
-		case WIN_FLUSH_CACHE:
-		case WIN_FLUSH_CACHE_EXT:
-		case WIN_STANDBYNOW1:
-		case WIN_STANDBYNOW2:
-		case WIN_SLEEPNOW1:
-		case WIN_SLEEPNOW2:
-		case WIN_SETIDLE1:
-		case WIN_CHECKPOWERMODE1:
-		case WIN_CHECKPOWERMODE2:
-		case WIN_GETMEDIASTATUS:
-		case WIN_MEDIAEJECT:
-		case CFA_REQ_EXT_ERROR_CODE:
-		case CFA_ERASE_SECTORS:
-		case WIN_VERIFY:
-		case WIN_VERIFY_EXT:
-		case WIN_SEEK:
-		case WIN_READ_NATIVE_MAX:
-		case WIN_SET_MAX:
-		case WIN_READ_NATIVE_MAX_EXT:
-		case WIN_SET_MAX_EXT:
-		case WIN_SECURITY_ERASE_PREPARE:
-		case WIN_SECURITY_FREEZE_LOCK:
-		case WIN_DOORLOCK:
-		case WIN_DOORUNLOCK:
-		case DISABLE_SEAGATE:
-		case EXABYTE_ENABLE_NEST:
-		case WIN_SETMULT:
-		case WIN_NOP:
-			ar->handler = task_no_data_intr;
-			ar->command_type = IDE_DRIVE_TASK_NO_DATA;
-			return;
-
-		case WIN_FORMAT:
-		case WIN_INIT:
-		case WIN_DEVICE_RESET:
-		case WIN_QUEUED_SERVICE:
-		case WIN_PACKETCMD:
-		default:
-			ar->command_type = IDE_DRIVE_TASK_INVALID;
-			return;
-	}
-}
-
-/*
  * This function issues a special IDE device request onto the request queue.
  *
  * If action is ide_wait, then the rq is queued at the end of the request
@@ -798,23 +364,72 @@
 
 }
 
-int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *args)
+
+/*
+ * Invoked on completion of a special REQ_SPECIAL command.
+ */
+ide_startstop_t ata_special_intr(struct ata_device *drive, struct
+		request *rq) {
+
+	struct ata_taskfile *ar = rq->special;
+	ide_startstop_t ret = ide_stopped;
+
+	ide__sti();	/* local CPU only */
+	if (rq->buffer && ar->taskfile.sector_number) {
+		if (!ata_status(drive, 0, DRQ_STAT) && ar->taskfile.sector_number) {
+			int retries = 10;
+
+			ata_read(drive, rq->buffer, ar->taskfile.sector_number * SECTOR_WORDS);
+
+			while (!ata_status(drive, 0, BUSY_STAT) && retries--)
+				udelay(100);
+		}
+	}
+
+	if (!ata_status(drive, READY_STAT, BAD_STAT)) {
+		/* Keep quiet for NOP because it is expected to fail. */
+		if (ar->cmd != WIN_NOP)
+			ret = ata_error(drive, rq, __FUNCTION__);
+		rq->errors = 1;
+	}
+
+	ar->taskfile.feature = IN_BYTE(IDE_ERROR_REG);
+	ata_in_regfile(drive, &ar->taskfile);
+	ar->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
+	if ((drive->id->command_set_2 & 0x0400) &&
+			(drive->id->cfs_enable_2 & 0x0400) &&
+			(drive->addressing == 1)) {
+		/* The following command goes to the hob file! */
+		OUT_BYTE(0x80, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
+		ar->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
+		ata_in_regfile(drive, &ar->hobfile);
+	}
+
+	blkdev_dequeue_request(rq);
+	drive->rq = NULL;
+	end_that_request_last(rq);
+
+	return ret;
+}
+
+int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *ar)
 {
-	struct request rq;
+	struct request req;
+
+	ar->command_type = IDE_DRIVE_TASK_NO_DATA;
+	ar->handler = ata_special_intr;
 
-	memset(&rq, 0, sizeof(rq));
-	rq.flags = REQ_DRIVE_ACB;
-	rq.special = args;
+	memset(&req, 0, sizeof(req));
+	req.flags = REQ_SPECIAL;
+	req.special = ar;
 
-	return ide_do_drive_cmd(drive, &rq, ide_wait);
+	return ide_do_drive_cmd(drive, &req, ide_wait);
 }
 
 EXPORT_SYMBOL(drive_is_ready);
+EXPORT_SYMBOL(ide_do_drive_cmd);
 EXPORT_SYMBOL(ata_read);
 EXPORT_SYMBOL(ata_write);
 EXPORT_SYMBOL(ata_taskfile);
-EXPORT_SYMBOL(recal_intr);
-EXPORT_SYMBOL(task_no_data_intr);
-EXPORT_SYMBOL(ide_do_drive_cmd);
+EXPORT_SYMBOL(ata_special_intr);
 EXPORT_SYMBOL(ide_raw_taskfile);
-EXPORT_SYMBOL(ide_cmd_type_parser);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/ide.c	Sat Jun  8 22:31:37 2002
@@ -67,9 +67,6 @@
 #include "pcihost.h"
 #include "ioctl.h"
 
-/* default maximum number of failures */
-#define IDE_DEFAULT_MAX_FAILURES	1
-
 /*
  * CompactFlash cards and their relatives pretend to be removable hard disks, except:
  *	(1) they never have a slave unit, and
@@ -392,43 +389,6 @@
 		 IN_BYTE(IDE_SECTOR_REG);
 }
 
-/*
- * Clean up after success/failure of an explicit drive cmd
- *
- * Should be called under lock held.
- */
-void ide_end_drive_cmd(struct ata_device *drive, struct request *rq)
-{
-	if (rq->flags & REQ_DRIVE_ACB) {
-		struct ata_taskfile *ar = rq->special;
-
-		rq->errors = !ata_status(drive, READY_STAT, BAD_STAT);
-		if (ar) {
-			ar->taskfile.feature = IN_BYTE(IDE_ERROR_REG);
-			ar->taskfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
-			ar->taskfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
-			ar->taskfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
-			ar->taskfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
-			ar->taskfile.device_head = IN_BYTE(IDE_SELECT_REG);
-			if ((drive->id->command_set_2 & 0x0400) &&
-			    (drive->id->cfs_enable_2 & 0x0400) &&
-			    (drive->addressing == 1)) {
-				/* The following command goes to the hob file! */
-				OUT_BYTE(0x80, drive->channel->io_ports[IDE_CONTROL_OFFSET]);
-				ar->hobfile.feature = IN_BYTE(IDE_FEATURE_REG);
-				ar->hobfile.sector_count = IN_BYTE(IDE_NSECTOR_REG);
-				ar->hobfile.sector_number = IN_BYTE(IDE_SECTOR_REG);
-				ar->hobfile.low_cylinder = IN_BYTE(IDE_LCYL_REG);
-				ar->hobfile.high_cylinder = IN_BYTE(IDE_HCYL_REG);
-			}
-		}
-	}
-
-	blkdev_dequeue_request(rq);
-	drive->rq = NULL;
-	end_that_request_last(rq);
-}
-
 #if FANCY_STATUS_DUMPS
 struct ata_bit_messages {
 	u8 mask;
@@ -437,46 +397,46 @@
 };
 
 static struct ata_bit_messages ata_status_msgs[] = {
-	{ BUSY_STAT,  BUSY_STAT,  "Busy"           },
-	{ READY_STAT, READY_STAT, "DriveReady"     },
-	{ WRERR_STAT, WRERR_STAT, "DeviceFault"    },
-	{ SEEK_STAT,  SEEK_STAT,  "SeekComplete"   },
-	{ DRQ_STAT,   DRQ_STAT,   "DataRequest"    },
-	{ ECC_STAT,   ECC_STAT,   "CorrectedError" },
-	{ INDEX_STAT, INDEX_STAT, "Index"          },
-	{ ERR_STAT,   ERR_STAT,   "Error"          }
+	{ BUSY_STAT,  BUSY_STAT,  "busy"            },
+	{ READY_STAT, READY_STAT, "drive ready"     },
+	{ WRERR_STAT, WRERR_STAT, "device fault"    },
+	{ SEEK_STAT,  SEEK_STAT,  "seek complete"   },
+	{ DRQ_STAT,   DRQ_STAT,   "data request"    },
+	{ ECC_STAT,   ECC_STAT,   "corrected error" },
+	{ INDEX_STAT, INDEX_STAT, "index"           },
+	{ ERR_STAT,   ERR_STAT,   "error"           }
 };
 
 static struct ata_bit_messages ata_error_msgs[] = {
-	{ ICRC_ERR|ABRT_ERR,	ABRT_ERR,		"DriveStatusError"   },
-	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR,		"BadSector"	     },
-	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR|ABRT_ERR,	"BadCRC"	     },
-	{ ECC_ERR,		ECC_ERR,		"UncorrectableError" },
-	{ ID_ERR,		ID_ERR,			"SectorIdNotFound"   },
-	{ TRK0_ERR,		TRK0_ERR,		"TrackZeroNotFound"  },
-	{ MARK_ERR,		MARK_ERR,		"AddrMarkNotFound"   }
+	{ ICRC_ERR|ABRT_ERR,	ABRT_ERR,		"drive status error"	},
+	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR,		"bad sectorr"		},
+	{ ICRC_ERR|ABRT_ERR,	ICRC_ERR|ABRT_ERR,	"invalid checksum"	},
+	{ ECC_ERR,		ECC_ERR,		"uncorrectable error"	},
+	{ ID_ERR,		ID_ERR,			"sector id not found"   },
+	{ TRK0_ERR,		TRK0_ERR,		"track zero not found"	},
+	{ MARK_ERR,		MARK_ERR,		"addr mark not found"   }
 };
 
-static void ata_dump_bits(struct ata_bit_messages *msgs, int nr, byte bits)
+static void dump_bits(struct ata_bit_messages *msgs, int nr, byte bits)
 {
 	int i;
 
-	printk(" { ");
+	printk(" [ ");
 
 	for (i = 0; i < nr; i++, msgs++)
 		if ((bits & msgs->mask) == msgs->match)
 			printk("%s ", msgs->msg);
 
-	printk("} ");
+	printk("] ");
 }
 #else
-# define ata_dump_bits(msgs,nr,bits) do { } while (0)
+# define dump_bits(msgs,nr,bits) do { } while (0)
 #endif
 
 /*
  * Error reporting, in human readable form (luxurious, but a memory hog).
  */
-u8 ide_dump_status(struct ata_device *drive, struct request * rq, const char *msg, u8 stat)
+u8 ata_dump(struct ata_device *drive, struct request * rq, const char *msg)
 {
 	unsigned long flags;
 	u8 err = 0;
@@ -484,16 +444,16 @@
 	__save_flags (flags);	/* local CPU only */
 	ide__sti();		/* local CPU only */
 
-	printk("%s: %s: status=0x%02x", drive->name, msg, stat);
-	ata_dump_bits(ata_status_msgs, ARRAY_SIZE(ata_status_msgs), stat);
+	printk("%s: %s: status=0x%02x", drive->name, msg, drive->status);
+	dump_bits(ata_status_msgs, ARRAY_SIZE(ata_status_msgs), drive->status);
 	printk("\n");
 
-	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
+	if ((drive->status & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {
 		err = GET_ERR();
 		printk("%s: %s: error=0x%02x", drive->name, msg, err);
 #if FANCY_STATUS_DUMPS
 		if (drive->type == ATA_DISK) {
-			ata_dump_bits(ata_error_msgs, ARRAY_SIZE(ata_error_msgs), err);
+			dump_bits(ata_error_msgs, ARRAY_SIZE(ata_error_msgs), err);
 
 			if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR || (err & (ECC_ERR|ID_ERR|MARK_ERR))) {
 				if ((drive->id->command_set_2 & 0x0400) &&
@@ -566,7 +526,6 @@
  */
 static int do_recalibrate(struct ata_device *drive)
 {
-	printk(KERN_INFO "%s: recalibrating!\n", drive->name);
 
 	if (drive->type != ATA_DISK)
 		return ide_stopped;
@@ -574,11 +533,12 @@
 	if (!IS_PDC4030_DRIVE) {
 		struct ata_taskfile args;
 
+		printk(KERN_INFO "%s: recalibrating...\n", drive->name);
 		memset(&args, 0, sizeof(args));
 		args.taskfile.sector_count = drive->sect;
 		args.cmd = WIN_RESTORE;
-		args.handler = recal_intr;
-		ata_taskfile(drive, &args, NULL);
+		ide_raw_taskfile(drive, &args);
+		printk(KERN_INFO "%s: done!\n", drive->name);
 	}
 
 	return IS_PDC4030_DRIVE ? ide_stopped : ide_started;
@@ -592,14 +552,13 @@
 	u8 err;
 	u8 stat = drive->status;
 
-	err = ide_dump_status(drive, rq, msg, stat);
+	err = ata_dump(drive, rq, msg);
 	if (!drive || !rq)
 		return ide_stopped;
 
 	/* retry only "normal" I/O: */
 	if (!(rq->flags & REQ_CMD)) {
 		rq->errors = 1;
-		ide_end_drive_cmd(drive, rq);
 
 		return ide_stopped;
 	}
@@ -628,6 +587,7 @@
 		OUT_BYTE(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG);	/* force an abort */
 
 	if (rq->errors >= ERROR_MAX) {
+		printk(KERN_ERR "%s: max number of retries exceeded!\n", drive->name);
 		if (ata_ops(drive) && ata_ops(drive)->end_request)
 			ata_ops(drive)->end_request(drive, rq, 0);
 		else
@@ -724,10 +684,10 @@
 
 	/* Strange disk manager remap.
 	 */
-	if ((rq->flags & REQ_CMD) &&
-	    (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)) {
-		block += drive->sect0;
-	}
+	if (rq->flags & REQ_CMD)
+		if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY)
+			block += drive->sect0;
+
 
 	/* Yecch - this will shift the entire interval, possibly killing some
 	 * innocent following sector.
@@ -748,14 +708,8 @@
 
 	/* This issues a special drive command.
 	 */
-	if (rq->flags & REQ_DRIVE_ACB) {
-		struct ata_taskfile *ar = rq->special;
-
-		if (!(ar))
-			goto args_error;
-
-		return ata_taskfile(drive, ar, NULL);
-	}
+	if (rq->flags & REQ_SPECIAL)
+		return ata_taskfile(drive, rq->special, NULL);
 
 	/* The normal way of execution is to pass and execute the request
 	 * handler down to the device type driver.
@@ -784,19 +738,6 @@
 		ide_end_request(drive, rq, 0);
 
 	return ide_stopped;
-
-args_error:
-
-	/* NULL as arguemnt is used by ioctls as a way of waiting for all
-	 * current requests to be flushed from the queue.
-	 */
-
-#ifdef DEBUG
-	printk("%s: DRIVE_CMD (null)\n", drive->name);
-#endif
-	ide_end_drive_cmd(drive, rq);
-
-	return ide_stopped;
 }
 
 ide_startstop_t restart_request(struct ata_device *drive)
@@ -1476,12 +1417,12 @@
 EXPORT_SYMBOL(do_ide_request);
 
 EXPORT_SYMBOL(ide_set_handler);
-EXPORT_SYMBOL(ide_dump_status);
+EXPORT_SYMBOL(ata_dump);
 EXPORT_SYMBOL(ata_error);
 
 EXPORT_SYMBOL(ide_wait_stat);
+/* FIXME: this is a trully bad name */
 EXPORT_SYMBOL(restart_request);
-EXPORT_SYMBOL(ide_end_drive_cmd);
 EXPORT_SYMBOL(__ide_end_request);
 EXPORT_SYMBOL(ide_end_request);
 EXPORT_SYMBOL(ide_stall_queue);
diff -Nru a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c
--- a/drivers/ide/ioctl.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/ioctl.c	Sat Jun  8 22:31:37 2002
@@ -34,30 +34,6 @@
 #include "ioctl.h"
 
 /*
- * Invoked on completion of a special DRIVE_CMD.
- */
-static ide_startstop_t drive_cmd_intr(struct ata_device *drive, struct request *rq)
-{
-	struct ata_taskfile *ar = rq->special;
-
-	ide__sti();	/* local CPU only */
-	if (!ata_status(drive, 0, DRQ_STAT) && ar->taskfile.sector_number) {
-		int retries = 10;
-
-		ata_read(drive, rq->buffer, ar->taskfile.sector_number * SECTOR_WORDS);
-
-		while (!ata_status(drive, 0, BUSY_STAT) && retries--)
-			udelay(100);
-	}
-
-	if (!ata_status(drive, READY_STAT, BAD_STAT))
-		return ata_error(drive, rq, __FUNCTION__); /* already calls ide_end_drive_cmd */
-	ide_end_drive_cmd(drive, rq);
-
-	return ide_stopped;
-}
-
-/*
  * Implement generic ioctls invoked from userspace to imlpement specific
  * functionality.
  *
@@ -79,7 +55,7 @@
 		return -EFAULT;
 
 	memset(&rq, 0, sizeof(rq));
-	rq.flags = REQ_DRIVE_ACB;
+	rq.flags = REQ_SPECIAL;
 
 	memset(&args, 0, sizeof(args));
 
@@ -107,7 +83,7 @@
 
 	/* Issue ATA command and wait for completion.
 	 */
-	args.handler = drive_cmd_intr;
+	args.handler = ata_special_intr;
 
 	rq.buffer = argbuf + 4;
 	rq.special = &args;
@@ -150,19 +126,22 @@
 	 * configuration.
 	 */
 
-	if (!capable(CAP_SYS_ADMIN))
-		return -EACCES;
-
 	switch (cmd) {
 		case HDIO_GET_32BIT: {
 			unsigned long val = drive->channel->io_32bit;
 
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 			return 0;
 		}
 
 		case HDIO_SET_32BIT:
+		        if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (arg < 0 || arg > 1)
 				return -EINVAL;
 
@@ -178,6 +157,9 @@
 			return 0;
 
 		case HDIO_SET_PIO_MODE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (arg < 0 || arg > 255)
 				return -EINVAL;
 
@@ -198,6 +180,9 @@
 		case HDIO_GET_UNMASKINTR: {
 			unsigned long val = drive->channel->unmask;
 
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 
@@ -205,6 +190,9 @@
 		}
 
 		case HDIO_SET_UNMASKINTR:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (arg < 0 || arg > 1)
 				return -EINVAL;
 
@@ -222,6 +210,9 @@
 		case HDIO_GET_DMA: {
 			unsigned long val = drive->using_dma;
 
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (put_user(val, (unsigned long *) arg))
 				return -EFAULT;
 
@@ -229,6 +220,9 @@
 		}
 
 		case HDIO_SET_DMA:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (arg < 0 || arg > 1)
 				return -EINVAL;
 
@@ -250,6 +244,9 @@
 			struct hd_geometry *loc = (struct hd_geometry *) arg;
 			unsigned short bios_cyl = drive->bios_cyl; /* truncate */
 
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
 				return -EINVAL;
 
@@ -272,6 +269,9 @@
 		case HDIO_GETGEO_BIG_RAW: {
 			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;
 
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (!loc || (drive->type != ATA_DISK && drive->type != ATA_FLOPPY))
 				return -EINVAL;
 
@@ -292,6 +292,9 @@
 		}
 
 		case HDIO_GET_IDENTITY:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (minor(inode->i_rdev) & PARTN_MASK)
 				return -EINVAL;
 
@@ -304,11 +307,17 @@
 			return 0;
 
 		case HDIO_GET_NICE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP |
 					drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP,
 					(long *) arg);
 
 		case HDIO_SET_NICE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (arg != (arg & ((1 << IDE_NICE_DSC_OVERLAP))))
 				return -EPERM;
 
@@ -322,18 +331,27 @@
 			return 0;
 
 		case HDIO_GET_BUSSTATE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (put_user(drive->channel->bus_state, (long *)arg))
 				return -EFAULT;
 
 			return 0;
 
 		case HDIO_SET_BUSSTATE:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (drive->channel->busproc)
 				drive->channel->busproc(drive, (int)arg);
 
 			return 0;
 
 		case HDIO_DRIVE_CMD:
+			if (!capable(CAP_SYS_ADMIN))
+				return -EACCES;
+
 			if (!arg) {
 				if (ide_spin_wait_hwgroup(drive))
 					return -EBUSY;
diff -Nru a/drivers/ide/pcidma.c b/drivers/ide/pcidma.c
--- a/drivers/ide/pcidma.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/ide/pcidma.c	Sat Jun  8 22:31:36 2002
@@ -58,18 +58,19 @@
  * FIXME: taskfiles should be a map of pages, not a long virt address... /jens
  * FIXME: I agree with Jens --mdcki!
  */
-static int build_sglist(struct ata_channel *ch, struct request *rq)
+static int build_sglist(struct ata_device *drive, struct request *rq)
 {
+	struct ata_channel *ch = drive->channel;
 	struct scatterlist *sg = ch->sg_table;
 	int nents = 0;
 
-	if (rq->flags & REQ_DRIVE_ACB) {
+	if (rq->flags & REQ_SPECIAL) {
 		struct ata_taskfile *args = rq->special;
 #if 1
 		unsigned char *virt_addr = rq->buffer;
 		int sector_count = rq->nr_sectors;
 #else
-		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
+		nents = blk_rq_map_sg(&drive->queue, rq, ch->sg_table);
 
 		if (nents > rq->nr_segments)
 			printk("ide-dma: received %d segments, build %d\n", rq->nr_segments, nents);
@@ -99,7 +100,7 @@
 		sg[nents].length =  sector_count  * SECTOR_SIZE;
 		++nents;
 	} else {
-		nents = blk_rq_map_sg(rq->q, rq, ch->sg_table);
+		nents = blk_rq_map_sg(&drive->queue, rq, ch->sg_table);
 
 		if (rq->q && nents > rq->nr_phys_segments)
 			printk("ide-dma: received %d phys segments, build %d\n", rq->nr_phys_segments, nents);
@@ -150,7 +151,7 @@
 		reading = 1 << 3;
 
 	/* try PIO instead of DMA */
-	if (!udma_new_table(ch, rq))
+	if (!udma_new_table(drive, rq))
 		return 1;
 
 	outl(ch->dmatable_dma, dma_base + 4); /* PRD table */
@@ -306,8 +307,9 @@
  * This prepares a dma request.  Returns 0 if all went okay, returns 1
  * otherwise.  May also be invoked from trm290.c
  */
-int udma_new_table(struct ata_channel *ch, struct request *rq)
+int udma_new_table(struct ata_device *drive, struct request *rq)
 {
+	struct ata_channel *ch = drive->channel;
 	unsigned int *table = ch->dmatable_cpu;
 #ifdef CONFIG_BLK_DEV_TRM290
 	unsigned int is_trm290_chipset = (ch->chipset == ide_trm290);
@@ -318,7 +320,7 @@
 	int i;
 	struct scatterlist *sg;
 
-	ch->sg_nents = i = build_sglist(ch, rq);
+	ch->sg_nents = i = build_sglist(drive, rq);
 	if (!i)
 		return 0;
 
@@ -523,6 +525,7 @@
 	if (ata_start_dma(drive, rq))
 		return 1;
 
+	/* No DMA transfers on ATAPI devices. */
 	if (drive->type != ATA_DISK)
 		return 0;
 
@@ -531,13 +534,8 @@
 	else
 		cmd = 0x00;
 
-	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);	/* issue cmd to drive */
-	if ((rq->flags & REQ_DRIVE_ACB) && (drive->addressing == 1)) {
-		/* FIXME: this should never happen */
-		struct ata_taskfile *args = rq->special;
-
-		outb(args->cmd, IDE_COMMAND_REG);
-	} else if (drive->addressing)
+	ide_set_handler(drive, ide_dma_intr, WAIT_CMD, dma_timer_expiry);
+	if (drive->addressing)
 		outb(cmd ? WIN_READDMA_EXT : WIN_WRITEDMA_EXT, IDE_COMMAND_REG);
 	else
 		outb(cmd ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
diff -Nru a/drivers/ide/piix.c b/drivers/ide/piix.c
--- a/drivers/ide/piix.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/ide/piix.c	Sat Jun  8 22:31:37 2002
@@ -1,6 +1,5 @@
-/**** vi:set ts=8 sts=8 sw=8:************************************************
- *
- * $Id: piix.c,v 1.3 2002/03/29 16:06:06 vojtech Exp $
+/*
+ *  piix.c, v1.5 2002/05/03
  *
  *  Copyright (c) 2000-2002 Vojtech Pavlik
  *
@@ -9,6 +8,7 @@
  *      Andre Hedrick
  *
  *  Thanks to Daniela Egbert for advice on PIIX bugs.
+ *  Thanks to Ulf Axelsson for noticing that ICH4 only documents UDMA100.
  */
 
 /*
@@ -85,20 +85,20 @@
 	unsigned short id;
 	unsigned char flags;
 } piix_ide_chips[] = {
-	{ PCI_DEVICE_ID_INTEL_82801DB_9,	PIIX_UDMA_133 | PIIX_PINGPONG },                    /* Intel 82801DB ICH4 */
-	{ PCI_DEVICE_ID_INTEL_82801CA_11,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801CA ICH3/ICH3-S */
-	{ PCI_DEVICE_ID_INTEL_82801CA_10,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801CAM ICH3-M */
-	{ PCI_DEVICE_ID_INTEL_82801E_9,		PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801E C-ICH */
-	{ PCI_DEVICE_ID_INTEL_82801BA_9,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801BA ICH2 */
-	{ PCI_DEVICE_ID_INTEL_82801BA_8,	PIIX_UDMA_100 | PIIX_PINGPONG },                    /* Intel 82801BAM ICH2-M */
-	{ PCI_DEVICE_ID_INTEL_82801AB_1,	PIIX_UDMA_33  | PIIX_PINGPONG },                    /* Intel 82801AB ICH0 */
-	{ PCI_DEVICE_ID_INTEL_82801AA_1,	PIIX_UDMA_66  | PIIX_PINGPONG },                    /* Intel 82801AA ICH */
-	{ PCI_DEVICE_ID_INTEL_82372FB_1,	PIIX_UDMA_66 },	                                    /* Intel 82372FB PIIX5 */
-	{ PCI_DEVICE_ID_INTEL_82443MX_1,	PIIX_UDMA_33 },                                     /* Intel 82443MX MPIIX4 */
-	{ PCI_DEVICE_ID_INTEL_82371AB,		PIIX_UDMA_33 },                                     /* Intel 82371AB/EB PIIX4/PIIX4E */
-	{ PCI_DEVICE_ID_INTEL_82371SB_1,	PIIX_UDMA_NONE },                                   /* Intel 82371SB PIIX3 */
-	{ PCI_DEVICE_ID_INTEL_82371FB_1,	PIIX_UDMA_NONE | PIIX_NO_SITRE | PIIX_CHECK_REV },  /* Intel 82371FB PIIX */
-	{ PCI_DEVICE_ID_EFAR_SLC90E66_1,	PIIX_UDMA_66 | PIIX_VICTORY },                      /* Efar Victory66 */
+	{ PCI_DEVICE_ID_INTEL_82801DB_9,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801DB ICH4 */
+	{ PCI_DEVICE_ID_INTEL_82801CA_11,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801CA ICH3/ICH3-S */
+	{ PCI_DEVICE_ID_INTEL_82801CA_10,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801CAM ICH3-M */
+	{ PCI_DEVICE_ID_INTEL_82801E_9,		PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801E C-ICH */
+	{ PCI_DEVICE_ID_INTEL_82801BA_9,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801BA ICH2 */
+	{ PCI_DEVICE_ID_INTEL_82801BA_8,	PIIX_UDMA_100 | PIIX_PINGPONG },			/* Intel 82801BAM ICH2-M */
+	{ PCI_DEVICE_ID_INTEL_82801AB_1,	PIIX_UDMA_33  | PIIX_PINGPONG},				/* Intel 82801AB ICH0 */
+	{ PCI_DEVICE_ID_INTEL_82801AA_1,	PIIX_UDMA_66  | PIIX_PINGPONG },			/* Intel 82801AA ICH */
+	{ PCI_DEVICE_ID_INTEL_82372FB_1,	PIIX_UDMA_66 },						/* Intel 82372FB PIIX5 */
+	{ PCI_DEVICE_ID_INTEL_82443MX_1,	PIIX_UDMA_33 },						/* Intel 82443MX MPIIX4 */
+	{ PCI_DEVICE_ID_INTEL_82371AB,		PIIX_UDMA_33 },						/* Intel 82371AB/EB PIIX4/PIIX4E */
+	{ PCI_DEVICE_ID_INTEL_82371SB_1,	PIIX_UDMA_NONE },					/* Intel 82371SB PIIX3 */
+	{ PCI_DEVICE_ID_INTEL_82371FB_1,	PIIX_UDMA_NONE | PIIX_NO_SITRE | PIIX_CHECK_REV },	/* Intel 82371FB PIIX */
+	{ PCI_DEVICE_ID_EFAR_SLC90E66_1,	PIIX_UDMA_66 | PIIX_VICTORY },				/* Efar Victory66 */
 	{ 0 }
 };
 
@@ -122,7 +122,7 @@
 
 	switch (dn & 1) {
 
-		case 1: 
+		case 1:
 			if (timing->cycle > 9) {
 				t &= ~0x30;
 				break;
@@ -177,7 +177,7 @@
 			&& ~piix_config->flags & PIIX_VICTORY) {
 
 			pci_read_config_dword(dev, PIIX_IDECFG, &c);
-			
+
 			if ((piix_config->flags & PIIX_UDMA) > PIIX_UDMA_66)
 				c &= ~(1 << (dn + 12));
 			c &= ~(1 << dn);
@@ -214,7 +214,7 @@
 		umul = 2;
 	if (speed > XFER_UDMA_4 && (piix_config->flags & PIIX_UDMA) >= PIIX_UDMA_100)
 		umul = 4;
-	
+
 	T = 1000000000 / system_bus_speed;
 	UT = T / umul;
 
@@ -280,6 +280,7 @@
  */
 static unsigned int __init piix_init_chipset(struct pci_dev *dev)
 {
+	struct pci_dev *orion = NULL;
 	unsigned int u;
 	unsigned short w;
 	unsigned char t;
@@ -293,55 +294,24 @@
 		if (dev->device == piix_config->id)
 			break;
 
-	if (!piix_config->id) {
-		printk(KERN_WARNING "PIIX: Unknown PIIX/ICH chip %#x, contact Vojtech Pavlik <vojtech@ucw.cz>\n", dev->device);
-		return -ENODEV;
-	}
-
 /*
  * Check for possibly broken DMA configs.
  */
 
-	{
-		struct pci_dev *orion = NULL;
-
-		if (piix_config->flags & PIIX_CHECK_REV) {
-			pci_read_config_byte(dev, PCI_REVISION_ID, &t);
-			if (t < 2) {
-				printk(KERN_INFO "PIIX: Found buggy old PIIX rev %#x, disabling DMA\n", t);
-				piix_config->flags |= PIIX_NODMA;
-			}
-		}
-
-		if ((orion = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, NULL))) {
-			pci_read_config_byte(orion, PCI_REVISION_ID, &t);
-			if (t < 4) {
-				printk(KERN_INFO "PIIX: Found buggy 82454GX Orion bridge rev %#x, disabling DMA\n", t);
-				piix_config->flags |= PIIX_NODMA;
-			}
+	if (piix_config->flags & PIIX_CHECK_REV) {
+		pci_read_config_byte(dev, PCI_REVISION_ID, &t);
+		if (t < 2) {
+			printk(KERN_INFO "PIIX: Found buggy old PIIX rev %#x, disabling DMA\n", t);
+			piix_config->flags |= PIIX_NODMA;
 		}
 	}
 
-/*
- * Check 80-wire cable presence.
- */
-
-	switch (piix_config->flags & PIIX_UDMA) {
-
-		case PIIX_UDMA_66:
-			if (piix_config->flags && PIIX_VICTORY) {
-				pci_read_config_byte(dev, PIIX_IDESTAT, &t);
-				piix_80w = ((t & 2) ? 1 : 0) | ((t & 1) ? 2 : 0);
-				break;
-			}
-
-#ifndef CONFIG_BLK_DEV_PIIX_TRY133
-		case PIIX_UDMA_100:
-#endif
-		case PIIX_UDMA_133:
-			pci_read_config_dword(dev, PIIX_IDECFG, &u);
-			piix_80w = ((u & 0x30) ? 1 : 0) | ((u & 0xc0) ? 2 : 0);
-			break;
+	if ((orion = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454GX, NULL))) {
+		pci_read_config_byte(orion, PCI_REVISION_ID, &t);
+		if (t < 4) {
+			printk(KERN_INFO "PIIX: Found buggy 82454GX Orion bridge rev %#x, disabling DMA\n", t);
+			piix_config->flags |= PIIX_NODMA;
+		}
 	}
 
 /*
@@ -377,32 +347,44 @@
 	return 0;
 }
 
-static unsigned int __init piix_ata66_check(struct ata_channel *hwif)
+static unsigned int __init piix_ata66_check(struct ata_channel *ch)
 {
-	return ((piix_enabled & piix_80w) >> hwif->unit) & 1;
+	unsigned char t;
+	unsigned int u;
+
+	if ((piix_config->flags & PIIX_UDMA) < PIIX_UDMA_66)
+		return 0;
+
+	if (piix_config->flags & PIIX_VICTORY) {
+		pci_read_config_byte(ch->pci_dev, PIIX_IDESTAT, &t);
+		return ch->unit ? (t & 1) : !!(t & 2);
+	}
+
+	pci_read_config_dword(ch->pci_dev, PIIX_IDECFG, &u);
+	return ch->unit ? !!(u & 0xc0) : !!(u & 0x30);
 }
 
-static void __init piix_init_channel(struct ata_channel *hwif)
+static void __init piix_init_channel(struct ata_channel *ch)
 {
 	int i;
 
-	hwif->tuneproc = &piix_tune_drive;
-	hwif->speedproc = &piix_set_drive;
-	hwif->autodma = 0;
-	hwif->io_32bit = 1;
-	hwif->unmask = 1;
+	ch->tuneproc = &piix_tune_drive;
+	ch->speedproc = &piix_set_drive;
+	ch->autodma = 0;
+	ch->io_32bit = 1;
+	ch->unmask = 1;
 	for (i = 0; i < 2; i++) {
-		hwif->drives[i].autotune = 1;
-		hwif->drives[i].dn = hwif->unit * 2 + i;
+		ch->drives[i].autotune = 1;
+		ch->drives[i].dn = ch->unit * 2 + i;
 	}
 
 #ifdef CONFIG_BLK_DEV_IDEDMA
-	if (hwif->dma_base) {
-		hwif->highmem = 1;
-		hwif->udma_setup = piix_udma_setup;
+	if (ch->dma_base) {
+		ch->highmem = 1;
+		ch->udma_setup = piix_udma_setup;
 # ifdef CONFIG_IDEDMA_AUTO
 		if (!noautodma)
-			hwif->autodma = 1;
+			ch->autodma = 1;
 # endif
 	}
 #endif
@@ -412,11 +394,11 @@
  * We allow the BM-DMA driver only work on enabled interfaces,
  * and only if DMA is safe with the chip and bridge.
  */
-static void __init piix_init_dma(struct ata_channel *hwif, unsigned long dmabase)
+static void __init piix_init_dma(struct ata_channel *ch, unsigned long dmabase)
 {
-	if (((piix_enabled >> hwif->unit) & 1)
+	if (((piix_enabled >> ch->unit) & 1)
 		&& !(piix_config->flags & PIIX_NODMA))
-			ata_init_dma(hwif, dmabase);
+			ata_init_dma(ch, dmabase);
 }
 
 
diff -Nru a/drivers/ide/probe.c b/drivers/ide/probe.c
--- a/drivers/ide/probe.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/ide/probe.c	Sat Jun  8 22:31:35 2002
@@ -385,7 +385,7 @@
 	enable_irq(ch->irq);
 
 	if (error) {
-		ide_dump_status(drive, NULL, "set_drive_speed_status", drive->status);
+		ata_dump(drive, NULL, "set drive speed");
 		return error;
 	}
 
@@ -875,7 +875,8 @@
 
 	/* Register this hardware interface within the global device tree.
 	 */
-	sprintf(ch->dev.bus_id, "%04x", ch->io_ports[IDE_DATA_OFFSET]);
+	sprintf(ch->dev.bus_id, "%04lx",
+		(unsigned long) ch->io_ports[IDE_DATA_OFFSET]);
 	sprintf(ch->dev.name, "ide");
 	ch->dev.driver_data = ch;
 #ifdef CONFIG_PCI
diff -Nru a/drivers/ide/tcq.c b/drivers/ide/tcq.c
--- a/drivers/ide/tcq.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/ide/tcq.c	Sat Jun  8 22:31:51 2002
@@ -60,7 +60,9 @@
 	struct ata_taskfile *args = rq->special;
 
 	ide__sti();
-	ide_end_drive_cmd(drive, rq);
+	blkdev_dequeue_request(rq);
+	drive->rq = NULL;
+	end_that_request_last(rq);
 	kfree(args);
 
 	return ide_stopped;
@@ -247,8 +249,7 @@
 	OUT_BYTE(WIN_QUEUED_SERVICE, IDE_COMMAND_REG);
 
 	if (wait_altstat(drive, &stat, BUSY_STAT)) {
-		printk(KERN_ERR"%s: BUSY clear took too long\n", __FUNCTION__);
-		ide_dump_status(drive, rq, __FUNCTION__, stat);
+		ata_dump(drive, rq, "BUSY clear took too long");
 		tcq_invalidate_queue(drive);
 
 		return ide_stopped;
@@ -262,7 +263,7 @@
 	 * FIXME, invalidate queue
 	 */
 	if (stat & ERR_STAT) {
-		ide_dump_status(drive, rq, __FUNCTION__, stat);
+		ata_dump(drive, rq, "ERR condition");
 		tcq_invalidate_queue(drive);
 
 		return ide_stopped;
@@ -328,8 +329,7 @@
 	 * must be end of I/O, check status and complete as necessary
 	 */
 	if (!ata_status(drive, READY_STAT, drive->bad_wstat | DRQ_STAT)) {
-		printk(KERN_ERR "%s: %s: error status %x\n", __FUNCTION__, drive->name, drive->status);
-		ide_dump_status(drive, rq, __FUNCTION__, drive->status);
+		ata_dump(drive, rq, __FUNCTION__);
 		tcq_invalidate_queue(drive);
 
 		return ide_stopped;
@@ -404,17 +404,14 @@
 	if (drives <= 1)
 		return 0;
 
-	memset(&args, 0, sizeof(args));
-
-	args.taskfile.feature = 0x01;
-	args.cmd = WIN_NOP;
-	ide_cmd_type_parser(&args);
-
 	/*
 	 * do taskfile and check ABRT bit -- intelligent adapters will not
 	 * pass NOP with sub-code 0x01 to device, so the command will not
 	 * fail there
 	 */
+	memset(&args, 0, sizeof(args));
+	args.taskfile.feature = 0x01;
+	args.cmd = WIN_NOP;
 	ide_raw_taskfile(drive, &args);
 	if (args.taskfile.feature & ABRT_ERR)
 		return 1;
@@ -443,8 +440,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_EN_WCACHE;
 	args.cmd = WIN_SETFEATURES;
-	ide_cmd_type_parser(&args);
-
 	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: failed to enable write cache\n", drive->name);
 		return 1;
@@ -457,8 +452,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_DIS_RI;
 	args.cmd = WIN_SETFEATURES;
-	ide_cmd_type_parser(&args);
-
 	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: disabling release interrupt fail\n", drive->name);
 		return 1;
@@ -471,8 +464,6 @@
 	memset(&args, 0, sizeof(args));
 	args.taskfile.feature = SETFEATURES_EN_SI;
 	args.cmd = WIN_SETFEATURES;
-	ide_cmd_type_parser(&args);
-
 	if (ide_raw_taskfile(drive, &args)) {
 		printk("%s: enabling service interrupt fail\n", drive->name);
 		return 1;
@@ -557,7 +548,7 @@
 	OUT_BYTE(args->cmd, IDE_COMMAND_REG);
 
 	if (wait_altstat(drive, &stat, BUSY_STAT)) {
-		ide_dump_status(drive, rq, "queued start", stat);
+		ata_dump(drive, rq, "queued start");
 		tcq_invalidate_queue(drive);
 		return ide_stopped;
 	}
@@ -567,7 +558,7 @@
 #endif
 
 	if (stat & ERR_STAT) {
-		ide_dump_status(drive, rq, "tcq_start", stat);
+		ata_dump(drive, rq, "tcq_start");
 		return ide_stopped;
 	}
 
diff -Nru a/drivers/ide/trm290.c b/drivers/ide/trm290.c
--- a/drivers/ide/trm290.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/ide/trm290.c	Sat Jun  8 22:31:36 2002
@@ -217,7 +217,7 @@
 		writing = 0;
 	}
 
-	if (!(count = udma_new_table(ch, rq))) {
+	if (!(count = udma_new_table(drive, rq))) {
 		trm290_prepare_drive(drive, 0);	/* select PIO xfer */
 		return 1;	/* try PIO instead of DMA */
 	}
diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/capi/capi.c	Sat Jun  8 22:31:52 2002
@@ -141,13 +141,6 @@
 static LIST_HEAD(capiminor_list);
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-static kmem_cache_t *capidev_cachep;
-static kmem_cache_t *capincci_cachep;
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-static kmem_cache_t *capiminor_cachep;
-static kmem_cache_t *capidh_cachep;
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 /* -------- datahandles --------------------------------------------- */
 
@@ -155,8 +148,7 @@
 {
 	struct datahandle_queue *n, **pp;
 
-	n = (struct datahandle_queue *)
-	kmem_cache_alloc(capidh_cachep, GFP_ATOMIC);
+	n = kmalloc(sizeof(*n), GFP_ATOMIC);
 	if (!n) {
 	   printk(KERN_ERR "capi: alloc datahandle failed\n");
 	   return -1;
@@ -177,7 +169,7 @@
  		if ((*pp)->datahandle == datahandle) {
 			p = *pp;
 			*pp = (*pp)->next;
-			kmem_cache_free(capidh_cachep, p);
+			kfree(p);
 			mp->nack--;
 			return 0;
 		}
@@ -193,7 +185,7 @@
 	while (*pp) {
 		p = *pp;
 		*pp = (*pp)->next;
-		kmem_cache_free(capidh_cachep, p);
+		kfree(p);
 		mp->nack--;
 	}
 }
@@ -209,7 +201,7 @@
 	unsigned long flags;
   
   	MOD_INC_USE_COUNT;
-	mp = kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC);
+	mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
   	if (!mp) {
   		MOD_DEC_USE_COUNT;
   		printk(KERN_ERR "capi: can't alloc capiminor\n");
@@ -258,7 +250,7 @@
 	skb_queue_purge(&mp->inqueue);
 	skb_queue_purge(&mp->outqueue);
 	capiminor_del_all_ack(mp);
-	kmem_cache_free(capiminor_cachep, mp);
+	kfree(mp);
 	MOD_DEC_USE_COUNT;
 #ifdef _DEBUG_REFCOUNT
 	printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE));
@@ -294,7 +286,7 @@
 	kdev_t kdev;
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-	np = (struct capincci *)kmem_cache_alloc(capincci_cachep, GFP_ATOMIC);
+	np = kmalloc(sizeof(*np), GFP_ATOMIC);
 	if (!np)
 		return 0;
 	memset(np, 0, sizeof(struct capincci));
@@ -350,7 +342,7 @@
 				}
 			}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-			kmem_cache_free(capincci_cachep, np);
+			kfree(np);
 			if (*pp == 0) return;
 		} else {
 			pp = &(*pp)->next;
@@ -376,7 +368,7 @@
 	struct capidev *cdev;
 	unsigned long flags;
 
-	cdev = kmem_cache_alloc(capidev_cachep, GFP_KERNEL);
+	cdev = kmalloc(sizeof(*cdev), GFP_KERNEL);
 	if (!cdev)
 		return 0;
 	memset(cdev, 0, sizeof(struct capidev));
@@ -402,7 +394,7 @@
 	write_lock_irqsave(&capidev_list_lock, flags);
 	list_del(&cdev->list);
 	write_unlock_irqrestore(&capidev_list_lock, flags);
-	kmem_cache_free(capidev_cachep, cdev);
+	kfree(cdev);
 }
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
@@ -1476,72 +1468,6 @@
 /* -------- init function and module interface ---------------------- */
 
 
-static void alloc_exit(void)
-{
-	if (capidev_cachep) {
-		(void)kmem_cache_destroy(capidev_cachep);
-		capidev_cachep = 0;
-	}
-	if (capincci_cachep) {
-		(void)kmem_cache_destroy(capincci_cachep);
-		capincci_cachep = 0;
-	}
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-	if (capidh_cachep) {
-		(void)kmem_cache_destroy(capidh_cachep);
-		capidh_cachep = 0;
-	}
-	if (capiminor_cachep) {
-		(void)kmem_cache_destroy(capiminor_cachep);
-		capiminor_cachep = 0;
-	}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-}
-
-static int __init alloc_init(void)
-{
-	capidev_cachep = kmem_cache_create("capi20_dev",
-					 sizeof(struct capidev),
-					 0,
-					 SLAB_HWCACHE_ALIGN,
-					 NULL, NULL);
-	if (!capidev_cachep) {
-		alloc_exit();
-		return -ENOMEM;
-	}
-
-	capincci_cachep = kmem_cache_create("capi20_ncci",
-					 sizeof(struct capincci),
-					 0,
-					 SLAB_HWCACHE_ALIGN,
-					 NULL, NULL);
-	if (!capincci_cachep) {
-		alloc_exit();
-		return -ENOMEM;
-	}
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-	capidh_cachep = kmem_cache_create("capi20_dh",
-					 sizeof(struct datahandle_queue),
-					 0,
-					 SLAB_HWCACHE_ALIGN,
-					 NULL, NULL);
-	if (!capidh_cachep) {
-		alloc_exit();
-		return -ENOMEM;
-	}
-	capiminor_cachep = kmem_cache_create("capi20_minor",
-					 sizeof(struct capiminor),
-					 0,
-					 SLAB_HWCACHE_ALIGN,
-					 NULL, NULL);
-	if (!capiminor_cachep) {
-		alloc_exit();
-		return -ENOMEM;
-	}
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-	return 0;
-}
-
 static char rev[32];
 
 static int __init capi_init(void)
@@ -1578,19 +1504,7 @@
 	}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
 
-	if (alloc_init() < 0) {
-#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
-		capinc_tty_exit();
-#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
-		devfs_unregister_chrdev(capi_major, "capi20");
-		devfs_unregister(devfs_find_handle(NULL, "capi20",
-						   capi_major, 0,
-						   DEVFS_SPECIAL_CHR, 0));
-		MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-
-	(void)proc_init();
+	proc_init();
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 #if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
@@ -1610,8 +1524,7 @@
 
 static void __exit capi_exit(void)
 {
-	alloc_exit();
-	(void)proc_exit();
+	proc_exit();
 
 	devfs_unregister_chrdev(capi_major, "capi20");
 	devfs_unregister(devfs_find_handle(NULL, "isdn/capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0));
diff -Nru a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
--- a/drivers/isdn/capi/kcapi_proc.c	Sat Jun  8 22:31:49 2002
+++ b/drivers/isdn/capi/kcapi_proc.c	Sat Jun  8 22:31:49 2002
@@ -13,7 +13,7 @@
 #include "kcapi.h"
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
-
+#include <linux/init.h>
 
 static char *
 cardstate2str(unsigned short cardstate)
diff -Nru a/drivers/isdn/hisax/Config.in b/drivers/isdn/hisax/Config.in
--- a/drivers/isdn/hisax/Config.in	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hisax/Config.in	Sat Jun  8 22:31:36 2002
@@ -43,6 +43,7 @@
    bool '  HFC-S+, HFC-SP, HFC-PCMCIA cards' CONFIG_HISAX_HFC_SX
    if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then
 #      bool '  TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU
+      bool '  Formula-n enter:now PCI card' CONFIG_HISAX_ENTERNOW_PCI
       if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then
 	 bool '  Am7930' CONFIG_HISAX_AMD7930
       fi
diff -Nru a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
--- a/drivers/isdn/hisax/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/Makefile	Sat Jun  8 22:31:37 2002
@@ -6,7 +6,7 @@
 
 # Objects that export symbols.
 
-export-objs	  := config.o fsm.o hisax_isac.o hisax_hscx.o
+export-objs	  := config.o hisax_isac.o hisax_hscx.o
 
 # Each configuration option enables a list of files.
 
@@ -39,7 +39,7 @@
 hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
 hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
-hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o
+hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipacx.o
 hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
 hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o isar.o
@@ -57,6 +57,7 @@
 hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o
 hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
+hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
 #hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
 
 hisax-objs += $(hisax-objs-y)
diff -Nru a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/amd7930_fn.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,761 @@
+/* gerdes_amd7930.c,v 0.99 2001/10/02
+ *
+ * gerdes_amd7930.c     Amd 79C30A and 79C32A specific routines
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ *
+ * Notes:
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ *
+ * Please don't report any malfunction to me without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary this driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include "hisax.h"
+#include "isdnl1.h"
+#include "isac.h"
+#include "amd7930_fn.h"
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+static void Amd7930_new_ph(struct IsdnCardState *cs);
+
+
+void /* macro wWordAMD */
+WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
+{
+        wByteAMD(cs, 0x00, reg);
+        wByteAMD(cs, 0x01, LOBYTE(val));
+        wByteAMD(cs, 0x01, HIBYTE(val));
+}
+
+WORD /* macro rWordAMD */
+ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
+{
+        WORD res;
+        /* direct access register */
+        if(reg < 8) {
+        	res = rByteAMD(cs, reg);
+                res += 256*rByteAMD(cs, reg);
+        }
+        /* indirect access register */
+        else {
+                wByteAMD(cs, 0x00, reg);
+	        res = rByteAMD(cs, 0x01);
+                res += 256*rByteAMD(cs, 0x01);
+        }
+	return (res);
+}
+
+
+static void
+Amd7930_ph_command(struct IsdnCardState *cs, u_char command, char *s)
+{
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: %s: ph_command 0x%02X", s, command);
+
+        cs->dc.amd7930.lmr1 = command;
+        wByteAMD(cs, 0xA3, command);
+}
+
+
+
+static BYTE i430States[] = {
+// to   reset  F3    F4    F5    F6    F7    F8    AR     from
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // init
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x07, 0x05, 0x00,   // reset
+        0x01, 0x02, 0x00, 0x00, 0x00, 0x09, 0x05, 0x04,   // F3
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F4
+        0x01, 0x02, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00,   // F5
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00,   // F6
+        0x11, 0x13, 0x00, 0x00, 0x1B, 0x00, 0x15, 0x00,   // F7
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00,   // F8
+        0x01, 0x03, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0A};  // AR
+
+
+/*                    Row     init    -   reset  F3    F4    F5    F6    F7    F8    AR */
+static BYTE stateHelper[] = { 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
+
+
+
+
+static void
+Amd7930_get_state(struct IsdnCardState *cs) {
+        BYTE lsr = rByteAMD(cs, 0xA1);
+        cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+        Amd7930_new_ph(cs);
+}
+
+
+
+static void
+Amd7930_new_ph(struct IsdnCardState *cs)
+{
+        u_char index = stateHelper[cs->dc.amd7930.old_state]*8 + stateHelper[cs->dc.amd7930.ph_state]-1;
+        u_char message = i430States[index];
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "AMD7930: new_ph %d, old_ph %d, message %d, index %d",
+                        cs->dc.amd7930.ph_state, cs->dc.amd7930.old_state, message & 0x0f, index);
+
+        cs->dc.amd7930.old_state = cs->dc.amd7930.ph_state;
+
+        /* abort transmit if nessesary */
+        if ((message & 0xf0) && (cs->tx_skb)) {
+                wByteAMD(cs, 0x21, 0xC2);
+                wByteAMD(cs, 0x21, 0x02);
+        }
+
+	switch (message & 0x0f) {
+
+                case (1):
+                        l1_msg(cs, HW_RESET | INDICATION, NULL);
+                        Amd7930_get_state(cs);
+                        break;
+                case (2): /* init, Card starts in F3 */
+                        l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+                        break;
+                case (3):
+                        l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+                        break;
+                case (4):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        Amd7930_ph_command(cs, 0x50, "HW_ENABLE REQUEST");
+                        break;
+                case (5):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+                        break;
+                case (6):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (7): /* init, Card starts in F7 */
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (8):
+                        l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+                        /* fall through */
+                case (9):
+                        Amd7930_ph_command(cs, 0x40, "HW_ENABLE REQ cleared if set");
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+                        break;
+                case (10):
+                        Amd7930_ph_command(cs, 0x40, "T3 expired, HW_ENABLE REQ cleared");
+                        cs->dc.amd7930.old_state = 3;
+                        break;
+                case (11):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+                        break;
+		default:
+			break;
+	}
+}
+
+
+
+static void
+Amd7930_bh(struct IsdnCardState *cs)
+{
+
+        struct PStack *stptr;
+
+	if (!cs)
+		return;
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+                if (cs->debug)
+			debugl1(cs, "Amd7930: bh, D-Channel Busy cleared");
+		stptr = cs->stlist;
+		while (stptr != NULL) {
+			stptr->l2.l1l2(stptr, PH_PAUSE | CONFIRM, NULL);
+			stptr = stptr->next;
+		}
+	}
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_L1STATECHANGE");
+                Amd7930_new_ph(cs);
+        }
+
+        if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_RCVBUFREADY");
+                DChannel_proc_rcv(cs);
+        }
+
+        if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+	        if (cs->debug & L1_DEB_ISAC)
+		        debugl1(cs, "AMD7930: bh, D_XMTBUFREADY");
+                DChannel_proc_xmt(cs);
+        }
+}
+
+
+void
+Amd7930_sched_event(struct IsdnCardState *cs, int event) // ok
+{
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "AMD7930: sched_event 0x%X", event);
+        }
+
+        test_and_set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
+{
+
+        BYTE stat, der;
+	BYTE *ptr;
+	struct sk_buff *skb;
+
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: empty_Dfifo");
+
+
+	ptr = cs->rcvbuf + cs->rcvidx;
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+	/* read D-Channel-Fifo*/
+	stat = rByteAMD(cs, 0x07); // DSR2
+
+		/* while Data in Fifo ... */
+		while ( (stat & 2) && ((ptr-cs->rcvbuf) < MAX_DFRAME_LEN_L1) ) {
+			*ptr = rByteAMD(cs, 0x04); // DCRB
+			ptr++;
+	                stat = rByteAMD(cs, 0x07); // DSR2
+			cs->rcvidx = ptr - cs->rcvbuf;
+
+                        /* Paket ready? */
+			if (stat & 1) {
+
+                                der = rWordAMD(cs, 0x03);
+
+                                /* no errors, packet ok */
+                                if(!der && !flag) {
+					rWordAMD(cs, 0x89); // clear DRCR
+
+                                        if ((cs->rcvidx) > 0) {
+                                                if (!(skb = alloc_skb(cs->rcvidx, GFP_ATOMIC)))
+							printk(KERN_WARNING "HiSax: Amd7930: empty_Dfifo, D receive out of memory!\n");
+						else {
+                                                        /* Debugging */
+                                                        if (cs->debug & L1_DEB_ISAC_FIFO) {
+								char *t = cs->dlog;
+
+								t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
+								QuickHex(t, cs->rcvbuf, cs->rcvidx);
+								debugl1(cs, cs->dlog);
+							}
+                                                        /* moves recieved data in sk-buffer */
+							memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
+							skb_queue_tail(&cs->rq, skb);
+						}
+					}
+
+				}
+                                /* throw damaged packets away, reset recieve-buffer, indicate RX */
+				ptr = cs->rcvbuf;
+				cs->rcvidx = 0;
+				Amd7930_sched_event(cs, D_RCVBUFREADY);
+			}
+                }
+		/* Packet to long, overflow */
+		if(cs->rcvidx >= MAX_DFRAME_LEN_L1) {
+			if (cs->debug & L1_DEB_WARN)
+			        debugl1(cs, "AMD7930: empty_Dfifo L2-Framelength overrun");
+			cs->rcvidx = 0;
+			return;
+		}
+	/* AMD interrupts on */
+	AmdIrqOn(cs);
+}
+
+
+static void
+Amd7930_fill_Dfifo(struct IsdnCardState *cs)
+{
+
+        WORD dtcrr, dtcrw, len, count;
+        BYTE txstat, dmr3;
+        BYTE *ptr, *deb_ptr;
+
+	if ((cs->debug & L1_DEB_ISAC) && !(cs->debug & L1_DEB_ISAC_FIFO))
+		debugl1(cs, "Amd7930: fill_Dfifo");
+
+	if ((!cs->tx_skb) || (cs->tx_skb->len <= 0))
+		return;
+
+        dtcrw = 0;
+        if(!cs->dc.amd7930.tx_xmtlen)
+                /* new Frame */
+                len = dtcrw = cs->tx_skb->len;
+        /* continue frame */
+        else len = cs->dc.amd7930.tx_xmtlen;
+
+
+	/* AMD interrupts off */
+	AmdIrqOff(cs);
+
+        deb_ptr = ptr = cs->tx_skb->data;
+
+        /* while free place in tx-fifo available and data in sk-buffer */
+        txstat = 0x10;
+        while((txstat & 0x10) && (cs->tx_cnt < len)) {
+                wByteAMD(cs, 0x04, *ptr);
+                ptr++;
+                cs->tx_cnt++;
+                txstat= rByteAMD(cs, 0x07);
+        }
+        count = ptr - cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+
+
+        dtcrr = rWordAMD(cs, 0x85); // DTCR
+        dmr3  = rByteAMD(cs, 0x8E);
+
+	if (cs->debug & L1_DEB_ISAC) {
+		debugl1(cs, "Amd7930: fill_Dfifo, DMR3: 0x%02X, DTCR read: 0x%04X write: 0x%02X 0x%02X", dmr3, dtcrr, LOBYTE(dtcrw), HIBYTE(dtcrw));
+        }
+
+        /* writeing of dtcrw starts transmit */
+        if(!cs->dc.amd7930.tx_xmtlen) {
+                wWordAMD(cs, 0x85, dtcrw);
+                cs->dc.amd7930.tx_xmtlen = dtcrw;
+        }
+
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "Amd7930: fill_Dfifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ) / 1000);
+	add_timer(&cs->dbusytimer);
+
+	if (cs->debug & L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
+		QuickHex(t, deb_ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+	/* AMD interrupts on */
+        AmdIrqOn(cs);
+}
+
+
+void Amd7930_interrupt(struct IsdnCardState *cs, BYTE irflags)
+{
+	BYTE dsr1, dsr2, lsr;
+        WORD der;
+
+ while (irflags)
+ {
+
+        dsr1 = rByteAMD(cs, 0x02);
+        der  = rWordAMD(cs, 0x03);
+        dsr2 = rByteAMD(cs, 0x07);
+        lsr  = rByteAMD(cs, 0xA1);
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: interrupt: flags: 0x%02X, DSR1: 0x%02X, DSR2: 0x%02X, LSR: 0x%02X, DER=0x%04X", irflags, dsr1, dsr2, lsr, der);
+
+        /* D error -> read DER and DSR2 bit 2 */
+	if (der || (dsr2 & 4)) {
+
+                if (cs->debug & L1_DEB_WARN)
+			debugl1(cs, "Amd7930: interrupt: D error DER=0x%04X", der);
+
+                /* RX, TX abort if collision detected */
+                if (der & 2) {
+                        wByteAMD(cs, 0x21, 0xC2);
+                        wByteAMD(cs, 0x21, 0x02);
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+                        /* restart frame */
+                        if (cs->tx_skb) {
+				skb_push(cs->tx_skb, cs->tx_cnt);
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+				Amd7930_fill_Dfifo(cs);
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930 D-Collision, no skb\n");
+				debugl1(cs, "Amd7930: interrupt: D-Collision, no skb");
+			}
+                }
+                /* remove damaged data from fifo */
+		Amd7930_empty_Dfifo(cs, 1);
+
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+                /* restart TX-Frame */
+                if (cs->tx_skb) {
+			skb_push(cs->tx_skb, cs->tx_cnt);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen = 0;
+			Amd7930_fill_Dfifo(cs);
+		}
+	}
+
+        /* D TX FIFO empty -> fill */
+	if (irflags & 1) {
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: clear Timer and fill D-TX-FIFO if data");
+
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+		if (cs->tx_skb) {
+			if (cs->tx_skb->len)
+				Amd7930_fill_Dfifo(cs);
+		}
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+
+        /* D RX FIFO full or tiny packet in Fifo -> empty */
+	if ((irflags & 2) || (dsr1 & 2)) {
+                if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd7930: interrupt: empty D-FIFO");
+                Amd7930_empty_Dfifo(cs, 0);
+	}
+
+
+        /* D-Frame transmit complete */
+	if (dsr1 & 64) {
+		if (cs->debug & L1_DEB_ISAC) {
+			debugl1(cs, "Amd7930: interrupt: transmit packet ready");
+        	}
+		/* AMD interrupts off */
+                AmdIrqOff(cs);
+
+                if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			Amd7930_sched_event(cs, D_CLEARBUSY);
+
+                if (cs->tx_skb) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, freeing skb");
+                        dev_kfree_skb_irq(cs->tx_skb);
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			cs->tx_skb = NULL;
+                }
+                if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+        		if (cs->debug & L1_DEB_ISAC)
+	        		debugl1(cs, "Amd7930: interrupt: TX-Packet ready, next packet dequeued");
+	        	cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+			Amd7930_fill_Dfifo(cs);
+		}
+                else
+			Amd7930_sched_event(cs, D_XMTBUFREADY);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+        }
+
+	/* LIU status interrupt -> read LSR, check statechanges */
+	if (lsr & 0x38) {
+                /* AMD interrupts off */
+                AmdIrqOff(cs);
+
+		if (cs->debug & L1_DEB_ISAC)
+			debugl1(cs, "Amd: interrupt: LSR=0x%02X, LIU is in state %d", lsr, ((lsr & 0x7) +2));
+
+		cs->dc.amd7930.ph_state = (lsr & 0x7) + 2;
+
+		Amd7930_sched_event(cs, D_L1STATECHANGE);
+		/* AMD interrupts on */
+                AmdIrqOn(cs);
+	}
+
+        /* reads Interrupt-Register again. If there is a new interrupt-flag: restart handler */
+        irflags = rByteAMD(cs, 0x00);
+ }
+
+}
+
+static void
+Amd7930_l1hw(struct PStack *st, int pr, void *arg)
+{
+        struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: l1hw called, pr: 0x%04X", pr);
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+                        if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+                                cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+				if (cs->debug & L1_DEB_LAPD)
+					Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA", 0);
+#endif
+				Amd7930_fill_Dfifo(cs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, "Amd7930: l1hw: l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)
+				LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE)
+				dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+                        cs->dc.amd7930.tx_xmtlen=0;
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				Logl2Frame(cs, skb, "Amd7930: l1hw: PH_DATA_PULLED", 0);
+#endif
+			Amd7930_fill_Dfifo(cs);
+			break;
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG		/* psa */
+			if (cs->debug & L1_DEB_LAPD)
+				debugl1(cs, "Amd7930: l1hw: -> PH_REQUEST_PULL, skb: %s", (cs->tx_skb)? "yes":"no");
+#endif
+			if (!cs->tx_skb) {
+				test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l2.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (HW_RESET | REQUEST):
+
+                        if ((cs->dc.amd7930.ph_state == 8))
+                                /* b-channels off, PH-AR cleared
+                                 * change to F3 */
+                                Amd7930_ph_command(cs, 0x20, "HW_RESET REQEST"); //LMR1 bit 5
+			else {
+                                Amd7930_ph_command(cs, 0x40, "HW_RESET REQUEST");
+                                cs->dc.amd7930.ph_state = 2;
+                                Amd7930_new_ph(cs);
+                        }
+			break;
+		case (HW_ENABLE | REQUEST):
+                        cs->dc.amd7930.ph_state = 9;
+                        Amd7930_new_ph(cs);
+			break;
+		case (HW_INFO3 | REQUEST):
+			// automatic
+			break;
+		case (HW_TESTLOOP | REQUEST):
+			/* not implemented yet */
+			break;
+		case (HW_DEACTIVATE | RESPONSE):
+                        skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+				Amd7930_sched_event(cs, D_CLEARBUSY);
+			break;
+		default:
+			if (cs->debug & L1_DEB_WARN)
+				debugl1(cs, "Amd7930: l1hw: unknown %04x", pr);
+			break;
+	}
+}
+
+void
+setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
+{
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: setstack called");
+
+        st->l1.l1hw = Amd7930_l1hw;
+}
+
+
+void
+DC_Close_Amd7930(struct IsdnCardState *cs) {
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: DC_Close called");
+}
+
+
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *stptr;
+        WORD dtcr, der;
+        BYTE dsr1, dsr2;
+
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer expired!");
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+                /* D Transmit Byte Count Register:
+                 * Counts down packet's number of Bytes, 0 if packet ready */
+                dtcr = rWordAMD(cs, 0x85);
+                dsr1 = rByteAMD(cs, 0x02);
+                dsr2 = rByteAMD(cs, 0x07);
+                der  = rWordAMD(cs, 0x03);
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: dbusy_timer_handler: DSR1=0x%02X, DSR2=0x%02X, DER=0x%04X, cs->tx_skb->len=%u, tx_stat=%u, dtcr=%u, cs->tx_cnt=%u", dsr1, dsr2, der, cs->tx_skb->len, cs->dc.amd7930.tx_xmtlen, dtcr, cs->tx_cnt);
+
+		if ((cs->dc.amd7930.tx_xmtlen - dtcr) < cs->tx_cnt) {	/* D-Channel Busy */
+			test_and_set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+			stptr = cs->stlist;
+			while (stptr != NULL) {
+				stptr->l2.l1l2(stptr, PH_PAUSE | INDICATION, NULL);
+				stptr = stptr->next;
+			}
+
+		} else {
+			/* discard frame; reset transceiver */
+			test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+                                cs->dc.amd7930.tx_xmtlen = 0;
+			} else {
+				printk(KERN_WARNING "HiSax: Amd7930: D-Channel Busy no skb\n");
+				debugl1(cs, "Amd7930: D-Channel Busy no skb");
+
+			}
+			/* Transmitter reset, abort transmit */
+			wByteAMD(cs, 0x21, 0x82);
+			wByteAMD(cs, 0x21, 0x02);
+			cs->irq_func(cs->irq, cs, NULL);
+
+                        if (cs->debug & L1_DEB_ISAC)
+				debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
+		}
+	}
+}
+
+
+
+void __devinit
+Amd7930_init(struct IsdnCardState *cs)
+{
+    WORD *ptr;
+    BYTE cmd, cnt;
+
+        if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "Amd7930: initamd called");
+
+        cs->dc.amd7930.tx_xmtlen = 0;
+        cs->dc.amd7930.old_state = 0;
+        cs->dc.amd7930.lmr1 = 0x40;
+        cs->dc.amd7930.ph_command = Amd7930_ph_command;
+        cs->tqueue.routine = (void *) (void *) Amd7930_bh;
+	cs->setstack_d = setstack_Amd7930;
+	cs->DC_Close = DC_Close_Amd7930;
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+	/* AMD Initialisation */
+	for (ptr = initAMD; *ptr != 0xFFFF; ) {
+		cmd = LOBYTE(*ptr);
+
+                /* read */
+                if (*ptr++ >= 0x100) {
+			if (cmd < 8)
+                                /* setzt Register zurück */
+                                rByteAMD(cs, cmd);
+			else {
+				wByteAMD(cs, 0x00, cmd);
+				for (cnt = *ptr++; cnt > 0; cnt--)
+					rByteAMD(cs, 0x01);
+			}
+		}
+                /* write */
+                else if (cmd < 8)
+			wByteAMD(cs, cmd, LOBYTE(*ptr++));
+
+		else {
+			wByteAMD(cs, 0x00, cmd);
+			for (cnt = *ptr++; cnt > 0; cnt--)
+				wByteAMD(cs, 0x01, LOBYTE(*ptr++));
+		}
+	}
+}
diff -Nru a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/amd7930_fn.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,69 @@
+/* 2001/10/02
+ *
+ * gerdes_amd7930.h     Header-file included by
+ *                      gerdes_amd7930.c
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define rByteAMD(cs, reg)					cs->readisac(cs, reg)
+#define wByteAMD(cs, reg, val)					cs->writeisac(cs, reg, val)
+#define rWordAMD(cs, reg)					ReadWordAmd7930(cs, reg)
+#define wWordAMD(cs, reg, val)					WriteWordAmd7930(cs, reg, val)
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+
+#define AmdIrqOff(cs)						cs->dc.amd7930.setIrqMask(cs, 0)
+#define AmdIrqOn(cs)						cs->dc.amd7930.setIrqMask(cs, 1)
+
+#define AMD_CR		0x00
+#define AMD_DR		0x01
+
+
+#define DBUSY_TIMER_VALUE 80
+
+static WORD initAMD[] = {
+	0x0100,
+
+	0x00A5, 3, 0x01, 0x40, 0x58,				// LPR, LMR1, LMR2
+	0x0086, 1, 0x0B,					// DMR1 (D-Buffer TH-Interrupts on)
+	0x0087, 1, 0xFF,					// DMR2
+	0x0092, 1, 0x03,					// EFCR (extended mode d-channel-fifo on)
+	0x0090, 4, 0xFE, 0xFF, 0x02, 0x0F,			// FRAR4, SRAR4, DMR3, DMR4 (address recognition )
+	0x0084, 2, 0x80, 0x00,					// DRLR
+	0x00C0, 1, 0x47,					// PPCR1
+	0x00C8, 1, 0x01,					// PPCR2
+
+	0x0102,
+	0x0107,
+	0x01A1, 1,
+	0x0121, 1,
+	0x0189, 2,
+
+	0x0045, 4, 0x61, 0x72, 0x00, 0x00,			// MCR1, MCR2, MCR3, MCR4
+	0x0063, 2, 0x08, 0x08,					// GX
+	0x0064, 2, 0x08, 0x08,					// GR
+	0x0065, 2, 0x99, 0x00,					// GER
+	0x0066, 2, 0x7C, 0x8B,					// STG
+	0x0067, 2, 0x00, 0x00,					// FTGR1, FTGR2
+	0x0068, 2, 0x20, 0x20,					// ATGR1, ATGR2
+	0x0069, 1, 0x4F,					// MMR1
+	0x006A, 1, 0x00,					// MMR2
+	0x006C, 1, 0x40,					// MMR3
+	0x0021, 1, 0x02,					// INIT
+	0x00A3, 1, 0x40,					// LMR1
+
+	0xFFFF};
+
+extern void Amd7930_interrupt(struct IsdnCardState *cs, unsigned char irflags);
+extern void Amd7930_init(struct IsdnCardState *cs);
diff -Nru a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
--- a/drivers/isdn/hisax/asuscom.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/asuscom.c	Sat Jun  8 22:31:37 2002
@@ -14,6 +14,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "ipac.h"
@@ -309,6 +310,27 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id asus_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688), 
+	  (unsigned long) "Asus1688 PnP" },
+	{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690),
+	  ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1690), 
+	  (unsigned long) "Asus1690 PnP" },
+	{ ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020),
+	  ISAPNP_VENDOR('S', 'I', 'E'), ISAPNP_FUNCTION(0x0020), 
+	  (unsigned long) "Isurf2 PnP" },
+	{ ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000),
+	  ISAPNP_VENDOR('E', 'L', 'F'), ISAPNP_FUNCTION(0x0000), 
+	  (unsigned long) "Iscas TE320" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *adev = &asus_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_asuscom(struct IsdnCard *card)
 {
@@ -321,7 +343,45 @@
 	printk(KERN_INFO "HiSax: Asuscom ISDNLink driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_ASUSCOM)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(adev->card_vendor) {
+			if ((pb = isapnp_find_card(adev->card_vendor,
+				adev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					adev->vendor, adev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)adev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "AsusPnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "AsusPnP: PnP error card found, no device\n");
+				}
+			}
+			adev++;
+			pnp_c=NULL;
+		} 
+		if (!adev->card_vendor) {
+			printk(KERN_INFO "AsusPnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	bytecnt = 8;
 	cs->hw.asus.cfg_reg = card->para[1];
 	cs->irq = card->para[0];
diff -Nru a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
--- a/drivers/isdn/hisax/avm_pci.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/avm_pci.c	Sat Jun  8 22:31:37 2002
@@ -19,6 +19,7 @@
 #include "isac.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/interrupt.h>
 
 extern const char *CardType[];
@@ -763,6 +764,10 @@
 }
 
 static struct pci_dev *dev_avm __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *bus_avm __initdata = NULL;
+static struct pci_dev *pnp_avm __initdata = NULL;
+#endif
 
 int __init
 setup_avm_pcipnp(struct IsdnCard *card)
@@ -776,10 +781,47 @@
 	if (cs->typ != ISDN_CTYPE_FRITZPCI)
 		return (0);
 	if (card->para[1]) {
+		/* old manual method */
 		cs->hw.avm.cfg_reg = card->para[1];
 		cs->irq = card->para[0];
 		cs->subtyp = AVM_FRITZ_PNP;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *ba;
+			if ((ba = isapnp_find_card(
+				ISAPNP_VENDOR('A', 'V', 'M'),
+				ISAPNP_FUNCTION(0x0900), bus_avm))) {
+				bus_avm = ba;
+				pnp_avm = NULL;
+				if ((pnp_avm = isapnp_find_dev(bus_avm,
+					ISAPNP_VENDOR('A', 'V', 'M'),
+					ISAPNP_FUNCTION(0x0900), pnp_avm))) {
+					pnp_avm->prepare(pnp_avm);
+					pnp_avm->deactivate(pnp_avm);
+					pnp_avm->activate(pnp_avm);
+					cs->hw.avm.cfg_reg =
+						pnp_avm->resource[0].start;
+					cs->irq = 
+						pnp_avm->irq_resource[0].start;
+					if (!cs->irq) {
+						printk(KERN_ERR "FritzPnP:No IRQ\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					if (!cs->hw.avm.cfg_reg) {
+						printk(KERN_ERR "FritzPnP:No IO address\n");
+						pnp_avm->deactivate(pnp_avm);
+						return(0);
+					}
+					cs->subtyp = AVM_FRITZ_PNP;
+					goto ready;
+				}
+			}
+		} else {
+			printk(KERN_INFO "FritzPnP: no ISA PnP present\n");
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "FritzPCI: no PCI bus present\n");
@@ -810,6 +852,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}
+ready:
 	cs->hw.avm.isac = cs->hw.avm.cfg_reg + 0x10;
 	if (check_region((cs->hw.avm.cfg_reg), 32)) {
 		printk(KERN_WARNING
diff -Nru a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
--- a/drivers/isdn/hisax/config.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/hisax/config.c	Sat Jun  8 22:31:52 2002
@@ -75,6 +75,8 @@
  *   37 HFC 2BDS0 S+/SP         p0=irq p1=iobase
  *   38 Travers Technologies NETspider-U PCI card
  *   39 HFC 2BDS0-SP PCMCIA     p0=irq p1=iobase
+ *   40 hotplug interface
+ *   41 Formula-n enter:now ISDN PCI a/b   none
  *
  * protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6 or ISDN_PTYPE_NI1
  *
@@ -93,6 +95,7 @@
 	"Siemens I-Surf", "Acer P10", "HST Saphir", "Telekom A4T",
 	"Scitel Quadro", "Gazel", "HFC 2BDS0 PCI", "Winbond 6692",
 	"HFC 2BDS0 SX", "NETspider-U", "HFC-2BDS0-SP PCMCIA",
+	"Hotplug", "Formula-n enter:now PCI a/b", 
 };
 
 void HiSax_closecard(int cardnr);
@@ -601,6 +604,10 @@
 extern int setup_netjet_u(struct IsdnCard *card);
 #endif
 
+#if CARD_FN_ENTERNOW_PCI
+extern int setup_enternow_pci(struct IsdnCard *card);
+#endif
+
 /*
  * Find card with given driverId
  */
@@ -1138,6 +1145,11 @@
 		ret = setup_netjet_u(card);
 		break;
 #endif
+#if CARD_FN_ENTERNOW_PCI
+	case ISDN_CTYPE_ENTERNOW:
+		ret = setup_enternow_pci(card);
+		break;
+#endif
 	case ISDN_CTYPE_DYNAMIC:
 		ret = 2;
 		break;
@@ -2094,6 +2106,7 @@
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20,     PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA20_U,   PCI_ANY_ID, PCI_ANY_ID},
 	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA201,    PCI_ANY_ID, PCI_ANY_ID},
+	{PCI_VENDOR_ID_EICON,    PCI_DEVICE_ID_EICON_DIVA202,    PCI_ANY_ID, PCI_ANY_ID},
 #endif
 #ifdef CONFIG_HISAX_ELSA
 	{PCI_VENDOR_ID_ELSA,     PCI_DEVICE_ID_ELSA_MICROLINK,   PCI_ANY_ID, PCI_ANY_ID},
@@ -2152,3 +2165,11 @@
 
 module_init(HiSax_init);
 module_exit(HiSax_exit);
+
+EXPORT_SYMBOL(FsmNew);
+EXPORT_SYMBOL(FsmFree);
+EXPORT_SYMBOL(FsmEvent);
+EXPORT_SYMBOL(FsmChangeState);
+EXPORT_SYMBOL(FsmInitTimer);
+EXPORT_SYMBOL(FsmDelTimer);
+EXPORT_SYMBOL(FsmRestartTimer);
diff -Nru a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
--- a/drivers/isdn/hisax/diva.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/diva.c	Sat Jun  8 22:31:37 2002
@@ -22,8 +22,10 @@
 #include "isac.h"
 #include "hscx.h"
 #include "ipac.h"
+#include "ipacx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -49,6 +51,7 @@
 #define DIVA_PCI	2
 #define DIVA_IPAC_ISA	3
 #define DIVA_IPAC_PCI	4
+#define DIVA_IPACX_PCI	5
 
 /* CTRL (Read) */
 #define DIVA_IRQ_STAT	0x01
@@ -68,10 +71,12 @@
 #define PITA_MISC_REG		0x1c
 #ifdef __BIG_ENDIAN
 #define PITA_PARA_SOFTRESET	0x00000001
+#define PITA_SER_SOFTRESET	0x00000002
 #define PITA_PARA_MPX_MODE	0x00000004
 #define PITA_INT0_ENABLE	0x00000200
 #else
 #define PITA_PARA_SOFTRESET	0x01000000
+#define PITA_SER_SOFTRESET	0x02000000
 #define PITA_PARA_MPX_MODE	0x04000000
 #define PITA_INT0_ENABLE	0x00020000
 #endif
@@ -239,6 +244,47 @@
 	memwritereg(cs->hw.diva.cfg_reg, offset + (hscx ? 0x40 : 0), value);
 }
 
+/* IO-Functions for IPACX type cards */
+static u_char
+MemReadISAC_IPACX(struct IsdnCardState *cs, u_char offset)
+{
+	return (memreadreg(cs->hw.diva.cfg_reg, offset));
+}
+
+static void
+MemWriteISAC_IPACX(struct IsdnCardState *cs, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset, value);
+}
+
+static void
+MemReadISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		*data++ = memreadreg(cs->hw.diva.cfg_reg, 0);
+}
+
+static void
+MemWriteISACfifo_IPACX(struct IsdnCardState *cs, u_char * data, int size)
+{
+	while(size--)
+		memwritereg(cs->hw.diva.cfg_reg, 0, *data++);
+}
+
+static u_char
+MemReadHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset)
+{
+	return(memreadreg(cs->hw.diva.cfg_reg, offset + 
+                    (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1)));
+}
+
+static void
+MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+{
+	memwritereg(cs->hw.diva.cfg_reg, offset + 
+              (hscx ? IPACX_OFF_B2 : IPACX_OFF_B1), value);
+}
+
 /*
  * fast interrupt HSCX stuff goes here
  */
@@ -549,7 +595,7 @@
 	u_char exval;
 	struct BCState *bcs;
 
-	if (val & 0x01) {
+	if (val & 0x01) { // EXB
 		bcs = cs->bcs + 1;
 		exval = MemReadHSCX(cs, 1, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -576,7 +622,7 @@
 			debugl1(cs, "HSCX B interrupt %x", val);
 		Memhscx_interrupt(cs, val, 1);
 	}
-	if (val & 0x02) {
+	if (val & 0x02) {	// EXA
 		bcs = cs->bcs;
 		exval = MemReadHSCX(cs, 0, HSCX_EXIR);
 		if (exval & 0x40) {
@@ -598,7 +644,7 @@
 		} else if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A EXIR %x", exval);
 	}
-	if (val & 0x04) {
+	if (val & 0x04) {	// ICA
 		exval = MemReadHSCX(cs, 0, HSCX_ISTA);
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX A interrupt %x", exval);
@@ -659,12 +705,31 @@
 	memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xC0);
 }
 
+static void
+diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	u_char val;
+	u_char *cfg;
+
+	if (!cs) {
+		printk(KERN_WARNING "Diva: Spurious interrupt!\n");
+		return;
+	}
+	cfg = (u_char *) cs->hw.diva.pci_cfg;
+	val = *cfg;
+	if (!(val &PITA_INT0_STATUS)) return; // other shared IRQ
+  interrupt_ipacx(cs);      // handler for chip
+	*cfg = PITA_INT0_STATUS;  // Reset PLX interrupt
+}
+
 void
 release_io_diva(struct IsdnCardState *cs)
 {
 	int bytecnt;
 
-	if (cs->subtyp == DIVA_IPAC_PCI) {
+	if ((cs->subtyp == DIVA_IPAC_PCI) || 
+	    (cs->subtyp == DIVA_IPACX_PCI)   ) {
 		u_int *cfg = (unsigned int *)cs->hw.diva.pci_cfg;
 
 		*cfg = 0; /* disable INT0/1 */ 
@@ -711,6 +776,16 @@
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule_timeout((10*HZ)/1000);
 		memwritereg(cs->hw.diva.cfg_reg, IPAC_MASK, 0xc0);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		unsigned int *ireg = (unsigned int *)(cs->hw.diva.pci_cfg +
+					PITA_MISC_REG);
+		*ireg = PITA_PARA_SOFTRESET | PITA_PARA_MPX_MODE;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+		*ireg = PITA_PARA_MPX_MODE | PITA_SER_SOFTRESET;
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);
+    MemWriteISAC_IPACX(cs, IPACX_MASK, 0xff); // Interrupts off
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.ctrl_reg = 0;        /* Reset On */
 		byteout(cs->hw.diva.ctrl, cs->hw.diva.ctrl_reg);
@@ -739,7 +814,10 @@
 {
 	int blink = 0;
 
-	if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+//	if ((cs->subtyp == DIVA_IPAC_ISA) || (cs->subtyp == DIVA_IPAC_PCI))
+	if ((cs->subtyp == DIVA_IPAC_ISA) ||
+	    (cs->subtyp == DIVA_IPAC_PCI) ||
+	    (cs->subtyp == DIVA_IPACX_PCI)   )
 		return;
 	del_timer(&cs->hw.diva.tl);
 	if (cs->hw.diva.status & DIVA_ASSIGN)
@@ -782,6 +860,12 @@
 			release_io_diva(cs);
 			return(0);
 		case CARD_INIT:
+			if (cs->subtyp == DIVA_IPACX_PCI) {
+				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
+				*ireg = PITA_INT0_ENABLE;
+			  init_ipacx(cs, 3); // init chip and enable interrupts
+        return (0);
+			}
 			if (cs->subtyp == DIVA_IPAC_PCI) {
 				ireg = (unsigned int *)cs->hw.diva.pci_cfg;
 				*ireg = PITA_INT0_ENABLE;
@@ -818,7 +902,9 @@
 			}
 			break;
 	}
-	if ((cs->subtyp != DIVA_IPAC_ISA) && (cs->subtyp != DIVA_IPAC_PCI))
+	if ((cs->subtyp != DIVA_IPAC_ISA) && 
+	    (cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   )
 		diva_led_handler(cs);
 	return(0);
 }
@@ -826,11 +912,38 @@
 static struct pci_dev *dev_diva __initdata = NULL;
 static struct pci_dev *dev_diva_u __initdata = NULL;
 static struct pci_dev *dev_diva201 __initdata = NULL;
+#ifdef __ISAPNP__
+static struct isapnp_device_id diva_ids[] __initdata = {
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x51), 
+	  (unsigned long) "Diva picola" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x71),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0x71), 
+	  (unsigned long) "Diva 2.0" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0xA1),
+	  ISAPNP_VENDOR('E', 'I', 'C'), ISAPNP_FUNCTION(0xA1), 
+	  (unsigned long) "Diva 2.01" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &diva_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_diva(struct IsdnCard *card)
 {
-	int bytecnt;
+	int bytecnt = 8;
 	u_char val;
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -863,8 +976,75 @@
 			cs->hw.diva.hscx_adr = card->para[1] + DIVA_HSCX_ADR;
 		}
 		cs->irq = card->para[0];
-		bytecnt = 8;
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Diva PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.diva.cfg_reg  = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0xA1)) {
+							cs->subtyp = DIVA_IPAC_ISA;
+							cs->hw.diva.ctrl = 0;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_IPAC_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_IPAC_ADR;
+							test_and_set_bit(HW_IPAC, &cs->HW_Flags);
+						} else {
+							cs->subtyp = DIVA_ISA;
+							cs->hw.diva.ctrl =
+								card->para[1] + DIVA_ISA_CTRL;
+							cs->hw.diva.isac =
+								card->para[1] + DIVA_ISA_ISAC_DATA;
+							cs->hw.diva.hscx =
+								card->para[1] + DIVA_HSCX_DATA;
+							cs->hw.diva.isac_adr =
+								card->para[1] + DIVA_ISA_ISAC_ADR;
+							cs->hw.diva.hscx_adr =
+								card->para[1] + DIVA_HSCX_ADR;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Diva PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Diva PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 #if CONFIG_PCI
 		if (!pci_present()) {
 			printk(KERN_ERR "Diva: no PCI bus present\n");
@@ -916,7 +1096,8 @@
 		printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
 		return (0);
 #endif /* CONFIG_PCI */
-		if (cs->subtyp == DIVA_IPAC_PCI) {
+		if ((cs->subtyp == DIVA_IPAC_PCI) ||
+		    (cs->subtyp == DIVA_IPACX_PCI)   ) {
 			cs->hw.diva.ctrl = 0;
 			cs->hw.diva.isac = 0;
 			cs->hw.diva.hscx = 0;
@@ -933,18 +1114,23 @@
 			bytecnt = 32;
 		}
 	}
-
+ready:
 	printk(KERN_INFO
 		"Diva: %s card configured at %#lx IRQ %d\n",
 		(cs->subtyp == DIVA_PCI) ? "PCI" :
 		(cs->subtyp == DIVA_ISA) ? "ISA" : 
-		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" : "IPAC PCI",
+		(cs->subtyp == DIVA_IPAC_ISA) ? "IPAC ISA" :
+		(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
 		cs->hw.diva.cfg_reg, cs->irq);
-	if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_PCI))
-		printk(KERN_INFO "Diva: %s PCI space at %#lx\n",
-			(cs->subtyp == DIVA_PCI) ? "PCI" : "IPAC PCI",
+	if ((cs->subtyp == DIVA_IPAC_PCI)  || 
+	    (cs->subtyp == DIVA_IPACX_PCI) || 
+	    (cs->subtyp == DIVA_PCI)         )
+		printk(KERN_INFO "Diva: %s space at %#lx\n",
+			(cs->subtyp == DIVA_PCI) ? "PCI" :
+			(cs->subtyp == DIVA_IPAC_PCI) ? "IPAC PCI" : "IPACX PCI",
 			cs->hw.diva.pci_cfg);
-	if (cs->subtyp != DIVA_IPAC_PCI) {
+	if ((cs->subtyp != DIVA_IPAC_PCI) &&
+	    (cs->subtyp != DIVA_IPACX_PCI)   ) {
 		if (check_region(cs->hw.diva.cfg_reg, bytecnt)) {
 			printk(KERN_WARNING
 			       "HiSax: %s config port %lx-%lx already in use\n",
@@ -980,6 +1166,17 @@
 		cs->irq_func = &diva_irq_ipac_pci;
 		val = memreadreg(cs->hw.diva.cfg_reg, IPAC_ID);
 		printk(KERN_INFO "Diva: IPAC version %x\n", val);
+	} else if (cs->subtyp == DIVA_IPACX_PCI) {
+		cs->readisac  = &MemReadISAC_IPACX;
+		cs->writeisac = &MemWriteISAC_IPACX;
+		cs->readisacfifo  = &MemReadISACfifo_IPACX;
+		cs->writeisacfifo = &MemWriteISACfifo_IPACX;
+		cs->BC_Read_Reg  = &MemReadHSCX_IPACX;
+		cs->BC_Write_Reg = &MemWriteHSCX_IPACX;
+		cs->BC_Send_Data = 0; // function located in ipacx module
+		cs->irq_func = &diva_irq_ipacx_pci;
+		printk(KERN_INFO "Diva: IPACX Design Id: %x\n", 
+            MemReadISAC_IPACX(cs, IPACX_ID) &0x3F);
 	} else { /* DIVA 2.0 */
 		cs->hw.diva.tl.function = (void *) diva_led_handler;
 		cs->hw.diva.tl.data = (long) cs;
diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
--- a/drivers/isdn/hisax/elsa.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hisax/elsa.c	Sat Jun  8 22:31:36 2002
@@ -28,6 +28,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 #include <linux/serial.h>
 #include <linux/serial_reg.h>
 
@@ -860,6 +861,21 @@
 static 	struct pci_dev *dev_qs1000 __devinitdata = NULL;
 static 	struct pci_dev *dev_qs3000 __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id elsa_ids[] __initdata = {
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0133), 
+	  (unsigned long) "Elsa QS1000" },
+	{ ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134),
+	  ISAPNP_VENDOR('E', 'L', 'S'), ISAPNP_FUNCTION(0x0134), 
+	  (unsigned long) "Elsa QS3000" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &elsa_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_elsa(struct IsdnCard *card)
 {
@@ -874,6 +890,7 @@
 	cs->hw.elsa.ctrl_reg = 0;
 	cs->hw.elsa.status = 0;
 	cs->hw.elsa.MFlag = 0;
+	cs->subtyp = 0;
 	if (cs->typ == ISDN_CTYPE_ELSA) {
 		cs->hw.elsa.base = card->para[0];
 		printk(KERN_INFO "Elsa: Microlink IO probing\n");
@@ -935,9 +952,60 @@
 			return (0);
 		}
 	} else if (cs->typ == ISDN_CTYPE_ELSA_PNP) {
-		cs->hw.elsa.base = card->para[1];
-		cs->irq = card->para[0];
-		cs->subtyp = ELSA_QS1000;
+#ifdef __ISAPNP__
+		if (!card->para[1] && isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Elsa PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						if (pdev->function == ISAPNP_FUNCTION(0x133))
+							cs->subtyp = ELSA_QS1000;
+						else
+							cs->subtyp = ELSA_QS3000;
+						break;
+					} else {
+						printk(KERN_ERR "Elsa PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Elsa PnP: no ISAPnP card found\n");
+				return(0);
+			}
+		}
+#endif
+		if (card->para[1] && card->para[0]) { 
+			cs->hw.elsa.base = card->para[1];
+			cs->irq = card->para[0];
+			if (!cs->subtyp)
+				cs->subtyp = ELSA_QS1000;
+		} else {
+			printk(KERN_ERR "Elsa PnP: no parameter\n");
+		}
 		cs->hw.elsa.cfg = cs->hw.elsa.base + ELSA_CONFIG;
 		cs->hw.elsa.ale = cs->hw.elsa.base + ELSA_ALE;
 		cs->hw.elsa.isac = cs->hw.elsa.base + ELSA_ISAC;
@@ -1048,6 +1116,7 @@
 			break;
 		case ELSA_PCFPRO:
 		case ELSA_PCF:
+		case ELSA_QS3000:
 		case ELSA_QS3000PCI:
 			bytecnt = 16;
 			break;
@@ -1073,7 +1142,7 @@
 		}
 	
 	if ((cs->subtyp == ELSA_QS1000PCI) || (cs->subtyp == ELSA_QS3000PCI)) {
-		if (!pci_request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
+		if (!request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci")) {
 			printk(KERN_WARNING
 			       "HiSax: %s pci port %x-%x already in use\n",
 				CardType[card->typ],
diff -Nru a/drivers/isdn/hisax/enternow.h b/drivers/isdn/hisax/enternow.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/enternow.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,51 @@
+/* 2001/10/02
+ *
+ * enternow.h   Header-file included by
+ *              enternow_pci.c
+ *
+ * Author       Christoph Ersfeld <info@formula-n.de>
+ *              Formula-n Europe AG (www.formula-n.com)
+ *              previously Gerdes AG
+ *
+ *
+ *              This file is (c) under GNU PUBLIC LICENSE
+ */
+
+
+/* ***************************************************************************************** *
+ * ****************************** datatypes and macros ************************************* *
+ * ***************************************************************************************** */
+
+#define BYTE							unsigned char
+#define WORD							unsigned int
+#define HIBYTE(w)						((unsigned char)((w & 0xff00) / 256))
+#define LOBYTE(w)						((unsigned char)(w & 0x00ff))
+#define InByte(addr)						inb(addr)
+#define OutByte(addr,val)					outb(val,addr)
+
+
+
+/* ***************************************************************************************** *
+ * *********************************** card-specific *************************************** *
+ * ***************************************************************************************** */
+
+/* für PowerISDN PCI */
+#define TJ_AMD_IRQ 						0x20
+#define TJ_LED1 						0x40
+#define TJ_LED2 						0x80
+
+
+/* Das Fenster zum AMD...
+ * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
+ * den TigerJet i/o-Raum gemappt
+ * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+#define TJ_AMD_PORT						0xC0
+
+
+
+/* ***************************************************************************************** *
+ * *************************************** Prototypen ************************************** *
+ * ***************************************************************************************** */
+
+BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
+void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
diff -Nru a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/enternow_pci.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,447 @@
+/* enternow_pci.c,v 0.99 2001/10/02
+ *
+ * enternow_pci.c       Card-specific routines for
+ *                      Formula-n enter:now ISDN PCI ab
+ *                      Gerdes AG Power ISDN PCI
+ *                      Woerltronic SA 16 PCI
+ *                      (based on HiSax driver by Karsten Keil)
+ *
+ * Author               Christoph Ersfeld <info@formula-n.de>
+ *                      Formula-n Europe AG (www.formula-n.com)
+ *                      previously Gerdes AG
+ *
+ *
+ *                      This file is (c) under GNU PUBLIC LICENSE
+ *
+ * Notes:
+ * This driver interfaces to netjet.c which performs B-channel
+ * processing.
+ *
+ * Version 0.99 is the first release of this driver and there are
+ * certainly a few bugs.
+ * It isn't testet on linux 2.4 yet, so consider this code to be
+ * beta.
+ *
+ * Please don't report me any malfunction without sending
+ * (compressed) debug-logs.
+ * It would be nearly impossible to retrace it.
+ *
+ * Log D-channel-processing as follows:
+ *
+ * 1. Load hisax with card-specific parameters, this example ist for
+ *    Formula-n enter:now ISDN PCI and compatible
+ *    (f.e. Gerdes Power ISDN PCI)
+ *
+ *    modprobe hisax type=41 protocol=2 id=gerdes
+ *
+ *    if you chose an other value for id, you need to modify the
+ *    code below, too.
+ *
+ * 2. set debug-level
+ *
+ *    hisaxctrl gerdes 1 0x3ff
+ *    hisaxctrl gerdes 11 0x4f
+ *    cat /dev/isdnctrl >> ~/log &
+ *
+ * Please take also a look into /var/log/messages if there is
+ * anything importand concerning HISAX.
+ *
+ *
+ * Credits:
+ * Programming the driver for Formula-n enter:now ISDN PCI and
+ * neccessary the driver for the used Amd 7930 D-channel-controller
+ * was spnsored by Formula-n Europe AG.
+ * Thanks to Karsten Keil and Petr Novak, who gave me support in
+ * Hisax-specific questions.
+ * I want so say special thanks to Carl-Friedrich Braun, who had to
+ * answer a lot of questions about generally ISDN and about handling
+ * of the Amd-Chip.
+ *
+ */
+
+
+#define __NO_VERSION__
+#include <linux/config.h>
+#include "hisax.h"
+#include "isac.h"
+#include "isdnl1.h"
+#include "amd7930_fn.h"
+#include "enternow.h"
+#include <linux/interrupt.h>
+#include <linux/ppp_defs.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "netjet.h"
+
+
+
+const char *enternow_pci_rev = "$Revision: 1.1.2.1 $";
+
+
+/* *************************** I/O-Interface functions ************************************* */
+
+
+/* cs->readisac, macro rByteAMD */
+BYTE
+ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
+{
+	/* direktes Register */
+	if(offset < 8)
+		return (InByte(cs->hw.njet.isac + 4*offset));
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		return(InByte(cs->hw.njet.isac + 4*AMD_DR));
+	}
+}
+
+/* cs->writeisac, macro wByteAMD */
+void
+WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
+{
+	/* direktes Register */
+	if(offset < 8)
+		OutByte(cs->hw.njet.isac + 4*offset, value);
+
+	/* indirektes Register */
+	else {
+		OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
+		OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
+	}
+}
+
+
+void
+enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
+        if (!val)
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
+        else
+	        OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
+}
+
+
+static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+{
+        return(5);
+}
+
+static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+{
+
+}
+
+
+/* ******************************************************************************** */
+
+
+static void
+reset_enpci(struct IsdnCardState *cs)
+{
+	long flags;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: reset");
+
+	save_flags(flags);
+	sti();
+	/* Reset on, (also for AMD) */
+	cs->hw.njet.ctrl_reg = 0x07;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80 ms delay */
+	schedule_timeout((80*HZ)/1000);
+	/* Reset off */
+	cs->hw.njet.ctrl_reg = 0x70;
+	OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	/* 80ms delay */
+	schedule_timeout((80*HZ)/1000);
+	restore_flags(flags);
+	cs->hw.njet.auxd = 0;  // LED-status
+	cs->hw.njet.dmactrl = 0;
+	OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+	OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
+
+}
+
+
+static int
+enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+{
+        BYTE *chan;
+
+	if (cs->debug & L1_DEB_ISAC)
+		debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
+
+        switch (mt) {
+		case CARD_RESET:
+			reset_enpci(cs);
+                        Amd7930_init(cs);
+			break;
+		case CARD_RELEASE:
+			release_io_netjet(cs);
+			break;
+		case CARD_INIT:
+			inittiger(cs);
+			Amd7930_init(cs);
+			break;
+		case CARD_TEST:
+			break;
+                case MDL_ASSIGN:
+                        /* TEI assigned, LED1 on */
+                        cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_REMOVE:
+                        /* TEI removed, LEDs off */
+	                cs->hw.njet.auxd = 0;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+                        break;
+                case MDL_BC_ASSIGN:
+                        /* activate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
+                        /* at least one b-channel in use, LED 2 on */
+                        cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
+                        OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        break;
+                case MDL_BC_RELEASE:
+                        /* deactivate B-channel */
+                        chan = (BYTE *)arg;
+
+                        if (cs->debug & L1_DEB_ISAC)
+		                debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
+
+                        cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 & ~(*chan + 1)), "MDL_BC_RELEASE");
+                        /* no b-channel active -> LED2 off */
+                        if (!(cs->dc.amd7930.lmr1 & 3)) {
+                                cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
+                                OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+                        }
+                        break;
+                default:
+                        break;
+
+	}
+	return(0);
+}
+
+
+static void
+enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+{
+	struct IsdnCardState *cs = dev_id;
+	BYTE sval, ir;
+	long flags;
+
+
+	if (!cs) {
+		printk(KERN_WARNING "enter:now PCI: Spurious interrupt!\n");
+		return;
+	}
+
+	sval = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+
+        /* AMD threw an interrupt */
+	if (!(sval & TJ_AMD_IRQ)) {
+                /* read and clear interrupt-register */
+		ir = ReadByteAmd7930(cs, 0x00);
+		Amd7930_interrupt(cs, ir);
+	}
+
+	/* DMA-Interrupt: B-channel-stuff */
+	/* set bits in sval to indicate which page is free */
+
+	save_flags(flags);
+	cli();
+	/* set bits in sval to indicate which page is free */
+	if (inl(cs->hw.njet.base + NETJET_DMA_WRITE_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_WRITE_IRQ))
+		/* the 2nd write page is free */
+		sval = 0x08;
+	else	/* the 1st write page is free */
+		sval = 0x04;
+	if (inl(cs->hw.njet.base + NETJET_DMA_READ_ADR) <
+		inl(cs->hw.njet.base + NETJET_DMA_READ_IRQ))
+		/* the 2nd read page is free */
+		sval = sval | 0x02;
+	else	/* the 1st read page is free */
+		sval = sval | 0x01;
+	if (sval != cs->hw.njet.last_is0) /* we have a DMA interrupt */
+	{
+		if (test_and_set_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags)) {
+			restore_flags(flags);
+			return;
+		}
+		cs->hw.njet.irqstat0 = sval;
+		restore_flags(flags);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_READ) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_READ))
+			/* we have a read dma int */
+			read_tiger(cs);
+		if ((cs->hw.njet.irqstat0 & NETJET_IRQM0_WRITE) !=
+			(cs->hw.njet.last_is0 & NETJET_IRQM0_WRITE))
+			/* we have a write dma int */
+			write_tiger(cs);
+		test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+	} else
+		restore_flags(flags);
+}
+
+
+static struct pci_dev *dev_netjet __initdata = NULL;
+
+/* called by config.c */
+int __init
+setup_enternow_pci(struct IsdnCard *card)
+{
+	int bytecnt;
+	struct IsdnCardState *cs = card->cs;
+	char tmp[64];
+	long flags;
+
+#if CONFIG_PCI
+#ifdef __BIG_ENDIAN
+#error "not running on big endian machines now"
+#endif
+        strcpy(tmp, enternow_pci_rev);
+	printk(KERN_INFO "HiSax: Formula-n Europe AG enter:now ISDN PCI driver Rev. %s\n", HiSax_getrev(tmp));
+	if (cs->typ != ISDN_CTYPE_ENTERNOW)
+		return(0);
+	test_and_clear_bit(FLG_LOCK_ATOMIC, &cs->HW_Flags);
+
+	for ( ;; )
+	{
+		if (!pci_present()) {
+			printk(KERN_ERR "enter:now PCI: no PCI bus present\n");
+			return(0);
+		}
+		if ((dev_netjet = pci_find_device(PCI_VENDOR_ID_TIGERJET,
+			PCI_DEVICE_ID_TIGERJET_300,  dev_netjet))) {
+			if (pci_enable_device(dev_netjet))
+				return(0);
+			cs->irq = dev_netjet->irq;
+			if (!cs->irq) {
+				printk(KERN_WARNING "enter:now PCI: No IRQ for PCI card found\n");
+				return(0);
+			}
+			cs->hw.njet.base = pci_resource_start(dev_netjet, 0);
+			if (!cs->hw.njet.base) {
+				printk(KERN_WARNING "enter:now PCI: No IO-Adr for PCI card found\n");
+				return(0);
+			}
+                        /* checks Sub-Vendor ID because system crashes with Traverse-Card */
+			if ((dev_netjet->subsystem_vendor != 0x55) ||
+				(dev_netjet->subsystem_device != 0x02)) {
+				printk(KERN_WARNING "enter:now: You tried to load this driver with an incompatible TigerJet-card\n");
+                                printk(KERN_WARNING "Use type=20 for Traverse NetJet PCI Card.\n");
+                                return(0);
+                        }
+		} else {
+                        printk(KERN_WARNING "enter:now PCI: No PCI card found\n");
+			return(0);
+		}
+
+		cs->hw.njet.auxa = cs->hw.njet.base + NETJET_AUXDATA;
+		cs->hw.njet.isac = cs->hw.njet.base + 0xC0; // Fenster zum AMD
+
+		save_flags(flags);
+		sti();
+
+		/* Reset an */
+		cs->hw.njet.ctrl_reg = 0x07;  // geändert von 0xff
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		/* 50 ms Pause */
+		schedule_timeout((50*HZ)/1000);
+
+		cs->hw.njet.ctrl_reg = 0x30;  /* Reset Off and status read clear */
+		OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout((10*HZ)/1000);	/* Timeout 10ms */
+
+		restore_flags(flags);
+
+		cs->hw.njet.auxd = 0x00; // war 0xc0
+		cs->hw.njet.dmactrl = 0;
+
+		OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
+		OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+
+			   break;
+	}
+#else
+
+	printk(KERN_WARNING "enter:now PCI: NO_PCI_BIOS\n");
+	printk(KERN_WARNING "enter:now PCI: unable to config Formula-n enter:now ISDN PCI ab\n");
+	return (0);
+
+#endif /* CONFIG_PCI */
+
+	bytecnt = 256;
+
+	printk(KERN_INFO
+		"enter:now PCI: PCI card configured at 0x%lx IRQ %d\n",
+		cs->hw.njet.base, cs->irq);
+	if (check_region(cs->hw.njet.base, bytecnt)) {
+		printk(KERN_WARNING
+			   "HiSax: %s config port %lx-%lx already in use\n",
+			   CardType[card->typ],
+			   cs->hw.njet.base,
+			   cs->hw.njet.base + bytecnt);
+		return (0);
+	} else {
+		request_region(cs->hw.njet.base, bytecnt, "Fn_ISDN");
+	}
+	reset_enpci(cs);
+	cs->hw.njet.last_is0 = 0;
+        /* macro rByteAMD */
+        cs->readisac = &ReadByteAmd7930;
+        /* macro wByteAMD */
+        cs->writeisac = &WriteByteAmd7930;
+        cs->dc.amd7930.setIrqMask = &enpci_setIrqMask;
+
+        cs->BC_Read_Reg  = &dummyrr;
+	cs->BC_Write_Reg = &dummywr;
+	cs->BC_Send_Data = &netjet_fill_dma;
+	cs->cardmsg = &enpci_card_msg;
+	cs->irq_func = &enpci_interrupt;
+	cs->irq_flags |= SA_SHIRQ;
+
+        return (1);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -Nru a/drivers/isdn/hisax/fsm.c b/drivers/isdn/hisax/fsm.c
--- a/drivers/isdn/hisax/fsm.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hisax/fsm.c	Sat Jun  8 22:31:36 2002
@@ -21,14 +21,6 @@
 
 #define FSM_TIMER_DEBUG 0
 
-EXPORT_SYMBOL(FsmNew);
-EXPORT_SYMBOL(FsmFree);
-EXPORT_SYMBOL(FsmEvent);
-EXPORT_SYMBOL(FsmChangeState);
-EXPORT_SYMBOL(FsmInitTimer);
-EXPORT_SYMBOL(FsmDelTimer);
-EXPORT_SYMBOL(FsmRestartTimer);
-
 int __init
 FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount)
 {
diff -Nru a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
--- a/drivers/isdn/hisax/hfc_pci.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/hfc_pci.c	Sat Jun  8 22:31:37 2002
@@ -76,6 +76,8 @@
 {
 	unsigned long flags;
 
+	printk(KERN_INFO "HiSax: release hfcpci at %p\n",
+		cs->hw.hfcpci.pci_io);
 	save_flags(flags);
 	cli();
 	cs->hw.hfcpci.int_m2 = 0;	/* interrupt output off ! */
@@ -86,9 +88,7 @@
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout((30 * HZ) / 1000);	/* Timeout 30ms */
 	Write_hfc(cs, HFCPCI_CIRM, 0);	/* Reset Off */
-#if CONFIG_PCI
 	pcibios_write_config_word(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_COMMAND, 0);	/* disable memory mapped ports + busmaster */
-#endif				/* CONFIG_PCI */
 	del_timer(&cs->hw.hfcpci.timer);
 	iounmap(cs->hw.hfcpci.pci_io);
 	pci_free_consistent(cs->hw.hfcpci.pdev, 32768, cs->hw.hfcpci.fifos, cs->hw.hfcpci.fifos_dma);
diff -Nru a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
--- a/drivers/isdn/hisax/hfc_sx.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/isdn/hisax/hfc_sx.c	Sat Jun  8 22:31:35 2002
@@ -17,6 +17,7 @@
 #include "hfc_sx.h"
 #include "isdnl1.h"
 #include <linux/interrupt.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -1460,7 +1461,17 @@
 	return (0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2620), 
+	  (unsigned long) "Teles 16.3c2" },
+	{ 0, }
+};
 
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __devinit
 setup_hfcsx(struct IsdnCard *card)
@@ -1471,6 +1482,45 @@
 
 	strcpy(tmp, hfcsx_revision);
 	printk(KERN_INFO "HiSax: HFC-SX driver Rev. %s\n", HiSax_getrev(tmp));
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcsx.base = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcsx.int_s1 = 0;
@@ -1553,7 +1603,3 @@
 	cs->auxcmd = &hfcsx_auxcmd;
 	return (1);
 }
-
-
-
-
diff -Nru a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
--- a/drivers/isdn/hisax/hfcscard.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/hisax/hfcscard.c	Sat Jun  8 22:31:52 2002
@@ -12,6 +12,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
@@ -139,6 +140,36 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id hfc_ids[] __initdata = {
+	{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
+	  ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114), 
+	  (unsigned long) "Acer P10" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0002), 
+	  (unsigned long) "Billion 2" },
+	{ ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('B', 'I', 'L'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Billion 1" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x7410), 
+	  (unsigned long) "IStar PnP" },
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2610), 
+	  (unsigned long) "Teles 16.3c" },
+	{ ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('S', 'F', 'M'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Tornado Tipa C" },
+	{ ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001),
+	  ISAPNP_VENDOR('K', 'Y', 'E'), ISAPNP_FUNCTION(0x0001), 
+	  (unsigned long) "Genius Speed Surfer" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *hdev = &hfc_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __init
 setup_hfcs(struct IsdnCard *card)
 {
@@ -147,6 +178,46 @@
 
 	strcpy(tmp, hfcs_revision);
 	printk(KERN_INFO "HiSax: HFC-S driver Rev. %s\n", HiSax_getrev(tmp));
+
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(hdev->card_vendor) {
+			if ((pb = isapnp_find_card(hdev->card_vendor,
+				hdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					hdev->vendor, hdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)hdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "HFC PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "HFC PnP: PnP error card found, no device\n");
+				}
+			}
+			hdev++;
+			pnp_c=NULL;
+		} 
+		if (!hdev->card_vendor) {
+			printk(KERN_INFO "HFC PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	cs->hw.hfcD.addr = card->para[1] & 0xfffe;
 	cs->irq = card->para[0];
 	cs->hw.hfcD.cip = 0;
diff -Nru a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
--- a/drivers/isdn/hisax/hisax.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/isdn/hisax/hisax.h	Sat Jun  8 22:31:51 2002
@@ -67,6 +67,9 @@
 #define DL_DATA		0x0220
 #define DL_FLUSH	0x0224
 #define DL_UNIT_DATA	0x0230
+
+#define MDL_BC_RELEASE  0x0278  // Formula-n enter:now
+#define MDL_BC_ASSIGN   0x027C  // Formula-n enter:now
 #define MDL_ASSIGN	0x0280
 #define MDL_REMOVE	0x0284
 #define MDL_ERROR	0x0288
@@ -835,6 +838,17 @@
 	int ph_state;
 };
 
+struct amd7930_chip {
+	u_char lmr1;
+	u_char ph_state;
+	u_char old_state;
+	u_char flg_t3;
+	unsigned int tx_xmtlen;
+	struct timer_list timer3;
+	void (*ph_command) (struct IsdnCardState *, u_char, char *);
+	void (*setIrqMask) (struct IsdnCardState *, u_char);
+};
+
 struct icc_chip {
 	int ph_state;
 	u_char *mon_tx;
@@ -932,6 +946,7 @@
 		struct hfcpci_chip hfcpci;
 		struct hfcsx_chip hfcsx;
 		struct w6692_chip w6692;
+		struct amd7930_chip amd7930;
 		struct icc_chip icc;
 	} dc;
 	u_char *rcvbuf;
@@ -993,7 +1008,8 @@
 #define  ISDN_CTYPE_NETJET_U	38
 #define  ISDN_CTYPE_HFC_SP_PCMCIA      39
 #define  ISDN_CTYPE_DYNAMIC     40
-#define  ISDN_CTYPE_COUNT	40
+#define  ISDN_CTYPE_ENTERNOW	41
+#define  ISDN_CTYPE_COUNT	41
 
 
 #ifdef ISDN_CHIP_ISAC
@@ -1250,6 +1266,10 @@
 #endif
 #else
 #define CARD_NETJET_U 0
+#endif
+
+#ifdef CONFIG_HISAX_ENTERNOW_PCI
+#define CARD_FN_ENTERNOW_PCI 1
 #endif
 
 #define TEI_PER_CARD 1
diff -Nru a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/ipacx.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,1029 @@
+/* 
+ *
+ * IPACX specific routines
+ *
+ * Author       Joerg Petersohn
+ * Derived from hisax_isac.c, isac.c, hscx.c and others
+ * 
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+#define __NO_VERSION__
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include "hisax_if.h"
+#include "hisax.h"
+#include "isdnl1.h"
+#include "ipacx.h"
+
+#define DBUSY_TIMER_VALUE 80
+#define TIMER3_VALUE      7000
+#define MAX_DFRAME_LEN_L1 300
+#define B_FIFO_SIZE       64
+#define D_FIFO_SIZE       32
+
+
+// ipacx interrupt mask values    
+#define _MASK_IMASK     0x2E  // global mask
+#define _MASKB_IMASK    0x0B
+#define _MASKD_IMASK    0x03  // all on
+
+//----------------------------------------------------------
+// local function declarations
+//----------------------------------------------------------
+static void ph_command(struct IsdnCardState *cs, unsigned int command);
+static inline void cic_int(struct IsdnCardState *cs);
+static void dch_l2l1(struct PStack *st, int pr, void *arg);
+static void dbusy_timer_handler(struct IsdnCardState *cs);
+static void ipacx_new_ph(struct IsdnCardState *cs);
+static void dch_bh(struct IsdnCardState *cs);
+static void dch_sched_event(struct IsdnCardState *cs, int event);
+static void dch_empty_fifo(struct IsdnCardState *cs, int count);
+static void dch_fill_fifo(struct IsdnCardState *cs);
+static inline void dch_int(struct IsdnCardState *cs);
+static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void __devinit dch_init(struct IsdnCardState *cs);
+static void bch_l2l1(struct PStack *st, int pr, void *arg);
+static void bch_sched_event(struct BCState *bcs, int event);
+static void bch_empty_fifo(struct BCState *bcs, int count);
+static void bch_fill_fifo(struct BCState *bcs);
+static void bch_int(struct IsdnCardState *cs, u_char hscx);
+static void bch_mode(struct BCState *bcs, int mode, int bc);
+static void bch_close_state(struct BCState *bcs);
+static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
+static int bch_setstack(struct PStack *st, struct BCState *bcs);
+static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
+static void __init clear_pending_ints(struct IsdnCardState *cs);
+
+//----------------------------------------------------------
+// Issue Layer 1 command to chip
+//----------------------------------------------------------
+static void 
+ph_command(struct IsdnCardState *cs, unsigned int command)
+{
+	if (cs->debug &L1_DEB_ISAC)
+		debugl1(cs, "ph_command (%#x) in (%#x)", command,
+			cs->dc.isac.ph_state);
+//###################################  
+//	printk(KERN_INFO "ph_command (%#x)\n", command);
+//###################################  
+	cs->writeisac(cs, IPACX_CIX0, (command << 4) | 0x0E);
+}
+
+//----------------------------------------------------------
+// Transceiver interrupt handler
+//----------------------------------------------------------
+static inline void 
+cic_int(struct IsdnCardState *cs)
+{
+	u_char event;
+
+	event = cs->readisac(cs, IPACX_CIR0) >> 4;
+	if (cs->debug &L1_DEB_ISAC) debugl1(cs, "cic_int(event=%#x)", event);
+//#########################################  
+//	printk(KERN_INFO "cic_int(%x)\n", event);
+//#########################################  
+  cs->dc.isac.ph_state = event;
+  dch_sched_event(cs, D_L1STATECHANGE);
+}
+
+//==========================================================
+// D channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Command entry point
+//----------------------------------------------------------
+static void
+dch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct IsdnCardState *cs = (struct IsdnCardState *) st->l1.hardware;
+	struct sk_buff *skb = arg;
+  u_char cda1_cr, cda2_cr;
+
+	switch (pr) {
+		case (PH_DATA |REQUEST):
+			if (cs->debug &DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug &DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			if (cs->tx_skb) {
+				skb_queue_tail(&cs->sq, skb);
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA Queued", 0);
+#endif
+			} else {
+				cs->tx_skb = skb;
+				cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+				if (cs->debug &L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA", 0);
+#endif
+				dch_fill_fifo(cs);
+			}
+			break;
+      
+		case (PH_PULL |INDICATION):
+			if (cs->tx_skb) {
+				if (cs->debug & L1_DEB_WARN)
+					debugl1(cs, " l2l1 tx_skb exist this shouldn't happen");
+				skb_queue_tail(&cs->sq, skb);
+				break;
+			}
+			if (cs->debug & DEB_DLOG_HEX)     LogFrame(cs, skb->data, skb->len);
+			if (cs->debug & DEB_DLOG_VERBOSE) dlogframe(cs, skb, 0);
+			cs->tx_skb = skb;
+			cs->tx_cnt = 0;
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) Logl2Frame(cs, skb, "PH_DATA_PULLED", 0);
+#endif
+			dch_fill_fifo(cs);
+			break;
+      
+		case (PH_PULL | REQUEST):
+#ifdef L2FRAME_DEBUG
+			if (cs->debug & L1_DEB_LAPD) debugl1(cs, "-> PH_REQUEST_PULL");
+#endif
+			if (!cs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l2.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+
+		case (HW_RESET | REQUEST):
+		case (HW_ENABLE | REQUEST):
+			ph_command(cs, IPACX_CMD_TIM);
+			break;
+
+		case (HW_INFO3 | REQUEST):
+			ph_command(cs, IPACX_CMD_AR8);
+			break;
+
+		case (HW_TESTLOOP | REQUEST):
+      cs->writeisac(cs, IPACX_CDA_TSDP10, 0x80); // Timeslot 0 is B1
+      cs->writeisac(cs, IPACX_CDA_TSDP11, 0x81); // Timeslot 0 is B1
+      cda1_cr = cs->readisac(cs, IPACX_CDA1_CR);
+      cda2_cr = cs->readisac(cs, IPACX_CDA2_CR);
+			if ((long)arg &1) { // loop B1
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x0a); 
+      }
+      else {  // B1 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x0a); 
+      }
+			if ((long)arg &2) { // loop B2
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr |0x14); 
+      }
+      else {  // B2 off
+        cs->writeisac(cs, IPACX_CDA1_CR, cda1_cr &~0x14); 
+      }
+			break;
+
+		case (HW_DEACTIVATE | RESPONSE):
+			skb_queue_purge(&cs->rq);
+			skb_queue_purge(&cs->sq);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_skb = NULL;
+			}
+			if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+				del_timer(&cs->dbusytimer);
+			break;
+
+		default:
+			if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_l2l1 unknown %04x", pr);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+dbusy_timer_handler(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	int	rbchd, stard;
+
+	if (test_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		rbchd = cs->readisac(cs, IPACX_RBCHD);
+		stard = cs->readisac(cs, IPACX_STARD);
+		if (cs->debug) 
+      debugl1(cs, "D-Channel Busy RBCHD %02x STARD %02x", rbchd, stard);
+		if (!(stard &0x40)) { // D-Channel Busy
+			set_bit(FLG_L1_DBUSY, &cs->HW_Flags);
+      for (st = cs->stlist; st; st = st->next) {
+				st->l2.l1l2(st, PH_PAUSE | INDICATION, NULL); // flow control on
+			}
+		} else {
+			// seems we lost an interrupt; reset transceiver */
+			clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags);
+			if (cs->tx_skb) {
+				dev_kfree_skb_any(cs->tx_skb);
+				cs->tx_cnt = 0;
+				cs->tx_skb = NULL;
+			} else {
+				printk(KERN_WARNING "HiSax: ISAC D-Channel Busy no skb\n");
+				debugl1(cs, "D-Channel Busy no skb");
+			}
+			cs->writeisac(cs, IPACX_CMDRD, 0x01); // Tx reset, generates XPR
+		}
+	}
+}
+
+//----------------------------------------------------------
+// L1 state machine intermediate layer to isdnl1 module
+//----------------------------------------------------------
+static void
+ipacx_new_ph(struct IsdnCardState *cs)
+{
+	switch (cs->dc.isac.ph_state) {
+		case (IPACX_IND_RES):
+			ph_command(cs, IPACX_CMD_DI);
+			l1_msg(cs, HW_RESET | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_DC):
+			l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
+			break;
+      
+		case (IPACX_IND_DR):
+			l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_PU):
+			l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
+			break;
+
+		case (IPACX_IND_RSY):
+			l1_msg(cs, HW_RSYNC | INDICATION, NULL);
+			break;
+
+		case (IPACX_IND_AR):
+			l1_msg(cs, HW_INFO2 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI8):
+			l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
+			break;
+      
+		case (IPACX_IND_AI10):
+			l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
+			break;
+      
+		default:
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// bottom half handler for D channel
+//----------------------------------------------------------
+static void
+dch_bh(struct IsdnCardState *cs)
+{
+	struct PStack *st;
+	
+	if (!cs) return;
+  
+	if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
+		if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
+		for (st = cs->stlist; st; st = st->next) {
+			st->l2.l1l2(st, PH_PAUSE | CONFIRM, NULL);
+		}
+	}
+  
+	if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
+		DChannel_proc_rcv(cs);
+  }  
+  
+	if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
+		DChannel_proc_xmt(cs);
+  }  
+  
+	if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
+    ipacx_new_ph(cs);
+  }  
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler dch_bh()
+//----------------------------------------------------------
+static void
+dch_sched_event(struct IsdnCardState *cs, int event)
+{
+	set_bit(event, &cs->event);
+	queue_task(&cs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Fill buffer from receive FIFO
+//----------------------------------------------------------
+static void 
+dch_empty_fifo(struct IsdnCardState *cs, int count)
+{
+	long flags;
+	u_char *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_empty_fifo()");
+
+  // message too large, remove
+	if ((cs->rcvidx + count) >= MAX_DFRAME_LEN_L1) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "dch_empty_fifo() incoming message too large");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+		cs->rcvidx = 0;
+		return;
+	}
+  
+	ptr = cs->rcvbuf + cs->rcvidx;
+	cs->rcvidx += count;
+  
+	save_flags(flags);
+	cli();
+	cs->readisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, 0x80); // RMC
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_empty_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill transmit FIFO
+//----------------------------------------------------------
+static void 
+dch_fill_fifo(struct IsdnCardState *cs)
+{
+	long flags;
+	int count;
+	u_char cmd, *ptr;
+
+	if ((cs->debug &L1_DEB_ISAC) && !(cs->debug &L1_DEB_ISAC_FIFO))
+		debugl1(cs, "dch_fill_fifo()");
+    
+	if (!cs->tx_skb) return;
+	count = cs->tx_skb->len;
+	if (count <= 0) return;
+
+	if (count > D_FIFO_SIZE) {
+		count = D_FIFO_SIZE;
+		cmd   = 0x08; // XTF
+	} else {
+		cmd   = 0x0A; // XTF | XME
+	}
+  
+	save_flags(flags);
+	cli();
+	ptr = cs->tx_skb->data;
+	skb_pull(cs->tx_skb, count);
+	cs->tx_cnt += count;
+	cs->writeisacfifo(cs, ptr, count);
+	cs->writeisac(cs, IPACX_CMDRD, cmd);
+  
+  // set timeout for transmission contol
+	if (test_and_set_bit(FLG_DBUSY_TIMER, &cs->HW_Flags)) {
+		debugl1(cs, "dch_fill_fifo dbusytimer running");
+		del_timer(&cs->dbusytimer);
+	}
+	init_timer(&cs->dbusytimer);
+	cs->dbusytimer.expires = jiffies + ((DBUSY_TIMER_VALUE * HZ)/1000);
+	add_timer(&cs->dbusytimer);
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_ISAC_FIFO) {
+		char *t = cs->dlog;
+
+		t += sprintf(t, "dch_fill_fifo() cnt %d", count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, cs->dlog);
+	}
+}
+
+//----------------------------------------------------------
+// D channel interrupt handler
+//----------------------------------------------------------
+static inline void 
+dch_int(struct IsdnCardState *cs)
+{
+	struct sk_buff *skb;
+	u_char istad, rstad;
+	long flags;
+	int count;
+
+	istad = cs->readisac(cs, IPACX_ISTAD);
+//##############################################  
+//	printk(KERN_WARNING "dch_int(istad=%02x)\n", istad);
+//##############################################  
+  
+	if (istad &0x80) {  // RME
+	  rstad = cs->readisac(cs, IPACX_RSTAD);
+		if ((rstad &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstad &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): invalid frame");
+			if ((rstad &0x40))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): RDO");
+			if (!(rstad &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "dch_int(): CRC error");
+	    cs->writeisac(cs, IPACX_CMDRD, 0x80);  // RMC
+		} else {  // received frame ok
+			count = cs->readisac(cs, IPACX_RBCLD);
+      if (count) count--; // RSTAB is last byte
+			count &= D_FIFO_SIZE-1;
+			if (count == 0) count = D_FIFO_SIZE;
+			dch_empty_fifo(cs, count);
+			save_flags(flags);
+			cli();
+			if ((count = cs->rcvidx) > 0) {
+	      cs->rcvidx = 0;
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax dch_int(): receive out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), cs->rcvbuf, count);
+					skb_queue_tail(&cs->rq, skb);
+				}
+			}
+			restore_flags(flags);
+    }
+	  cs->rcvidx = 0;
+		dch_sched_event(cs, D_RCVBUFREADY);
+	}
+
+	if (istad &0x40) {  // RPF
+		dch_empty_fifo(cs, D_FIFO_SIZE);
+	}
+
+	if (istad &0x20) {  // RFO
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): RFO");
+	  cs->writeisac(cs, IPACX_CMDRD, 0x40); //RRES
+	}
+  
+  if (istad &0x10) {  // XPR
+		if (test_and_clear_bit(FLG_DBUSY_TIMER, &cs->HW_Flags))
+			del_timer(&cs->dbusytimer);
+		if (test_and_clear_bit(FLG_L1_DBUSY, &cs->HW_Flags))
+			dch_sched_event(cs, D_CLEARBUSY);
+    if (cs->tx_skb) {
+      if (cs->tx_skb->len) {
+        dch_fill_fifo(cs);
+        goto afterXPR;
+      }
+      else {
+        dev_kfree_skb_irq(cs->tx_skb);
+        cs->tx_skb = NULL;
+        cs->tx_cnt = 0;
+      }
+    }
+    if ((cs->tx_skb = skb_dequeue(&cs->sq))) {
+      cs->tx_cnt = 0;
+      dch_fill_fifo(cs);
+    } 
+    else {
+      dch_sched_event(cs, D_XMTBUFREADY);
+    }  
+  }  
+  afterXPR:
+
+	if (istad &0x0C) {  // XDU or XMR
+		if (cs->debug &L1_DEB_WARN) debugl1(cs, "dch_int(): XDU");
+	  if (cs->tx_skb) {
+	    skb_push(cs->tx_skb, cs->tx_cnt); // retransmit
+	    cs->tx_cnt = 0;
+			dch_fill_fifo(cs);
+		} else {
+			printk(KERN_WARNING "HiSax: ISAC XDU no skb\n");
+			debugl1(cs, "ISAC XDU no skb");
+		}
+  }
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_setstack(struct PStack *st, struct IsdnCardState *cs)
+{
+	st->l1.l1hw = dch_l2l1;
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+dch_init(struct IsdnCardState *cs)
+{
+	printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
+
+	cs->tqueue.routine  = (void *)(void *) dch_bh;
+	cs->setstack_d      = dch_setstack;
+  
+	cs->dbusytimer.function = (void *) dbusy_timer_handler;
+	cs->dbusytimer.data = (long) cs;
+	init_timer(&cs->dbusytimer);
+
+  cs->writeisac(cs, IPACX_TR_CONF0, 0x00);  // clear LDD
+  cs->writeisac(cs, IPACX_TR_CONF2, 0x00);  // enable transmitter
+  cs->writeisac(cs, IPACX_MODED,    0xC9);  // transparent mode 0, RAC, stop/go
+  cs->writeisac(cs, IPACX_MON_CR,   0x00);  // disable monitor channel
+}
+
+
+//==========================================================
+// B channel functions
+//==========================================================
+
+//----------------------------------------------------------
+// Entry point for commands
+//----------------------------------------------------------
+static void
+bch_l2l1(struct PStack *st, int pr, void *arg)
+{
+	struct sk_buff *skb = arg;
+	long flags;
+
+	switch (pr) {
+		case (PH_DATA | REQUEST):
+			save_flags(flags);
+			cli();
+			if (st->l1.bcs->tx_skb) {
+				skb_queue_tail(&st->l1.bcs->squeue, skb);
+				restore_flags(flags);
+			} else {
+				st->l1.bcs->tx_skb = skb;
+				set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+				st->l1.bcs->hw.hscx.count = 0;
+				restore_flags(flags);
+        bch_fill_fifo(st->l1.bcs);
+			}
+			break;
+		case (PH_PULL | INDICATION):
+			if (st->l1.bcs->tx_skb) {
+				printk(KERN_WARNING "HiSax bch_l2l1(): this shouldn't happen\n");
+				break;
+			}
+			set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			st->l1.bcs->tx_skb = skb;
+			st->l1.bcs->hw.hscx.count = 0;
+      bch_fill_fifo(st->l1.bcs);
+			break;
+		case (PH_PULL | REQUEST):
+			if (!st->l1.bcs->tx_skb) {
+				clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+				st->l2.l1l2(st, PH_PULL | CONFIRM, NULL);
+			} else
+				set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
+			break;
+		case (PH_ACTIVATE | REQUEST):
+			set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, st->l1.mode, st->l1.bc);
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | REQUEST):
+			l1_msg_b(st, pr, arg);
+			break;
+		case (PH_DEACTIVATE | CONFIRM):
+			clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
+			clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
+			bch_mode(st->l1.bcs, 0, st->l1.bc);
+			st->l2.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
+			break;
+	}
+}
+
+//----------------------------------------------------------
+// proceed with bottom half handler BChannel_bh()
+//----------------------------------------------------------
+static void
+bch_sched_event(struct BCState *bcs, int event)
+{
+	bcs->event |= 1 << event;
+	queue_task(&bcs->tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+//----------------------------------------------------------
+// Read B channel fifo to receive buffer
+//----------------------------------------------------------
+static void
+bch_empty_fifo(struct BCState *bcs, int count)
+{
+	u_char *ptr, hscx;
+	struct IsdnCardState *cs;
+	long flags;
+	int cnt;
+
+	cs = bcs->cs;
+  hscx = bcs->hw.hscx.hscx;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_empty_fifo()");
+
+  // message too large, remove
+	if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
+		if (cs->debug &L1_DEB_WARN)
+			debugl1(cs, "bch_empty_fifo() incoming packet too large");
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		bcs->hw.hscx.rcvidx = 0;
+		return;
+	}
+  
+  // Read data uninterruptible
+	save_flags(flags);
+	cli();
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	cnt = count;
+	while (cnt--) *ptr++ = cs->BC_Read_Reg(cs, hscx, IPACX_RFIFOB); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+  
+	ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
+	bcs->hw.hscx.rcvidx += count;
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// Fill buffer to transmit FIFO
+//----------------------------------------------------------
+static void
+bch_fill_fifo(struct BCState *bcs)
+{
+	struct IsdnCardState *cs;
+	int more, count, cnt;
+	u_char *ptr, *p, hscx;
+	long flags;
+
+	cs = bcs->cs;
+	if ((cs->debug &L1_DEB_HSCX) && !(cs->debug &L1_DEB_HSCX_FIFO))
+		debugl1(cs, "bch_fill_fifo()");
+
+	if (!bcs->tx_skb)           return;
+	if (bcs->tx_skb->len <= 0)  return;
+
+	hscx = bcs->hw.hscx.hscx;
+	more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
+	if (bcs->tx_skb->len > B_FIFO_SIZE) {
+		more  = 1;
+		count = B_FIFO_SIZE;
+	} else {
+		count = bcs->tx_skb->len;
+	}  
+	cnt = count;
+    
+	save_flags(flags);
+	cli();
+	p = ptr = bcs->tx_skb->data;
+	skb_pull(bcs->tx_skb, count);
+	bcs->tx_cnt -= count;
+	bcs->hw.hscx.count += count;
+	while (cnt--) cs->BC_Write_Reg(cs, hscx, IPACX_XFIFOB, *p++); 
+	cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, (more ? 0x08 : 0x0a));
+	restore_flags(flags);
+  
+	if (cs->debug &L1_DEB_HSCX_FIFO) {
+		char *t = bcs->blog;
+
+		t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
+		QuickHex(t, ptr, count);
+		debugl1(cs, bcs->blog);
+	}
+}
+
+//----------------------------------------------------------
+// B channel interrupt handler
+//----------------------------------------------------------
+static void
+bch_int(struct IsdnCardState *cs, u_char hscx)
+{
+	u_char istab;
+	struct BCState *bcs;
+	struct sk_buff *skb;
+	int count;
+	u_char rstab;
+
+	bcs = cs->bcs + hscx;
+	istab = cs->BC_Read_Reg(cs, hscx, IPACX_ISTAB);
+//##############################################  
+//	printk(KERN_WARNING "bch_int(istab=%02x)\n", istab);
+//##############################################  
+	if (!test_bit(BC_FLG_INIT, &bcs->Flag)) return;
+
+	if (istab &0x80) {	// RME
+		rstab = cs->BC_Read_Reg(cs, hscx, IPACX_RSTAB);
+		if ((rstab &0xf0) != 0xa0) { // !(VFR && !RDO && CRC && !RAB)
+			if (!(rstab &0x80))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: invalid frame", hscx);
+			if ((rstab &0x40) && (bcs->mode != L1_MODE_NULL))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: RDO mode=%d", hscx, bcs->mode);
+			if (!(rstab &0x20))
+				if (cs->debug &L1_DEB_WARN) 
+          debugl1(cs, "bch_int() B-%d: CRC error", hscx);
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x80);  // RMC
+		} 
+    else {  // received frame ok
+			count = cs->BC_Read_Reg(cs, hscx, IPACX_RBCLB) &(B_FIFO_SIZE-1);
+			if (count == 0) count = B_FIFO_SIZE;
+			bch_empty_fifo(bcs, count);
+			if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
+				if (cs->debug &L1_DEB_HSCX_FIFO)
+					debugl1(cs, "bch_int Frame %d", count);
+				if (!(skb = dev_alloc_skb(count)))
+					printk(KERN_WARNING "HiSax bch_int(): receive frame out of memory\n");
+				else {
+					memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
+					skb_queue_tail(&bcs->rqueue, skb);
+				}
+			}
+		}
+		bcs->hw.hscx.rcvidx = 0;
+		bch_sched_event(bcs, B_RCVBUFREADY);
+	}
+  
+	if (istab &0x40) {	// RPF
+		bch_empty_fifo(bcs, B_FIFO_SIZE);
+
+		if (bcs->mode == L1_MODE_TRANS) { // queue every chunk
+			// receive transparent audio data
+			if (!(skb = dev_alloc_skb(B_FIFO_SIZE)))
+				printk(KERN_WARNING "HiSax bch_int(): receive transparent out of memory\n");
+			else {
+				memcpy(skb_put(skb, B_FIFO_SIZE), bcs->hw.hscx.rcvbuf, B_FIFO_SIZE);
+				skb_queue_tail(&bcs->rqueue, skb);
+			}
+			bcs->hw.hscx.rcvidx = 0;
+			bch_sched_event(bcs, B_RCVBUFREADY);
+		}
+	}
+  
+	if (istab &0x20) {	// RFO
+		if (cs->debug &L1_DEB_WARN) 
+      debugl1(cs, "bch_int() B-%d: RFO error", hscx);
+	  cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x40);  // RRES
+	}
+
+	if (istab &0x10) {	// XPR
+		if (bcs->tx_skb) {
+			if (bcs->tx_skb->len) {
+		    bch_fill_fifo(bcs);
+        goto afterXPR;
+      }
+      else {
+				if (bcs->st->lli.l1writewakeup &&
+					  (PACKET_NOACK != bcs->tx_skb->pkt_type)) {    
+					bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
+        }  
+			  dev_kfree_skb_irq(bcs->tx_skb);
+			  bcs->hw.hscx.count = 0; 
+			  bcs->tx_skb = NULL;
+      }
+    }    
+    if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
+      bcs->hw.hscx.count = 0;
+      set_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_fill_fifo(bcs);
+    } else {
+      clear_bit(BC_FLG_BUSY, &bcs->Flag);
+      bch_sched_event(bcs, B_XMTBUFREADY);
+    }
+  }
+  afterXPR:
+
+	if (istab &0x04) {	// XDU
+    if (bcs->mode == L1_MODE_TRANS) {
+			bch_fill_fifo(bcs);
+    }  
+    else {
+      if (bcs->tx_skb) {  // restart transmitting the whole frame
+        skb_push(bcs->tx_skb, bcs->hw.hscx.count);
+        bcs->tx_cnt += bcs->hw.hscx.count;
+        bcs->hw.hscx.count = 0;
+      }
+	    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x01);  // XRES
+      if (cs->debug &L1_DEB_WARN)
+        debugl1(cs, "bch_int() B-%d XDU error", hscx);
+    }
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_mode(struct BCState *bcs, int mode, int bc)
+{
+	struct IsdnCardState *cs = bcs->cs;
+	int hscx = bcs->hw.hscx.hscx;
+
+        bc = bc ? 1 : 0;  // in case bc is greater than 1
+	if (cs->debug & L1_DEB_HSCX)
+		debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
+	bcs->mode = mode;
+	bcs->channel = bc;
+  
+  // map controller to according timeslot
+  if (!hscx)
+  {
+    cs->writeisac(cs, IPACX_BCHA_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHA_CR,       0x88); 
+  }
+  else
+  {
+    cs->writeisac(cs, IPACX_BCHB_TSDP_BC1, 0x80 | bc);
+    cs->writeisac(cs, IPACX_BCHB_CR,       0x88); 
+  }
+
+	switch (mode) {
+		case (L1_MODE_NULL):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC0);  // rec off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x30);  // std adj.
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, 0xFF);  // ints off
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    break;
+		case (L1_MODE_TRANS):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0x88);  // ext transp mode
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x00);  // xxx00000
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+		case (L1_MODE_HDLC):
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MODEB, 0xC8);  // transp mode 0
+		    cs->BC_Write_Reg(cs, hscx, IPACX_EXMB,  0x01);  // idle=hdlc flags crc enabled
+		    cs->BC_Write_Reg(cs, hscx, IPACX_CMDRB, 0x41);  // validate adjustments
+		    cs->BC_Write_Reg(cs, hscx, IPACX_MASKB, _MASKB_IMASK);
+		    break;
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void
+bch_close_state(struct BCState *bcs)
+{
+	bch_mode(bcs, 0, bcs->channel);
+	if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (bcs->hw.hscx.rcvbuf) {
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+		}
+		if (bcs->blog) {
+			kfree(bcs->blog);
+			bcs->blog = NULL;
+		}
+		skb_queue_purge(&bcs->rqueue);
+		skb_queue_purge(&bcs->squeue);
+		if (bcs->tx_skb) {
+			dev_kfree_skb_any(bcs->tx_skb);
+			bcs->tx_skb = NULL;
+			clear_bit(BC_FLG_BUSY, &bcs->Flag);
+		}
+	}
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_open_state(struct IsdnCardState *cs, struct BCState *bcs)
+{
+	if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
+		if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate(): No memory for hscx.rcvbuf\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			return (1);
+		}
+		if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
+			printk(KERN_WARNING
+				"HiSax open_bchstate: No memory for bcs->blog\n");
+			clear_bit(BC_FLG_INIT, &bcs->Flag);
+			kfree(bcs->hw.hscx.rcvbuf);
+			bcs->hw.hscx.rcvbuf = NULL;
+			return (2);
+		}
+		skb_queue_head_init(&bcs->rqueue);
+		skb_queue_head_init(&bcs->squeue);
+	}
+	bcs->tx_skb = NULL;
+	clear_bit(BC_FLG_BUSY, &bcs->Flag);
+	bcs->event = 0;
+	bcs->hw.hscx.rcvidx = 0;
+	bcs->tx_cnt = 0;
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static int
+bch_setstack(struct PStack *st, struct BCState *bcs)
+{
+	bcs->channel = st->l1.bc;
+	if (bch_open_state(st->l1.hardware, bcs)) return (-1);
+	st->l1.bcs = bcs;
+	st->l1.l2l1 = bch_l2l1;
+	setstack_manager(st);
+	bcs->st = st;
+	setstack_l1_B(st);
+	return (0);
+}
+
+//----------------------------------------------------------
+//----------------------------------------------------------
+static void __devinit
+bch_init(struct IsdnCardState *cs, int hscx)
+{
+	cs->bcs[hscx].BC_SetStack   = bch_setstack;
+	cs->bcs[hscx].BC_Close      = bch_close_state;
+	cs->bcs[hscx].hw.hscx.hscx  = hscx;
+	cs->bcs[hscx].cs            = cs;
+	bch_mode(cs->bcs + hscx, 0, hscx);
+}
+
+
+//==========================================================
+// Shared functions
+//==========================================================
+
+//----------------------------------------------------------
+// Main interrupt handler
+//----------------------------------------------------------
+void 
+interrupt_ipacx(struct IsdnCardState *cs)
+{
+	u_char ista;
+  
+	while ((ista = cs->readisac(cs, IPACX_ISTA))) {
+//#################################################  
+//		printk(KERN_WARNING "interrupt_ipacx(ista=%02x)\n", ista);
+//#################################################  
+    if (ista &0x80) bch_int(cs, 0); // B channel interrupts
+    if (ista &0x40) bch_int(cs, 1);
+    
+    if (ista &0x01) dch_int(cs);    // D channel
+    if (ista &0x10) cic_int(cs);    // Layer 1 state
+  }  
+}
+
+//----------------------------------------------------------
+// Clears chip interrupt status
+//----------------------------------------------------------
+static void __init
+clear_pending_ints(struct IsdnCardState *cs)
+{
+	int ista;
+
+  // all interrupts off
+  cs->writeisac(cs, IPACX_MASK, 0xff);
+	cs->writeisac(cs, IPACX_MASKD, 0xff);
+	cs->BC_Write_Reg(cs, 0, IPACX_MASKB, 0xff);
+	cs->BC_Write_Reg(cs, 1, IPACX_MASKB, 0xff);
+  
+  ista = cs->readisac(cs, IPACX_ISTA); 
+  if (ista &0x80) cs->BC_Read_Reg(cs, 0, IPACX_ISTAB);
+  if (ista &0x40) cs->BC_Read_Reg(cs, 1, IPACX_ISTAB);
+  if (ista &0x10) cs->readisac(cs, IPACX_CIR0);
+  if (ista &0x01) cs->readisac(cs, IPACX_ISTAD); 
+}
+
+//----------------------------------------------------------
+// Does chip configuration work
+// Work to do depends on bit mask in part
+//----------------------------------------------------------
+void __init
+init_ipacx(struct IsdnCardState *cs, int part)
+{
+	if (part &1) {  // initialise chip
+//##################################################  
+//	printk(KERN_INFO "init_ipacx(%x)\n", part);
+//##################################################  
+		clear_pending_ints(cs);
+		bch_init(cs, 0);
+		bch_init(cs, 1);
+		dch_init(cs);
+	}
+	if (part &2) {  // reenable all interrupts and start chip
+		cs->BC_Write_Reg(cs, 0, IPACX_MASKB, _MASKB_IMASK);
+		cs->BC_Write_Reg(cs, 1, IPACX_MASKB, _MASKB_IMASK);
+		cs->writeisac(cs, IPACX_MASKD, _MASKD_IMASK);
+		cs->writeisac(cs, IPACX_MASK, _MASK_IMASK); // global mask register
+
+    // reset HDLC Transmitters/receivers
+		cs->writeisac(cs, IPACX_CMDRD, 0x41); 
+    cs->BC_Write_Reg(cs, 0, IPACX_CMDRB, 0x41);
+    cs->BC_Write_Reg(cs, 1, IPACX_CMDRB, 0x41);
+  	ph_command(cs, IPACX_CMD_RES);
+	}
+}
+
+//----------------- end of file -----------------------
+
diff -Nru a/drivers/isdn/hisax/ipacx.h b/drivers/isdn/hisax/ipacx.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/isdn/hisax/ipacx.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,161 @@
+/*
+ *
+ * IPACX specific defines
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ */
+
+/* All Registers original Siemens Spec  */
+
+#ifndef INCLUDE_IPACX_H
+#define INCLUDE_IPACX_H
+
+/* D-channel registers   */
+#define IPACX_RFIFOD        0x00    /* RD       */
+#define IPACX_XFIFOD        0x00    /* WR       */
+#define IPACX_ISTAD         0x20    /* RD       */
+#define IPACX_MASKD         0x20    /* WR       */
+#define IPACX_STARD         0x21    /* RD       */
+#define IPACX_CMDRD         0x21    /* WR       */
+#define IPACX_MODED         0x22    /* RD/WR    */
+#define IPACX_EXMD1         0x23    /* RD/WR    */
+#define IPACX_TIMR1         0x24    /* RD/WR    */
+#define IPACX_SAP1          0x25    /* WR       */
+#define IPACX_SAP2          0x26    /* WR       */
+#define IPACX_RBCLD         0x26    /* RD       */
+#define IPACX_RBCHD         0x27    /* RD       */
+#define IPACX_TEI1          0x27    /* WR       */
+#define IPACX_TEI2          0x28    /* WR       */
+#define IPACX_RSTAD         0x28    /* RD       */
+#define IPACX_TMD           0x29    /* RD/WR    */
+#define IPACX_CIR0          0x2E    /* RD       */
+#define IPACX_CIX0          0x2E    /* WR       */
+#define IPACX_CIR1          0x2F    /* RD       */
+#define IPACX_CIX1          0x2F    /* WR       */
+
+/* Transceiver registers    */
+#define IPACX_TR_CONF0      0x30    /* RD/WR    */
+#define IPACX_TR_CONF1      0x31    /* RD/WR    */
+#define IPACX_TR_CONF2      0x32    /* RD/WR    */
+#define IPACX_TR_STA        0x33    /* RD       */
+#define IPACX_TR_CMD        0x34    /* RD/WR    */
+#define IPACX_SQRR1         0x35    /* RD       */
+#define IPACX_SQXR1         0x35    /* WR       */
+#define IPACX_SQRR2         0x36    /* RD       */
+#define IPACX_SQXR2         0x36    /* WR       */
+#define IPACX_SQRR3         0x37    /* RD       */
+#define IPACX_SQXR3         0x37    /* WR       */
+#define IPACX_ISTATR        0x38    /* RD       */
+#define IPACX_MASKTR        0x39    /* RD/WR    */
+#define IPACX_TR_MODE       0x3A    /* RD/WR    */
+#define IPACX_ACFG1         0x3C    /* RD/WR    */
+#define IPACX_ACFG2         0x3D    /* RD/WR    */
+#define IPACX_AOE           0x3E    /* RD/WR    */
+#define IPACX_ARX           0x3F    /* RD       */
+#define IPACX_ATX           0x3F    /* WR       */
+
+/* IOM: Timeslot, DPS, CDA  */
+#define IPACX_CDA10         0x40    /* RD/WR    */
+#define IPACX_CDA11         0x41    /* RD/WR    */
+#define IPACX_CDA20         0x42    /* RD/WR    */
+#define IPACX_CDA21         0x43    /* RD/WR    */
+#define IPACX_CDA_TSDP10    0x44    /* RD/WR    */
+#define IPACX_CDA_TSDP11    0x45    /* RD/WR    */
+#define IPACX_CDA_TSDP20    0x46    /* RD/WR    */
+#define IPACX_CDA_TSDP21    0x47    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC1 0x48    /* RD/WR    */
+#define IPACX_BCHA_TSDP_BC2 0x49    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC1 0x4A    /* RD/WR    */
+#define IPACX_BCHB_TSDP_BC2 0x4B    /* RD/WR    */
+#define IPACX_TR_TSDP_BC1   0x4C    /* RD/WR    */
+#define IPACX_TR_TSDP_BC2   0x4D    /* RD/WR    */
+#define IPACX_CDA1_CR       0x4E    /* RD/WR    */
+#define IPACX_CDA2_CR       0x4F    /* RD/WR    */
+
+/* IOM: Contol, Sync transfer, Monitor    */
+#define IPACX_TR_CR         0x50    /* RD/WR    */
+#define IPACX_TRC_CR        0x50    /* RD/WR    */
+#define IPACX_BCHA_CR       0x51    /* RD/WR    */
+#define IPACX_BCHB_CR       0x52    /* RD/WR    */
+#define IPACX_DCI_CR        0x53    /* RD/WR    */
+#define IPACX_DCIC_CR       0x53    /* RD/WR    */
+#define IPACX_MON_CR        0x54    /* RD/WR    */
+#define IPACX_SDS1_CR       0x55    /* RD/WR    */
+#define IPACX_SDS2_CR       0x56    /* RD/WR    */
+#define IPACX_IOM_CR        0x57    /* RD/WR    */
+#define IPACX_STI           0x58    /* RD       */
+#define IPACX_ASTI          0x58    /* WR       */
+#define IPACX_MSTI          0x59    /* RD/WR    */
+#define IPACX_SDS_CONF      0x5A    /* RD/WR    */
+#define IPACX_MCDA          0x5B    /* RD       */
+#define IPACX_MOR           0x5C    /* RD       */
+#define IPACX_MOX           0x5C    /* WR       */
+#define IPACX_MOSR          0x5D    /* RD       */
+#define IPACX_MOCR          0x5E    /* RD/WR    */
+#define IPACX_MSTA          0x5F    /* RD       */
+#define IPACX_MCONF         0x5F    /* WR       */
+
+/* Interrupt and general registers */
+#define IPACX_ISTA          0x60    /* RD       */
+#define IPACX_MASK          0x60    /* WR       */
+#define IPACX_AUXI          0x61    /* RD       */
+#define IPACX_AUXM          0x61    /* WR       */
+#define IPACX_MODE1         0x62    /* RD/WR    */
+#define IPACX_MODE2         0x63    /* RD/WR    */
+#define IPACX_ID            0x64    /* RD       */
+#define IPACX_SRES          0x64    /* WR       */
+#define IPACX_TIMR2         0x65    /* RD/WR    */
+
+/* B-channel registers */
+#define IPACX_OFF_B1        0x70
+#define IPACX_OFF_B2        0x80
+
+#define IPACX_ISTAB         0x00    /* RD       */
+#define IPACX_MASKB         0x00    /* WR       */
+#define IPACX_STARB         0x01    /* RD       */
+#define IPACX_CMDRB         0x01    /* WR       */
+#define IPACX_MODEB         0x02    /* RD/WR    */
+#define IPACX_EXMB          0x03    /* RD/WR    */
+#define IPACX_RAH1          0x05    /* WR       */
+#define IPACX_RAH2          0x06    /* WR       */
+#define IPACX_RBCLB         0x06    /* RD       */
+#define IPACX_RBCHB         0x07    /* RD       */
+#define IPACX_RAL1          0x07    /* WR       */
+#define IPACX_RAL2          0x08    /* WR       */
+#define IPACX_RSTAB         0x08    /* RD       */
+#define IPACX_TMB           0x09    /* RD/WR    */
+#define IPACX_RFIFOB        0x0A    /*- RD      */
+#define IPACX_XFIFOB        0x0A    /*- WR      */
+
+/* Layer 1 Commands */
+#define IPACX_CMD_TIM    0x0
+#define IPACX_CMD_RES    0x1
+#define IPACX_CMD_SSP    0x2
+#define IPACX_CMD_SCP    0x3
+#define IPACX_CMD_AR8    0x8
+#define IPACX_CMD_AR10   0x9
+#define IPACX_CMD_ARL    0xa
+#define IPACX_CMD_DI     0xf
+
+/* Layer 1 Indications */
+#define IPACX_IND_DR     0x0
+#define IPACX_IND_RES    0x1
+#define IPACX_IND_TMA    0x2
+#define IPACX_IND_SLD    0x3
+#define IPACX_IND_RSY    0x4
+#define IPACX_IND_DR6    0x5
+#define IPACX_IND_PU     0x7
+#define IPACX_IND_AR     0x8
+#define IPACX_IND_ARL    0xa
+#define IPACX_IND_CVR    0xb
+#define IPACX_IND_AI8    0xc
+#define IPACX_IND_AI10   0xd
+#define IPACX_IND_AIL    0xe
+#define IPACX_IND_DC     0xf
+
+extern void init_ipacx(struct IsdnCardState *cs, int part);
+extern void interrupt_ipacx(struct IsdnCardState *cs);
+
+#endif
diff -Nru a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
--- a/drivers/isdn/hisax/isurf.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/isdn/hisax/isurf.c	Sat Jun  8 22:31:35 2002
@@ -16,6 +16,7 @@
 #include "isac.h"
 #include "isar.h"
 #include "isdnl1.h"
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -193,6 +194,10 @@
 	return(isar_auxcmd(cs, ic));
 }
 
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_surf __devinitdata = NULL;
+#endif
+
 int __init
 setup_isurf(struct IsdnCard *card)
 {
@@ -210,9 +215,48 @@
 		cs->hw.isurf.phymem = card->para[2];
 		cs->irq = card->para[0];
 	} else {
+#ifdef __ISAPNP__
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if (isapnp_present()) {
+			cs->subtyp = 0;
+			if ((pb = isapnp_find_card(
+				ISAPNP_VENDOR('S', 'I', 'E'),
+				ISAPNP_FUNCTION(0x0010), pnp_surf))) {
+				pnp_surf = pb;
+				pd = NULL;
+				if (!(pd = isapnp_find_dev(pnp_surf,
+					ISAPNP_VENDOR('S', 'I', 'E'),
+					ISAPNP_FUNCTION(0x0010), pd))) {
+					printk(KERN_ERR "ISurfPnP: PnP error card found, no device\n");
+					return (0);
+				}
+				pd->prepare(pd);
+				pd->deactivate(pd);
+				pd->activate(pd);
+				cs->hw.isurf.reset = pd->resource[0].start;
+				cs->hw.isurf.phymem = pd->resource[1].start;
+				cs->irq = pd->irq_resource[0].start;
+				if (!cs->irq || !cs->hw.isurf.reset || !cs->hw.isurf.phymem) {
+					printk(KERN_ERR "ISurfPnP:some resources are missing %d/%x/%lx\n",
+						cs->irq, cs->hw.isurf.reset, cs->hw.isurf.phymem);
+					pd->deactivate(pd);
+					return(0);
+				}
+			} else {
+				printk(KERN_INFO "ISurfPnP: no ISAPnP card found\n");
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "ISurfPnP: no ISAPnP bus found\n");
+			return(0);
+		}
+#else
 		printk(KERN_WARNING "HiSax: %s port/mem not set\n",
 			CardType[card->typ]);
 		return (0);
+#endif
 	}
 	if (check_region(cs->hw.isurf.reset, 1)) {
 		printk(KERN_WARNING
diff -Nru a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
--- a/drivers/isdn/hisax/ix1_micro.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/hisax/ix1_micro.c	Sat Jun  8 22:31:52 2002
@@ -19,6 +19,7 @@
 
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -218,6 +219,21 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id itk_ids[] __initdata = {
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25), 
+	  (unsigned long) "ITK micro 2" },
+	{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29),
+	  ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x29), 
+	  (unsigned long) "ITK micro 2." },
+	{ 0, }
+};
+
+static struct isapnp_device_id *idev = &itk_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 
 int __init
 setup_ix1micro(struct IsdnCard *card)
@@ -230,6 +246,45 @@
 	if (cs->typ != ISDN_CTYPE_IX1MICROR2)
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(idev->card_vendor) {
+			if ((pb = isapnp_find_card(idev->card_vendor,
+				idev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					idev->vendor, idev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)idev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1]) {
+						printk(KERN_ERR "ITK PnP:some resources are missing %ld/%lx\n",
+						card->para[0], card->para[1]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "ITK PnP: PnP error card found, no device\n");
+				}
+			}
+			idev++;
+			pnp_c=NULL;
+		} 
+		if (!idev->card_vendor) {
+			printk(KERN_INFO "ITK PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	/* IO-Ports */
 	cs->hw.ix1.isac_ale = card->para[1] + ISAC_COMMAND_OFFSET;
 	cs->hw.ix1.hscx_ale = card->para[1] + HSCX_COMMAND_OFFSET;
diff -Nru a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
--- a/drivers/isdn/hisax/netjet.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hisax/netjet.c	Sat Jun  8 22:31:36 2002
@@ -8,7 +8,9 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
- * Thanks to Traverse Technologie Australia for documents and information
+ * Thanks to Traverse Technologies Australia for documents and information
+ *
+ * 16-Apr-2002 - led code added - Guy Ellis (guy@traverse.com.au)
  *
  */
 
@@ -133,6 +135,7 @@
 mode_tiger(struct BCState *bcs, int mode, int bc)
 {
 	struct IsdnCardState *cs = bcs->cs;
+        u_char led;
 
 	if (cs->debug & L1_DEB_HSCX)
 		debugl1(cs, "Tiger mode %d bchan %d/%d",
@@ -154,6 +157,15 @@
 					cs->hw.njet.dmactrl);
 				byteout(cs->hw.njet.base + NETJET_IRQMASK0, 0);
 			}
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led off
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                led = ~led;
+                                cs->hw.njet.auxd &= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 		case (L1_MODE_TRANS):
 			break;
@@ -179,6 +191,14 @@
 			bcs->hw.tiger.sendp = bcs->hw.tiger.send;
 			bcs->hw.tiger.free = NETJET_DMA_TXSIZE;
 			test_and_set_bit(BC_FLG_EMPTY, &bcs->Flag);
+                        if (cs->typ == ISDN_CTYPE_NETJET_S)
+                        {
+                                // led on
+                                led = bc & 0x01;
+                                led = 0x01 << (6 + led); // convert to mask
+                                cs->hw.njet.auxd |= led;
+                                byteout(cs->hw.njet.auxa, cs->hw.njet.auxd);
+                        }
 			break;
 	}
 	if (cs->debug & L1_DEB_HSCX)
@@ -858,9 +878,13 @@
 		case (PH_ACTIVATE | REQUEST):
 			test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
 			mode_tiger(st->l1.bcs, st->l1.mode, st->l1.bc);
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_ASSIGN, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | REQUEST):
+			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG */
+			st->l1.bcs->cs->cardmsg(st->l1.bcs->cs, MDL_BC_RELEASE, (void *)(&st->l1.bc));
 			l1_msg_b(st, pr, arg);
 			break;
 		case (PH_DEACTIVATE | CONFIRM):
diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
--- a/drivers/isdn/hisax/niccy.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/niccy.c	Sat Jun  8 22:31:37 2002
@@ -22,6 +22,7 @@
 #include "hscx.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 const char *niccy_revision = "$Revision: 1.15.6.6 $";
@@ -238,6 +239,9 @@
 }
 
 static struct pci_dev *niccy_dev __initdata = NULL;
+#ifdef __ISAPNP__
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
 
 int __init
 setup_niccy(struct IsdnCard *card)
@@ -249,7 +253,39 @@
 	printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_NICCY)
 		return (0);
-
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		if ((pb = isapnp_find_card(
+			ISAPNP_VENDOR('S', 'D', 'A'),
+			ISAPNP_FUNCTION(0x0150), pnp_c))) {
+			pnp_c = pb;
+			pd = NULL;
+			if (!(pd = isapnp_find_dev(pnp_c,
+				ISAPNP_VENDOR('S', 'D', 'A'),
+				ISAPNP_FUNCTION(0x0150), pd))) {
+				printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
+				return (0);
+			}
+			pd->prepare(pd);
+			pd->deactivate(pd);
+			pd->activate(pd);
+			card->para[1] = pd->resource[0].start;
+			card->para[2] = pd->resource[1].start;
+			card->para[0] = pd->irq_resource[0].start;
+			if (!card->para[0] || !card->para[1] || !card->para[2]) {
+				printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
+					card->para[0], card->para[1], card->para[2]);
+				pd->deactivate(pd);
+				return(0);
+			}
+		} else {
+			printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
+		}
+	}
+#endif
 	if (card->para[1]) {
 		cs->hw.niccy.isac = card->para[1] + ISAC_PNP;
 		cs->hw.niccy.hscx = card->para[1] + HSCX_PNP;
diff -Nru a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
--- a/drivers/isdn/hisax/nj_s.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hisax/nj_s.c	Sat Jun  8 22:31:36 2002
@@ -184,6 +184,14 @@
 				printk(KERN_WARNING "NETjet-S: No IO-Adr for PCI card found\n");
 				return(0);
 			}
+ 			/* 2001/10/04 Christoph Ersfeld, Formula-n Europe AG www.formula-n.com */
+ 			if ((dev_netjet->subsystem_vendor == 0x55) &&
+ 				(dev_netjet->subsystem_device == 0x02)) {
+ 				printk(KERN_WARNING "Netjet: You tried to load this driver with an incompatible TigerJet-card\n");
+ 				printk(KERN_WARNING "Use type=41 for Formula-n enter:now ISDN PCI and compatible\n");
+ 				return(0);
+ 			}
+ 			/* end new code */
 			cs->hw.njet.pdev = dev_netjet;
 		} else {
 			printk(KERN_WARNING "NETjet-S: No PCI card found\n");
diff -Nru a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
--- a/drivers/isdn/hisax/sedlbauer.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/sedlbauer.c	Sat Jun  8 22:31:37 2002
@@ -48,6 +48,7 @@
 #include "isar.h"
 #include "isdnl1.h"
 #include <linux/pci.h>
+#include <linux/isapnp.h>
 
 extern const char *CardType[];
 
@@ -530,6 +531,21 @@
 
 static struct pci_dev *dev_sedl __devinitdata = NULL;
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id sedl_ids[] __initdata = {
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x01), 
+	  (unsigned long) "Speed win" },
+	{ ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02),
+	  ISAPNP_VENDOR('S', 'A', 'G'), ISAPNP_FUNCTION(0x02), 
+	  (unsigned long) "Speed Fax+" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *pdev = &sedl_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_sedlbauer(struct IsdnCard *card)
 {
@@ -565,6 +581,57 @@
 			bytecnt = 16;
 		}
 	} else {
+#ifdef __ISAPNP__
+		if (isapnp_present()) {
+			struct pci_bus *pb;
+			struct pci_dev *pd;
+
+			while(pdev->card_vendor) {
+				if ((pb = isapnp_find_card(pdev->card_vendor,
+					pdev->card_device, pnp_c))) {
+					pnp_c = pb;
+					pd = NULL;
+					if ((pd = isapnp_find_dev(pnp_c,
+						pdev->vendor, pdev->function, pd))) {
+						printk(KERN_INFO "HiSax: %s detected\n",
+							(char *)pdev->driver_data);
+						pd->prepare(pd);
+						pd->deactivate(pd);
+						pd->activate(pd);
+						card->para[1] =
+							pd->resource[0].start;
+						card->para[0] =
+							pd->irq_resource[0].start;
+						if (!card->para[0] || !card->para[1]) {
+							printk(KERN_ERR "Sedlbauer PnP:some resources are missing %ld/%lx\n",
+								card->para[0], card->para[1]);
+							pd->deactivate(pd);
+							return(0);
+						}
+						cs->hw.sedl.cfg_reg = card->para[1];
+						cs->irq = card->para[0];
+						if (pdev->function == ISAPNP_FUNCTION(0x2)) {
+							cs->subtyp = SEDL_SPEED_FAX;
+							cs->hw.sedl.chip = SEDL_CHIP_ISAC_ISAR;
+							bytecnt = 16;
+						} else {
+							cs->subtyp = SEDL_SPEED_CARD_WIN;
+							cs->hw.sedl.chip = SEDL_CHIP_TEST;
+						}
+						goto ready;
+					} else {
+						printk(KERN_ERR "Sedlbauer PnP: PnP error card found, no device\n");
+						return(0);
+					}
+				}
+				pdev++;
+				pnp_c=NULL;
+			} 
+			if (!pdev->card_vendor) {
+				printk(KERN_INFO "Sedlbauer PnP: no ISAPnP card found\n");
+			}
+		}
+#endif
 /* Probe for Sedlbauer speed pci */
 #if CONFIG_PCI
 		if (!pci_present()) {
@@ -630,7 +697,7 @@
 		return (0);
 #endif /* CONFIG_PCI */
 	}	
-	
+ready:	
 	/* In case of the sedlbauer pcmcia card, this region is in use,
 	 * reserved for us by the card manager. So we do not check it
 	 * here, it would fail.
diff -Nru a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
--- a/drivers/isdn/hisax/teles3.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/isdn/hisax/teles3.c	Sat Jun  8 22:31:37 2002
@@ -15,6 +15,7 @@
  */
 #define __NO_VERSION__
 #include <linux/init.h>
+#include <linux/isapnp.h>
 #include "hisax.h"
 #include "isac.h"
 #include "hscx.h"
@@ -254,6 +255,24 @@
 	return(0);
 }
 
+#ifdef __ISAPNP__
+static struct isapnp_device_id teles_ids[] __initdata = {
+	{ ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110),
+	  ISAPNP_VENDOR('T', 'A', 'G'), ISAPNP_FUNCTION(0x2110), 
+	  (unsigned long) "Teles 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0),
+	  ISAPNP_VENDOR('C', 'T', 'X'), ISAPNP_FUNCTION(0x0), 
+	  (unsigned long) "Creatix 16.3 PnP" },
+	{ ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002),
+	  ISAPNP_VENDOR('C', 'P', 'Q'), ISAPNP_FUNCTION(0x1002), 
+	  (unsigned long) "Compaq ISDN S0" },
+	{ 0, }
+};
+
+static struct isapnp_device_id *tdev = &teles_ids[0];
+static struct pci_bus *pnp_c __devinitdata = NULL;
+#endif
+
 int __devinit
 setup_teles3(struct IsdnCard *card)
 {
@@ -267,6 +286,47 @@
 	    && (cs->typ != ISDN_CTYPE_TELESPCMCIA) && (cs->typ != ISDN_CTYPE_COMPAQ_ISA))
 		return (0);
 
+#ifdef __ISAPNP__
+	if (!card->para[1] && isapnp_present()) {
+		struct pci_bus *pb;
+		struct pci_dev *pd;
+
+		while(tdev->card_vendor) {
+			if ((pb = isapnp_find_card(tdev->card_vendor,
+				tdev->card_device, pnp_c))) {
+				pnp_c = pb;
+				pd = NULL;
+				if ((pd = isapnp_find_dev(pnp_c,
+					tdev->vendor, tdev->function, pd))) {
+					printk(KERN_INFO "HiSax: %s detected\n",
+						(char *)tdev->driver_data);
+					pd->prepare(pd);
+					pd->deactivate(pd);
+					pd->activate(pd);
+					card->para[3] = pd->resource[2].start;
+					card->para[2] = pd->resource[1].start;
+					card->para[1] = pd->resource[0].start;
+					card->para[0] = pd->irq_resource[0].start;
+					if (!card->para[0] || !card->para[1] || !card->para[2]) {
+						printk(KERN_ERR "Teles PnP:some resources are missing %ld/%lx/%lx\n",
+						card->para[0], card->para[1], card->para[2]);
+						pd->deactivate(pd);
+						return(0);
+					}
+					break;
+				} else {
+					printk(KERN_ERR "Teles PnP: PnP error card found, no device\n");
+				}
+			}
+			tdev++;
+			pnp_c=NULL;
+		} 
+		if (!tdev->card_vendor) {
+			printk(KERN_INFO "Teles PnP: no ISAPnP card found\n");
+			return(0);
+		}
+	}
+#endif
 	if (cs->typ == ISDN_CTYPE_16_3) {
 		cs->hw.teles3.cfg_reg = card->para[1];
 		switch (cs->hw.teles3.cfg_reg) {
diff -Nru a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
--- a/drivers/isdn/hisax/w6692.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/hisax/w6692.c	Sat Jun  8 22:31:52 2002
@@ -29,11 +29,17 @@
 
 static const PCI_ENTRY id_list[] =
 {
-	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
 	{PCI_VENDOR_ID_WINBOND2, PCI_DEVICE_ID_WINBOND2_6692, "Winbond", "W6692"},
-	{0, 0, NULL, NULL}
+	{PCI_VENDOR_ID_DYNALINK, PCI_DEVICE_ID_DYNALINK_IS64PH, "Dynalink/AsusCom", "IS64PH"},
+	{0, 0, "U.S.Robotics", "ISDN PCI Card TA"}
 };
 
+#define W6692_SV_USR   0x16ec
+#define W6692_SD_USR   0x3409
+#define W6692_WINBOND  0
+#define W6692_DYNALINK 1
+#define W6692_USR      2
+
 extern const char *CardType[];
 
 const char *w6692_revision = "$Revision: 1.12.6.6 $";
@@ -859,6 +865,28 @@
 	return (0);
 }
 
+void resetW6692(struct IsdnCardState *cs)
+{
+	cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
+	schedule_timeout((10*HZ)/1000);
+	cs->writeW6692(cs, W_D_CTL, 0x00);
+	schedule_timeout((10*HZ)/1000);
+	cs->writeW6692(cs, W_IMASK, 0xff);
+	cs->writeW6692(cs, W_D_SAM, 0xff);
+	cs->writeW6692(cs, W_D_TAM, 0xff);
+	cs->writeW6692(cs, W_D_EXIM, 0x00);
+	cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
+	cs->writeW6692(cs, W_IMASK, 0x18);
+	if (cs->subtyp == W6692_USR) {
+		/* seems that USR implemented some power control features
+		 * Pin 79 is connected to the oscilator circuit so we
+		 * have to handle it here
+		 */
+		cs->writeW6692(cs, W_PCTL, 0x80);
+		cs->writeW6692(cs, W_XDATA, 0x00);
+	}
+}
+
 void __init initW6692(struct IsdnCardState *cs, int part)
 {
 	if (part & 1) {
@@ -868,15 +896,7 @@
 		cs->dbusytimer.function = (void *) dbusy_timer_handler;
 		cs->dbusytimer.data = (long) cs;
 		init_timer(&cs->dbusytimer);
-
-		cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
-		cs->writeW6692(cs, W_D_CTL, 0x00);
-		cs->writeW6692(cs, W_IMASK, 0xff);
-		cs->writeW6692(cs, W_D_SAM, 0xff);
-		cs->writeW6692(cs, W_D_TAM, 0xff);
-		cs->writeW6692(cs, W_D_EXIM, 0x00);
-		cs->writeW6692(cs, W_D_MODE, W_D_MODE_RACT);
-		cs->writeW6692(cs, W_IMASK, 0x18);
+		resetW6692(cs);
 		ph_command(cs, W_L1CMD_RST);
 		cs->dc.w6692.ph_state = W_L1CMD_RST;
 		W6692_new_ph(cs);
@@ -943,9 +963,14 @@
 {
 	switch (mt) {
 		case CARD_RESET:
+			resetW6692(cs);
 			return (0);
 		case CARD_RELEASE:
+			cs->writeW6692(cs, W_IMASK, 0xff);
 			release_region(cs->hw.w6692.iobase, 256);
+			if (cs->subtyp == W6692_USR) {
+				cs->writeW6692(cs, W_XDATA, 0x04);
+			}
 			return (0);
 		case CARD_INIT:
 			initW6692(cs, 3);
@@ -988,6 +1013,7 @@
 		if (dev_w6692) {
 			if (pci_enable_device(dev_w6692))
 				continue;
+			cs->subtyp = id_idx;
 			break;
 		}
 		id_idx++;
@@ -998,6 +1024,13 @@
 		/* I think address 0 is allways the configuration area */
 		/* and address 1 is the real IO space KKe 03.09.99 */
 		pci_ioaddr = pci_resource_start(dev_w6692, 1);
+		/* USR ISDN PCI card TA need some special handling */
+		if (cs->subtyp == W6692_WINBOND) {
+			if ((W6692_SV_USR == dev_w6692->subsystem_vendor) &&
+			    (W6692_SD_USR == dev_w6692->subsystem_device)) {
+				cs->subtyp = W6692_USR;
+			}
+		}
 	}
 	if (!found) {
 		printk(KERN_WARNING "W6692: No PCI card found\n");
@@ -1014,18 +1047,18 @@
 	}
 	cs->hw.w6692.iobase = pci_ioaddr;
 	printk(KERN_INFO "Found: %s %s, I/O base: 0x%x, irq: %d\n",
-	       id_list[id_idx].vendor_name, id_list[id_idx].card_name,
-	       pci_ioaddr, dev_w6692->irq);
+	       id_list[cs->subtyp].vendor_name, id_list[cs->subtyp].card_name,
+	       pci_ioaddr, pci_irq);
 	if (check_region((cs->hw.w6692.iobase), 256)) {
 		printk(KERN_WARNING
 		       "HiSax: %s I/O ports %x-%x already in use\n",
-		       id_list[id_idx].card_name,
+		       id_list[cs->subtyp].card_name,
 		       cs->hw.w6692.iobase,
 		       cs->hw.w6692.iobase + 255);
 		return (0);
 	} else {
 		request_region(cs->hw.w6692.iobase, 256,
-			       id_list[id_idx].card_name);
+			       id_list[cs->subtyp].card_name);
 	}
 #else
 	printk(KERN_WARNING "HiSax: W6692 and NO_PCI_BIOS\n");
@@ -1035,7 +1068,7 @@
 
 	printk(KERN_INFO
 	       "HiSax: %s config irq:%d I/O:%x\n",
-	       id_list[id_idx].card_name, cs->irq,
+	       id_list[cs->subtyp].card_name, cs->irq,
 	       cs->hw.w6692.iobase);
 
 	cs->readW6692 = &ReadW6692;
diff -Nru a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
--- a/drivers/isdn/hysdn/hycapi.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/isdn/hysdn/hycapi.c	Sat Jun  8 22:31:35 2002
@@ -82,10 +82,6 @@
 #ifdef HYCAPI_PRINTFNAMES
 	printk(KERN_NOTICE "HYCAPI hycapi_remove_ctr\n");
 #endif 
-	if(!hy_di) {
-		printk(KERN_ERR "No capi_driver_interface set!");
-		return;
-	}
 	cinfo = (hycapictrl_info *)(ctrl->driverdata);
 	if(!cinfo) {
 		printk(KERN_ERR "No hycapictrl_info set!");
@@ -686,10 +682,6 @@
 int hycapi_init()
 {
 	int i;
-	if(hy_di) {
-		printk(KERN_NOTICE "HyDI allready set\n");
-		return 0;
-	}
 	for(i=0;i<CAPI_MAXAPPL;i++) {
 		memset(&(hycapi_applications[i]), 0, sizeof(hycapi_appl));
 	}
diff -Nru a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
--- a/drivers/isdn/hysdn/hysdn_defs.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/isdn/hysdn/hysdn_defs.h	Sat Jun  8 22:31:36 2002
@@ -276,7 +276,6 @@
 
 #ifdef CONFIG_HYSDN_CAPI
 extern unsigned int hycapi_enable; 
-extern struct capi_driver_interface *hy_di;
 extern int hycapi_capi_create(hysdn_card *);	/* create a new capi device */
 extern int hycapi_capi_release(hysdn_card *);	/* delete the device */
 extern int hycapi_capi_stop(hysdn_card *card);   /* suspend */
diff -Nru a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
--- a/drivers/isdn/i4l/isdn_net.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/isdn/i4l/isdn_net.c	Sat Jun  8 22:31:43 2002
@@ -9,6 +9,14 @@
  * This software may be used and distributed according to the terms
  * of the GNU General Public License, incorporated herein by reference.
  *
+ * Data Over Voice (DOV) support added - Guy Ellis 23-Mar-02 
+ *                                       guy@traverse.com.au
+ * Outgoing calls - looks for a 'V' in first char of dialed number
+ * Incoming calls - checks first character of eaz as follows:
+ *   Numeric - accept DATA only - original functionality
+ *   'V'     - accept VOICE (DOV) only
+ *   'B'     - accept BOTH DATA and DOV types
+ *
  * Jan 2001: fix CISCO HDLC      Bjoern A. Zeeb <i4l@zabbadoz.net>
  *           for info on the protocol, see 
  *           http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
@@ -569,6 +577,7 @@
 	int i;
 	unsigned long flags;
 	isdn_ctrl cmd;
+        u_char *phone_number;
 
 	while (p) {
 		isdn_net_local *lp = p->local;
@@ -667,7 +676,20 @@
 							break;
 						}
 
-					sprintf(cmd.parm.setup.phone, "%s", lp->dial->num);
+					cmd.driver = lp->isdn_device;
+					cmd.command = ISDN_CMD_DIAL;
+					cmd.parm.setup.si2 = 0;
+
+                                        /* check for DOV */
+                                        phone_number = lp->dial->num;
+                                        if ((*phone_number == 'v') ||
+					    (*phone_number == 'V')) { /* DOV call */
+                                                cmd.parm.setup.si1 = 1;
+                                        } else { /* DATA call */
+                                                cmd.parm.setup.si1 = 7;
+					}
+
+					strcpy(cmd.parm.setup.phone, phone_number);
 					/*
 					 * Switch to next number or back to start if at end of list.
 					 */
@@ -687,10 +709,6 @@
 						}
 					}
 					restore_flags(flags);
-					cmd.driver = lp->isdn_device;
-					cmd.command = ISDN_CMD_DIAL;
-					cmd.parm.setup.si1 = 7;
-					cmd.parm.setup.si2 = 0;
 					sprintf(cmd.parm.setup.eazmsn, "%s",
 						isdn_map_eaz2msn(lp->msn, cmd.driver));
 					i = isdn_dc2minor(lp->isdn_device, lp->isdn_channel);
@@ -699,8 +717,9 @@
 						dev->usage[i] |= ISDN_USAGE_OUTGOING;
 						isdn_info_update();
 					}
-					printk(KERN_INFO "%s: dialing %d %s...\n", lp->name,
-					       lp->dialretry, cmd.parm.setup.phone);
+					printk(KERN_INFO "%s: dialing %d %s... %s\n", lp->name,
+					       lp->dialretry, cmd.parm.setup.phone,
+					       (cmd.parm.setup.si1 == 1) ? "DOV" : "");
 					lp->dtimer = 0;
 #ifdef ISDN_DEBUG_NET_DIAL
 					printk(KERN_DEBUG "dial: d=%d c=%d\n", lp->isdn_device,
@@ -1746,10 +1765,6 @@
 	}
 
 	switch (type) {
-	case CISCO_TYPE_INET:
-		skb->protocol = htons(ETH_P_IP);
-		netif_rx(skb);
-		break;
 	case CISCO_TYPE_SLARP:
 		isdn_net_ciscohdlck_slarp_in(lp, skb);
 		goto out_free;
@@ -1759,11 +1774,11 @@
 				"\"no cdp enable\" on cisco.\n", lp->name);
 		goto out_free;
 	default:
-		printk(KERN_WARNING "%s: Unknown Cisco type 0x%04x\n",
-		       lp->name, type);
-		goto out_free;
+		/* no special cisco protocol */
+		skb->protocol = htons(type);
+		netif_rx(skb);
+		return;
 	}
-	return;
 
  out_free:
 	kfree_skb(skb);
@@ -2144,6 +2159,8 @@
 	isdn_net_phone *n;
 	ulong flags;
 	char nr[32];
+	char *my_eaz;
+
 	/* Search name in netdev-chain */
 	save_flags(flags);
 	cli();
@@ -2162,15 +2179,17 @@
 		eaz = setup->eazmsn;
 	if (dev->net_verbose > 1)
 		printk(KERN_INFO "isdn_net: call from %s,%d,%d -> %s\n", nr, si1, si2, eaz);
-	/* Accept only calls with Si1 = 7 (Data-Transmission) */
-	if (si1 != 7) {
-		restore_flags(flags);
-		if (dev->net_verbose > 1)
-			printk(KERN_INFO "isdn_net: Service-Indicator not 7, ignored\n");
-		return 0;
-	}
-	n = (isdn_net_phone *) 0;
-	p = dev->netdev;
+        /* Accept DATA and VOICE calls at this stage
+        local eaz is checked later for allowed call types */
+        if ((si1 != 7) && (si1 != 1)) {
+                restore_flags(flags);
+                if (dev->net_verbose > 1)
+                        printk(KERN_INFO "isdn_net: Service-Indicator not 1 or 7, ignored\n");
+                return 0;
+        }
+
+n = (isdn_net_phone *) 0;
+p = dev->netdev;
 	ematch = wret = swapped = 0;
 #ifdef ISDN_DEBUG_NET_ICALL
 	printk(KERN_DEBUG "n_fi: di=%d ch=%d idx=%d usg=%d\n", di, ch, idx,
@@ -2190,8 +2209,25 @@
 				break;
 		}
 		swapped = 0;
-		if (!(matchret = isdn_msncmp(eaz, isdn_map_eaz2msn(lp->msn, di))))
-			ematch = 1;
+                /* check acceptable call types for DOV */
+                my_eaz = isdn_map_eaz2msn(lp->msn, di);
+                if (si1 == 1) { /* it's a DOV call, check if we allow it */
+                        if (*my_eaz == 'v' || *my_eaz == 'V' ||
+			    *my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                        else
+                                my_eaz = 0; /* force non match */
+                } else { /* it's a DATA call, check if we allow it */
+                        if (*my_eaz == 'b' || *my_eaz == 'B')
+                                my_eaz++; /* skip to allow a match */
+                }
+                if (my_eaz)
+                        matchret = isdn_msncmp(eaz, my_eaz);
+                else
+                        matchret = 1;
+                if (!matchret)
+                        ematch = 1;
+
 		/* Remember if more numbers eventually can match */
 		if (matchret > wret)
 			wret = matchret;
diff -Nru a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h
--- a/drivers/isdn/i4l/isdn_net.h	Sat Jun  8 22:31:52 2002
+++ b/drivers/isdn/i4l/isdn_net.h	Sat Jun  8 22:31:52 2002
@@ -26,7 +26,6 @@
 #define CISCO_ADDR_BROADCAST  0x8f
 #define CISCO_CTRL            0x00
 #define CISCO_TYPE_CDP        0x2000
-#define CISCO_TYPE_INET       0x0800
 #define CISCO_TYPE_SLARP      0x8035
 #define CISCO_SLARP_REQUEST   0
 #define CISCO_SLARP_REPLY     1
@@ -129,8 +128,12 @@
 	spin_lock_irqsave(&master_lp->netdev->queue_lock, flags);
 	lp->last->next = lp->next;
 	lp->next->last = lp->last;
-	if (master_lp->netdev->queue == lp)
+	if (master_lp->netdev->queue == lp) {
 		master_lp->netdev->queue = lp->next;
+		if (lp->next == lp) { /* last in queue */
+			master_lp->netdev->queue = master_lp->netdev->local;
+		}
+	}
 	lp->next = lp->last = lp;	/* (re)set own pointers */
 	spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags);
 }
diff -Nru a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
--- a/drivers/isdn/i4l/isdn_ppp.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/isdn/i4l/isdn_ppp.c	Sat Jun  8 22:31:51 2002
@@ -108,8 +108,11 @@
 	unsigned long flags;
 	struct ippp_struct *is;
 
-	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return 0;
+	}
 
 	save_flags(flags);
 	cli();
@@ -125,7 +128,12 @@
 	lp->netdev->pb->ref_ct--;
 	spin_unlock(&lp->netdev->pb->lock);
 #endif /* CONFIG_ISDN_MPP */
-
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) now invalid\n",
+			lp->ppp_slot);
+		restore_flags(flags);
+		return 0;
+	}
 	is = ippp_table[lp->ppp_slot];
 	if ((is->state & IPPP_CONNECT))
 		isdn_ppp_closewait(lp->ppp_slot);	/* force wakeup on ippp device */
@@ -221,12 +229,13 @@
 void
 isdn_ppp_wakeup_daemon(isdn_net_local * lp)
 {
-	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS)
+	if (lp->ppp_slot < 0 || lp->ppp_slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
 		return;
-
+	}
 	ippp_table[lp->ppp_slot]->state = IPPP_OPEN | IPPP_CONNECT | IPPP_NOBLOCK;
-
-		wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
+	wake_up_interruptible(&ippp_table[lp->ppp_slot]->wq);
 }
 
 /*
@@ -239,13 +248,14 @@
 {
 	struct ippp_struct *is;
 
-	if (slot < 0 || slot >= ISDN_MAX_CHANNELS)
+	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+			slot);
 		return 0;
+	}
 	is = ippp_table[slot];
-
 	if (is->state)
 		wake_up_interruptible(&is->wq);
-
 	is->state = IPPP_CLOSEWAIT;
 	return 1;
 }
@@ -282,7 +292,7 @@
 	}
 	is = file->private_data = ippp_table[slot];
 
-		printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
+	printk(KERN_DEBUG "ippp, open, slot: %d, minor: %d, state: %04x\n", slot, minor, is->state);
 
 	/* compression stuff */
 	is->link_compressor   = is->compressor = NULL;
@@ -339,6 +349,11 @@
 	if (is->lp) {           /* a lp address says: this link is still up */
 		isdn_net_dev *p = is->lp->netdev;
 
+ 		if (!p) {
+ 			printk(KERN_ERR __FUNCTION__": no lp->netdev\n");
+			unlock_kernel();
+ 			return 0;
+ 		}
 		is->state &= ~IPPP_CONNECT;	/* -> effect: no call of wakeup */
 		/*
 		 * isdn_net_hangup() calls isdn_ppp_free()
@@ -642,7 +657,7 @@
 	struct ippp_struct *is;
 
 	if (slot < 0 || slot >= ISDN_MAX_CHANNELS) {
-		printk(KERN_WARNING "ippp: illegal slot.\n");
+		printk(KERN_WARNING "ippp: illegal slot(%d).\n", slot);
 		return 0;
 	}
 	is = ippp_table[slot];
@@ -964,7 +979,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_receive: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return;
 	}
@@ -1017,7 +1033,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_push_higher: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		goto drop_packet;
 	}
 	is = ippp_table[slot];
@@ -1025,7 +1042,8 @@
  	if (lp->master) { // FIXME?
  		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
  		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
- 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot %d\n", lp->ppp_slot);
+ 			printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n",
+ 				lp->ppp_slot);
 			goto drop_packet;
  		}
  	}
@@ -1059,6 +1077,11 @@
 		case PPP_VJC_UNCOMP:
 			if (is->debug & 0x20)
 				printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n");
+			if (net_dev->local->ppp_slot < 0) {
+				printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+					net_dev->local->ppp_slot);
+				goto drop_packet;
+			}
 			if (slhc_remember(ippp_table[net_dev->local->ppp_slot]->slcomp, skb->data, skb->len) <= 0) {
 				printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n");
 				goto drop_packet;
@@ -1080,6 +1103,11 @@
 				}
 				skb_put(skb, skb_old->len + 128);
 				memcpy(skb->data, skb_old->data, skb_old->len);
+				if (net_dev->local->ppp_slot < 0) {
+					printk(KERN_ERR __FUNCTION__": net_dev->local->ppp_slot(%d) out of range\n",
+						net_dev->local->ppp_slot);
+					goto drop_packet;
+				}
 				pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp,
 						skb->data, skb_old->len);
 				kfree_skb(skb_old);
@@ -1168,7 +1196,8 @@
 
 	slot = mlp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", mlp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			mlp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1203,7 +1232,8 @@
 
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR "isdn_ppp_xmit: lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		kfree_skb(skb);
 		return 0;
 	}
@@ -1408,8 +1438,15 @@
 
 static int isdn_ppp_mp_init( isdn_net_local * lp, ippp_bundle * add_to )
 {
-	struct ippp_struct * is = ippp_table[lp->ppp_slot];
-   
+	struct ippp_struct * is;
+
+	if (lp->ppp_slot < 0) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return(-EINVAL);
+	}
+
+	is = ippp_table[lp->ppp_slot];
 	if (add_to) {
 		if( lp->netdev->pb )
 			lp->netdev->pb->ref_ct--;
@@ -1455,7 +1492,8 @@
         stats = &mp->stats;
 	slot = lp->ppp_slot;
 	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-		printk(KERN_ERR "isdn_ppp_mp_receive: lp->ppp_slot %d\n", lp->ppp_slot);
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d)\n",
+			lp->ppp_slot);
 		stats->frame_drops++;
 		dev_kfree_skb(skb);
 		spin_unlock_irqrestore(&mp->lock, flags);
@@ -1491,7 +1529,8 @@
 	for (lpq = net_dev->queue;;) {
 		slot = lpq->ppp_slot;
 		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
-			printk(KERN_ERR "isdn_ppp_mp_receive: lpq->ppp_slot %d\n", lpq->ppp_slot);
+			printk(KERN_ERR __FUNCTION__": lpq->ppp_slot(%d)\n",
+				lpq->ppp_slot);
 		} else {
 			u32 lls = ippp_table[slot]->last_link_seqno;
 			if (MP_LT(lls, minseq))
@@ -1723,9 +1762,14 @@
 	struct sk_buff * skb;
 	unsigned int tot_len;
 
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
 	if( MP_FLAGS(from) == (MP_BEGIN_FRAG | MP_END_FRAG) ) {
 		if( ippp_table[lp->ppp_slot]->debug & 0x40 )
-			printk(KERN_DEBUG"isdn_mppp: reassembly: frame %d, "
+			printk(KERN_DEBUG "isdn_mppp: reassembly: frame %d, "
 					"len %d\n", MP_SEQ(from), from->len );
 		skb = from;
 		skb_pull(skb, MP_HEADER_LEN);
@@ -1844,8 +1888,10 @@
 	memset(&t, 0, sizeof(struct ppp_stats));
 	if (dev->flags & IFF_UP) {
 		t.p.ppp_ipackets = lp->stats.rx_packets;
+		t.p.ppp_ibytes = lp->stats.rx_bytes;
 		t.p.ppp_ierrors = lp->stats.rx_errors;
 		t.p.ppp_opackets = lp->stats.tx_packets;
+		t.p.ppp_obytes = lp->stats.tx_bytes;
 		t.p.ppp_oerrors = lp->stats.tx_errors;
 #ifdef CONFIG_ISDN_PPP_VJ
 		if (slot >= 0 && ippp_table[slot]->slcomp) {
@@ -2485,18 +2531,31 @@
 static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp,
 	 struct sk_buff *skb,int proto)
 {
-	struct ippp_struct *is = ippp_table[lp->ppp_slot];
+	struct ippp_struct *is;
 	struct ippp_struct *mis;
 	int len;
 	struct isdn_ppp_resetparams rsparm;
 	unsigned char rsdata[IPPP_RESET_MAXDATABYTES];	
 
-	printk(KERN_DEBUG "Received CCP frame from peer\n");
+	printk(KERN_DEBUG "Received CCP frame from peer slot(%d)\n",
+		lp->ppp_slot);
+	if (lp->ppp_slot < 0 || lp->ppp_slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			lp->ppp_slot);
+		return;
+	}
+	is = ippp_table[lp->ppp_slot];
 	isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-	if(lp->master)
-		mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-	else
+	if(lp->master) {
+		int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
 		mis = is;
 
 	switch(skb->data[0]) {
@@ -2648,13 +2707,18 @@
 
 static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct sk_buff *skb)
 {
-	struct ippp_struct *mis,*is = ippp_table[lp->ppp_slot];
-	int proto;
+	struct ippp_struct *mis,*is;
+	int proto, slot = lp->ppp_slot;
 	unsigned char *data;
 
 	if(!skb || skb->len < 3)
 		return;
-
+	if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+		printk(KERN_ERR __FUNCTION__": lp->ppp_slot(%d) out of range\n",
+			slot);
+		return;
+	}	
+	is = ippp_table[slot];
 	/* Daemon may send with or without address and control field comp */
 	data = skb->data;
 	if(!(is->pppcfg & SC_COMP_AC) && data[0] == 0xff && data[1] == 0x03) {
@@ -2670,12 +2734,17 @@
 	printk(KERN_DEBUG "Received CCP frame from daemon:\n");
 	isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot);
 
-        if(lp->master)
-                mis = ippp_table[((isdn_net_local *) (lp->master->priv))->ppp_slot];
-        else
-                mis = is;
-	
-	if(mis != is)
+	if (lp->master) {
+		slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot;
+		if (slot < 0 || slot > ISDN_MAX_CHANNELS) {
+			printk(KERN_ERR __FUNCTION__": slot(%d) out of range\n",
+				slot);
+			return;
+		}	
+		mis = ippp_table[slot];
+	} else
+		mis = is;
+	if (mis != is)
 		printk(KERN_DEBUG "isdn_ppp: Ouch! Master CCP sends on slave slot!\n");
 	
         switch(data[2]) {
diff -Nru a/drivers/net/bonding.c b/drivers/net/bonding.c
--- a/drivers/net/bonding.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/net/bonding.c	Sat Jun  8 22:31:37 2002
@@ -161,6 +161,21 @@
  *     - Remove possibility of calling bond_sethwaddr with NULL slave_dev ptr 
  *     - Handle hot swap ethernet interface deregistration events to remove
  *       kernel oops following hot swap of enslaved interface
+ *
+ * 2002/1/2 - Chad N. Tindel <ctindel at ieee dot org>
+ *     - Restore original slave flags at release time.
+ *
+ * 2002/02/18 - Erik Habbinga <erik_habbinga at hp dot com>
+ *     - bond_release(): calling kfree on our_slave after call to
+ *       bond_restore_slave_flags, not before
+ *     - bond_enslave(): saving slave flags into original_flags before
+ *       call to netdev_set_master, so the IFF_SLAVE flag doesn't end
+ *       up in original_flags
+ *
+ * 2002/04/05 - Mark Smith <mark.smith at comdev dot cc> and
+ *              Steve Mead <steve.mead at comdev dot cc>
+ *     - Port Gleb Natapov's multicast support patchs from 2.4.12
+ *       to 2.4.18 adding support for multicast.
  */
 
 #include <linux/config.h>
@@ -208,11 +223,8 @@
 #define MII_ENDOF_NWAY	0x20
 
 #undef  MII_LINK_READY
-/*#define MII_LINK_READY	(MII_LINK_UP | MII_ENDOF_NWAY)*/
 #define MII_LINK_READY	(MII_LINK_UP)
 
-#define MAX_BOND_ADDR 256
-
 #ifndef BOND_LINK_ARP_INTERV
 #define BOND_LINK_ARP_INTERV	0
 #endif
@@ -223,7 +235,7 @@
 static u32 my_ip = 0;
 char *arp_target_hw_addr = NULL;
 
-static int max_bonds	= MAX_BONDS;
+static int max_bonds	= BOND_DEFAULT_MAX_BONDS;
 static int miimon	= BOND_LINK_MON_INTERV;
 static int mode		= BOND_MODE_ROUNDROBIN;
 static int updelay	= 0;
@@ -234,7 +246,7 @@
 static struct bonding *these_bonds =  NULL;
 static struct net_device *dev_bonds = NULL;
 
-MODULE_PARM(max_bonds, "1-" __MODULE_STRING(INT_MAX) "i");
+MODULE_PARM(max_bonds, "i");
 MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
 MODULE_PARM(miimon, "i");
 MODULE_PARM_DESC(miimon, "Link check interval in milliseconds");
@@ -260,6 +272,15 @@
 static void bond_mii_monitor(struct net_device *dev);
 static void bond_arp_monitor(struct net_device *dev);
 static int bond_event(struct notifier_block *this, unsigned long event, void *ptr);
+static void bond_restore_slave_flags(slave_t *slave);
+static void bond_mc_list_destroy(struct bonding *bond);
+static void bond_mc_add(bonding_t *bond, void *addr, int alen);
+static void bond_mc_delete(bonding_t *bond, void *addr, int alen);
+static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst, int gpf_flag);
+static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2);
+static void bond_set_promiscuity(bonding_t *bond, int inc);
+static void bond_set_allmulti(bonding_t *bond, int inc);
+static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi, struct dev_mc_list *mc_list);
 static void bond_set_slave_inactive_flags(slave_t *slave);
 static void bond_set_slave_active_flags(slave_t *slave);
 static int bond_enslave(struct net_device *master, struct net_device *slave);
@@ -282,6 +303,11 @@
 #define IS_UP(dev)	((((dev)->flags & (IFF_UP)) == (IFF_UP)) && \
 			(netif_running(dev) && netif_carrier_ok(dev)))
 
+static void bond_restore_slave_flags(slave_t *slave)
+{
+	slave->dev->flags = slave->original_flags;
+}
+
 static void bond_set_slave_inactive_flags(slave_t *slave)
 {
 	slave->state = BOND_STATE_BACKUP;
@@ -431,6 +457,7 @@
 
 	/* Release the bonded slaves */
 	bond_release_all(master);
+	bond_mc_list_destroy (bond);
 
 	write_unlock_irqrestore(&bond->lock, flags);
 
@@ -438,19 +465,180 @@
 	return 0;
 }
 
-static void set_multicast_list(struct net_device *master)
+/* 
+ * flush all members of flush->mc_list from device dev->mc_list
+ */
+static void bond_mc_list_flush(struct net_device *dev, struct net_device *flush)
+{ 
+	struct dev_mc_list *dmi; 
+ 
+	for (dmi = flush->mc_list; dmi != NULL; dmi = dmi->next) 
+		dev_mc_delete(dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+}
+
+/*
+ * Totally destroys the mc_list in bond
+ */
+static void bond_mc_list_destroy(struct bonding *bond)
 {
+	struct dev_mc_list *dmi;
+
+	dmi = bond->mc_list; 
+	while (dmi) { 
+		bond->mc_list = dmi->next; 
+		kfree(dmi); 
+		dmi = bond->mc_list; 
+	}
+}
+
 /*
-	bonding_t *bond = master->priv;
+ * Add a Multicast address to every slave in the bonding group
+ */
+static void bond_mc_add(bonding_t *bond, void *addr, int alen)
+{ 
 	slave_t *slave;
 
-	for (slave = bond->next; slave != (slave_t*)bond; slave = slave->next) {
-		slave->dev->mc_list = master->mc_list;
-		slave->dev->mc_count = master->mc_count;
-		slave->dev->flags = master->flags;
-		slave->dev->set_multicast_list(slave->dev);
+	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev) {
+		dev_mc_add(slave->dev, addr, alen, 0);
 	}
+} 
+
+/*
+ * Remove a multicast address from every slave in the bonding group
+ */
+static void bond_mc_delete(bonding_t *bond, void *addr, int alen)
+{ 
+	slave_t *slave; 
+
+	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+		dev_mc_delete(slave->dev, addr, alen, 0);
+} 
+
+/*
+ * Copy all the Multicast addresses from src to the bonding device dst
  */
+static int bond_mc_list_copy (struct dev_mc_list *src, struct bonding *dst,
+ int gpf_flag)
+{
+	struct dev_mc_list *dmi, *new_dmi;
+
+   	for (dmi = src; dmi != NULL; dmi = dmi->next) { 
+		new_dmi = kmalloc(sizeof(struct dev_mc_list), gpf_flag);
+
+		if (new_dmi == NULL) {
+			return -ENOMEM; 
+		}
+
+		new_dmi->next = dst->mc_list; 
+		dst->mc_list = new_dmi;
+
+		new_dmi->dmi_addrlen = dmi->dmi_addrlen; 
+		memcpy(new_dmi->dmi_addr, dmi->dmi_addr, dmi->dmi_addrlen); 
+		new_dmi->dmi_users = dmi->dmi_users;
+		new_dmi->dmi_gusers = dmi->dmi_gusers; 
+	} 
+	return 0;
+}
+
+/*
+ * Returns 0 if dmi1 and dmi2 are the same, non-0 otherwise
+ */
+static inline int dmi_same(struct dev_mc_list *dmi1, struct dev_mc_list *dmi2)
+{ 
+	return memcmp(dmi1->dmi_addr, dmi2->dmi_addr, dmi1->dmi_addrlen) == 0 &&
+	 dmi1->dmi_addrlen == dmi2->dmi_addrlen;
+} 
+
+/*
+ * Push the promiscuity flag down to all slaves
+ */
+static void bond_set_promiscuity(bonding_t *bond, int inc)
+{ 
+	slave_t *slave; 
+ 
+	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+		dev_set_promiscuity(slave->dev, inc);
+} 
+
+/*
+ * Push the allmulti flag down to all slaves
+ */
+static void bond_set_allmulti(bonding_t *bond, int inc)
+{ 
+	slave_t *slave; 
+ 
+	for (slave = bond->prev; slave != (slave_t*)bond; slave = slave->prev)
+		dev_set_allmulti(slave->dev, inc);
+} 
+
+/* 
+ * returns dmi entry if found, NULL otherwise 
+ */
+static struct dev_mc_list* bond_mc_list_find_dmi(struct dev_mc_list *dmi,
+ struct dev_mc_list *mc_list)
+{ 
+	struct dev_mc_list *idmi;
+
+	for (idmi = mc_list; idmi != NULL; idmi = idmi->next) {
+		if (dmi_same(dmi, idmi)) {
+			return idmi; 
+		}
+	}
+	return NULL;
+} 
+
+static void set_multicast_list(struct net_device *master)
+{
+	bonding_t *bond = master->priv;
+	struct dev_mc_list *dmi;
+	unsigned long flags = 0;
+
+	/*
+	 * Lock the private data for the master
+	 */
+	write_lock_irqsave(&bond->lock, flags);
+
+	/*
+	 * Lock the master device so that noone trys to transmit
+	 * while we're changing things
+	 */
+	spin_lock_bh(&master->xmit_lock);
+
+	/* set promiscuity flag to slaves */
+	if ( (master->flags & IFF_PROMISC) && !(bond->flags & IFF_PROMISC) )
+		bond_set_promiscuity(bond, 1); 
+
+	if ( !(master->flags & IFF_PROMISC) && (bond->flags & IFF_PROMISC) ) 
+		bond_set_promiscuity(bond, -1); 
+
+	/* set allmulti flag to slaves */ 
+	if ( (master->flags & IFF_ALLMULTI) && !(bond->flags & IFF_ALLMULTI) ) 
+		bond_set_allmulti(bond, 1); 
+
+	if ( !(master->flags & IFF_ALLMULTI) && (bond->flags & IFF_ALLMULTI) )
+		bond_set_allmulti(bond, -1); 
+
+	bond->flags = master->flags; 
+
+	/* looking for addresses to add to slaves' mc list */ 
+	for (dmi = master->mc_list; dmi != NULL; dmi = dmi->next) { 
+		if (bond_mc_list_find_dmi(dmi, bond->mc_list) == NULL) 
+		 bond_mc_add(bond, dmi->dmi_addr, dmi->dmi_addrlen); 
+	} 
+
+	/* looking for addresses to delete from slaves' list */ 
+	for (dmi = bond->mc_list; dmi != NULL; dmi = dmi->next) { 
+		if (bond_mc_list_find_dmi(dmi, master->mc_list) == NULL) 
+		 bond_mc_delete(bond, dmi->dmi_addr, dmi->dmi_addrlen); 
+	}
+
+
+	/* save master's multicast list */ 
+	bond_mc_list_destroy (bond);
+	bond_mc_list_copy (master->mc_list, bond, GFP_KERNEL);
+
+	spin_unlock_bh(&master->xmit_lock);
+	write_unlock_irqrestore(&bond->lock, flags);
 }
 
 /*
@@ -476,6 +664,7 @@
 	unsigned long flags = 0;
 	int ndx = 0;
 	int err = 0;
+	struct dev_mc_list *dmi;
 
 	if (master_dev == NULL || slave_dev == NULL) {
 		return -ENODEV;
@@ -513,6 +702,8 @@
 	}
 	memset(new_slave, 0, sizeof(slave_t));
 
+	/* save flags before call to netdev_set_master */
+	new_slave->original_flags = slave_dev->flags;
 	err = netdev_set_master(slave_dev, master_dev);
 
 	if (err) {
@@ -526,10 +717,38 @@
 
 	new_slave->dev = slave_dev;
 
+	/* set promiscuity level to new slave */ 
+	if (master_dev->flags & IFF_PROMISC)
+		dev_set_promiscuity(slave_dev, 1); 
+ 
+	/* set allmulti level to new slave */
+	if (master_dev->flags & IFF_ALLMULTI) 
+		dev_set_allmulti(slave_dev, 1); 
+ 
+	/* upload master's mc_list to new slave */ 
+	for (dmi = master_dev->mc_list; dmi != NULL; dmi = dmi->next) 
+		dev_mc_add (slave_dev, dmi->dmi_addr, dmi->dmi_addrlen, 0);
+
 	/* 
 	 * queue to the end of the slaves list, make the first element its
 	 * successor, the last one its predecessor, and make it the bond's
 	 * predecessor. 
+	 *
+	 * Just to clarify, so future bonding driver hackers don't go through
+	 * the same confusion stage I did trying to figure this out, the
+	 * slaves are stored in a double linked circular list, sortof.
+	 * In the ->next direction, the last slave points to the first slave,
+	 * bypassing bond; only the slaves are in the ->next direction.
+	 * In the ->prev direction, however, the first slave points to bond
+	 * and bond points to the last slave.
+	 *
+	 * It looks like a circle with a little bubble hanging off one side
+	 * in the ->prev direction only.
+	 *
+	 * When going through the list once, its best to start at bond->prev
+	 * and go in the ->prev direction, testing for bond.  Doing this
+	 * in the ->next direction doesn't work.  Trust me, I know this now.
+	 * :)  -mts 2002.03.14
 	 */
 	new_slave->prev       = bond->prev;
 	new_slave->prev->next = new_slave;
@@ -838,10 +1057,20 @@
 			} else {
 				printk(".\n");
 			}
-			kfree(our_slave);
 
 			/* release the slave from its bond */
-			 
+
+			/* flush master's mc_list from slave */ 
+			bond_mc_list_flush (slave, master); 
+       
+			/* unset promiscuity level from slave */
+			if (master->flags & IFF_PROMISC) 
+				dev_set_promiscuity(slave, -1); 
+       
+			/* unset allmulti level from slave */ 
+			if (master->flags & IFF_ALLMULTI)
+				dev_set_allmulti(slave, -1); 
+
 			netdev_set_master(slave, NULL);
 
 			/* only restore its RUNNING flag if monitoring set it down */
@@ -854,6 +1083,9 @@
 					dev_close(slave);
 			}
 
+			bond_restore_slave_flags(our_slave);
+			kfree(our_slave);
+
 			if (bond->current_slave == NULL) {
 				printk(KERN_INFO
 					"%s: now running without any active interface !\n",
@@ -1121,8 +1353,8 @@
 					master->name, bestslave->dev->name,
 					(updelay - bestslave->delay) * miimon);
 
-				bestslave->delay= 0;
-				bestslave->link = BOND_LINK_UP;
+				bestslave->delay = 0;
+				bestslave->link  = BOND_LINK_UP;
 			}
 
 			if (mode == BOND_MODE_ACTIVEBACKUP) {
@@ -1192,7 +1424,7 @@
 
 		read_lock(&bond->ptrlock);
 	  	if ( (!(slave->link == BOND_LINK_UP))  
-				&& (slave!= bond->current_slave) ) {
+				&& (slave != bond->current_slave) ) {
 
 			read_unlock(&bond->ptrlock);
 
@@ -1207,7 +1439,7 @@
 					slave->state = BOND_STATE_ACTIVE;
 					bond->current_slave = slave;
 				}
-				if (slave!=bond->current_slave) {
+				if (slave != bond->current_slave) {
 					slave->dev->flags |= IFF_NOARP;
 				}
 				write_unlock(&bond->ptrlock);
@@ -1311,7 +1543,7 @@
 #define isdigit(c) (c >= '0' && c <= '9')
 __inline static int atoi( char **s) 
 {
-int i=0;
+int i = 0;
 while (isdigit(**s))
   i = i*20 + *((*s)++) - '0';
 return i;
@@ -1388,7 +1620,7 @@
 		goto ret_0;
 	}
 
-	if (the_addr!= NULL) {
+	if (the_addr != NULL) {
 		*the_addr = res.word | htonl (val);
 	}
 
@@ -1420,7 +1652,7 @@
 	info->miimon = miimon;
 
 	read_lock_irqsave(&bond->lock, flags);
-	for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) {
+	for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) {
 		info->num_slaves++;
 	}
 	read_unlock_irqrestore(&bond->lock, flags);
@@ -1696,7 +1928,7 @@
 
 	/* if we are sending arp packets, try to at least 
 	   identify our own ip address */
-	if ( (arp_interval > 0) && (my_ip==0) &&
+	if ( (arp_interval > 0) && (my_ip == 0) &&
 		(skb->protocol == __constant_htons(ETH_P_ARP) ) ) {
 		char *the_ip = (((char *)skb->data)) 
 				+ sizeof(struct ethhdr)  
@@ -1708,7 +1940,7 @@
 	/* if we are sending arp packets and don't know 
 	   the target hw address, save it so we don't need 
 	   to use a broadcast address */
-	if ( (arp_interval > 0) && (arp_target_hw_addr==NULL) &&
+	if ( (arp_interval > 0) && (arp_target_hw_addr == NULL) &&
 	     (skb->protocol == __constant_htons(ETH_P_IP) ) ) {
 		struct ethhdr *eth_hdr = 
 			(struct ethhdr *) (((char *)skb->data));
@@ -1751,7 +1983,7 @@
 
 	read_lock_irqsave(&bond->lock, flags);
 
-	for (slave = bond->prev; slave!=(slave_t *)bond; slave = slave->prev) {
+	for (slave = bond->prev; slave != (slave_t *)bond; slave = slave->prev) {
 		sstats = slave->dev->get_stats(slave->dev);
  
 		stats->rx_packets += sstats->rx_packets;
@@ -1861,7 +2093,7 @@
 static int bond_event(struct notifier_block *this, unsigned long event, 
 			void *ptr)
 {
-	struct bonding *this_bond=(struct bonding *)these_bonds;
+	struct bonding *this_bond = (struct bonding *)these_bonds;
 	struct bonding *last_bond;
 	struct net_device *event_dev = (struct net_device *)ptr;
 
@@ -1905,10 +2137,8 @@
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block bond_netdev_notifier={
-	bond_event,
-	NULL,
-	0
+static struct notifier_block bond_netdev_notifier = {
+	notifier_call: bond_event,
 };
 
 static int __init bond_init(struct net_device *dev)
@@ -2038,6 +2268,13 @@
 	/* Find a name for this unit */
 	static struct net_device *dev_bond = NULL;
 
+	if (max_bonds < 1 || max_bonds > INT_MAX) {
+		printk(KERN_WARNING 
+		       "bonding_init(): max_bonds (%d) not in range %d-%d, "
+		       "so it was reset to BOND_DEFAULT_MAX_BONDS (%d)",
+		       max_bonds, 1, INT_MAX, BOND_DEFAULT_MAX_BONDS);
+		max_bonds = BOND_DEFAULT_MAX_BONDS;
+	}
 	dev_bond = dev_bonds = kmalloc(max_bonds*sizeof(struct net_device), 
 					GFP_KERNEL);
 	if (dev_bond == NULL) {
diff -Nru a/drivers/net/hamradio/soundmodem/Makefile b/drivers/net/hamradio/soundmodem/Makefile
--- a/drivers/net/hamradio/soundmodem/Makefile	Sat Jun  8 22:31:35 2002
+++ b/drivers/net/hamradio/soundmodem/Makefile	Sat Jun  8 22:31:35 2002
@@ -16,19 +16,21 @@
 soundmodem-$(CONFIG_SOUNDMODEM_FSK9600)		+= sm_fsk9600.o
 soundmodem-objs					:= $(soundmodem-y)
 
+host-progs := gentbl
+HOST_LOADLIBES := -lm
+
 include $(TOPDIR)/Rules.make
 
 # Dependencies on generates files need to be listed explicitly
 
-sm_%.o: sm_tbl_%.h
-
-TBLHDR		:= sm_tbl_afsk1200.h sm_tbl_afsk2400_7.h sm_tbl_afsk2400_8.h \
-		   sm_tbl_afsk2666.h sm_tbl_psk4800.h	 sm_tbl_hapn4800.h \
-		   sm_tbl_fsk9600.h
-
-$(TBLHDR):	gentbl
-		./gentbl
+sm_afsk1200.o:   sm_tbl_afsk1200.h
+sm_afsk2400_7.o: sm_tbl_afsk2400_7.h
+sm_afsk2400_8.o: sm_tbl_afsk2400_8.h
+sm_afsk2666.o:   sm_tbl_afsk2666.h
+sm_psk4800.o:    sm_tbl_psk4800.h
+sm_hapn4800.o:   sm_tbl_hapn4800.h
+sm_fsk9600.o:    sm_tbl_fsk9600.h
 
-gentbl:		gentbl.c
-		$(HOSTCC) $(HOSTCFLAGS) $< -o $@ -lm
+sm_tbl_%: gentbl
+	./gentbl
 
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Sat Jun  8 22:31:49 2002
+++ b/drivers/net/irda/irda-usb.c	Sat Jun  8 22:31:49 2002
@@ -857,7 +857,7 @@
         new->mac.raw  = new->data;
         new->protocol = htons(ETH_P_IRDA);
         netif_rx(new);
-		self->netdev->last_rx = jiffies;
+        self->netdev->last_rx = jiffies;
 
 done:
 	/* Note : at this point, the URB we've just received (urb)
diff -Nru a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
--- a/drivers/net/wan/pc300_drv.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/net/wan/pc300_drv.c	Sat Jun  8 22:31:52 2002
@@ -2564,7 +2564,7 @@
 				return -EINVAL;
 			return 0;
 		case SIOCSPC300CONF:
-			if (!suser())
+			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			if (!arg || 
 				copy_from_user(&conf_aux.conf, arg, sizeof(pc300chconf_t)))
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/net/wireless/airo.c	Sat Jun  8 22:31:36 2002
@@ -191,12 +191,6 @@
 #ifndef RUN_AT
 #define RUN_AT(x) (jiffies+(x))
 #endif
-#ifndef PDE
-static inline struct proc_dir_entry *PDE(const struct inode *inode)
-{
-	return inode->u.generic_ip;
-}
-#endif
 
 
 /* These variables are for insmod, since it seems that the rates
@@ -723,7 +717,7 @@
 
 /* Leave gap of 40 commands after AIROGSTATSD32 for future */
 
-#define AIROPCAP               	AIROGSTATSD32 + 40
+#define AIROPCAP		AIROGSTATSD32 + 40
 #define AIROPVLIST              AIROPCAP      + 1
 #define AIROPSLIST		AIROPVLIST    + 1
 #define AIROPCFG		AIROPSLIST    + 1
@@ -845,7 +839,7 @@
 	struct proc_dir_entry *proc_entry;
 	struct airo_info *next;
         spinlock_t aux_lock;
-        int flags;
+        unsigned long flags;
 #define FLAG_PROMISC   IFF_PROMISC
 #define FLAG_RADIO_OFF 0x02
 #define FLAG_LOCKED    2
@@ -866,7 +860,7 @@
 #ifdef WIRELESS_EXT
 	struct iw_statistics	wstats;		// wireless stats
 	unsigned long		scan_timestamp;	/* Time started to scan */
-	struct tq_struct 	event_task;
+	struct tq_struct	event_task;
 #ifdef WIRELESS_SPY
 	int			spy_number;
 	u_char			spy_address[IW_MAX_SPY][6];
diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile	Sat Jun  8 22:31:52 2002
+++ b/drivers/pci/Makefile	Sat Jun  8 22:31:52 2002
@@ -30,12 +30,11 @@
 obj-y += syscall.o
 endif
 
+host-progs := gen-devlist
+
 include $(TOPDIR)/Rules.make
 
-names.o: names.c devlist.h classlist.h
+names.o: devlist.h classlist.h
 
 devlist.h classlist.h: pci.ids gen-devlist
 	./gen-devlist <pci.ids
-
-gen-devlist: gen-devlist.c
-	$(HOSTCC) $(HOSTCFLAGS) -o gen-devlist gen-devlist.c
diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
--- a/drivers/pci/pci-driver.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/pci/pci-driver.c	Sat Jun  8 22:31:51 2002
@@ -38,23 +38,35 @@
 static int pci_device_probe(struct device * dev)
 {
 	int error = 0;
+	struct pci_driver *drv;
+	struct pci_dev *pci_dev;
 
-	struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
-	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+	drv = list_entry(dev->driver, struct pci_driver, driver);
+	pci_dev = list_entry(dev, struct pci_dev, dev);
+
+	if (drv->probe) {
+		const struct pci_device_id *id;
 
-	if (drv->probe)
-		error = drv->probe(pci_dev,drv->id_table);
-	return error > 0 ? 0 : -ENODEV;
+		id = pci_match_device(drv->id_table, pci_dev);
+		if (id)
+			error = drv->probe(pci_dev, id);
+		if (error >= 0) {
+			pci_dev->driver = drv;
+			error = 0;
+		}
+	}
+	return error;
 }
 
 static int pci_device_remove(struct device * dev)
 {
 	struct pci_dev * pci_dev = list_entry(dev,struct pci_dev,dev);
+	struct pci_driver * drv = pci_dev->driver;
 
-	if (dev->driver) {
-		struct pci_driver * drv = list_entry(dev->driver,struct pci_driver,driver);
+	if (drv) {
 		if (drv->remove)
 			drv->remove(pci_dev);
+		pci_dev->driver = NULL;
 	}
 	return 0;
 }
@@ -124,7 +136,7 @@
 void
 pci_unregister_driver(struct pci_driver *drv)
 {
-	put_driver(&drv->driver);
+	remove_driver(&drv->driver);
 }
 
 static struct pci_driver pci_compat_driver = {
@@ -153,7 +165,7 @@
 }
 
 /**
- * pci_bus_bind - Tell if a PCI device structure has a matching PCI device id structure
+ * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure
  * @ids: array of PCI device id structures to search in
  * @dev: the PCI device structure to match against
  * 
@@ -161,7 +173,7 @@
  * system is in its list of supported devices.Returns the matching
  * pci_device_id structure or %NULL if there is no match.
  */
-static int pci_bus_bind(struct device * dev, struct device_driver * drv) 
+static int pci_bus_match(struct device * dev, struct device_driver * drv) 
 {
 	struct pci_dev * pci_dev = list_entry(dev, struct pci_dev, dev);
 	struct pci_driver * pci_drv = list_entry(drv,struct pci_driver,driver);
@@ -184,7 +196,7 @@
 
 struct bus_type pci_bus_type = {
 	name:	"pci",
-	bind:	pci_bus_bind,
+	match:	pci_bus_match,
 };
 
 static int __init pci_driver_init(void)
@@ -192,7 +204,7 @@
 	return bus_register(&pci_bus_type);
 }
 
-subsys_initcall(pci_driver_init);
+postcore_initcall(pci_driver_init);
 
 EXPORT_SYMBOL(pci_match_device);
 EXPORT_SYMBOL(pci_register_driver);
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/pci/quirks.c	Sat Jun  8 22:31:35 2002
@@ -486,7 +486,7 @@
 	{ 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_8361,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C576,	quirk_vsfx },
 	{ 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 },
diff -Nru a/drivers/s390/Config.help b/drivers/s390/Config.help
--- a/drivers/s390/Config.help	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/Config.help	Sat Jun  8 22:31:36 2002
@@ -321,6 +321,18 @@
 CONFIG_DASD_FBA
   FBA devices are currently unsupported.
 
+CONFIG_DASD_AUTO_DIAG
+  Enable this option if you want your DIAG discipline module loaded
+  on DASD driver startup.
+
+CONFIG_DASD_AUTO_ECKD
+  Enable this option if you want your ECKD discipline module loaded
+  on DASD driver startup.
+
+CONFIG_DASD_AUTO_FBA
+  Enable this option if you want your FBA discipline module loaded
+  on DASD driver startup.
+
 CONFIG_TN3215
   Include support for IBM 3215 line-mode terminals.
 
@@ -342,6 +354,15 @@
 CONFIG_HWC_CONSOLE
   Include support for using an IBM HWC line-mode terminal as the Linux
   system console.
+
+CONFIG_HWC_CPI
+  This option enables the hardware console interface for system
+  identification This is commonly used for workload management and
+  gives you a nice name for the system on the service element.
+  Please select this option as a module since built-in operation is
+  completely untested.
+  You should only select this option if you know what you are doing,
+  need this feature and intend to run your kernel in LPAR.
 
 CONFIG_S390_TAPE
   Select this option if you want to access channel-attached tape
diff -Nru a/drivers/s390/Config.in b/drivers/s390/Config.in
--- a/drivers/s390/Config.in	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/Config.in	Sat Jun  8 22:31:37 2002
@@ -63,8 +63,8 @@
   bool '   Support for tape character devices' CONFIG_S390_TAPE_CHAR
   bool '   Support for tape block devices' CONFIG_S390_TAPE_BLOCK
   comment 'S/390 tape hardware support'
-  bool '   Support for 3490 tape hardware' CONFIG_S390_TAPE_3490
-  bool '   Support for 3480 tape hardware' CONFIG_S390_TAPE_3480
+  dep_tristate '   Support for 3490 tape hardware' CONFIG_S390_TAPE_3490 $CONFIG_S390_TAPE
+  dep_tristate '   Support for 3480 tape hardware' CONFIG_S390_TAPE_3480 $CONFIG_S390_TAPE
 fi
 endmenu
 
@@ -85,6 +85,10 @@
     bool 'Channel Device Configuration' CONFIG_CHANDEV
     if [ "$CONFIG_CHANDEV" = "y" ]; then
 	define_bool CONFIG_HOTPLUG y
+    fi
+
+    if [ "$CONFIG_NET_ETHERNET" != "n" -o "$CONFIG_TR" != "n" ]; then
+      tristate 'Lan Channel Station Interface' CONFIG_LCS
     fi
 
     tristate 'CTC device support' CONFIG_CTC
diff -Nru a/drivers/s390/Makefile b/drivers/s390/Makefile
--- a/drivers/s390/Makefile	Sat Jun  8 22:31:43 2002
+++ b/drivers/s390/Makefile	Sat Jun  8 22:31:43 2002
@@ -2,11 +2,14 @@
 # Makefile for the S/390 specific device drivers
 #
 
-mod-subdirs := block char misc net
+mod-subdirs := block char misc net scsi cio
 
-export-objs += ccwcache.o idals.o s390dyn.o s390io.o
+export-objs += s390dyn.o
 
-obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
-obj-y += block/ char/ misc/ net/
+obj-$(CONFIG_QDIO) += qdio.o
+export-objs += qdio.o
+
+obj-y += s390mach.o s390dyn.o sysinfo.o
+obj-y += block/ char/ misc/ net/ scsi/ cio/
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
--- a/drivers/s390/block/Makefile	Sat Jun  8 22:31:52 2002
+++ b/drivers/s390/block/Makefile	Sat Jun  8 22:31:52 2002
@@ -2,12 +2,13 @@
 # S/390 block devices
 #
 
-export-objs := dasd.o
+export-objs := dasd.o dasd_devmap.o dasd_ioctl.o dasd_erp.o
 
 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
+dasd_mod-objs      := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
+			dasd_genhd.o dasd_erp.o
 
 obj-$(CONFIG_DASD) += dasd_mod.o
 obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
diff -Nru a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
--- a/drivers/s390/block/dasd.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd.c	Sat Jun  8 22:31:37 2002
@@ -1,1016 +1,943 @@
 /*
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
- *                  Carsten Otte <Cotte@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (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 added dynamic registration of ioctls
- *          fixed bug in registration of new majors
- *          fixed handling of request during dasd_end_request
- *          fixed handling of plugged queues
- *          fixed partition handling and HDIO_GETGEO
- *          fixed traditional naming scheme for devices beyond 702
- *          fixed some race conditions related to modules
- *          added devfs suupport
+ *	    fixed bug in registration of new majors
+ *	    fixed handling of request during dasd_end_request
+ *	    fixed handling of plugged queues
+ *	    fixed partition handling and HDIO_GETGEO
+ *	    fixed traditional naming scheme for devices beyond 702
+ *	    fixed some race conditions related to modules
+ *	    added devfs suupport
  * 03/06/01 refined dynamic attach/detach for leaving devices which are online.
  * 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
+ *	    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)
+ *	    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
+ *	    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
+ * 01/22/01 fixed PL030579KBE (wrong statistics)
+ * 05/04/02 code restructuring.
  */
 
+#define LOCAL_END_REQUEST /* Don't generate end_request in blk.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/slab.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/ctype.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif				/* CONFIG_PROC_FS */
-#include <linux/spinlock.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/blkpg.h>
-#include <linux/wait.h>
-
-#include <asm/ccwcache.h>
-#include <asm/debug.h>
-
-#include <asm/atomic.h>
-#include <asm/delay.h>
-#include <asm/io.h>
-#include <asm/semaphore.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/slab.h>
+#include <linux/buffer_head.h>
+
+#include <asm/div64.h>
 #include <asm/ebcdic.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/s390_ext.h>
-#include <asm/s390dyn.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
+#include <asm/todclk.h>
 
-#include "dasd_int.h"
+/* This is ugly... */
+#define PRINTK_HEADER "dasd:"
 
-#ifdef CONFIG_DASD_ECKD
+#include "dasd_int.h"
 #include "dasd_eckd.h"
-#endif				/*  CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
 #include "dasd_fba.h"
-#endif				/*  CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_DIAG
 #include "dasd_diag.h"
-#endif				/*  CONFIG_DASD_DIAG */
 
-/* SECTION: exported variables of dasd.c */
+/*
+ * SECTION: Constant definitions to be used within this file
+ */
+#define DASD_CHANQ_MAX_SIZE 5
 
+/*
+ * 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");
-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_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":"
-#undef  DASD_PROFILE            /* fill profile information - used for */
-                                /* statistics and perfomance           */
-
-#define DASD_MIN_SIZE_FOR_QUEUE 32
-#undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
-#define DASD_CHANQ_MAX_SIZE 6
-
-/* SECTION: prototypes for static functions of dasd.c */
-
-static request_fn_proc do_dasd_request;
-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);
-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 void dasd_destroy_partitions ( dasd_device_t *);
-static inline int dasd_setup_blkdev(dasd_device_t*);
-static void dasd_deactivate_queue (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;
-static wait_queue_head_t dasd_init_waitq;
-static atomic_t dasd_init_pending = ATOMIC_INIT (0);
+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");
+MODULE_PARM(dasd_disciplines, "1-" __MODULE_STRING(8) "s");
 
-#ifdef CONFIG_DASD_DYNAMIC
+/*
+ * SECTION: prototypes for static functions of dasd.c
+ */
+static void dasd_enable_discipline(dasd_discipline_t *);
+static void dasd_disable_discipline(dasd_discipline_t *);
+static void dasd_not_oper_handler(int irq, int status);
+static int  dasd_setup_blkdev(dasd_device_t * device);
+static void dasd_disable_blkdev(dasd_device_t * device);
+static void dasd_flush_request_queue(dasd_device_t *);
+static void dasd_int_handler(int, void *, struct pt_regs *);
+static void dasd_flush_ccw_queue(dasd_device_t *, int);
+static void dasd_tasklet(dasd_device_t *);
 
-/* SECTION: managing dynamic configuration of dasd_driver */
+/*
+ * Parameter parsing functions. There are two for the dasd driver:
+ *   <dasd_disciplines> : <dasd_module>(,<dasd_module>)*
+ */
 
-static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);
+static char *dasd_disciplines[8];
 
+#ifndef MODULE
 /*
- * function: dasd_create_devreg
- * creates a dasd_devreg_t related to a devno
+ * The parameter parsing functions for builtin-drivers are called
+ * before kmalloc works. Store the pointers to the parameters strings
+ * into dasd_disciplines[] for later processing.
  */
-static inline dasd_devreg_t *
-dasd_create_devreg (int devno)
+static int __init
+dasd_disciplines_setup(char *str)
 {
-	dasd_devreg_t *r = kmalloc (sizeof (dasd_devreg_t), GFP_KERNEL);
-	if (r != NULL) {
-		memset (r, 0, sizeof (dasd_devreg_t));
-		r->devreg.ci.devno = devno;
-		r->devreg.flag = DEVREG_TYPE_DEVNO;
-		r->devreg.oper_func = dasd_oper_handler;
-	}
-	return r;
+	static int count = 0;
+
+	if (count < 8)
+		dasd_disciplines[count++] = str;
+	return 1;
 }
 
+__setup ("dasd_disciplines=", dasd_disciplines_setup);
+#endif	/* #ifndef MODULE */
+
 /*
- * function: dasd_destroy_devreg
- * destroys the dasd_devreg_t given as argument
+ * SECTION: managing dasd disciplines
  */
-static inline void
-dasd_destroy_devreg (dasd_devreg_t * devreg)
+static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
+static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Add a discipline to the head of the discipline chain. The last added
+ * discipline that matches a device is used. In particular disciplines
+ * added by a module will have precedence over statically linked 
+ * disciplines.
+ */
+void
+dasd_discipline_add(dasd_discipline_t * discipline)
 {
-	kfree (devreg);
+	MOD_INC_USE_COUNT;
+	spin_lock(&discipline_lock);
+	list_add(&discipline->list, &dasd_disc_head);
+	spin_unlock(&discipline_lock);
+	/* Setup devices for discipline. */
+	dasd_enable_discipline(discipline);
 }
 
-#endif				/* CONFIG_DASD_DYNAMIC */
+/*
+ * Remove a discipline from the discipline list and disable all devices
+ * that rely on that discipline.
+ */
+void
+dasd_discipline_del(dasd_discipline_t * discipline)
+{
+	struct list_head *l;
+
+	spin_lock(&discipline_lock);
+	/* Check if the discipline was added. */
+	list_for_each(l, &dasd_disc_head) {
+		if (list_entry(l, dasd_discipline_t, list) == discipline) {
+			list_del(&discipline->list);
+			break;
+		}
+	}
+	spin_unlock(&discipline_lock);
+	/* Disable devices for discipline. */
+	dasd_disable_discipline(discipline);
+	MOD_DEC_USE_COUNT;
+}
 
-/* SECTION: managing setup of dasd_driver */
+/*
+ * Find the discipline for a device.
+ */
+static inline int
+dasd_find_disc(dasd_device_t * device)
+{
+	struct list_head *l;
+	dasd_discipline_t *discipline, *tmp;
 
-/* default setting is probeonly, autodetect */
-static int dasd_probeonly = 1;	/* is true, when probeonly mode is active */
-static int dasd_autodetect = 1;	/* is true, when autodetection is active */
+	discipline = NULL;
+	spin_lock(&discipline_lock);
+	list_for_each(l, &dasd_disc_head) {
+		tmp = list_entry(l, dasd_discipline_t, list);
+		if (tmp->check_device(device) == 0) {
+			/* Found a matching discipline. */
+			discipline = tmp;
+			break;
+		}
+	}
+	device->discipline = discipline;
+	spin_unlock(&discipline_lock);
+	return (discipline != NULL) ? 0 : -ENODEV;
+}
 
-static dasd_range_t dasd_range_head =
-    { list:LIST_HEAD_INIT (dasd_range_head.list) };
-static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * SECTION: Operations on the device structure.
+ */
+static devfs_handle_t dasd_devfs_handle;
+static wait_queue_head_t dasd_init_waitq;
 
 /*
- * function: dasd_create_range
- * creates a dasd_range_t according to the arguments
- * FIXME: no check is performed for reoccurrence of a devno
+ * Allocate memory for a new device structure.
  */
-static inline dasd_range_t *
-dasd_create_range (int from, int to, int features)
+dasd_device_t *
+dasd_alloc_device(dasd_devmap_t *devmap)
 {
-	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);
+	dasd_device_t *device;
+	int rc;
 
-		return NULL;
+	/* Make sure the gendisk structure for this device exists. */
+	while (dasd_gendisk_from_devindex(devmap->devindex) == NULL) {
+		rc = dasd_gendisk_new_major();
+		if (rc)
+			return ERR_PTR(rc);
+	}
+
+	device = kmalloc(sizeof (dasd_device_t), GFP_ATOMIC);
+	if (device == NULL)
+		return ERR_PTR(-ENOMEM);
+	memset(device, 0, sizeof (dasd_device_t));
+
+	/* Get two pages for normal block device operations. */
+	device->ccw_mem = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1);
+	if (device->ccw_mem == NULL) {
+		kfree(device);
+		return ERR_PTR(-ENOMEM);
+	}
+	/* Get one page for error recovery. */
+	device->erp_mem = (void *) get_free_page(GFP_ATOMIC | GFP_DMA);
+	if (device->erp_mem == NULL) {
+		free_pages((unsigned long) device->ccw_mem, 1);
+		kfree(device);
+		return ERR_PTR(-ENOMEM);
 	}
-	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;
-        range->to = to;
-        range->features = features;
-	return range;
+
+	/* Get devinfo from the common io layer. */
+	rc = get_dev_info_by_devno(devmap->devno, &device->devinfo);
+	if (rc) {
+ 		free_page((unsigned long) device->erp_mem);
+		free_pages((unsigned long) device->ccw_mem, 1);
+		kfree(device);
+		return ERR_PTR(rc);
+	}
+	DBF_EVENT(DBF_NOTICE, "got devinfo CU-type %04x and dev-type %04x",
+		  device->devinfo.sid_data.cu_type,
+		  device->devinfo.sid_data.dev_type);
+
+	dasd_init_chunklist(&device->ccw_chunks, device->ccw_mem, PAGE_SIZE*2);
+	dasd_init_chunklist(&device->erp_chunks, device->erp_mem, PAGE_SIZE);
+	spin_lock_init(&device->request_queue_lock);
+	atomic_set (&device->tasklet_scheduled, 0);
+	tasklet_init(&device->tasklet, 
+		     (void (*)(unsigned long)) dasd_tasklet,
+		     (unsigned long) device);
+	INIT_LIST_HEAD(&device->ccw_queue);
+	init_timer(&device->timer);
+	device->state = DASD_STATE_NEW;
+	device->target = DASD_STATE_NEW;
+
+	return device;
 }
 
 /*
- * function dasd_destroy_range
- * destroy a range allocated wit dasd_crate_range
- * CAUTION: must not be callen in arunning sysztem, because it destroys
- * the mapping of DASDs
+ * Free memory of a device structure.
  */
-static inline void
-dasd_destroy_range (dasd_range_t * range)
+void
+dasd_free_device(dasd_device_t *device)
 {
-	kfree (range);
+	if (device->private)
+		kfree(device->private);
+	free_page((unsigned long) device->erp_mem);
+	free_pages((unsigned long) device->ccw_mem, 1);
+	kfree(device);
 }
 
 /*
- * function: dasd_append_range
- * appends the range given as argument to the list anchored at dasd_range_head.
+ * Make a new device known to the system.
  */
-static inline void
-dasd_append_range (dasd_range_t * range)
+static inline int
+dasd_state_new_to_known(dasd_device_t *device)
 {
-	long flags;
+	char buffer[5];
+	struct gendisk *gdp;
+	dasd_devmap_t *devmap;
+	umode_t devfs_perm;
+	devfs_handle_t dir;
+	int minor, rc;
+
+	devmap = dasd_devmap_from_devno(device->devinfo.devno);
+	if (devmap == NULL)
+		return -ENODEV;
+	gdp = dasd_gendisk_from_devindex(devmap->devindex);
+	if (gdp == NULL)
+		return -ENODEV;
+	minor = devmap->devindex % DASD_PER_MAJOR;
+
+	/* Set kdev and the device name. */
+	device->kdev = mk_kdev(gdp->major, minor << DASD_PARTN_BITS);
+	dasd_device_name(device->name, minor, 0, gdp);
+
+	/* Find a discipline for the device. */
+	rc = dasd_find_disc(device);
+	if (rc)
+		return rc;
 
-	spin_lock_irqsave (&range_lock, flags);
-	list_add_tail (&range->list, &dasd_range_head.list);
-	spin_unlock_irqrestore (&range_lock, flags);
+	/* Add a proc directory and the dasd device entry to devfs. */
+	sprintf(buffer, "%04x", device->devinfo.devno);
+	dir = devfs_mk_dir(dasd_devfs_handle, buffer, device);
+	gdp->de_arr[minor(device->kdev) >> DASD_PARTN_BITS] = dir;
+	if (devmap->features & DASD_FEATURE_READONLY)
+		devfs_perm = S_IFBLK | S_IRUSR;
+	else
+		devfs_perm = S_IFBLK | S_IRUSR | 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->state = DASD_STATE_KNOWN;
+	return 0;
 }
 
 /*
- * function dasd_dechain_range
- * removes a range from the chain of ranges
- * CAUTION: must not be called in a running system because it destroys
- * the mapping of devices
+ * Let the system forget about a device.
  */
 static inline void
-dasd_dechain_range (dasd_range_t * range)
+dasd_state_known_to_new(dasd_device_t * device)
 {
-	unsigned long flags;
+	struct gendisk *gdp;
+	dasd_devmap_t *devmap;
+	int minor;
+
+	devmap = dasd_devmap_from_devno(device->devinfo.devno);
+	gdp = dasd_gendisk_from_devindex(devmap->devindex);
+	if (gdp == NULL)
+		return;
+	minor = devmap->devindex % DASD_PER_MAJOR;
 
-	spin_lock_irqsave (&range_lock, flags);
-	list_del (&range->list);
-	spin_unlock_irqrestore (&range_lock, flags);
-}
+	/* Remove device entry and devfs directory. */
+	devfs_unregister(device->devfs_entry);
+	devfs_unregister(gdp->de_arr[minor]);
 
-/*
- * 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
- */
-static inline dasd_range_t *
-dasd_add_range (int from, int to, int features)
-{
-	dasd_range_t *range;
-
-	range = dasd_create_range (from, to, features);
-	if (!range)
-		return NULL;
-
-	dasd_append_range (range);
-#ifdef CONFIG_DASD_DYNAMIC
-	/* allocate and chain devreg infos for the devnos... */
-	{
-		int i;
-		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);
-		}
-	}
-#endif				/* CONFIG_DASD_DYNAMIC */
-	return range;
+	/* Forget the discipline information. */
+	device->discipline = NULL;
+	device->state = DASD_STATE_NEW;
 }
 
 /*
- * 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
- * the mapping of devices!
+ * Request the irq line for the device.
  */
-static inline void
-dasd_remove_range (dasd_range_t * range)
+static inline int
+dasd_state_known_to_basic(dasd_device_t * device)
 {
-#ifdef CONFIG_DASD_DYNAMIC
-	/* deallocate and dechain devreg infos for the devnos... */
-	{
-		int i;
-		for (i = range->from; i <= range->to; i++) {
-			struct list_head *l;
-			dasd_devreg_t *reg = NULL;
-			list_for_each (l, &dasd_devreg_head) {
-				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)
-					break;
-			}
-			if (l == &dasd_devreg_head)
-				BUG ();
-                        list_del(&reg->list);
-			s390_device_unregister (&reg->devreg);
-			dasd_destroy_devreg (reg);
-		}
+	int rc;
+
+	/* register 'device' debug area, used for all DBF_DEV_XXX calls */
+	device->debug_area = debug_register(device->name, 0, 2,
+					    8 * sizeof (long));
+	debug_register_view(device->debug_area, &debug_sprintf_view);
+	debug_set_level(device->debug_area, DBF_ERR);
+	DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
+
+	/*
+	 * We request the "official" irq line even for dasd diag device.
+	 * The interrupts for dasd diag will arrive at dasd_ext_handler
+	 * instead of dasd_int_handler so this is just a placeholder.
+	 */
+	rc = s390_request_irq_special(device->devinfo.irq,
+				      dasd_int_handler,
+				      dasd_not_oper_handler,
+				      0, "dasd", &device->dev_status);
+	if (rc) {
+		MESSAGE(KERN_ERR, "%s", "No request IRQ");
+		return rc;
 	}
-#endif				/* CONFIG_DASD_DYNAMIC */
-	dasd_dechain_range (range);
-	dasd_destroy_range (range);
+	device->state = DASD_STATE_BASIC;
+	return 0;
 }
 
-/* 
- * function: dasd_devindex_from_devno
- * finds the logical number of the devno supplied as argument in the list
- * of dasd ranges and returns it or ENODEV when not found
+/*
+ * Release the irq line for the device. Terminate any running i/o.
  */
-static int
-dasd_devindex_from_devno (int devno)
+static inline void
+dasd_state_basic_to_known(dasd_device_t * device)
 {
-	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 devindex + devno - temp->from;
-		}
-		devindex += temp->to - temp->from + 1;
-	}
-	spin_unlock_irqrestore (&range_lock, flags);
-	return -ENODEV;
+	dasd_flush_ccw_queue(device, 1);
+	free_irq(device->devinfo.irq, &device->dev_status);
+	DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
+	if (device->debug_area != NULL) {
+		debug_unregister(device->debug_area);
+		device->debug_area = NULL;
+	}
+	device->state = DASD_STATE_KNOWN;
 }
 
 /*
- * function: dasd_devno_from_devindex
+ * Do the initial analysis. The do_analysis function may return
+ * -EAGAIN in which case the device keeps the state DASD_STATE_BASIC
+ * until the discipline decides to continue the startup sequence
+ * by calling the function dasd_change_state. The eckd disciplines
+ * uses this to start a ccw that detects the format. The completion
+ * interrupt for this detection ccw uses the kernel event daemon to
+ * trigger the call to dasd_change_state. All this is done in the
+ * discipline code, see dasd_eckd.c.
  */
-static int
-dasd_devno_from_devindex (int devindex)
+static inline int
+dasd_state_basic_to_accept(dasd_device_t * device)
 {
-	dasd_range_t *temp;
-	unsigned long flags;
-	struct list_head *l;
+	int rc;
 
-	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;
+	rc = 0;
+	if (device->discipline->do_analysis != NULL)
+		rc = device->discipline->do_analysis(device);
+	if (rc == 0)
+		device->state = DASD_STATE_ACCEPT;
+	return rc;
 }
 
-/* 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.
+ * Forget everything the initial analysis found out.
  */
-char *dasd[256];
-char *dasd_disciplines[8];
+static inline void
+dasd_state_accept_to_basic(dasd_device_t * device)
+{
+	device->blocks = 0;
+	device->bp_block = 0;
+	device->s2b_shift = 0;
+	device->state = DASD_STATE_BASIC;
+}
 
-#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
+ * Setup block device.
  */
-static void
-dasd_split_parm_string (char *str)
+static inline int
+dasd_state_accept_to_ready(dasd_device_t * device)
 {
-	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++;
-		}
-		dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
-		if (dasd[count] == NULL) {
-			printk (KERN_WARNING PRINTK_HEADER
-				"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;
-	};
+	dasd_devmap_t *devmap;
+	int major, minor;
+	int rc, i;
+
+	devmap = dasd_devmap_from_devno(device->devinfo.devno);
+	if (devmap->features & DASD_FEATURE_READONLY) {
+		major = major(device->kdev);
+		minor = minor(device->kdev);
+		for (i = 0; i < (1 << DASD_PARTN_BITS); i++)
+			set_device_ro(mk_kdev(major, minor+i), 1);
+		DEV_MESSAGE (KERN_WARNING, device, "%s",
+			     "setting read-only mode ");
+	}
+	rc = dasd_setup_blkdev(device);
+	if (rc == 0) {
+		dasd_setup_partitions(device);
+		device->state = DASD_STATE_READY;
+	}
+	return rc;
 }
 
 /*
- * dasd_parm_string holds a concatenated version of all 'dasd=' parameters
- * supplied in the parmline, which is later to be split by
- * dasd_split_parm_string
- * FIXME: why first concatenate then split ?
+ * Remove device from block device layer. Destroy dirty buffers.
  */
-static char dasd_parm_string[1024] __initdata = { 0, };
+static inline void
+dasd_state_ready_to_accept(dasd_device_t * device)
+{
+	dasd_flush_ccw_queue(device, 0);
+	dasd_destroy_partitions(device);
+	dasd_flush_request_queue(device);
+	dasd_disable_blkdev(device);
+	device->state = DASD_STATE_ACCEPT;
+}
 
 /*
- * function: dasd_setup
- * is invoked for any single 'dasd=' parameter supplied in the parmline
- * it merges all the arguments into dasd_parm_string
+ * Make the device online and schedule the bottom half to start
+ * the requeueing of requests from the linux request queue to the
+ * ccw queue.
  */
-void __init
-dasd_setup (char *str, int *ints)
+static inline int
+dasd_state_ready_to_online(dasd_device_t * device)
 {
-	int len = strlen (dasd_parm_string);
-	if (len != 0) {
-		strcat (dasd_parm_string, ",");
-	}
-	strcat (dasd_parm_string, str);
+	device->state = DASD_STATE_ONLINE;
+	dasd_schedule_bh(device);
+	return 0;
 }
 
 /*
- * function: dasd_call_setup
- * is the 2.4 version of dasd_setup and
- * is invoked for any single 'dasd=' parameter supplied in the parmline
+ * Stop the requeueing of requests again.
  */
-int __init
-dasd_call_setup (char *str)
+static inline void
+dasd_state_online_to_ready(dasd_device_t * device)
 {
-	int dummy;
-	dasd_setup (str, &dummy);
-	return 1;
+	device->state = DASD_STATE_READY;
 }
 
-int __init
-dasd_disciplines_setup (char *str)
+/*
+ * Device startup state changes.
+ */
+static inline int
+dasd_increase_state(dasd_device_t *device)
 {
-	return 1;
-}
+	int rc;
 
-__setup ("dasd=", dasd_call_setup);
-__setup ("dasd_disciplines=", dasd_disciplines_setup);
+	rc = 0;
+	if (device->state == DASD_STATE_NEW &&
+	    device->target >= DASD_STATE_KNOWN)
+		rc = dasd_state_new_to_known(device);
+
+	if (device->state == DASD_STATE_KNOWN &&
+	    device->target >= DASD_STATE_BASIC)
+		rc = dasd_state_known_to_basic(device);
+
+	if (device->state == DASD_STATE_BASIC &&
+	    device->target >= DASD_STATE_ACCEPT)
+		rc = dasd_state_basic_to_accept(device);
+
+	if (device->state == DASD_STATE_ACCEPT &&
+	    device->target >= DASD_STATE_READY)
+		rc = dasd_state_accept_to_ready(device);
+
+	if (device->state == DASD_STATE_READY &&
+	    device->target >= DASD_STATE_ONLINE)
+		rc = dasd_state_ready_to_online(device);
 
-#endif				/* MODULE */
+	return rc;
+}
 
 /*
- * function: dasd_strtoul
- * provides a wrapper to simple_strtoul to strip leading '0x' and
- * interpret any argument to dasd=[range,...] as hexadecimal
+ * Device shutdown state changes.
  */
 static inline int
-dasd_strtoul (char *str, char **stra, int* features)
+dasd_decrease_state(dasd_device_t *device)
 {
-        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; temp[i]!='\0' && temp[i]!='(' && 
-                  temp[i]!='-'  && temp[i]!=' '; i++){
-                if (isxdigit(temp[i])) {
-                        buffer[i]=temp[i];
-                } else {
-                        return -EINVAL;
-                }
-        }
-
-        buffer[i]='\0';
-
-        val = simple_strtoul (buffer, &buffer, 16);
+	if (device->state == DASD_STATE_ONLINE &&
+	    device->target <= DASD_STATE_READY)
+		dasd_state_online_to_ready(device);
+	
+	if (device->state == DASD_STATE_READY &&
+	    device->target <= DASD_STATE_ACCEPT)
+		dasd_state_ready_to_accept(device);
+	
+	if (device->state == DASD_STATE_ACCEPT && 
+	    device->target <= DASD_STATE_BASIC)
+		dasd_state_accept_to_basic(device);
+	
+	if (device->state == DASD_STATE_BASIC && 
+	    device->target <= DASD_STATE_KNOWN)
+		dasd_state_basic_to_known(device);
+	
+	if (device->state == DASD_STATE_KNOWN &&
+	    device->target <= DASD_STATE_NEW)
+		dasd_state_known_to_new(device);
 
-        /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */
-        *features = DASD_DEFAULT_FEATURES;
+	return 0;
+}
 
-        if (temp[i]=='(') {
+/*
+ * This is the main startup/shutdown routine.
+ */
+static void
+dasd_change_state(dasd_device_t *device)
+{
+        int rc;
 
-                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);
-                        }
-                }
+	if (device->state == device->target)
+		/* Already where we want to go today... */
+		return;
+	if (device->state < device->target)
+		rc = dasd_increase_state(device);
+	else
+		rc = dasd_decrease_state(device);
+        if (rc && rc != -EAGAIN) {
+		if (rc != -ENODEV)
+			MESSAGE (KERN_INFO, "giving up on dasd device with "
+				 "devno %04x", device->devinfo.devno);
+                device->target = device->state;
         }
 
-        *stra = temp+i;
-        return val;
+	if (device->state == device->target)
+		wake_up(&dasd_init_waitq);
 }
 
 /*
- * function: dasd_parse
- * examines the strings given in the string array str and
- * creates and adds the ranges to the apropriate lists
+ * Kick starter for devices that did not complete the startup/shutdown
+ * procedure or were sleeping because of a pending state.
+ * dasd_kick_device will schedule a call do do_kick_device to the kernel
+ * event daemon.
  */
-static int
-dasd_parse (char **str)
+static void
+do_kick_device(int devno)
 {
-	char *temp;
-	int from, to;
-        int features;
-        int rc = 0;
-
-	if (*str) {
-		/* turn off probeonly mode, if any dasd parameter is present */
-		dasd_probeonly = 0;
-		dasd_autodetect = 0;
-	}
-	while (*str) {
-		temp = *str;
-		from = 0;
-		to = 0;
-		if (strcmp ("autodetect", *str) == 0) {
-			dasd_autodetect = 1;
-			printk (KERN_INFO "turning to autodetection mode\n");
-			break;
-		} else if (strcmp ("probeonly", *str) == 0) {
-			dasd_probeonly = 1;
-			printk (KERN_INFO "turning to probeonly mode\n");
-			break;
-		} else {
-			/* turn off autodetect mode, if any range is present */
-			dasd_autodetect = 0;
-			from = dasd_strtoul (temp, &temp, &features);
-                        to = from;
-			if (*temp == '-') {
-				temp++;
-				to = dasd_strtoul (temp, &temp, &features);
-			}
-                        if (from == -EINVAL ||
-                            to   == -EINVAL    ) {
-                                rc = -EINVAL;
-                                break;
-                        } else {
-                                dasd_add_range (from, to ,features);
-                        }
-                }
-		str++;
-	}
-
-        return rc;
-}
-
-/* SECTION: Dealing with devices registered to multiple major numbers */
-
-static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
-
-static major_info_t dasd_major_info[] = {
-	{
-	      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}
-};
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
 
-static major_info_t *
-get_new_major_info (void)
-{
-	major_info_t *major_info = NULL;
+	devmap = dasd_devmap_from_devno(devno);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return;
+	atomic_dec(&device->ref_count);
+	dasd_change_state(device);
+	dasd_schedule_bh(device);
+	dasd_put_device(devmap);
+}
 
-	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)}
-		};
-		memcpy (major_info, &temp_major_info, sizeof (major_info_t));
-	}
-	return major_info;
+void
+dasd_kick_device(dasd_device_t *device)
+{
+	atomic_inc(&device->ref_count);
+	device->kick_tq.routine = (void *) do_kick_device;
+	device->kick_tq.data = (void *) (addr_t) device->devinfo.devno;
+	/* queue call to dasd_kick_device to the kernel event daemon. */
+	schedule_task(&device->kick_tq);
 }
 
 /*
- * register major number
- * is called with the 'static' major_info during init of the driver or 'NULL' to
- * allocate an additional dynamic major.
+ * Set the target state for a device and starts the state change.
  */
-static int
-dasd_register_major (major_info_t * major_info)
+void
+dasd_set_target_state(dasd_device_t *device, int target)
 {
-	int rc = 0;
-	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;
-		}
+	/* If we are in probeonly mode stop at DASD_STATE_ACCEPT. */
+	if (dasd_probeonly && target > DASD_STATE_ACCEPT)
+		target = DASD_STATE_ACCEPT;
+	if (device->target != target) {
+                if (device->state == target)
+                        wake_up(&dasd_init_waitq);
+		device->target = target;
 	}
+	if (device->state != device->target)
+		dasd_change_state(device);
+}
 
-	major = major_info->gendisk.major;
-
-        /* 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);
-		goto out_reg_blkdev; 
-	} else {
-		major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
-	}
+/*
+ * Enable devices with device numbers in [from..to].
+ */
+static inline int
+_wait_for_devices(int from, int to)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devno, rc;
 
-	/* 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;
-	}
-
-        /* 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_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_blk_size;
-	memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int));
-
-	/* finally do the gendisk stuff */
-	major_info->gendisk.part = kmalloc ((1 << MINORBITS) *
-					    sizeof (struct hd_struct),
-					    GFP_ATOMIC);
-	if (!major_info->gendisk.part)
-		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);
-
-	major_info->gendisk.sizes = blk_size[major];
-	major_info->gendisk.major = major;
-	add_gendisk (&major_info->gendisk);
-	return major;
-
-        /* error handling - free the prior allocated memory */  
-      out_gendisk:
-	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;
+	rc = 0;
+	for (devno = from; devno <= to && rc == 0; devno++) {
+		devmap = dasd_devmap_from_devno(devno);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		if (device->state != device->target)
+			rc = 1;
+		dasd_put_device(devmap);
 	}
+	return rc;
+}
 
-      out_reg_blkdev:
-        kfree (major_info->gendisk.flags);
-        kfree (major_info->gendisk.de_arr);
+void
+dasd_enable_devices(int from, int to)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devno;
 
-	/* Delete the new major info from dasd_major_info if needed */
-	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
-		kfree (major_info);
+	for (devno = from; devno <= to; devno++) {
+		devmap = dasd_devmap_from_devno(devno);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		dasd_set_target_state(device, DASD_STATE_ONLINE);
+		if (device->state <= DASD_STATE_KNOWN)
+			/* No discipline for device found. */
+			dasd_set_target_state(device, DASD_STATE_NEW);
+		dasd_put_device(devmap);
 	}
-
-	return -ENOMEM;
+	/* Now wait for the devices to come up. */
+	wait_event(dasd_init_waitq, _wait_for_devices(from, to) == 0);
 }
 
-static int
-dasd_unregister_major (major_info_t * major_info)
+/*
+ * Disable devices with device numbers in [from..to].
+ */
+void
+dasd_disable_devices(int from, int to)
 {
-	int rc = 0;
-	int major;
-	unsigned long flags;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devno;
 
-	if (major_info == NULL) {
-		return -EINVAL;
+	for (devno = from; devno <= to; devno++) {
+		devmap = dasd_devmap_from_devno(devno);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		dasd_set_target_state(device, DASD_STATE_NEW);
+		dasd_put_device(devmap);
 	}
-	major = major_info->gendisk.major;
-	INIT_BLK_DEV (major, NULL, NULL, NULL);
-
-	del_gendisk (&major_info->gendisk);
-
-	kfree (major_info->dasd_device);
-	kfree (major_info->gendisk.part);
-
-	kfree (blk_size[major]);
+}
 
-	blk_clear(major);
+/*
+ * Enable devices that use a specific discipline.
+ */
+static inline int
+_wait_for_disc_devices(dasd_discipline_t *discipline)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devindex, rc;
 
-	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);
-		return rc;
-	} else {
-		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
+	rc = 0;
+	for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
+		devmap = dasd_devmap_from_devindex(devindex);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		if (device->discipline == discipline &&
+		    device->state != device->target)
+			rc = 1;
+		dasd_put_device(devmap);
 	}
+	return rc;
+}
 
-	kfree (major_info->gendisk.flags);
-	kfree (major_info->gendisk.de_arr);
+static void
+dasd_enable_discipline(dasd_discipline_t *discipline)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devindex;
 
-	/* 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);
+	for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
+		devmap = dasd_devmap_from_devindex(devindex);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		if (device->discipline != NULL &&
+		    device->discipline != discipline)
+			continue;
+		dasd_set_target_state(device, DASD_STATE_ONLINE);
+		if (device->discipline == NULL)
+			/* No discipline for device found. */
+			dasd_set_target_state(device, DASD_STATE_NEW);
+		dasd_put_device(devmap);
 	}
-	return rc;
+	/* Now wait for the devices to come up. */
+	wait_event(dasd_init_waitq, _wait_for_disc_devices(discipline) == 0);
 }
 
 /*
- * 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
+ * Disable devices that use a specific discipline.
  */
-static inline dasd_device_t *
-dasd_device_from_kdev (kdev_t kdev)
+static void
+dasd_disable_discipline(dasd_discipline_t *discipline)
 {
-	major_info_t *major_info = NULL;
-	struct list_head *l;
-	unsigned long flags;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devindex;
 
-	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))
-			break;
+	/* Shutdown device that use the discipline. */
+	for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
+		devmap = dasd_devmap_from_devindex(devindex);
+		device = (devmap != NULL) ?
+			dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+		if (IS_ERR(device))
+			continue;
+		if (device->discipline == discipline)
+			dasd_set_target_state(device, DASD_STATE_NEW);
+		dasd_put_device(devmap);
 	}
-	spin_unlock_irqrestore (&dasd_major_lock, flags);
-	if (major_info != &dasd_major_info[0])
-		return major_info->dasd_device[MINOR (kdev) >> DASD_PARTN_BITS];
-	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
- * it or NULL when not found
+ * Deactivate a device that has vaninshed.
  */
-static inline dasd_device_t **
-dasd_device_from_devno (int devno)
+
+static void
+do_not_oper_handler(void *data)
 {
-	major_info_t *major_info;
-	struct list_head *l;
-	int devindex = dasd_devindex_from_devno (devno);
-	unsigned long flags;
+	struct {
+		struct tq_struct tq;
+		int irq;
+	} *p;
+	dasd_device_t *device;
+	dasd_devmap_t *devmap;
 
-	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 (devindex < DASD_PER_MAJOR) {
-			spin_unlock_irqrestore (&dasd_major_lock, flags);
-			return &major_info->dasd_device[devindex];
-		}
-		devindex -= DASD_PER_MAJOR;
-	}
-	spin_unlock_irqrestore (&dasd_major_lock, flags);
-	return NULL;
+	/*
+	 * find out devno of leaving device: CIO has already deleted
+	 * this information so we need to find it by irq!
+	 */
+	p = data;
+	devmap = dasd_devmap_from_irq(p->irq);
+	if (devmap == NULL) {
+		MESSAGE(KERN_WARNING,
+			"not_oper_handler called on irq 0x%04x no devno!",
+			p->irq);
+		return;
+	} else
+		DBF_EVENT(DBF_NOTICE, "called for devno %04x", devmap->devno);
+	device = dasd_get_device(devmap);
+	if (IS_ERR(device))
+		return;
+	dasd_set_target_state(device, DASD_STATE_NEW);
+	dasd_put_device(devmap);
+	kfree(p);
+}
+
+void
+dasd_not_oper_handler(int irq, int status)
+{
+	struct {
+		struct tq_struct tq;
+		int irq;
+	} *p;
+
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == NULL)
+		/* FIXME: No memory, we loose. */
+		return;
+	p->tq.routine = (void *) do_not_oper_handler;
+	p->tq.data = (void *) p;
+	p->irq = irq;
+	/* queue call to do_not_oper_handler to the kernel event daemon. */
+	schedule_task(&p->tq);
 }
 
 /*
- * 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
+ * Activate a device that appeared out of nowhere.
  */
-
-static int
-dasd_features_from_devno (int devno)
+static void
+do_oper_handler(void *data)
 {
-	dasd_range_t *temp;
-	int devindex = 0;
-	unsigned long flags;
-	struct list_head *l;
+	struct {
+		struct tq_struct tq;
+		int devno;
+	} *p;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
 
-	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;
+	p = data;
+	DBF_EVENT(DBF_NOTICE, "called for devno %04x", p->devno);
+
+	if (dasd_autodetect &&
+            dasd_add_range(p->devno, p->devno, DASD_FEATURE_DEFAULT) != 0)
+                return;
+
+	/* Get/create the device structure for devno. */
+	devmap = dasd_devmap_from_devno(p->devno);
+	if (devmap == NULL) {
+		DBF_EXC(DBF_ALERT, "no dasd: devno %04x", p->devno);
+		return;
 	}
-	spin_unlock_irqrestore (&range_lock, flags);
-	return -ENODEV;
+	device = dasd_get_device(devmap);
+	if (IS_ERR(device))
+		return;
+	dasd_enable_devices(p->devno, p->devno);
+	dasd_put_device(devmap);
+	kfree(p);
 }
 
+int
+dasd_oper_handler(int irq, devreg_t * devreg)
+{
+	struct {
+		struct tq_struct tq;
+		int devno;
+	} *p;
+
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == NULL)
+		/* FIXME: No memory, we loose. */
+		return -ENOMEM;
+	p->devno = get_devno_by_irq(irq);
+	if (p->devno == -ENODEV)
+		return -ENODEV;
+	p->tq.routine = (void *) do_oper_handler;
+	p->tq.data = (void *) p;
+	/* queue call to do_oper_handler to the kernel event daemon. */
+	schedule_task(&p->tq);
+        return 0;
 
+}
 
-/* SECTION: managing dasd disciplines */
+/*
+ * SECTION: device operation (interrupt handler, start_IO, term_IO ...)
+ */
+#ifdef CONFIG_DASD_PROFILE
 
-/* anchor and spinlock for list of disciplines */
-static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
-static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
+dasd_profile_info_t dasd_global_profile;
+unsigned int dasd_profile_level = DASD_PROFILE_OFF;
 
 /*
- * 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
+ * Increments counter in global and local profiling structures.
  */
-static inline void
-dasd_discipline_enq (dasd_discipline_t * d)
-{
-    list_add(&d->list, &dasd_disc_head);
+#define dasd_profile_counter(value, counter, device) \
+{ \
+	int index; \
+	for (index = 0; index < 31 && value >> (2+index); index++); \
+	dasd_global_profile.counter[index]++; \
+	device->profile.counter[index]++; \
 }
 
 /*
- * function dasd_discipline_deq
- * removes the discipline given as argument from the list of disciplines
+ * Add profiling information for cqr before execution.
  */
 static inline void
-dasd_discipline_deq (dasd_discipline_t * d)
+dasd_profile_start(dasd_device_t *device, dasd_ccw_req_t * cqr,
+		   struct request *req)
 {
-        list_del(&d->list);
-}
+	struct list_head *l;
+	unsigned int counter;
 
-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_disc (dasd_device_t * device, dasd_discipline_t *d)
-{
-        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 */
-
-static dasd_profile_info_t dasd_global_profile;
-
-#ifdef DASD_PROFILE
-/*
- * macro: dasd_profile_add_counter
- * increments counter in global and local profiling structures
- * according to the value
- */
-#define dasd_profile_add_counter( value, counter, device ) \
-{ \
-        int ind; \
-        long help; \
-	for (ind = 0, help = value >> 3; \
-             ind < 31 && help; \
-             help = help >> 1, ind++) {} \
-	dasd_global_profile.counter[ind]++; \
-        device->profile.counter[ind]++; \
+	if (dasd_profile_level != DASD_PROFILE_ON)
+		return;
+
+	/* count the length of the chanq for statistics */
+	counter = 0;
+	list_for_each(l, &device->ccw_queue)
+		if (++counter >= 31)
+			break;
+	dasd_global_profile.dasd_io_nr_req[counter]++;
+	device->profile.dasd_io_nr_req[counter]++;
 }
 
 /*
- * function dasd_profile_add
- * adds the profiling information from the cqr given as argument to the
- * global and device specific profiling information
+ * Add profiling information for cqr after execution.
  */
-void
-dasd_profile_add (ccw_req_t * cqr)
+static inline void
+dasd_profile_end(dasd_device_t *device, dasd_ccw_req_t * cqr,
+		 struct request *req)
 {
-	long strtime, irqtime, endtime, tottime; /* in microsecnds*/
+	long strtime, irqtime, endtime, tottime;	/* in microsecnds */
 	long tottimeps, sectors;
-	dasd_device_t *device = cqr->device;
 
-	if (!cqr->req)		/* safeguard against abnormal cqrs */
+	if (dasd_profile_level != DASD_PROFILE_ON)
 		return;
 
-        if ((!cqr->buildclk) ||
-            (!cqr->startclk) ||
-            (!cqr->stopclk ) ||
-            (!cqr->endclk  ) ||
-            (!(sectors = ((struct request *) (cqr->req))->nr_sectors)))
-                return;
+	sectors = req->nr_sectors;
+	if (!cqr->buildclk || !cqr->startclk ||
+	    !cqr->stopclk || !cqr->endclk ||
+	    !sectors)
+		return;
 
 	strtime = ((cqr->startclk - cqr->buildclk) >> 12);
 	irqtime = ((cqr->stopclk - cqr->startclk) >> 12);
@@ -1018,3283 +945,1432 @@
 	tottime = ((cqr->endclk - cqr->buildclk) >> 12);
 	tottimeps = tottime / sectors;
 
-	if (!dasd_global_profile.dasd_io_reqs) {
-		memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
-	};
-	if (!device->profile.dasd_io_reqs) {
-		memset (&device->profile, 0, sizeof (dasd_profile_info_t));
-	};
-
+	if (!dasd_global_profile.dasd_io_reqs)
+		memset(&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
 	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);
-	dasd_profile_add_counter (strtime, dasd_io_time1, device);
-	dasd_profile_add_counter (irqtime, dasd_io_time2, device);
-	dasd_profile_add_counter (irqtime / sectors, dasd_io_time2ps, device);
-	dasd_profile_add_counter (endtime, dasd_io_time3, device);
-}
-#endif
+	dasd_global_profile.dasd_io_sects += sectors;
 
-/* SECTION: All the gendisk stuff */
+	if (!device->profile.dasd_io_reqs)
+		memset(&device->profile, 0, sizeof (dasd_profile_info_t));
+	device->profile.dasd_io_reqs++;
+	device->profile.dasd_io_sects += sectors;
 
+	dasd_profile_counter(sectors, dasd_io_secs, device);
+	dasd_profile_counter(tottime, dasd_io_times, device);
+	dasd_profile_counter(tottimeps, dasd_io_timps, device);
+	dasd_profile_counter(strtime, dasd_io_time1, device);
+	dasd_profile_counter(irqtime, dasd_io_time2, device);
+	dasd_profile_counter(irqtime / sectors, dasd_io_time2ps, device);
+	dasd_profile_counter(endtime, dasd_io_time3, device);
+}
+#else
+#define dasd_profile_start(device, cqr, req) do {} while (0)
+#define dasd_profile_end(device, cqr, req) do {} while (0)
+#endif				/* CONFIG_DASD_PROFILE */
+
+/*
+ * Allocate memory for a channel program with 'cplength' channel
+ * command words and 'datasize' additional space. There are two
+ * variantes: 1) dasd_kmalloc_request uses kmalloc to get the needed
+ * memory and 2) dasd_smalloc_request uses the static ccw memory
+ * that gets allocated for each device.
+ */
+dasd_ccw_req_t *
+dasd_kmalloc_request(char *magic, int cplength, int datasize,
+		   dasd_device_t * device)
+{
+	dasd_ccw_req_t *cqr;
+
+	/* Sanity checks */
+	if ( magic == NULL || datasize > PAGE_SIZE ||
+	     (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
+		BUG();
+	debug_text_event ( dasd_debug_area, 1, "ALLC");
+	debug_text_event ( dasd_debug_area, 1, magic);
+	debug_int_event ( dasd_debug_area, 1, cplength);
+	debug_int_event ( dasd_debug_area, 1, datasize);
 
-/* SECTION: Managing wrappers for ccwcache */
+	cqr = kmalloc(sizeof(dasd_ccw_req_t), GFP_ATOMIC);
+	if (cqr == NULL)
+		return ERR_PTR(-ENOMEM);
+	memset(cqr, 0, sizeof(dasd_ccw_req_t));
+	cqr->cpaddr = NULL;
+	if (cplength > 0) {
+		cqr->cpaddr = kmalloc(cplength*sizeof(ccw1_t),
+				      GFP_ATOMIC | GFP_DMA);
+		if (cqr->cpaddr == NULL) {
+			kfree(cqr);
+			return ERR_PTR(-ENOMEM);
+		}
+		memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t));
+	}
+	cqr->data = NULL;
+	if (datasize > 0) {
+		cqr->data = kmalloc(datasize, GFP_ATOMIC | GFP_DMA);
+		if (cqr->data == NULL) {
+			if (cqr->cpaddr != NULL)
+				kfree(cqr->cpaddr);
+			kfree(cqr);
+			return ERR_PTR(-ENOMEM);
+		}
+		memset(cqr->data, 0, datasize);
+	}
+	strncpy((char *) &cqr->magic, magic, 4);
+	ASCEBC((char *) &cqr->magic, 4);
+	atomic_inc(&device->ref_count);
+	return cqr;
+}
 
-/*
- * 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, dasd_device_t* device)
+dasd_ccw_req_t *
+dasd_smalloc_request(char *magic, int cplength, int datasize,
+		   dasd_device_t * device)
 {
-	ccw_req_t *rv = NULL;
+	unsigned long flags;
+	dasd_ccw_req_t *cqr;
+	char *data;
+	int size;
 
-	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_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
-                                         "(%04x) Low memory! Using emergency request %p.",
-                                         device->devinfo.devno,
-                                         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_DRIVER_DEBUG_EVENT (2, dasd_alloc_request,
-                                         "(%04x) Refusing emergency mem for request "
-                                         "NULL, already in use at %p.",
-                                         device->devinfo.devno,
-                                         device->lowmem_ccws);
-	}
-	return rv;
+	/* Sanity checks */
+	if ( magic == NULL || datasize > PAGE_SIZE ||
+	     (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
+		BUG();
+	debug_text_event ( dasd_debug_area, 1, "ALLC");
+	debug_text_event ( dasd_debug_area, 1, magic);
+	debug_int_event ( dasd_debug_area, 1, cplength);
+	debug_int_event ( dasd_debug_area, 1, datasize);
+
+	size = (sizeof(dasd_ccw_req_t) + 7L) & -8L;
+	if (cplength > 0)
+		size += cplength * sizeof(ccw1_t);
+	if (datasize > 0)
+		size += datasize;
+	spin_lock_irqsave(&device->mem_lock, flags);
+	cqr = (dasd_ccw_req_t *) dasd_alloc_chunk(&device->ccw_chunks, size);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	if (cqr == NULL)
+		return ERR_PTR(-ENOMEM);
+	memset(cqr, 0, sizeof(dasd_ccw_req_t));
+	data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L);
+	cqr->cpaddr = NULL;
+	if (cplength > 0) {
+		cqr->cpaddr = (ccw1_t *) data;
+		data += cplength*sizeof(ccw1_t);
+		memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t));
+	}
+	cqr->data = NULL;
+	if (datasize > 0) {
+		cqr->data = data;
+ 		memset(cqr->data, 0, datasize);
+	}
+	strncpy((char *) &cqr->magic, magic, 4);
+	ASCEBC((char *) &cqr->magic, 4);
+	atomic_inc(&device->ref_count);
+	return cqr;
 }
 
 /*
- * function dasd_free_request
- * returns a ccw_req_t to the appropriate cache or emergeny request line
+ * Free memory of a channel program. This function needs to free all the
+ * idal lists that might have been created by dasd_set_cda and the
+ * dasd_ccw_req_t itself.
  */
 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 )
+dasd_kfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
 {
 #ifdef CONFIG_ARCH_S390X
-	int nridaws;
-        int count = cp->count;
-        
-        if (set_normalized_cda (cp, address)!=-ENOMEM) {
-                return 0;
-        }
+	ccw1_t *ccw;
 
-        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;
+	/* Clear any idals used for the request. */
+	ccw = cqr->cpaddr;
+	do {
+		clear_normalized_cda(ccw);
+	} while (ccw++->flags & (CCW_FLAG_CC | CCW_FLAG_DC));
 #endif
-	return 0;
+	if (cqr->dstat != NULL)
+		kfree(cqr->dstat);
+	debug_text_event ( dasd_debug_area, 1, "FREE");
+	debug_int_event ( dasd_debug_area, 1, (long) cqr);
+	if (cqr->cpaddr != NULL)
+		kfree(cqr->cpaddr);
+	if (cqr->data != NULL)
+		kfree(cqr->data);
+	kfree(cqr);
+	atomic_dec(&device->ref_count);
 }
 
-
-/* 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)
+void
+dasd_sfree_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
 {
-	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);
-
-       
-#ifdef DASD_PROFILE
-        /* save profile information for non erp cqr */
-        if (cqr->refers == NULL) {
-                unsigned int  counter = 0;
-                ccw_req_t     *ptr;
-                dasd_device_t *device = cqr->device;
-
-                /* count the length of the chanq for statistics */
-                for (ptr = q->head; 
-                     ptr->next != NULL && counter <=31; 
-                     ptr = ptr->next) {
-                        counter++;
-                }                
-                
-                dasd_global_profile.dasd_io_nr_req[counter]++;
-                device->profile.dasd_io_nr_req[counter]++;
-        }
-#endif 
-}
+	unsigned long flags;
 
-/*
- * 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
- */
-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);
+	if (cqr->dstat != NULL)
+		kfree(cqr->dstat);
+	debug_text_event(dasd_debug_area, 1, "FREE");
+	debug_int_event(dasd_debug_area, 1, (long) cqr);
+	spin_lock_irqsave(&device->mem_lock, flags);
+	dasd_free_chunk(&device->ccw_chunks, cqr);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	atomic_dec(&device->ref_count);
 }
 
 /*
- * 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
+ * Check discipline magic in cqr.
  */
-inline void
-dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
+static inline int
+dasd_check_cqr(dasd_ccw_req_t *cqr)
 {
-	ccw_req_t *prev;
+	dasd_device_t *device;
 
 	if (cqr == NULL)
-		BUG ();
-
-	if (cqr == q->head) {
-		q->head = cqr->next;
-		if (q->head == NULL)
-			q->tail = NULL;
-
-	} else {
-		prev = q->head;
-		while (prev && prev->next != cqr)
-			prev = prev->next;
-		if (prev == NULL)
-			return;
-		prev->next = cqr->next;
-		if (prev->next == NULL)
-			q->tail = prev;
+		return -EINVAL;
+	device = cqr->device;
+	if (strncmp((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+		DEV_MESSAGE(KERN_WARNING, device,
+			    " dasd_ccw_req_t 0x%08x magic doesn't match"
+			    " discipline 0x%08x",
+			    cqr->magic,
+			    *(unsigned int *) device->discipline->name);
+		return -EINVAL;
 	}
-	cqr->next = NULL;
+	return 0;
 }
 
-/* SECTION: Managing the device queues etc. */
-
 /*
- * DASD_TERM_IO
- *
- * attempts to terminate the the current IO and set it to failed if termination
- * was successful.
- * returns an appropriate return code
+ * Terminate the current i/o and set the request to failed.
+ * halt_IO/clear_IO can fail if the i/o subsystem is in a bad mood.
  */
 int
-dasd_term_IO (ccw_req_t * cqr)
+dasd_term_IO(dasd_ccw_req_t * cqr)
 {
-	int rc = 0;
-	dasd_device_t *device = cqr->device;
-	int irq;
-        int retries = 0;
+	dasd_device_t *device;
+	int retries, rc;
 
-	if (!cqr) {
-		BUG ();
-	}
-	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;
+	/* Check the cqr */
+	rc = dasd_check_cqr(cqr);
+	if (rc)
+		return rc;
+	retries = 0;
+	device = (dasd_device_t *) cqr->device;
+	while ((retries < 5) && (cqr->status == DASD_CQR_IN_IO)) {
+		if (retries < 2)
+			rc = halt_IO(device->devinfo.irq,
+				     (long) cqr, cqr->options);
+		else
+			rc = clear_IO(device->devinfo.irq,
+				      (long) cqr, cqr->options);
+		switch (rc) {
+		case 0:	/* termination successful */
+			cqr->status = DASD_CQR_FAILED;
+			cqr->stopclk = get_clock();
+			break;
+		case -ENODEV:
+			DBF_DEV_EVENT(DBF_ERR, device, "%s",
+				      "device gone, retry");
+			break;
+		case -EIO:
+			DBF_DEV_EVENT(DBF_ERR, device, "%s",
+				      "I/O error, retry");
+			break;
+		case -EBUSY:
+			DBF_DEV_EVENT(DBF_ERR, device, "%s",
+				      "device busy, retry later");
+			break;
+		default:
+			DEV_MESSAGE(KERN_ERR, device,
+				    "line %d unknown RC=%d, please "
+				    "report to linux390@de.ibm.com",
+				    __LINE__, rc);
+			BUG();
+			break;
+		}
 	}
-        
-        while ((retries < 5                    ) &&
-               (cqr->status == CQR_STATUS_IN_IO)   ) {
-
-                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:         /* termination successful */
-                        check_then_set (&cqr->status,
-                                        CQR_STATUS_IN_IO, 
-                                        CQR_STATUS_FAILED);
-                        
-                        asm volatile ("STCK %0":"=m" (cqr->stopclk));
-                        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;
-                }
-
-                retries ++;
-        }
+	dasd_schedule_bh(device);
 	return rc;
 }
 
 /*
- * function dasd_start_IO
- * attempts to start the IO and returns an appropriate return code
+ * Start the i/o. This start_IO can fail if the channel is really busy.
+ * In that case set up a timer to start the request later.
  */
 int
-dasd_start_IO (ccw_req_t * cqr)
+dasd_start_IO(dasd_ccw_req_t * cqr)
 {
-	int rc = 0;
-	dasd_device_t *device = cqr->device;
-	int irq;
-	unsigned long long now;
-
-	if (!cqr) {
-		BUG ();
-	}
-	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;
-	}
-
-	asm volatile ("STCK %0":"=m" (now));
-        cqr->startclk = now;
-
-	rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+	dasd_device_t *device;
+	int rc;
 
+	/* Check the cqr */
+	rc = dasd_check_cqr(cqr);
+	if (rc)
+		return rc;
+	device = (dasd_device_t *) cqr->device;
+	cqr->startclk = get_clock();
+	rc = do_IO(device->devinfo.irq,
+		   cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
 	switch (rc) {
 	case 0:
-                if (cqr->options & DOIO_WAIT_FOR_INTERRUPT) {
-                        /* request already finished (synchronous IO) */
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      " do_IO finished request... "
-                                      "DOIO_WAIT_FOR_INTERRUPT was set");
-                        check_then_set (&cqr->status,
-                                        CQR_STATUS_QUEUED, 
-                                        CQR_STATUS_DONE);
-
-                        cqr->stopclk = now;
-                        dasd_schedule_bh (device);
-                        
-                } else {
-                        check_then_set (&cqr->status,
-                                        CQR_STATUS_QUEUED, 
-                                        CQR_STATUS_IN_IO);
-                }
+		if (cqr->options & DOIO_WAIT_FOR_INTERRUPT) {
+			/* request already finished (synchronous IO) */
+			cqr->status = DASD_CQR_DONE;
+			cqr->stopclk = cqr->startclk;
+			dasd_schedule_bh(device);
+		} else
+			cqr->status = DASD_CQR_IN_IO;
 		break;
 	case -EBUSY:
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "device busy, retry later\n");
+		DBF_DEV_EVENT(DBF_ERR, device, "%s",
+			      "device busy, retry later");
 		break;
-	case -ETIMEDOUT: 
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "request timeout - terminated\n");
+	case -ETIMEDOUT:
+		DBF_DEV_EVENT(DBF_ERR, device, "%s",
+			      "request timeout - terminated");
 	case -ENODEV:
 	case -EIO:
-		check_then_set (&cqr->status,
-				CQR_STATUS_QUEUED, 
-                                CQR_STATUS_FAILED);
-
-                cqr->stopclk = now;
-                dasd_schedule_bh (device);
+		cqr->status = DASD_CQR_FAILED;
+		cqr->stopclk = cqr->startclk;
+		dasd_schedule_bh(device);
 		break;
 	default:
-		DASD_MESSAGE (KERN_ERR, device,
-			      "line %d unknown RC=%d, please report"
-			      " to linux390@de.ibm.com\n", __LINE__, rc);
-		BUG ();
+		DEV_MESSAGE(KERN_ERR, device,
+			    "line %d unknown RC=%d, please report"
+			    " to linux390@de.ibm.com", __LINE__, rc);
+		BUG();
 		break;
 	}
-
 	return rc;
 }
 
 /*
- * function dasd_sleep_on_req
- * attempts to start the IO and waits for completion
- * FIXME: replace handmade sleeping by wait_event
+ * Timeout function for dasd devices. This is used for different purposes
+ *  1) missing interrupt handler for normal operation
+ *  2) delayed start of request where start_IO failed with -EBUSY
+ *  3) timeout for missing state change interrupts
+ * The head of the ccw queue will have status DASD_CQR_IN_IO for 1),
+ * DASD_CQR_QUEUED for 2) and DASD_CQR_PENDING for 3).
  */
-int
-dasd_sleep_on_req (ccw_req_t * req)
+static void
+dasd_timeout_device(unsigned long ptr)
 {
 	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);
-	do {
-		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-		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);
-                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);
-	return rc;
-}				/* end dasd_sleep_on_req */
-
-/*
- * function dasd_end_request
- * posts the buffer_cache about a finalized request
- * FIXME: for requests splitted to serveral cqrs
- */
-static inline void
-dasd_end_request (struct request *req, int uptodate)
-{
-	while (end_that_request_first (req, uptodate, DASD_NAME)) {
-	}
-#ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness (MAJOR (req->rq_dev));
-#endif
-	end_that_request_last (req);
-	return;
-}
-
-/*
- * function dasd_get_queue
- * returns the queue corresponding to a device behind a kdev
- */
-static request_queue_t *
-dasd_get_queue (kdev_t kdev)
-{
-	dasd_device_t *device = dasd_device_from_kdev (kdev);
+	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
 
-	if (!device) {
-		return NULL;
+	device = (dasd_device_t *) ptr;
+	spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+	/* re-activate first request in queue */
+	if (!list_empty(&device->ccw_queue)) {
+		cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
+		if (cqr->status == DASD_CQR_PENDING)
+			cqr->status = DASD_CQR_QUEUED;
 	}
-
-	return device->request_queue;
+	spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
+	dasd_schedule_bh(device);
 }
 
 /*
- * function dasd_check_expire_time
- * check the request given as argument for expiration
- * and returns 0 if not yet expired, EIO else
+ * Setup timeout for a device.
  */
-static inline int
-dasd_check_expire_time (ccw_req_t * cqr)
+void
+dasd_set_timer(dasd_device_t *device, int expires)
 {
-	unsigned long long now;
-	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),
-			      "IO timeout 0x%08lx%08lx usecs in req %p\n",
-			      (long) (cqr->expires >> 44),
-			      (long) (cqr->expires >> 12), cqr);
-		cqr->expires <<= 1;
-                rc = -EIO;
+	/* FIXME: timeouts are based on jiffies but the timeout
+	 * comparision in __dasd_check_expire is based on the
+	 * TOD clock. */
+	if (expires != 0) {
+		if (!timer_pending(&device->timer)) {
+			device->timer.function = dasd_timeout_device;
+			device->timer.data = (unsigned long) device;
+			device->timer.expires = jiffies + expires;
+			add_timer(&device->timer);
+		} else
+			mod_timer(&device->timer, jiffies + expires);
+	} else {
+		if (timer_pending(&device->timer))
+			del_timer(&device->timer);
 	}
-	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
+ * Clear timeout for a device.
  */
-static inline void
-dasd_finalize_request (ccw_req_t * cqr)
+void
+dasd_clear_timer(dasd_device_t *device)
 {
-	dasd_device_t *device = cqr->device;
-
-	asm volatile ("STCK %0":"=m" (cqr->endclk));
-	if (cqr->req) {
-#ifdef DASD_PROFILE
-		dasd_profile_add (cqr);
-#endif
-		dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
-		/* free request if nobody is waiting on it */
-		dasd_free_request (cqr, cqr->device);
-	} else {
-                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;
+	if (timer_pending(&device->timer))
+		del_timer(&device->timer);
 }
 
 /*
- * 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
+ *   Handles the state change pending interrupt.
+ *   Search for the device related request queue and check if the first
+ *   cqr in queue in in status 'DASD_CQR_PENDING'.
+ *   If so the status is set to 'DASD_CQR_QUEUED' to reactivate
+ *   the device.
  */
 static void
-dasd_process_queues (dasd_device_t * device)
+do_state_change_pending(void *data)
 {
-	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 )   )) {
-
-		dasd_erp_action_fn_t erp_action;
-		ccw_req_t            *erp_cqr = NULL;
-
-		/*  preprocess requests with CQR_STATUS_ERROR */
-		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);
-
-                                asm volatile ("STCK %0":"=m" (qp->head->stopclk));
-
-                        } 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 {
-
-                                DASD_MESSAGE (KERN_ERR, device, "%s",
-                                              "ERP unsuccessful");
-			}
-
-			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);
-                        }
-
-			continue;
-		}
-
-		/* dechain request now */
-		if (final_requests == NULL)
-			final_requests = qp->head;
-
-		cqr      = qp->head;
-		qp->head = qp->head->next;
-
-		if (qp->head == NULL)
-			qp->tail = NULL;
-
-	} /* 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_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
-                                                         "(%04x) Rejecting write request %p\n",
-                                                         device->devinfo.devno,
-                                                         req);
-
-                                dasd_end_request (req, 0);
-                                dasd_dequeue_request (queue,req);
-                        } else {
-                            cqr = device->discipline->build_cp_from_req (device, req);
-                            if (cqr == NULL) {
-
-                                    DASD_DRIVER_DEBUG_EVENT (3, dasd_int_handler,
-                                                             "(%04x) CCW creation failed "
-                                                             "on request %p\n",
-                                                             device->devinfo.devno,
-                                                             req);
-
-                                    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 == 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 ();
-		}
-	}
-	s390irq_spin_unlock_irqrestore (irq, flags);
-
-} /* end dasd_process_queues */
+	struct {
+		struct tq_struct tq;
+		unsigned short devno;
+	} *p;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
 
-/*
- * function dasd_run_bh
- * acquires the locks needed and then runs the bh
- */
-static void
-dasd_run_bh (dasd_device_t * device)
-{
-	long flags;
-	spin_lock_irqsave (&device->request_queue.queue_lock, flags);
-	atomic_set (&device->bh_scheduled, 0);
-	dasd_process_queues (device);
-	spin_unlock_irqrestore (&device->request_queue.queue_lock, flags);
-}
+	p = data;
+	DBF_EVENT(DBF_NOTICE, "State change Interrupt: %04x", p->devno);
 
-/*
- * function dasd_schedule_bh
- * schedules the request_fn to run with next run_bh cycle
- */
-void
-dasd_schedule_bh (dasd_device_t * device)
-{
-	/* Protect against rescheduling, when already running */
-	if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) {
+	devmap = dasd_devmap_from_devno(p->devno);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device)) {
+		MESSAGE(KERN_DEBUG,
+			"unable to find device for state change pending "
+			"interrupt: devno%04x", p->devno);
 		return;
 	}
 
-	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;
-
-	queue_task (&device->bh_tq, &tq_immediate);
-	mark_bh (IMMEDIATE_BH);
-	return;
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	/* re-activate first request in queue */
+	if (!list_empty(&device->ccw_queue)) {
+		cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
+		if (cqr->status == DASD_CQR_PENDING)
+			cqr->status = DASD_CQR_QUEUED;
+	}
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
+	dasd_schedule_bh(device);
+	dasd_put_device(devmap);
+	kfree(p);
 }
 
-/*
- * function do_dasd_request
- * is called from ll_rw_blk.c and provides the caller of
- * dasd_process_queues
- */
+
 static void
-do_dasd_request (request_queue_t * queue)
+dasd_handle_state_change_pending(devstat_t * stat)
 {
-        dasd_device_t *device = (dasd_device_t *)queue->queuedata;
-	dasd_process_queues (device);
+	struct {
+		struct tq_struct tq;
+		unsigned short devno;
+	} *p;
+
+	p = kmalloc(sizeof(*p), GFP_ATOMIC);
+	if (p == NULL)
+		/* No memory, let the timeout do the reactivation. */
+		return;
+	p->tq.routine = (void *) do_state_change_pending;
+	p->tq.data = (void *) p;
+	p->devno = stat->devno;
+	/* queue call to do_state_change_pending to the kernel event daemon. */
+	schedule_task(&p->tq);
 }
 
 /*
- * DASD_HANDLE_STATE_CHANGE_PENDING
- *
- * DESCRIPTION
- *   Handles the state change pending interrupt.
- *   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.
- *
- *  PARAMETER
- *   stat               device status of state change pending interrupt.
+ * Interrupt handler for "normal" ssch-io based dasd devices.
  */
 void
-dasd_handle_state_change_pending (devstat_t * stat)
+dasd_int_handler(int irq, void *ds, struct pt_regs *regs)
 {
-	dasd_device_t **device_addr;
-	ccw_req_t *cqr;
-
-	device_addr = dasd_device_from_devno (stat->devno);
-
-	if (device_addr == NULL) {
-
-		printk (KERN_DEBUG PRINTK_HEADER
-			"unable to find device for state change pending "
-			"interrupt: devno%04x\n", 
-                        stat->devno);
-                return;
-	} 
-
-        /* re-activate first request in queue */
-        cqr = (*device_addr)->queue.head;
-        
-        if (cqr->status == CQR_STATUS_PENDING) {
-                
-                DASD_MESSAGE (KERN_DEBUG, (*device_addr), "%s",
-                              "device request queue restarted by "
-                              "state change pending interrupt\n");
-                
-                del_timer (&(*device_addr)->timer);
-                
-                check_then_set (&cqr->status,
-                                CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
-                
-                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
- */
-void
-dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
-{
-	int ip;
-	ccw_req_t *cqr;
+	dasd_ccw_req_t *cqr, *next;
 	dasd_device_t *device;
-        unsigned long long now;
-	dasd_era_t era = dasd_era_none; /* default is everything is okay */
-	devstat_t *stat = (devstat_t *)ds;
-
-        DASD_DRIVER_DEBUG_EVENT (6, dasd_int_handler,
-                                 "Interrupt: IRQ %02x, stat %02x, devno %04x",
-                                 irq,
-                                 stat->dstat,
-                                 stat->devno);
-        asm volatile ("STCK %0":"=m" (now));
-        if (stat == NULL) {
-                BUG();
-	}
-
-        /* first of all check for state change pending interrupt */
-        if ((stat->dstat & DEV_STAT_ATTENTION ) && 
-            (stat->dstat & DEV_STAT_DEV_END   ) &&
-            (stat->dstat & 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;
-        }
-
-	ip = stat->intparm;
-	if (!ip) {		/* no intparm: unsolicited interrupt */
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "Unsolicited Interrupt: %04x",
-                                         stat->devno);
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "unsolicited interrupt: irq 0x%x devno %04x\n",
-                        irq,
-                        stat->devno);
+	unsigned long long now;
+	int expires;
+	dasd_era_t era;
+	devstat_t *stat;
+	char mask;
+
+	now = get_clock();
+	stat = (devstat_t *) ds;
+
+	DBF_EVENT(DBF_DEBUG, "Interrupt: IRQ %02x, stat %02x, devno %04x",
+		  irq, stat->dstat, stat->devno);
+
+	/* first of all check for state change pending interrupt */
+	mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
+	if ((stat->dstat & mask) == mask) {
+		dasd_handle_state_change_pending(stat);
 		return;
 	}
-	if (ip & 0x80000001) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "spurious Interrupt: %04x",
-                                         stat->devno);
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "spurious interrupt: irq 0x%x devno %04x, parm %08x\n",
-                        irq,
-                        stat->devno,ip);
+
+	if (stat->intparm == 0) {	/* no intparm: unsolicited interrupt */
+		MESSAGE(KERN_DEBUG,
+			"unsolicited interrupt: irq 0x%x devno %04x",
+			irq, stat->devno);
 		return;
 	}
 
-	cqr = (ccw_req_t *)(long)ip;
-
-        /* check status - the request might have been killed because of dyn dettach */
-	if (cqr->status != CQR_STATUS_IN_IO) {
-                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
-                                         "invalid status %02x on device %04x",
-                                         cqr->status,
-                                         stat->devno);
-
-		printk (KERN_DEBUG PRINTK_HEADER
-                        "invalid status: irq 0x%x devno %04x, status %02x\n",
-                        irq,
-                        stat->devno,
-                        cqr->status);
+	cqr = (dasd_ccw_req_t *) (unsigned long) stat->intparm;
+	/*
+	 * check status - the request might have been killed
+	 * because of dyn detach
+	 */
+	if (cqr->status != DASD_CQR_IN_IO) {
+		MESSAGE(KERN_DEBUG,
+			"invalid status: irq 0x%x devno %04x, status %02x",
+			irq, stat->devno, cqr->status);
 		return;
 	}
 
 	device = (dasd_device_t *) cqr->device;
-	if (device == NULL || 
-            device != ds-offsetof(dasd_device_t,dev_status)) {
-                BUG();
-	}
-	if (device->devinfo.irq != irq) {
-                BUG();
-	}
-	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
-                BUG();
+	if (device == NULL ||
+	    device != ds - offsetof(dasd_device_t, dev_status) ||
+	    device->devinfo.irq != irq ||
+	    strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+		MESSAGE(KERN_DEBUG,
+			"invalid device in request: irq 0x%x devno %04x",
+			irq, stat->devno);
+		return;
 	}
 
-        /* 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));
+	DBF_DEV_EVENT(DBF_DEBUG, device,
+		      "Int: CS/DS 0x%04x", ((stat->cstat << 8) | stat->dstat));
 
-	/* first of all lets try to find out the appropriate era_action */
+	/* Find out the appropriate era_action. */
+	era = dasd_era_none;
 	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) {
+		/* The request did end abnormally. */
+		if (stat->flag & DEVSTAT_HALT_FUNCTION)
 			era = dasd_era_fatal;
-		} else {
-			era = device->discipline->examine_error (cqr, stat);
+		else
+			era = device->discipline->examine_error(cqr, stat);
+		DBF_EVENT(DBF_NOTICE, "era_code %d", era);
+	}
+	expires = 0;
+	if (era == dasd_era_none) {
+		cqr->status = DASD_CQR_DONE;
+		cqr->stopclk = now;
+		/* Start first request on queue if possible -> fast_io. */
+		if (cqr->list.next != &device->ccw_queue) {
+			next = list_entry(cqr->list.next,
+					  dasd_ccw_req_t, list);
+			if (next->status == DASD_CQR_QUEUED) {
+				if (device->discipline->start_IO(next) == 0)
+					expires = next->expires;
+				else
+					MESSAGE(KERN_WARNING, "%s",
+						"Interrupt fastpath failed!");
+			}
 		}
-                DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d",
-                                         era);
-	}
-        if ( era == dasd_era_none ) {
-                check_then_set(&cqr->status, 
-                               CQR_STATUS_IN_IO, 
-                               CQR_STATUS_DONE);
-
-                cqr->stopclk=now;
-		/* start the next queued request if possible -> fast_io */
-                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 */
+	} 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");
-		}
-
+			cqr->dstat = kmalloc(sizeof(devstat_t), GFP_ATOMIC);
+		if (cqr->dstat)
+			memcpy(cqr->dstat, stat, sizeof (devstat_t));
+		else
+			MESSAGE(KERN_ERR, "%s",
+				"no memory for dstat...ignoring");
 #ifdef ERP_DEBUG
 		/* dump sense data */
-		if (device->discipline            && 
-                    device->discipline->dump_sense  ) {
-
-                        device->discipline->dump_sense (device, 
-                                                        cqr);
-		}
+		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);
-
-                        cqr->stopclk = now;
+			cqr->status = DASD_CQR_FAILED;
+			cqr->stopclk = now;
 			break;
 		case dasd_era_recover:
-			check_then_set (&cqr->status, 
-                                        CQR_STATUS_IN_IO,
-					CQR_STATUS_ERROR);
+			cqr->status = DASD_CQR_ERROR;
 			break;
 		default:
-			BUG ();
+			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);
-
-} /* end dasd_int_handler */
-
-/* SECTION: Some stuff related to error recovery */
+	if (expires != 0)
+		dasd_set_timer(device, expires);
+	else
+		dasd_clear_timer(device);
+	dasd_schedule_bh(device);
+}
 
 /*
- * DEFAULT_ERP_ACTION
- *
- * DESCRIPTION
- *   sets up the default-ERP ccw_req_t, namely one, which performs a TIC
- *   to the original channel program with a retry counter of 16
- *
- * PARAMETER
- *   cqr                failed CQR
- *
- * RETURN VALUES
- *   erp                CQR performing the ERP
+ * posts the buffer_cache about a finalized request
  */
-ccw_req_t *
-dasd_default_erp_action (ccw_req_t * cqr)
+static inline void
+dasd_end_request(struct request *req, int uptodate)
 {
-
-        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);
-
-                asm volatile ("STCK %0":"=m" (cqr->stopclk));
-
-                return cqr;
-	}
-
-	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr;
-	erp->function = dasd_default_erp_action;
-	erp->refers = 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;
-
-} /* end dasd_default_erp_action */
+	if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
+		BUG();
+	add_blkdev_randomness(major(req->rq_dev));
+	end_that_request_last(req);
+	return;
+}
 
 /*
- * DEFAULT_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.
- *   NOTE: This function is only called if no discipline postaction
- *         is available
- *
- * PARAMETER
- *   erp                current erp_head
- *
- * RETURN VALUES
- *   cqr                pointer to the original CQR
+ * Process finished error recovery ccw.
  */
-ccw_req_t *
-dasd_default_erp_postaction (ccw_req_t *erp)
+static inline void
+__dasd_process_erp(dasd_device_t *device, dasd_ccw_req_t *cqr)
 {
+	dasd_erp_fn_t erp_fn;
 
-	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;
+	if (cqr->status == DASD_CQR_DONE)
+		DBF_DEV_EVENT(DBF_NOTICE, device, "%s", "ERP successful");
 	else
-		success = 0;
-
-	/* 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);
-
-                asm volatile ("STCK %0":"=m" (cqr->stopclk));
-	}
-
-	return cqr;
-
-} /* end default_erp_postaction */
-
-/* SECTION: The helpers of the struct file_operations */
+		DEV_MESSAGE(KERN_ERR, device, "%s", "ERP unsuccessful");
+	erp_fn = device->discipline->erp_postaction(cqr);
+	erp_fn(cqr);
+}
 
 /*
- * 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
- * devices this means CCWs are generated to format a single track.
+ * Process ccw request queue.
  */
-
-static int
-dasd_format (dasd_device_t * device, format_data_t * fdata)
-{
-	int rc = 0;
-	int openct = atomic_read (&device->open_count);
-
-	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;
-		}
-		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) ) {
-			rc = -ERESTARTSYS;
-			break;		
-                }
-		fdata->start_unit++;
-	}
-	return rc;
-}				/* end dasd_format */
-
-static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls);
-
-static dasd_ioctl_list_t *
-dasd_find_ioctl (int no)
+static inline void
+__dasd_process_ccw_queue(dasd_device_t * device, struct list_head *final_queue)
 {
-	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);
+	struct list_head *l, *n;
+	dasd_ccw_req_t *cqr;
+	dasd_erp_fn_t erp_fn;
+
+restart:
+	/* Process request with final status. */
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, dasd_ccw_req_t, list);
+		/* Stop list processing at the first non-final request. */
+		if (cqr->status != DASD_CQR_DONE &&
+		    cqr->status != DASD_CQR_FAILED &&
+		    cqr->status != DASD_CQR_ERROR)
+			break;
+		/*  Process requests with DASD_CQR_ERROR */
+		if (cqr->status == DASD_CQR_ERROR) {
+			cqr->retries--;
+			if (cqr->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+				cqr->status = DASD_CQR_FAILED;
+				cqr->stopclk = get_clock();
+			} else {
+				erp_fn = device->discipline->erp_action(cqr);
+				erp_fn(cqr);
+			}
+			goto restart;
 		}
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_process_erp(device, cqr);
+			goto restart;
+		}
+
+		/* Dechain request from device request queue ... */
+		cqr->endclk = get_clock();
+		list_del(&cqr->list);
+		/* ... and add it to list of final requests. */
+		list_add_tail(&cqr->list, final_queue);
 	}
-	return NULL;
 }
 
-int
-dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler)
+static void
+dasd_end_request_cb(dasd_ccw_req_t * cqr, void *data)
 {
-	dasd_ioctl_list_t *new;
-	if (dasd_find_ioctl (no))
-		return -EBUSY;
-	new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL);
-	if (new == NULL)
-		return -ENOMEM;
-	new->owner = owner;
-	new->no = no;
-	new->handler = handler;
-	list_add (&new->list, &dasd_ioctls);
-	MOD_INC_USE_COUNT;
-	return 0;
-}
+	struct request *req;
 
-int
-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 || owner != old->owner )
-		return -EINVAL;
-	list_del (&old->list);
-	kfree (old);
-	MOD_DEC_USE_COUNT;
-	return 0;
+	req = (struct request *) data;
+	dasd_profile_end(cqr->device, cqr, req);
+	dasd_end_request(req, (cqr->status == DASD_CQR_DONE));
+	dasd_sfree_request(cqr, cqr->device);
 }
 
-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;
-		invalidate_device(MKDEV (major, start+i), 1);
-	}
-        dasd_destroy_partitions(device);
-        dasd_setup_partitions(device);
-        return rc;
 
-}
-static int
-do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
+/*
+ * Fetch requests from the block device queue.
+ */
+static inline void
+__dasd_process_blk_queue(dasd_device_t * device)
 {
-	int rc = 0;
-	dasd_device_t *device = dasd_device_from_kdev (inp->i_rdev);
-	major_info_t *major_info;
-
-	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as device (%d:%d)\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
-		return -EINVAL;
-	}
-	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
-		PRINT_DEBUG ("empty data ptr");
-		return -EINVAL;
-	}
-	major_info = device->major_info;
-#if 0
-	printk (KERN_DEBUG PRINTK_HEADER
-		"ioctl 0x%08x %s'0x%x'%d(%d) on /dev/%s (%d:%d,"
-		" devno 0x%04x on irq %d) with 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),
-		device->name, 
-                MAJOR (inp->i_rdev), 
-                MINOR (inp->i_rdev),
-		device->devinfo.devno, 
-                device->devinfo.irq, 
-                data);
-#endif
-	switch (no) {
-        case DASDAPIVER: {
-			int ver = DASD_API_VERSION;
-			rc = put_user(ver, (int *) data);
-			break;
-        }
-	case BLKRRPART:{
-			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);
-			if (rc)
-				break;
-
-			rc = copy_to_user ((struct hd_geometry *) data, &geo,
-					   sizeof (struct hd_geometry));
-			if (rc)
-				rc = -EFAULT;
-			break;
-		}
-	case BIODASDDISABLE:{
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-                        if ( device->level > DASD_STATE_ACCEPT) {
-                                dasd_deactivate_queue(device);
-                                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;
-        }
-	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;
-			}
-                        if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
-                                rc = -EROFS;
-                                break;
-                        }
-			if (!data) {
-				rc = -EINVAL;
-				break;
-			}
-			rc = copy_from_user (&fdata, (void *) data,
-					     sizeof (format_data_t));
-			if (rc) {
-				rc = -EFAULT;
-				break;
-			}
-			if (partn != 0) {
-				DASD_MESSAGE (KERN_WARNING, device, "%s",
-					      "Cannot low-level format a partition");
-				return -EINVAL;
-			}
-			rc = dasd_format (device, &fdata);
-			break;
-		}
-	case BIODASDPRRST:{     /* reset device profile information */
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			memset (&device->profile, 0,
-				sizeof (dasd_profile_info_t));
-			break;
-		}
-	case BIODASDPRRD:{      /* retrun device profile information */
-			rc = copy_to_user((long *)data,
-					  (long *)&device->profile,
-					  sizeof(dasd_profile_info_t));
-			if (rc)
-				rc = -EFAULT;
-			break;
-		}
-	case BIODASDRSRV:{      /* reserve */
-			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:{      /* release */
-			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:{      /* steal lock - unconditional reserve */
-			ccw_req_t *req;
-			if (!capable (CAP_SYS_ADMIN)) {
-				rc = -EACCES;
-				break;
-			}
-			req = device->discipline->steal_lock (device);
-			rc = dasd_sleep_on_req (req);
-			dasd_free_request (req, device);
-			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;
-				request_queue_t *q = drive->request_queue;
-				ccw_req_t *cqr = device->queue.head;
-				spin_lock_irqsave (&q->queue_lock, flags);
-				list_for_each (l, q->queue_head, queue_head)
-					dasd_info.req_queue_len++;
-				spin_unlock_irqrestore (&q->queue_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_bdev, no, data);
-			else
-				rc = -EINVAL; 
-		}
-		break;
-		}
-#endif /* 0 */
-	case BLKGETSIZE:
-	case BLKGETSIZE64:
-	case BLKSSZGET:
-	case BLKROSET:
-	case BLKROGET:
-	case BLKFLSBUF:
-	case BLKPG:
-	case BLKELVGET:
-	case BLKELVSET:
-		return blk_ioctl (inp->i_bdev, no, data);
-		break;
-	default:{
-
-			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",
-					      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),
-					      data);
-				rc = -ENOTTY;
-			}
-			break;
-		}
-	}
-	return rc;
-}
+	request_queue_t *queue;
+	struct list_head *l;
+	struct request *req;
+	dasd_ccw_req_t *cqr;
+	int nr_queued;
 
-/* SECTION: The members of the struct file_operations */
+	queue = device->request_queue;
+	/* No queue ? Then there is nothing to do. */
+	if (queue == NULL)
+		return;
 
-static int
-dasd_ioctl (struct inode *inp, struct file *filp,
-	    unsigned int no, unsigned long data)
-{
-	int rc = 0;
-	if ((!inp) || !(inp->i_rdev)) {
-		return -EINVAL;
+	/*
+	 * We requeue request from the block device queue to the ccw
+	 * queue only in two states. In state DASD_STATE_ACCEPT the
+	 * partition detection is done and we need to requeue requests
+	 * for that. State DASD_STATE_ONLINE is normal block device
+	 * operation.
+	 */
+	if (device->state != DASD_STATE_ACCEPT &&
+	    device->state != DASD_STATE_ONLINE)
+		return;
+	nr_queued = 0;
+	/* Now we try to fetch requests from the request queue */
+	list_for_each(l, &device->ccw_queue) {
+		cqr = list_entry(l, dasd_ccw_req_t, list);
+		if (cqr->status == DASD_CQR_QUEUED)
+			nr_queued++;
+	}
+	while (!blk_queue_plugged(queue) &&
+	       !blk_queue_empty(queue) &&
+		nr_queued < DASD_CHANQ_MAX_SIZE) {
+		req = elv_next_request(queue);
+		if (is_read_only(device->kdev) && rq_data_dir(req) == WRITE) {
+			DBF_EVENT(DBF_ERR,
+				  "(%04x) Rejecting write request %p",
+				  device->devinfo.devno, req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, 0);
+			continue;
+		}
+		cqr = device->discipline->build_cp(device, req);
+		if (IS_ERR(cqr)) {
+			if (PTR_ERR(cqr) == -ENOMEM)
+				break;	/* terminate request queue loop */
+			DBF_EVENT(DBF_ERR,
+				  "(%04x) CCW creation failed on request %p",
+				  device->devinfo.devno, req);
+			blkdev_dequeue_request(req);
+			dasd_end_request(req, 0);
+			continue;
+		}
+		cqr->callback = dasd_end_request_cb;
+		cqr->callback_data = (void *) req;
+		cqr->status = DASD_CQR_QUEUED;
+		blkdev_dequeue_request(req);
+		list_add_tail(&cqr->list, &device->ccw_queue);
+		dasd_profile_start(device, cqr, req);
+		nr_queued++;
 	}
-	rc = do_dasd_ioctl (inp, no, data);
-	return rc;
 }
 
-static int
-dasd_open (struct inode *inp, struct file *filp)
+/*
+ * Take a look at the first request on the ccw queue and check
+ * if it reached its expire time.
+ */
+static inline void
+__dasd_check_expire(dasd_device_t * device)
 {
-	int rc = 0;
-        unsigned long flags;
-	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
+	unsigned long long now;
 
-	if ((!inp) || !(inp->i_rdev)) {
-		rc = -EINVAL;
-                goto fail;
+	if (list_empty(&device->ccw_queue))
+		return;
+	cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
+	if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
+		now = get_clock();
+		if (cqr->expires * (TOD_SEC / HZ) + cqr->startclk < now) {
+			if (device->discipline->term_IO(cqr) != 0)
+				/* Hmpf, try again in 1/100 sec */
+				dasd_set_timer(device, 1);
+		}
 	}
-	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));
-		rc = -EPERM;
-                goto fail;
-	}
-        spin_lock_irqsave(&discipline_lock,flags);
-	device = dasd_device_from_kdev (inp->i_rdev);
-	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as (%d:%d)\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
-		rc = -ENODEV;
-                goto unlock;
-	}
-	if (device->level <= DASD_STATE_ACCEPT ) {
-		DASD_MESSAGE (KERN_WARNING, device, " %s", 
-                              " Cannot open unrecognized device\n");
-		rc = -ENODEV;
-                goto unlock;
-	}
-	if (atomic_inc_return (&device->open_count) == 1 ) {
-                if ( device->discipline->owner )
-                        __MOD_INC_USE_COUNT(device->discipline->owner);
-        }
- unlock:
-        spin_unlock_irqrestore(&discipline_lock,flags);
- fail:
-	return rc;
 }
 
 /*
- * DASD_RELEASE
- *
- * DESCRIPTION
+ * Take a look at the first request on the ccw queue and check
+ * if it needs to be started.
  */
-static int
-dasd_release (struct inode *inp, struct file *filp)
+static inline void
+__dasd_start_head(dasd_device_t * device)
 {
-	int rc = 0;
-        int count;
-	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
+	int rc;
 
-	if ((!inp) || !(inp->i_rdev)) {
-		rc = -EINVAL;
-                goto out;
-	}
-	device = dasd_device_from_kdev (inp->i_rdev);
-	if (!device) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as %d:%d\n",
-			MAJOR (inp->i_rdev), 
-                        MINOR (inp->i_rdev));
-		rc = -EINVAL;
-                goto out;
-	}
-
-	if (device->level < DASD_STATE_ACCEPT ) {
-		DASD_MESSAGE (KERN_WARNING, device, " %s",
-                              " Cannot release unrecognized device\n");
-		rc = -ENODEV;
-                goto out;
-	}
-        count = atomic_dec_return (&device->open_count);
-        if ( count == 0) {
-                invalidate_bdev (inp->i_bdev, 0);
-                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;
+	if (list_empty(&device->ccw_queue))
+		return;
+	cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
+	if (cqr->status == DASD_CQR_QUEUED) {
+		/* try to start the first I/O that can be started */
+		rc = device->discipline->start_IO(cqr);
+		if (rc == 0)
+			dasd_set_timer(device, cqr->expires);
+		else if (rc == -EBUSY)
+				/* Hmpf, try again in 1/100 sec */
+			dasd_set_timer(device, 1);
+	}
 }
 
-static struct
-block_device_operations dasd_device_operations =
-{
-	owner:THIS_MODULE,
-	open:dasd_open,
-	release:dasd_release,
-	ioctl:dasd_ioctl,
-};
-
-/* SECTION: Management of device list */
-int
-dasd_fillgeo(kdev_t kdev,struct hd_geometry *geo)
-{
-	dasd_device_t *device = dasd_device_from_kdev (kdev);
-
-	if (!device)
-                return -EINVAL;
-
-        if (!device->discipline->fill_geometry)
-		return -EINVAL;
-
-	device->discipline->fill_geometry (device, geo);
-	geo->start = get_start_sect(kdev);
-        return 0;
-} 
-
-
-/* This one is needed for naming 18000+ possible dasd devices */
-int
-dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
+/*
+ * Remove requests from the ccw queue. 
+ */
+static void
+dasd_flush_ccw_queue(dasd_device_t * device, int all)
 {
-	int len = 0;
-	char first, second, third;
-
-	if (hd) {
-		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);
-			if (&major_info->gendisk == hd) {
-				break;
-			}
-			index += DASD_PER_MAJOR;
-		}
-		if (major_info == &dasd_major_info[0]) {
-			return -EINVAL;
+	struct list_head flush_queue;
+	struct list_head *l, *n;
+	dasd_ccw_req_t *cqr;
+
+	INIT_LIST_HEAD(&flush_queue);
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	list_for_each_safe(l, n, &device->ccw_queue) {
+		cqr = list_entry(l, dasd_ccw_req_t, list);
+		/* Flush all request or only block device requests? */
+		if (all == 0 && cqr->callback == dasd_end_request_cb)
+			continue;
+		if (cqr->status == DASD_CQR_IN_IO)
+			device->discipline->term_IO(cqr);
+		if (cqr->status != DASD_CQR_DONE ||
+		    cqr->status != DASD_CQR_FAILED) {
+			cqr->status = DASD_CQR_FAILED;
+			cqr->stopclk = get_clock();
+		}
+		/* Process finished ERP request. */
+		if (cqr->refers) {
+			__dasd_process_erp(device, cqr);
+			continue;
 		}
+		/* Dechain request from device request queue ... */
+		cqr->endclk = get_clock();
+		list_del(&cqr->list);
+		/* ... and add it to list of flushed requests. */
+		list_add_tail(&cqr->list, &flush_queue);
 	}
-	third = index % 26;
-	second = ((index - 26) / 26) % 26;
-	first = (((index - 702) / 26) / 26) % 26;
-
-	len = sprintf (str, "dasd");
-	if (index > 701) {
-		len += sprintf (str + len, "%c", first + 'a');
-	}
-	if (index > 25) {
-		len += sprintf (str + len, "%c", second + 'a');
-	}
-	len += sprintf (str + len, "%c", third + 'a');
-	if (partition) {
-		if (partition > 9) {
-			return -EINVAL;
-		} else {
-			len += sprintf (str + len, "%d", partition);
-		}
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
+	/* Now call the callback function of flushed requests */
+	list_for_each_safe(l, n, &flush_queue) {
+		cqr = list_entry(l, dasd_ccw_req_t, list);
+		if (cqr->callback != NULL)
+			(cqr->callback)(cqr, cqr->callback_data);
 	}
-	str[len] = '\0';
-	return 0;
 }
 
+/*
+ * Acquire the device lock and process queues for the device.
+ */
 static void
-dasd_plug_device (dasd_device_t * device)
+dasd_tasklet(dasd_device_t * device)
 {
-	atomic_set(&device->plugged,1);	
+	struct list_head final_queue;
+	struct list_head *l, *n;
+	dasd_ccw_req_t *cqr;
+
+	atomic_set (&device->tasklet_scheduled, 0);
+	INIT_LIST_HEAD(&final_queue);
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	/* Check expire time of first request on the ccw queue. */
+	__dasd_check_expire(device);
+	/* Finish off requests on ccw queue */
+	__dasd_process_ccw_queue(device, &final_queue);
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
+	/* Now call the callback function of requests with final status */
+	list_for_each_safe(l, n, &final_queue) {
+		cqr = list_entry(l, dasd_ccw_req_t, list);
+		list_del(&cqr->list);
+		if (cqr->callback != NULL)
+			(cqr->callback)(cqr, cqr->callback_data);
+	}
+	spin_lock_irq(&device->request_queue_lock);
+	spin_lock(get_irq_lock(device->devinfo.irq));
+	/* Get new request from the block device request queue */
+	__dasd_process_blk_queue(device);
+	/* Now check if the head of the ccw queue needs to be started. */
+	__dasd_start_head(device);
+	spin_unlock(get_irq_lock(device->devinfo.irq));
+	spin_unlock_irq(&device->request_queue_lock);
+	/* FIXME: what if ref_count == 0 && state == DASD_STATE_NEW ?? */
+	atomic_dec(&device->ref_count);
 }
 
-static void
-dasd_unplug_device (dasd_device_t * device)
+/*
+ * Schedules a call to dasd_process_queues over the device tasklet.
+ */
+void
+dasd_schedule_bh(dasd_device_t * device)
 {
-	atomic_set(&device->plugged,0);	
-        dasd_schedule_bh(device);
+	/* Protect against rescheduling. */
+	if (atomic_compare_and_swap (0, 1, &device->tasklet_scheduled))
+		return;
+	atomic_inc(&device->ref_count);
+	tasklet_hi_schedule(&device->tasklet);
 }
 
-static void
-dasd_flush_chanq ( dasd_device_t * device, int destroy ) 
+/*
+ * Queue a request to the head of the ccw_queue. Start the I/O if
+ * possible.
+ */
+void
+dasd_add_request_head(dasd_ccw_req_t *req)
 {
-        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;
-                                asm volatile ("STCK %0":"=m" (cqr->stopclk));
-
-                        }
-                        dasd_schedule_bh(device);
-                        cqr = cqr->next;
-                }
-                s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-        }
-        wait_event( device->wait_q, device->queue.head == NULL );
-}
+	dasd_device_t *device;
+	unsigned long flags;
 
-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)); 
-        } 
+	device = req->device;
+	spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+	req->status = DASD_CQR_QUEUED;
+	req->device = device;
+	list_add(&req->list, &device->ccw_queue);
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh(device);
+	spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
 }
 
-static int
-dasd_disable_volume ( dasd_device_t * device, int force ) 
+/*
+ * Queue a request to the tail of the ccw_queue. Start the I/O if
+ * possible.
+ */
+void
+dasd_add_request_tail(dasd_ccw_req_t *req)
 {
-        int rc = 0;
-        int target  = DASD_STATE_KNOWN;
-        int count = atomic_read (&device->open_count);
-        
-	if ( count ) {
-		DASD_MESSAGE (KERN_EMERG, device, "%s",
-			      "device has vanished although it was open!");
-        }
-        if ( force ) {
-                dasd_deactivate_queue(device);
-                dasd_flush_chanq(device,force);
-                dasd_flush_request_queues(device,force);
-                dasd_disable_blkdev(device);
-                target = DASD_STATE_DEL;
-        }
+	dasd_device_t *device;
+	unsigned long flags;
 
-        /* unregister partitions ('ungrok_partitions') */
-        devfs_register_partitions(&device->major_info->gendisk,
-                                  MINOR(device->kdev),1);
-        
-        DASD_MESSAGE (KERN_WARNING, device, 
-                      "disabling device, target state: %d",target);
-
-        dasd_set_device_level (device->devinfo.devno, 
-                               device->discipline, 
-                               target);
-        return rc;
+	device = req->device;
+	spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+	req->status = DASD_CQR_QUEUED;
+	req->device = device;
+	list_add_tail(&req->list, &device->ccw_queue);
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh(device);
+	spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
 }
 
+/*
+ * Wakeup callback.
+ */
 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);
+dasd_wakeup_cb(dasd_ccw_req_t *cqr, void *data)
+{
+	wake_up((wait_queue_head_t *) data);
 }
 
-static void
-dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all ) 
+static inline int
+_wait_for_wakeup(dasd_ccw_req_t *cqr)
 {
-        int retries = 0;
-	int j;
-        kdev_t tempdev;
-	dasd_range_t *rrange;
+	dasd_device_t *device;
+	int rc;
 
-	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 );
+	device = cqr->device;
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	rc = cqr->status == DASD_CQR_DONE || cqr->status == DASD_CQR_FAILED;
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
+	return rc;
 }
 
-#ifdef CONFIG_DASD_DYNAMIC
 /*
- * DASD_NOT_OPER_HANDLER
- *
- * DESCRIPTION
- *   handles leaving devices
+ * Attempts to start a special ccw queue and waits for its completion.
  */
-static void
-dasd_not_oper_handler (int irq, int status)
+int
+dasd_sleep_on(dasd_ccw_req_t * cqr)
 {
-	dasd_device_t *device = NULL;
-	major_info_t *major_info = NULL;
-	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);
-		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;
-	}
+	wait_queue_head_t wait_q;
+	dasd_device_t *device;
+	int rc;
+	
+	device = cqr->device;
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	
+	init_waitqueue_head (&wait_q);
+	cqr->callback = dasd_wakeup_cb;
+	cqr->callback_data = (void *) &wait_q;
+	cqr->status = DASD_CQR_QUEUED;
+	list_add_tail(&cqr->list, &device->ccw_queue);
+	
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh(device);
+	
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
 
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_not_oper_handler, 
-                                 "called for devno %04x", 
-                                 devno);
-
-	if (devno < 0) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"not_oper_handler called on irq 0x%04x no devno!\n", 
-                        irq);
-		return;
-	}
-        dasd_disable_volume(device, 1);
+	wait_event(wait_q, _wait_for_wakeup(cqr));
+	
+	/* Request status is either done or failed. */
+	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	return rc;
 }
 
 /*
- * DASD_OPER_HANDLER
- *
- * DESCRIPTION
- *   called by the machine check handler to make an device operational
+ * Attempts to start a special ccw queue and wait interruptible
+ * for its completion.
  */
 int
-dasd_oper_handler (int irq, devreg_t * devreg)
+dasd_sleep_on_interruptible(dasd_ccw_req_t * cqr)
 {
-	int devno;
-	int rc = 0;
-	major_info_t *major_info = NULL;
-        dasd_range_t *rptr,range;
-        dasd_device_t *device = NULL;
-	struct list_head *l;
-        int i;
+	wait_queue_head_t wait_q;
+	dasd_device_t *device;
+	int rc, finished;
 
-	devno = get_devno_by_irq (irq);
-	if (devno == -ENODEV) {
-		rc = -ENODEV;
-                goto out;
-	}
-
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_oper_handler, 
-                                 "called for devno %04x", 
-                                 devno);
-
-	/* find out devno of device */
-	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 */
+	device = cqr->device;
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
 
-static inline dasd_device_t **
-dasd_find_device_addr ( int devno ) 
-{
-        dasd_device_t **device_addr;
+	init_waitqueue_head (&wait_q);
+	cqr->callback = dasd_wakeup_cb;
+	cqr->callback_data = (void *) &wait_q;
+	cqr->status = DASD_CQR_QUEUED;
+	list_add_tail(&cqr->list, &device->ccw_queue);
 
-	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;
-}
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh(device);
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
 
-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;
+	finished = 0;
+	while (!finished) {
+		rc = wait_event_interruptible(wait_q, _wait_for_wakeup(cqr));
+		if (rc != -ERESTARTSYS) {
+			/* Request status is either done or failed. */
+			rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+			break;
+		}
+		spin_lock_irq(get_irq_lock(device->devinfo.irq));
+		if (cqr->status == DASD_CQR_IN_IO &&
+		    device->discipline->term_IO(cqr) == 0) {
+			list_del(&cqr->list);
+			finished = 1;
 		}
-		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;
+		spin_unlock_irq(get_irq_lock(device->devinfo.irq));
 	}
-#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;
-#ifdef CONFIG_ARCH_S390X
- noidal:
-        free_page ((long) device->lowmem_ccws);
-#endif
- noccw:
-        kfree(device);
- out:
-        return rc;
+	return rc;
 }
 
+/*
+ * Whoa nelly now it gets really hairy. For some functions (e.g. steal lock
+ * for eckd devices) the currently running request has to be terminated
+ * and be put back to status queued, before the special request is added
+ * to the head of the queue. Then the special request is waited on normally.
+ */
 static inline int
-dasd_state_new_to_del (dasd_device_t **addr )
+_dasd_term_running_cqr(dasd_device_t *device)
 {
-        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;
-}
+	dasd_ccw_req_t *cqr;
+	int rc;
 
-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 (list_empty(&device->ccw_queue))
+		return 0;
+	cqr = list_entry(device->ccw_queue.next, dasd_ccw_req_t, list);
+	rc = device->discipline->term_IO(cqr);
+	if (rc == 0) {
+		/* termination successful */
+		cqr->status = DASD_CQR_QUEUED;
+		cqr->startclk = cqr->stopclk = 0;
 	}
-        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;
-        }
-
-	DASD_DRIVER_DEBUG_EVENT (5, dasd_state_new_to_known, 
-                                 "got devinfo CU-type %04x and dev-type %04x", 
-                                 device->devinfo.sid_data.cu_type,
-                                 device->devinfo.sid_data.dev_type);
-
-
-        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;
+	return rc;
 }
 
-static inline int
-dasd_state_accept_to_init (dasd_device_t *device) 
+int
+dasd_sleep_on_immediatly(dasd_ccw_req_t * cqr)
 {
-        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;
-}
+	wait_queue_head_t wait_q;
+	dasd_device_t *device;
+	int rc;
+	
+	device = cqr->device;
+	spin_lock_irq(get_irq_lock(device->devinfo.irq));
+	rc = _dasd_term_running_cqr(device);
+	if (rc) {
+		spin_unlock_irq(get_irq_lock(device->devinfo.irq));
+		return rc;
+	}
+	
+	init_waitqueue_head (&wait_q);
+	cqr->callback = dasd_wakeup_cb;
+	cqr->callback_data = (void *) &wait_q;
+	cqr->status = DASD_CQR_QUEUED;
+	list_add(&cqr->list, &device->ccw_queue);
+	
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh(device);
+	
+	spin_unlock_irq(get_irq_lock(device->devinfo.irq));
 
-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 ) {
-                /* This pointer is no longer needed, BUT dont't free the       */ 
-                /* memory, because this is done in bh for finished request!!!! */
-                atomic_dec(&dasd_init_pending);
-                device->init_cqr = NULL; 
-        }
-        device->level = DASD_STATE_READY;
-        return rc;
+	wait_event(wait_q, _wait_for_wakeup(cqr));
+	
+	/* Request status is either done or failed. */
+	rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+	return rc;
 }
 
-static inline int
-dasd_state_ready_to_accept (dasd_device_t *device ) 
+/*
+ * Cancels a request that was started with dasd_sleep_on_req.
+ * This is usefull to timeout requests. The request will be
+ * terminated if it is currently in i/o.
+ * Returns 1 if the request has been terminated.
+ */
+int dasd_cancel_req(dasd_ccw_req_t *cqr)
 {
-        int rc = 0;
-        unsigned long flags;
-
-        s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-        if ( device->init_cqr != NULL &&  atomic_read(&dasd_init_pending) != 0 ) {
-                if ( device->discipline->term_IO == NULL )
-                        BUG();
-                device->discipline->term_IO (device->init_cqr);
-                atomic_dec (&dasd_init_pending);
-                dasd_free_request (device->init_cqr, device);
-                device->init_cqr = NULL;
-        }
-        s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags);
-        memset(&device->sizes,0,sizeof(dasd_sizes_t));
-        device->level = DASD_STATE_ACCEPT;
-        return rc;
-}
+	dasd_device_t *device = cqr->device;
+	unsigned long flags;
+	int 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;
-}
+	rc = 0;
+	spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+	switch (cqr->status) {
+	case DASD_CQR_QUEUED:
+		/* request was not started - just set to failed */
+		cqr->status = DASD_CQR_FAILED;
+		break;
+	case DASD_CQR_IN_IO:
+		/* request in IO - terminate IO and release again */
+		if (device->discipline->term_IO(cqr) != 0)
+			/* what to do if unable to terminate ??????
+			   e.g. not _IN_IO */
+			cqr->status = DASD_CQR_FAILED;
+		cqr->stopclk = get_clock();
+		rc = 1;
+		break;
+	case DASD_CQR_DONE:
+	case DASD_CQR_FAILED:
+		/* already finished - do nothing */
+		break;
+	default:
+		DEV_MESSAGE(KERN_ALERT, device,
+			    "invalid status %02x in request",
+			    cqr->status);
+		BUG();
 
-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;
+	}
+	spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
+	dasd_schedule_bh(device);
+	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);
-
-        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_hardsect_size(device->request_queue, device->sizes.bp_block);
-        elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
-
-        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;
-		blk_queue_max_sectors(device->request_queue,
-		 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;
-        }
-        return rc;
-}
+/*
+ * SECTION: Block device operations (request queue, partitions, open, release).
+ */
 
+/*
+ * Dasd request queue function. Called from ll_rw_blk.c
+ */
 static void
-dasd_deactivate_queue (dasd_device_t *device)
+do_dasd_request(request_queue_t * queue)
 {
-        int i;
-        int minor = MINOR(device->kdev);
+	dasd_device_t *device;
 
-        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                device->major_info->gendisk.sizes[minor + i] = 0;
-        }
+	device = (dasd_device_t *) queue->queuedata;
+	spin_lock(get_irq_lock(device->devinfo.irq));
+	/* Get new request from the block device request queue */
+	__dasd_process_blk_queue(device);
+	/* Now check if the head of the ccw queue needs to be started. */
+	__dasd_start_head(device);
+	spin_unlock(get_irq_lock(device->devinfo.irq));
 }
 
-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;
-        }
-        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
+ * Allocate request queue and initialize gendisk info for device.
  */
-static inline void
-dasd_setup_partitions ( dasd_device_t * device ) 
+static int
+dasd_setup_blkdev(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 max, rc;
 
-static inline void
-dasd_destroy_partitions ( dasd_device_t * device ) 
-{
-        int i;
-        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;
-        }
-        devfs_register_partitions(&device->major_info->gendisk,
-                                  MINOR(device->kdev),1);
+	device->request_queue = kmalloc(sizeof (request_queue_t), GFP_KERNEL);
+	if (device->request_queue == NULL)
+		return -ENOMEM;
+	device->request_queue->queuedata = device;
+	rc = blk_init_queue(device->request_queue, do_dasd_request,
+			    &device->request_queue_lock);
+	if (rc)
+		return rc;
+	elevator_exit(device->request_queue, &device->request_queue->elevator);
+	rc = elevator_init(device->request_queue,
+			   &device->request_queue->elevator,
+			   elevator_noop);
+	if (rc) {
+		blk_cleanup_queue(device->request_queue);
+		return rc;
+	}
+	blk_queue_hardsect_size(device->request_queue, device->bp_block);
+	max = device->discipline->max_blocks << device->s2b_shift;
+	blk_queue_max_sectors(device->request_queue, max);
+	blk_queue_max_phys_segments(device->request_queue, -1L);
+	blk_queue_max_hw_segments(device->request_queue, -1L);
+	blk_queue_max_segment_size(device->request_queue, -1L);
+	blk_queue_segment_boundary(device->request_queue, -1L);
+	return 0;
 }
 
-static inline void
-dasd_resetup_partitions ( dasd_device_t * device ) 
+/*
+ * Deactivate and free request queue.
+ */
+static void
+dasd_disable_blkdev(dasd_device_t * device)
 {
-    BUG();
-    dasd_destroy_partitions ( device ) ;
-    dasd_setup_partitions ( device ) ;
+	if (device->request_queue) {
+		blk_cleanup_queue(device->request_queue);
+		kfree(device->request_queue);
+		device->request_queue = NULL;
+	}
 }
 
 /*
- * function dasd_set_device_level
+ * Flush request on the request queue.
  */
-static int
-dasd_set_device_level (unsigned int devno, 
-                       dasd_discipline_t * discipline,
-                       int to_state)
-{
-	int rc = 0;
-        dasd_device_t **device_addr;
-        dasd_device_t *device;
-        int from_state;
-
-        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;
-        }
-
-        DASD_DRIVER_DEBUG_EVENT (3, dasd_set_device_level,
-                                 "devno %04x; from %i to %i",
-                                 devno,
-                                 from_state,
-                                 to_state);
-
-        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
-        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 */
-typedef struct {
-	char *data;
-	int len;
-} tempinfo_t;
-
-void
-dasd_fill_inode (struct inode *inode, int fill)
+static void
+dasd_flush_request_queue(dasd_device_t * device)
 {
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-}
+	struct request *req;
 
-static struct proc_dir_entry *dasd_proc_root_entry = NULL;
-static struct proc_dir_entry *dasd_devices_entry;
-static struct proc_dir_entry *dasd_statistics_entry;
+	if (!device->request_queue)
+		return;
+	
+	spin_lock_irq(&device->request_queue_lock);
+	while (!list_empty(&device->request_queue->queue_head)) {
+		req = elv_next_request(device->request_queue);
+		if (req == NULL)
+			break;
+		dasd_end_request(req, 0);
+		blkdev_dequeue_request(req);
+	}
+	spin_unlock_irq(&device->request_queue_lock);
+}
 
 static int
-dasd_devices_open (struct inode *inode, struct file *file)
+dasd_open(struct inode *inp, struct file *filp)
 {
-	int rc = 0;
-	int size = 1;
-	int len = 0;
-	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");
-                MOD_DEC_USE_COUNT;
-                return -ENOMEM;
-	} else {
-		file->private_data = (void *) info;
-	}
-	list_for_each (l, &dasd_major_info[0].list) {
-                size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
-	}
-	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;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int rc;
+	
+	if ((!inp) || kdev_none(inp->i_rdev))
+		return -EINVAL;
+	if (dasd_probeonly) {
+		MESSAGE(KERN_INFO,
+			"No access to device (%d:%d) due to probeonly mode",
+			major(inp->i_rdev), minor(inp->i_rdev));
+		return -EPERM;
+	}
+	devmap = dasd_devmap_from_kdev(inp->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device)) {
+		MESSAGE(KERN_WARNING,
+			"No device registered as (%d:%d)",
+			major(inp->i_rdev), minor(inp->i_rdev));
+		return PTR_ERR(device);
+	}
+	if (device->state < DASD_STATE_BASIC) {
+		DBF_DEV_EVENT(DBF_ERR, device, " %s",
+			      " Cannot open unrecognized device");
+		dasd_put_device(devmap);
+		return -ENODEV;
 	}
-	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;
-                        int devno = dasd_devno_from_devindex(index+i);
-                        int features;
-
-                        if ( devno == -ENODEV )
-                                continue;
-
-                        features = dasd_features_from_devno(devno);
-                        if (features < DASD_DEFAULT_FEATURES)
-                                features = DASD_DEFAULT_FEATURES;
-
-                        device = temp->dasd_device[i];
-			if (device) {
-
-				len += sprintf (info->data + len,
-						"%04x(%s) at (%3d:%3d) is %-7s%4s: ",
-						device->devinfo.devno,
-						device->discipline ?
-						device->
-						discipline->name : "none",
-						temp->gendisk.major,
-						i << DASD_PARTN_BITS,
-						device->name,
-                                                (features & DASD_FEATURE_READONLY) ? 
-                                                "(ro)" : " ");
-                                
-				switch (device->level) {
-				case DASD_STATE_NEW:
-                                        len +=
-					    sprintf (info->data + len,
-						     "new");
-                                        break;
-				case DASD_STATE_KNOWN:
-					len +=
-					    sprintf (info->data + len,
-						     "detected");
-					break;
-				case DASD_STATE_ACCEPT:
-                                        len += sprintf (info->data + len,"accepted");
-					break;
-				case DASD_STATE_INIT:
-					len +=
-					    sprintf (info->data + len,
-						     "busy   ");
-					break;
-				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");
-					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%4s: unknown",
-						temp->gendisk.major,
-						i << DASD_PARTN_BITS,
-						buffer,
-                                                (features & DASD_FEATURE_READONLY) ? 
-                                                "(ro)" : " ");
-                        }
-                        if ( dasd_probeonly )
-                            len += sprintf(info->data + len,"(probeonly)");
-                        len += sprintf(info->data + len,"\n");
+	rc = 0;
+	spin_lock(&discipline_lock);
+	if (atomic_inc_return(&device->open_count) == 1 &&
+	    device->discipline->owner != NULL) {
+		if (!try_inc_mod_count(device->discipline->owner)) {
+			/* Discipline is currently unloaded! */
+			atomic_dec(&device->open_count);
+			rc = -ENODEV;
 		}
-                index += 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
-	info->len = len;
-        spin_unlock_irqrestore(&discipline_lock,flags);
+	spin_unlock(&discipline_lock);
+	dasd_put_device(devmap);
 	return rc;
 }
 
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-static ssize_t
-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;
-
-	if (*offset >= p_info->len) {
-		return 0;	/* EOF */
-	} 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;	/* number of bytes "read" */
-	}
-}
-
-static ssize_t
-dasd_devices_write (struct file *file, const char *user_buf,
-		    size_t user_len, loff_t * offset)
+static int
+dasd_release(struct inode *inp, struct file *filp)
 {
-	char *buffer = vmalloc (user_len+1);
-	int off = 0;
-	char *temp;
-	dasd_range_t range;
-        int features;
-
-	if (buffer == NULL)
-		return -ENOMEM;
-	if (copy_from_user (buffer, user_buf, user_len)) {
-		vfree (buffer);
-		return -EFAULT;
-	}
-
-        /* replace LF with '\0' */
-        if (buffer[user_len -1] == '\n') {
-                buffer[user_len -1] = '\0';
-        } else {
-                buffer[user_len] = '\0';
-        }
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
 
-	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");
+	if ((!inp) || kdev_none(inp->i_rdev))
+		return -EINVAL;
+	devmap = dasd_devmap_from_kdev(inp->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device)) {
+		MESSAGE(KERN_WARNING,
+			"No device registered as %d:%d",
+			major(inp->i_rdev), minor(inp->i_rdev));
 		return -EINVAL;
 	}
-	off += 4;
-	while (buffer[off] && !isalnum (buffer[off]))
-		off++;
-	if (!strncmp (buffer + off, "device", strlen ("device"))) {
-		off += strlen ("device");
-		while (buffer[off] && !isalnum (buffer[off]))
-			off++;
-	}
-	if (!strncmp (buffer + off, "range=", strlen ("range="))) {
-		off += strlen ("range=");
-		while (buffer[off] && !isalnum (buffer[off]))
-			off++;
+	if (device->state < DASD_STATE_ACCEPT) {
+		DBF_DEV_EVENT(DBF_ERR, device, " %s",
+			      " Cannot release unrecognized device");
+		dasd_put_device(devmap);
+		return -EINVAL;
 	}
-	
-	temp = buffer + off;
-	range.from = dasd_strtoul (temp, &temp, &features);
-	range.to = range.from;
-
-	if (*temp == '-') {
-		temp++;
-		range.to = dasd_strtoul (temp, &temp, &features);
-	}
-
-        if (range.from == -EINVAL ||
-            range.to   == -EINVAL   ) {
-                
-                printk (KERN_WARNING PRINTK_HEADER
-                        "/proc/dasd/devices: range parse error in '%s'\n", 
-                        buffer);
-        } else {
-                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'\n",
-                                        buffer);
-                        }
-                }
-        }
-
-	vfree (buffer);
-	return user_len;
-}
-
-static int
-dasd_devices_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);
+	if (atomic_dec_return(&device->open_count) == 0) {
+		invalidate_buffers(inp->i_rdev);
+		if (device->discipline->owner)
+			__MOD_DEC_USE_COUNT(device->discipline->owner);
 	}
-	MOD_DEC_USE_COUNT;
-	return rc;
+	dasd_put_device(devmap);
+	return 0;
 }
 
-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 */
+struct
+block_device_operations dasd_device_operations = {
+	owner:THIS_MODULE,
+	open:dasd_open,
+	release:dasd_release,
+	ioctl:dasd_ioctl,
 };
 
-static struct inode_operations dasd_devices_inode_ops = {
-};
 
-static int
-dasd_statistics_open (struct inode *inode, struct file *file)
+static void
+dasd_exit(void)
 {
-	int rc = 0;
-	int len = 0;
-	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;
-	}
-	info->data = (char *) vmalloc (PAGE_SIZE);	/* FIXME! determine space needed in a better way */
-	if (info->data == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
-		vfree (info);
-		file->private_data = NULL;
-                MOD_DEC_USE_COUNT;
-		return -ENOMEM;
-	}
-        
-        /* prevent couter 'ouverflow' on output */
-	for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
-	     help > 9999999; 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, "%7d ",
-                                dasd_global_profile.dasd_io_secs[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-
-	len += sprintf (info->data + len, "Histogram of I/O times (microseconds)\n");
-	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_times[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                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");
-	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_timps[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                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, "%7d ",
-                                dasd_global_profile.dasd_io_time1[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                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");
-	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_time2[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                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");
-	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_time2ps[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                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");
-	for (i = 0; i < 16; i++) {
-		len +=
-		    sprintf (info->data + len, "%7d ",
-			     dasd_global_profile.dasd_io_time3[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_time3[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-
-	len += sprintf (info->data + len,
-                        "# of req in chanq at enqueuing (1..32) \n");
-	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_nr_req[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
-	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%7d ",
-                                dasd_global_profile.dasd_io_nr_req[i] >> shift);
-	}
-	len += sprintf (info->data + len, "\n");
+	dasd_disable_devices(0, dasd_max_devindex);
+#ifdef CONFIG_DASD_DIAG
+	if (MACHINE_IS_VM)
+		dasd_diag_cleanup();
+#endif
+#ifdef CONFIG_DASD_FBA
+	dasd_fba_cleanup();
+#endif
+#ifdef CONFIG_DASD_ECKD
+	dasd_eckd_cleanup();
+#endif
 
-	info->len = len;
-	return rc;
+#ifdef CONFIG_PROC_FS
+	dasd_proc_exit();
+#endif
+	dasd_ioctl_exit();
+	dasd_gendisk_exit();
+	dasd_devmap_exit();
+	if (dasd_devfs_handle)
+		devfs_unregister(dasd_devfs_handle);
+	if (dasd_debug_area != NULL) {
+		debug_unregister(dasd_debug_area);
+		dasd_debug_area = NULL;
+	}
 }
 
-static ssize_t
-dasd_statistics_write (struct file *file, const char *user_buf,
-		       size_t user_len, loff_t * offset)
+/*
+ * SECTION: Initializing the driver
+ */
+static int
+dasd_request_module(void *name)
 {
-	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 = {
-};
+	int rc = -ERESTARTSYS;
 
-int
-dasd_proc_init (void)
-{
-	int rc = 0;
-	dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root);
-	dasd_devices_entry = create_proc_entry ("devices",
-						S_IFREG | S_IRUGO | S_IWUSR,
-						dasd_proc_root_entry);
-	dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
-	dasd_devices_entry->proc_iops = &dasd_devices_inode_ops;
-	dasd_statistics_entry = create_proc_entry ("statistics",
-						   S_IFREG | S_IRUGO | S_IWUSR,
-						   dasd_proc_root_entry);
-	dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
-	dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
+	strcpy(current->comm, name);
+	daemonize();
+	while (current->fs->root == NULL)	/* wait for root-FS */
+		schedule_timeout(HZ);	/* wait a second */
+	while ((rc = request_module(name)) != 0) {
+		MESSAGE(KERN_INFO, "request_module returned %d for %s",
+			rc, (char *) name);
+		schedule_timeout(5 * HZ);	/* wait 5 seconds */
+	}
 	return rc;
 }
 
-void
-dasd_proc_cleanup (void)
+static int __init
+dasd_init(void)
 {
-	remove_proc_entry ("devices", dasd_proc_root_entry);
-	remove_proc_entry ("statistics", dasd_proc_root_entry);
-	remove_proc_entry ("dasd", &proc_root);
-}
-
-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;
-}
-
+	char **disc;
+	int irq, devno;
+	int rc;
 
-/* SECTION: Initializing the driver */
-int __init
-dasd_init (void)
-{
-	int rc = 0;
-	int irq;
-	major_info_t *major_info = NULL;
-	struct list_head *l;
-
-	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-	dasd_debug_area = debug_register (DASD_NAME, 0, 2, 5 * 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);
+	init_waitqueue_head(&dasd_init_waitq);
 
+	/* register 'common' DASD debug area, used faor all DBF_XXX calls */
+	dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long));
 	if (dasd_debug_area == NULL) {
+		rc = -ENOMEM;
 		goto failed;
 	}
-	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", 
-                                 "ENTRY");
-	dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
+	debug_register_view(dasd_debug_area, &debug_sprintf_view);
+	debug_set_level(dasd_debug_area, DBF_ERR);
+
+	DBF_EVENT(DBF_EMERG, "%s", "debug area created");
+
+	dasd_devfs_handle = devfs_mk_dir(NULL, "dasd", NULL);
 	if (dasd_devfs_handle < 0) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", 
-                                         "no devfs");
+		DBF_EVENT(DBF_ALERT, "%s", "no devfs");
+		rc = -ENOSYS;
 		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);
-			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register successfully to major no %d\n",
-				major_info->gendisk.major);
-			/* revert registration of major infos */
-			goto failed;
-		}
-	}
-#ifndef MODULE
-	dasd_split_parm_string (dasd_parm_string);
-#endif				/* ! MODULE */
-	rc = dasd_parse (dasd);
-	if (rc) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s",
-                                         "invalid range found");
+	rc = dasd_devmap_init();
+	if (rc)
 		goto failed;
-	}
-
-	rc = dasd_proc_init ();
-	if (rc) {
-		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
+	rc = dasd_gendisk_init();
+	if (rc)
 		goto failed;
-	}
-	genhd_dasd_name = dasd_device_name;
+	rc = dasd_parse();
+	if (rc)
+		goto failed;
+	rc = dasd_ioctl_init();
+	if (rc)
+		goto failed;
+#ifdef CONFIG_PROC_FS
+	rc = dasd_proc_init();
+	if (rc)
+		goto failed;
+#endif
 
-	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 (dasd_autodetect) {
+		/* update device range to all devices */
+		irq = get_irq_first();
+		while (irq != -ENODEV) {
+			devno = get_devno_by_irq(irq);
+			if (dasd_devmap_from_devno(devno) == NULL) {
+				/* devno not included yet */
+				DBF_EVENT(DBF_NOTICE, "add %04x to range",
+					  devno);
+				dasd_add_range(devno, devno,
+					       DASD_FEATURE_DEFAULT);
 			}
+			irq = get_irq_next(irq);
 		}
 	}
 
 	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");
+		rc = dasd_diag_init();
+		if (rc != 0) {
+			DBF_EVENT(DBF_ALERT, "%s",
+				  "Register DIAG discipline failed");
 			goto failed;
 		}
-#endif /* CONFIG_DASD_DIAG */
+#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 */
+		kernel_thread(dasd_request_module, "dasd_diag_mod", SIGCHLD);
+#endif
 	}
 #ifdef CONFIG_DASD_ECKD
-	rc = dasd_eckd_init ();
-	if (rc == 0) {
-		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");
+	rc = dasd_eckd_init();
+	if (rc != 0) {
+		DBF_EVENT(DBF_ALERT, "%s", "Register ECKD discipline failed");
 		goto failed;
 	}
-#endif /* CONFIG_DASD_ECKD */
+#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 */
+	kernel_thread(dasd_request_module, "dasd_eckd_mod", SIGCHLD);
+#endif
 #ifdef CONFIG_DASD_FBA
-	rc = dasd_fba_init ();
-	if (rc == 0) {
-		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");
+	rc = dasd_fba_init();
+	if (rc != 0) {
+		DBF_EVENT(DBF_ALERT, "%s", "Register FBA discipline failed");
 		goto failed;
 	}
-#endif /* CONFIG_DASD_FBA */
+#endif
 #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++;
-                }
-        }
-
-	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");
+	kernel_thread(dasd_request_module, "dasd_fba_mod", SIGCHLD);
+#endif				/* CONFIG_DASD_AUTO_FBA */
+	disc = dasd_disciplines;
+	while (*disc) {
+		kernel_thread(dasd_request_module, *disc, SIGCHLD);
+		disc++;
+	}
+	return 0;
+failed:
+	MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors");
+	dasd_exit();
 	return rc;
 }
 
-static void
-cleanup_dasd (void)
-{
-	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");
-	dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
-        if (MACHINE_IS_VM) {
-#ifdef CONFIG_DASD_DIAG
-                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");
-#endif /* CONFIG_DASD_ECKD_BUILTIN */
-	}
-#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_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_BUILTIN */
-        
-	dasd_proc_cleanup ();
-        
-	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) &&
-		    (rc = dasd_unregister_major (major_info)) == 0) {
-			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);
-		} else {
-			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);
-  		}
-  	}
-	list_for_each_safe (l, n, &dasd_range_head.list) {
-		range = list_entry (l, dasd_range_t, list);
-                dasd_remove_range(range);
-        }
-
-#ifndef MODULE
-        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");
-}
+module_init(dasd_init);
+module_exit(dasd_exit);
 
-#ifdef MODULE
-int
-init_module (void)
-{
-	int rc = 0;
-	rc = dasd_init ();
-	return rc;
-}
+EXPORT_SYMBOL(dasd_debug_area);
 
-void
-cleanup_module (void)
-{
-	cleanup_dasd ();
-	return;
-}
-#endif
+EXPORT_SYMBOL(dasd_add_request_head);
+EXPORT_SYMBOL(dasd_add_request_tail);
+EXPORT_SYMBOL(dasd_cancel_req);
+EXPORT_SYMBOL(dasd_clear_timer);
+EXPORT_SYMBOL(dasd_disable_devices);
+EXPORT_SYMBOL(dasd_discipline_add);
+EXPORT_SYMBOL(dasd_discipline_del);
+EXPORT_SYMBOL(dasd_enable_devices);
+EXPORT_SYMBOL(dasd_int_handler);
+EXPORT_SYMBOL(dasd_kfree_request);
+EXPORT_SYMBOL(dasd_kick_device);
+EXPORT_SYMBOL(dasd_kmalloc_request);
+EXPORT_SYMBOL(dasd_not_oper_handler);
+EXPORT_SYMBOL(dasd_oper_handler);
+EXPORT_SYMBOL(dasd_schedule_bh);
+EXPORT_SYMBOL(dasd_set_target_state);
+EXPORT_SYMBOL(dasd_set_timer);
+EXPORT_SYMBOL(dasd_sfree_request);
+EXPORT_SYMBOL(dasd_sleep_on);
+EXPORT_SYMBOL(dasd_sleep_on_immediatly);
+EXPORT_SYMBOL(dasd_sleep_on_interruptible);
+EXPORT_SYMBOL(dasd_smalloc_request);
+EXPORT_SYMBOL(dasd_start_IO);
+EXPORT_SYMBOL(dasd_term_IO);
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
@@ -4310,7 +2386,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
--- a/drivers/s390/block/dasd_3370_erp.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/block/dasd_3370_erp.c	Sat Jun  8 22:31:51 2002
@@ -5,14 +5,10 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <asm/ccwcache.h>
+#define PRINTK_HEADER "dasd_erp(3370)"
 
 #include "dasd_int.h"
-#include "dasd_3370_erp.h"
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#define PRINTK_HEADER "dasd_erp(3370)"
-#endif				/* PRINTK_HEADER */
+
 
 /*
  * DASD_3370_ERP_EXAMINE 
@@ -26,19 +22,19 @@
  *   'Chapter 7. 3370 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for all others.
+ *   dasd_era_none	no error 
+ *   dasd_era_fatal	for all fatal (unrecoverable errors)
+ *   dasd_era_recover	for all others.
  */
-dasd_era_t 
-dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_era_t
+dasd_3370_erp_examine(dasd_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;
 	if (sense[0] & 0x80) {	/* CMD reject */
 		return dasd_era_fatal;
 	}
@@ -100,7 +96,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_3370_erp.h b/drivers/s390/block/dasd_3370_erp.h
--- a/drivers/s390/block/dasd_3370_erp.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd_3370_erp.h	Sat Jun  8 22:31:37 2002
@@ -10,6 +10,6 @@
 #ifndef DASD_3370_ERP_H
 #define DASD_3370_ERP_H
 
-dasd_era_t dasd_3370_erp_examine (ccw_req_t *, devstat_t *);
+dasd_era_t dasd_3370_erp_examine(dasd_ccw_req_t *, devstat_t *);
 
 #endif				/* DASD_3990_ERP_H */
diff -Nru a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
--- a/drivers/s390/block/dasd_3990_erp.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd_3990_erp.c	Sat Jun  8 22:31:37 2002
@@ -1,185 +1,32 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_3990_erp.c
  * Author(s)......: Horst  Hummel    <Horst.Hummel@de.ibm.com> 
- *                  Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    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)
+ * 05/04/02 code restructuring.
  */
 
-#include <asm/ccwcache.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
 #include <asm/idals.h>
 #include <asm/s390io.h>
-#include <linux/timer.h>
+#include <asm/todclk.h>
+
+#define PRINTK_HEADER "dasd_erp(3990): "
 
 #include "dasd_int.h"
 #include "dasd_eckd.h"
-#include "dasd_3990_erp.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd_erp(3990): "
 
-/*
- ***************************************************************************** 
- * SECTION DEBUG ROUTINES
- ***************************************************************************** 
- */
-void
-log_erp_chain (ccw_req_t *cqr,
-               int       caller,
-               __u32     cpa)
-{
-
-        ccw_req_t     *loop_cqr = cqr;
-	dasd_device_t *device   = cqr->device;
-
-        int     i;
-        char    *nl, 
-                *end_cqr,
-                *begin, 
-                *end;
-        
-        /* dump sense data */
-        if (device->discipline            && 
-            device->discipline->dump_sense  ) {
-
-                device->discipline->dump_sense (device, 
-                                                cqr);
-        }
-
-        /* log the channel program */
-        while (loop_cqr != NULL) {
-                
-                DASD_MESSAGE (KERN_ERR, device, 
-                              "(%s) ERP chain report for req: %p",
-                              caller == 0 ? "EXAMINE" : "ACTION",
-                              loop_cqr);
-                
-                nl      = (char *) loop_cqr;
-                end_cqr = nl + sizeof (ccw_req_t); 
-                
-                while (nl < end_cqr) {
-                        
-                        DASD_MESSAGE (KERN_ERR, device, 
-                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                      "%02x%02x%02x%02x %02x%02x%02x%02x",
-                                      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 */
-
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      "Start of channel program:");
-                        
-                        for (i = 0; i < 20; i += 2) { 
-                                
-                                DASD_MESSAGE (KERN_ERR, device, 
-                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                              "%02x%02x%02x%02x %02x%02x%02x%02x",
-                                              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;
-                        }
-                        
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      "End of channel program:");
-                        
-                        nl  = (char *) loop_cqr->cpaddr;
-                        nl  += ((loop_cqr->cplength - 10) * 8);
-                        
-                        for (i = 0; i < 20; i += 2) { 
-                                
-                                DASD_MESSAGE (KERN_ERR, device, 
-                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                              "%02x%02x%02x%02x %02x%02x%02x%02x",
-                                              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 */
-                        
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      "Channel program (complete):");
-                        
-                        for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { 
-                                
-                                DASD_MESSAGE (KERN_ERR, device, 
-                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                              "%02x%02x%02x%02x %02x%02x%02x%02x",
-                                              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;
-                        }
-                }
-
-                /* log bytes arround failed CCW if not already done */ 
-                begin = (char *) loop_cqr->cpaddr;
-                end   = begin + ((loop_cqr->cplength+4) * 8);
-                nl = (void *)(long)cpa;
-
-                if (loop_cqr == cqr) {  /* log only once */
- 
-                        /* 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 */
-                                
-                                DASD_MESSAGE (KERN_ERR, device, 
-                                                "Failed CCW (%p) (area):",
-                                                (void *)(long)cpa);
-                                
-                                for (i = 0; i < 20; i += 2) { 
-                                        
-                                        DASD_MESSAGE (KERN_ERR, device, 
-                                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                      "%02x%02x%02x%02x %02x%02x%02x%02x",
-                                                      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 {
-                                
-                                DASD_MESSAGE (KERN_ERR, device, 
-                                              "Failed CCW (%p) already logged",
-                                              (void *)(long)cpa);
-                        }
-                }
-                
-                loop_cqr = loop_cqr->refers;
-        }
-        
-} /* end log_erp_chain */
+typedef struct DCTL_data_t {
+	unsigned char subcommand;	/* e.g Inhibit Write, Enable Write,... */
+	unsigned char modifier;	/* Subcommand modifier		       */
+	unsigned short res;	/* reserved */
+} __attribute__ ((packed)) DCTL_data_t;
 
 /*
  ***************************************************************************** 
@@ -202,51 +49,52 @@
  *   All other configurations are handled as recoverable errors.
  *
  * RETURN VALUES
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for all others.
+ *   dasd_era_fatal	for all fatal (unrecoverable errors)
+ *   dasd_era_recover	for all others.
  */
-dasd_era_t
-dasd_3990_erp_examine_24 (ccw_req_t *cqr,
-                          char      *sense)
+static dasd_era_t
+dasd_3990_erp_examine_24(dasd_ccw_req_t * cqr, char *sense)
 {
 
-        dasd_device_t *device = cqr->device;
-        
+	dasd_device_t *device = cqr->device;
+
 	/* check for 'Command Reject' */
-	if ((  sense[0] & SNS0_CMD_REJECT       ) &&
-	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+	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");
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "EXAMINE 24: Command Reject detected - "
+			    "fatal error");
 
-                return dasd_era_fatal;
+		return dasd_era_fatal;
 	}
 
 	/* check for 'Invalid Track Format' */
-	if ((  sense[1] & SNS1_INV_TRACK_FORMAT ) &&
-            (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+	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");
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "EXAMINE 24: Invalid Track Format detected "
+			    "- fatal error");
 
-                return dasd_era_fatal;
+		return dasd_era_fatal;
 	}
 
 	/* check for 'No Record Found' */
 	if (sense[1] & SNS1_NO_REC_FOUND) {
-                
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "EXAMINE 24: No Record Found detected "
-                              "- fatal error");
 
-                return dasd_era_fatal;
+                /* FIXME: fatal error ?!? */
+		DEV_MESSAGE(KERN_ERR, device,
+			    "EXAMINE 24: No Record Found detected %s",
+                            device->state <= DASD_STATE_BASIC ?
+			    " " : "- fatal error");
+
+		return dasd_era_fatal;
 	}
 
 	/* return recoverable for all others */
-  	return dasd_era_recover;
-} /* END dasd_3990_erp_examine_24 */
+	return dasd_era_recover;
+}				/* END dasd_3990_erp_examine_24 */
 
 /*
  * DASD_3990_ERP_EXAMINE_32 
@@ -257,24 +105,23 @@
  *   the interrupt handler.
  *
  * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for recoverable others.
+ *   dasd_era_none	no error 
+ *   dasd_era_fatal	for all fatal (unrecoverable errors)
+ *   dasd_era_recover	for recoverable others.
  */
-dasd_era_t
-dasd_3990_erp_examine_32 (ccw_req_t *cqr,
-                          char      *sense)
+static dasd_era_t
+dasd_3990_erp_examine_32(dasd_ccw_req_t * cqr, char *sense)
 {
 
-        dasd_device_t *device = cqr->device;
+	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");
+		DEV_MESSAGE(KERN_ERR, device, "%s", "EXAMINE 32: fatal error");
+
 		return dasd_era_fatal;
 
 	default:
@@ -282,7 +129,7 @@
 		return dasd_era_recover;
 	}
 
-} /* end dasd_3990_erp_examine_32 */
+}				/* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE 
@@ -296,47 +143,41 @@
  *   'Chapter 7. Error Recovery Procedures'.
  *
  * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for all others.
+ *   dasd_era_none	no error 
+ *   dasd_era_fatal	for all fatal (unrecoverable errors)
+ *   dasd_era_recover	for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine (ccw_req_t *cqr, 
-                       devstat_t *stat)
+dasd_3990_erp_examine(dasd_ccw_req_t * cqr, devstat_t * stat)
 {
 
-	char       *sense = stat->ii.sense.data;
-        dasd_era_t era    = dasd_era_recover;
+	char *sense = stat->ii.sense.data;
+	dasd_era_t era = dasd_era_recover;
+	dasd_device_t *device = cqr->device;
 
 	/* 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) {
 
-		era = dasd_3990_erp_examine_24 (cqr,
-                                                sense);
+		era = dasd_3990_erp_examine_24(cqr, sense);
 
 	} else {
 
-		era = dasd_3990_erp_examine_32 (cqr,
-                                                sense);
+		era = dasd_3990_erp_examine_32(cqr, sense);
 
-	} 
+	}
 
-        /* log the erp chain if fatal error occurred */
-        if (era == dasd_era_fatal) {
+	/* log the erp chain if fatal error occurred */
+	if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY))
+		dasd_log_ccw(cqr, 0, stat->cpa);
 
-                log_erp_chain (cqr, 
-                               0, 
-                               stat->cpa);
-        }
-        
-        return era;
+	return era;
 
-} /* END dasd_3990_erp_examine */
+}				/* END dasd_3990_erp_examine */
 
 /*
  ***************************************************************************** 
@@ -357,28 +198,22 @@
  *   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 
+ *   erp		request to be blocked
+ *   final_status	either DASD_CQR_DONE or DASD_CQR_FAILED 
  *
  * RETURN VALUES
- *   cqr                original cqr               
+ *   cqr		original cqr		   
  */
-ccw_req_t *
-dasd_3990_erp_cleanup (ccw_req_t *erp,
-                       char      final_status)
+static dasd_ccw_req_t *
+dasd_3990_erp_cleanup(dasd_ccw_req_t * erp, char final_status)
 {
+	dasd_ccw_req_t *cqr = erp->refers;
 
-        ccw_req_t *cqr = erp->refers;
-        
-        dasd_free_request (erp, erp->device);
-
-        check_then_set (&cqr->status,
-                        CQR_STATUS_ERROR,
-                        final_status);
-
-        return cqr;
+	dasd_free_erp_request(erp, erp->device);
+	cqr->status = final_status;
+	return cqr;
 
-} /* end dasd_3990_erp_cleanup */ 
+}				/* end dasd_3990_erp_cleanup */
 
 /*
  * DASD_3990_ERP_BLOCK_QUEUE 
@@ -389,82 +224,24 @@
  *   interrupt was received.
  *
  *  PARAMETER
- *   erp                request to be blocked
- *   expires            time to wait until restart (in seconds) 
+ *   erp		request to be blocked
+ *   expires		time to wait until restart (in jiffies) 
  *
  * RETURN VALUES
- *   void               
+ *   void		
  */
-void
-dasd_3990_erp_block_queue (ccw_req_t     *erp,
-                           unsigned long expires)
+static void
+dasd_3990_erp_block_queue(dasd_ccw_req_t * erp, int expires)
 {
 
 	dasd_device_t *device = erp->device;
 
-        DASD_MESSAGE (KERN_INFO, device,
-                      "blocking request queue for %is",
-                      (int) expires);
-
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_PENDING);
+	DEV_MESSAGE(KERN_INFO, device,
+		    "blocking request queue for %is", expires);
 
-        /* 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);
-
-        add_timer(&device->timer); 
-
-} /* end dasd_3990_erp_block_queue */ 
-
-/*
- * DASD_3990_ERP_RESTART_QUEUE 
- *
- * DESCRIPTION
- *   Restarts request currently in status PENDING.
- *   This has to be done if either an related interrupt has received, or 
- *   a timer has expired.
- *   
- *
- *  PARAMETER
- *   erp                pointer to the PENDING ERP
- *
- * RETURN VALUES
- *   void               
- *
- */
-void
-dasd_3990_erp_restart_queue (unsigned long erp)
-{
-
-        ccw_req_t     *cqr    = (void *) erp;
-	dasd_device_t *device = cqr->device;
-	unsigned long flags;
-        
-        /* get the needed locks to modify the request queue */
-	s390irq_spin_lock_irqsave (device->devinfo.irq, 
-                                   flags);
-
-        /* 'restart' the device queue */
-        if (cqr->status == CQR_STATUS_PENDING) {
-                
-                DASD_MESSAGE (KERN_INFO, device, "%s",
-                              "request queue restarted by MIH");
-
-                check_then_set (&cqr->status,
-                                CQR_STATUS_PENDING,
-                                CQR_STATUS_QUEUED);
-        }
-
-        /* release the lock */
-        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
-                                        flags);
-
-        dasd_schedule_bh (device);
-
-} /* end dasd_3990_erp_restart_queue */
+	erp->status = DASD_CQR_PENDING;
+	dasd_set_timer(device, expires);
+}
 
 /*
  * DASD_3990_ERP_INT_REQ 
@@ -474,38 +251,37 @@
  *   This means either device offline or not installed.
  *
  * PARAMETER
- *   erp                current erp
+ *   erp		current erp
  * RETURN VALUES
- *   erp                modified erp
+ *   erp		modified erp
  */
-ccw_req_t *
-dasd_3990_erp_int_req (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_int_req(dasd_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) {
+	/* 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;
+		erp->retries = 256;
+		erp->function = dasd_3990_erp_int_req;
 
-        } else {
+	} else {
+
+		/* issue a message and wait for 'device ready' interrupt */
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "is offline or not installed - "
+			    "INTERVENTION REQUIRED!!");
 
-                /* 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);
-        }
+		dasd_3990_erp_block_queue(erp, 60*HZ);
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_int_req */
+}				/* end dasd_3990_erp_int_req */
 
 /*
  * DASD_3990_ERP_ALTERNATE_PATH 
@@ -516,54 +292,47 @@
  *   permanent error.
  *
  *  PARAMETER
- *   erp                pointer to the current ERP
+ *   erp		pointer to the current ERP
  *
  * RETURN VALUES
- *   erp                modified pointer to the ERP
+ *   erp		modified pointer to the ERP
  *
  */
-void
-dasd_3990_erp_alternate_path (ccw_req_t *erp)
+static void
+dasd_3990_erp_alternate_path(dasd_ccw_req_t * erp)
 {
 
 	dasd_device_t *device = erp->device;
-        int irq = device->devinfo.irq;
+	int irq = device->devinfo.irq;
 
-        /* try alternate valid path */
-        erp->lpm     &= ~(erp->dstat->lpum);
-        erp->options |= DOIO_VALID_LPM;		/* use LPM for DO_IO */
+	/* 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_DEBUG, device,
-                              "try alternate lpm=%x (lpum=%x / opm=%x)",
-                              erp->lpm,
-                              erp->dstat->lpum,
-                              ioinfo[irq]->opm);
+		DEV_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,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
+		erp->status = DASD_CQR_QUEUED;
+
+		erp->retries = 1;
 
-                erp->retries = 1;
-                
 	} else {
-         
-                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,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-
-        }
-        
-} /* end dasd_3990_erp_alternate_path */
+
+		DEV_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 */
+		erp->status = DASD_CQR_FAILED;
+
+	}
+
+}				/* end dasd_3990_erp_alternate_path */
 
 /*
  * DASD_3990_ERP_DCTL
@@ -573,72 +342,56 @@
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
- *   erp                pointer to the current (failed) ERP
- *   modifier           subcommand modifier
+ *   erp		pointer to the current (failed) ERP
+ *   modifier		subcommand modifier
  *   
  * RETURN VALUES
- *   dctl_cqr           pointer to NEW dctl_cqr 
+ *   dctl_cqr		pointer to NEW dctl_cqr 
  *
  */
-ccw_req_t *
-dasd_3990_erp_DCTL (ccw_req_t *erp,
-                    char      modifier)
+static dasd_ccw_req_t *
+dasd_3990_erp_DCTL(dasd_ccw_req_t * erp, char modifier)
 {
 
 	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) {
-
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "Unable to allocate DCTL-CQR");
-                
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-
+	DCTL_data_t *DCTL_data;
+	ccw1_t *ccw;
+	dasd_ccw_req_t *dctl_cqr;
+
+	dctl_cqr = dasd_alloc_erp_request((char *) &erp->magic, 1,
+					  sizeof (DCTL_data_t), erp->device);
+	if (IS_ERR(dctl_cqr)) {
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Unable to allocate DCTL-CQR");
+		erp->status = DASD_CQR_FAILED;
 		return erp;
-        }
+	}
 
 	DCTL_data = dctl_cqr->data;
 
-        DCTL_data->subcommand = 0x02; /* Inhibit Write */
-        DCTL_data->modifier   = modifier;
+	DCTL_data->subcommand = 0x02;	/* Inhibit Write */
+	DCTL_data->modifier = modifier;
 
 	ccw = dctl_cqr->cpaddr;
-	memset (ccw, 0, sizeof (ccw1_t));
-        ccw->cmd_code = CCW_CMD_DCTL;
-        ccw->count    = 4;
-        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;
-	asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk));
+	memset(ccw, 0, sizeof (ccw1_t));
+	ccw->cmd_code = CCW_CMD_DCTL;
+	ccw->count = 4;
+	ccw->cda = (__u32)(addr_t) DCTL_data;
+	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 * 60 * HZ;
+	dctl_cqr->retries = 2;
 
-        dctl_cqr->status = CQR_STATUS_FILLED;
+	dctl_cqr->buildclk = get_clock();
+
+	dctl_cqr->status = DASD_CQR_FILLED;
 
 	return dctl_cqr;
 
-} /* end dasd_3990_erp_DCTL */
+}				/* end dasd_3990_erp_DCTL */
 
 /*
  * DASD_3990_ERP_ACTION_1 
@@ -651,23 +404,23 @@
  *   Note: duplex handling is not implemented (yet).
  *
  *  PARAMETER
- *   erp                pointer to the current ERP
+ *   erp		pointer to the current ERP
  *
  * RETURN VALUES
- *   erp                pointer to the ERP
+ *   erp		pointer to the ERP
  *
  */
-ccw_req_t *
-dasd_3990_erp_action_1 (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_action_1(dasd_ccw_req_t * erp)
 {
 
-        erp->function = dasd_3990_erp_action_1;
+	erp->function = dasd_3990_erp_action_1;
 
-        dasd_3990_erp_alternate_path (erp);
+	dasd_3990_erp_alternate_path(erp);
 
 	return erp;
 
-} /* end dasd_3990_erp_action_1 */
+}				/* end dasd_3990_erp_action_1 */
 
 /*
  * DASD_3990_ERP_ACTION_4 
@@ -679,51 +432,46 @@
  *   Use a timer (20 seconds) to retry the cqr if the interrupt is still missing.
  *
  *  PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the current ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the current ERP
  *
  * RETURN VALUES
- *   erp                pointer to the ERP
+ *   erp		pointer to the ERP
  *
  */
-ccw_req_t *
-dasd_3990_erp_action_4 (ccw_req_t *erp,
-			char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_action_4(dasd_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  = 256; 
-                erp->function = dasd_3990_erp_action_4;
-
-        } else {
-
-                if (sense[25] & 0x1D) {	/* state change pending */
-                        
-                        DASD_MESSAGE (KERN_INFO, device, "%s",
-                                      "waiting for state change pending "
-                                      "int");
-                        
-                        dasd_3990_erp_block_queue (erp,
-                                                   30);
-                        
-                } else {
-
-                        /* no state change pending - retry */
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_QUEUED);
-                }
-        }
+	/* 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 = 256;
+		erp->function = dasd_3990_erp_action_4;
+
+	} else {
+
+		if (sense[25] & 0x1D) {	/* state change pending */
+
+			DEV_MESSAGE(KERN_INFO, device, "%s",
+				    "waiting for state change pending " "int");
+
+			dasd_3990_erp_block_queue(erp, 30*HZ);
+
+		} else {
+
+			/* no state change pending - retry */
+			erp->status = DASD_CQR_QUEUED;
+		}
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_action_4 */
+}				/* end dasd_3990_erp_action_4 */
 
 /*
  ***************************************************************************** 
@@ -739,23 +487,23 @@
  *   NOTE: Further handling is done in xxx_further_erp after the retries.
  *
  *  PARAMETER
- *   erp                pointer to the current ERP
+ *   erp		pointer to the current ERP
  *
  * RETURN VALUES
- *   erp                pointer to the ERP
+ *   erp		pointer to the ERP
  *
  */
-ccw_req_t *
-dasd_3990_erp_action_5 (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_action_5(dasd_ccw_req_t * erp)
 {
 
-        /* first of all retry */
-        erp->retries = 10;
-        erp->function = dasd_3990_erp_action_5;
+	/* first of all retry */
+	erp->retries = 10;
+	erp->function = dasd_3990_erp_action_5;
 
-        return erp;
+	return erp;
 
-} /* end dasd_3990_erp_action_5 */
+}				/* end dasd_3990_erp_action_5 */
 
 /*
  * DASD_3990_HANDLE_ENV_DATA
@@ -766,23 +514,21 @@
  *   and prints the error messages.
  *
  * PARAMETER
- *   sense              current sense data
+ *   sense		current sense data
  *   
  * RETURN VALUES
  *   void
  */
-void
-dasd_3990_handle_env_data (ccw_req_t *erp,
-                           char      *sense)
+static void
+dasd_3990_handle_env_data(dasd_ccw_req_t * erp, char *sense)
 {
 
-        dasd_device_t *device = erp->device;
-	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 */
 
@@ -790,599 +536,596 @@
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Invalid Command");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Invalid Command");
 				break;
 			case 0x02:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Invalid Command "
-                                              "Sequence");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Invalid Command "
+					    "Sequence");
 				break;
 			case 0x03:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - CCW Count less than "
-                                              "required");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - CCW Count less than "
+					    "required");
 				break;
 			case 0x04:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Invalid Parameter");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Invalid Parameter");
 				break;
 			case 0x05:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Diagnostic of Sepecial"
-                                              " Command Violates File Mask");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Diagnostic of Sepecial"
+					    " Command Violates File Mask");
 				break;
 			case 0x07:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Channel Returned with "
-                                              "Incorrect retry CCW");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Channel Returned with "
+					    "Incorrect retry CCW");
 				break;
 			case 0x08:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Reset Notification");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Reset Notification");
 				break;
 			case 0x09:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Storage Path Restart");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Storage Path Restart");
 				break;
 			case 0x0A:
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "FORMAT 0 - Channel requested "
-                                              "... %02x",
-                                              sense[8]);
+				DEV_MESSAGE(KERN_WARNING, device,
+					    "FORMAT 0 - Channel requested "
+					    "... %02x", sense[8]);
 				break;
 			case 0x0B:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Invalid Defective/"
-                                              "Alternate Track Pointer");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Invalid Defective/"
+					    "Alternate Track Pointer");
 				break;
 			case 0x0C:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - DPS Installation "
-                                              "Check");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - DPS Installation "
+					    "Check");
 				break;
 			case 0x0E:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Command Invalid on "
-                                              "Secondary Address");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Command Invalid on "
+					    "Secondary Address");
 				break;
 			case 0x0F:
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "FORMAT 0 - Status Not As "
-                                              "Required: reason %02x",
-                                              sense[8]);
+				DEV_MESSAGE(KERN_WARNING, device,
+					    "FORMAT 0 - Status Not As "
+					    "Required: reason %02x", sense[8]);
 				break;
 			default:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Reseved");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Reseved");
 			}
 		} else {
 			switch (msg_no) {
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Device Error Source");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Device Error Source");
 				break;
 			case 0x02:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Reserved");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Reserved");
 				break;
 			case 0x03:
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "FORMAT 0 - Device Fenced - "
-                                              "device = %02x",
-                                              sense[4]);
+				DEV_MESSAGE(KERN_WARNING, device,
+					    "FORMAT 0 - Device Fenced - "
+					    "device = %02x", sense[4]);
 				break;
 			case 0x04:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Data Pinned for "
-                                              "Device");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Data Pinned for "
+					    "Device");
 				break;
 			default:
-                                DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                              "FORMAT 0 - Reserved");
+				DEV_MESSAGE(KERN_WARNING, device, "%s",
+					    "FORMAT 0 - Reserved");
 			}
-                }
-                break;
-		
-	case 0x10:	/* Format 1 - Device Equipment Checks */
+		}
+		break;
+
+	case 0x10:		/* Format 1 - Device Equipment Checks */
 		switch (msg_no) {
 		case 0x00:	/* No Message */
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Device Status 1 not as "
-                                      "expected");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Device Status 1 not as "
+				    "expected");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Index missing");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Index missing");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Interruption cannot be reset");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Interruption cannot be reset");
 			break;
 		case 0x05:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Device did not respond to "
-                                      "selection");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Device did not respond to "
+				    "selection");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Device check-2 error or Set "
-                                      "Sector is not complete");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Device check-2 error or Set "
+				    "Sector is not complete");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Head address does not "
-                                      "compare");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Head address does not "
+				    "compare");
 			break;
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Device status 1 not valid");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Device status 1 not valid");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Device not ready");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Device not ready");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Track physical address did "
-                                      "not compare");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Track physical address did "
+				    "not compare");
 			break;
 		case 0x0B:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Missing device address bit");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Missing device address bit");
 			break;
 		case 0x0C:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Drive motor switch is off");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Drive motor switch is off");
 			break;
 		case 0x0D:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Seek incomplete");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Seek incomplete");
 			break;
 		case 0x0E:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Cylinder address did not "
-                                      "compare");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Cylinder address did not "
+				    "compare");
 			break;
 		case 0x0F:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Offset active cannot be "
-                                      "reset");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Offset active cannot be "
+				    "reset");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 1 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 1 - Reserved");
 		}
-                break;		
-                        
-	case 0x20:	/* Format 2 - 3990 Equipment Checks */
+		break;
+
+	case 0x20:		/* Format 2 - 3990 Equipment Checks */
 		switch (msg_no) {
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 2 - 3990 check-2 error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 2 - 3990 check-2 error");
 			break;
 		case 0x0E:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 2 - Support facility errors");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 2 - Support facility errors");
 			break;
 		case 0x0F:
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "FORMAT 2 - Microcode detected error %02x",
-                                      sense[8]);
+			DEV_MESSAGE(KERN_WARNING, device,
+				    "FORMAT 2 - Microcode detected error %02x",
+				    sense[8]);
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 2 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 2 - Reserved");
 		}
-                break;		
+		break;
 
-	case 0x30:	/* Format 3 - 3990 Control Checks */
+	case 0x30:		/* Format 3 - 3990 Control Checks */
 		switch (msg_no) {
 		case 0x0F:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 3 - Allegiance terminated");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 3 - Allegiance terminated");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 3 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 3 - Reserved");
 		}
-                break;		
+		break;
 
-	case 0x40:	/* Format 4 - Data Checks */
+	case 0x40:		/* Format 4 - Data Checks */
 		switch (msg_no) {
 		case 0x00:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Home address area error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Home address area error");
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Count area error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Count area error");
 			break;
 		case 0x02:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Key area error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Key area error");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Data area error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Data area error");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in home address "
-                                      "area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in home address "
+				    "area");
 			break;
 		case 0x05:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in count address "
-                                      "area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in count address "
+				    "area");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in key area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in key area");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in data area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in data area");
 			break;
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Home address area error; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Home address area error; "
+				    "offset active");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Count area error; offset "
-                                      "active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Count area error; offset "
+				    "active");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Key area error; offset "
-                                      "active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Key area error; offset "
+				    "active");
 			break;
 		case 0x0B:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Data area error; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Data area error; "
+				    "offset active");
 			break;
 		case 0x0C:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in home "
-                                      "address area; offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in home "
+				    "address area; offset active");
 			break;
 		case 0x0D:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No syn byte in count "
-                                      "address area; offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No syn byte in count "
+				    "address area; offset active");
 			break;
 		case 0x0E:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No sync byte in key area; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No sync byte in key area; "
+				    "offset active");
 			break;
 		case 0x0F:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - No syn byte in data area; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - No syn byte in data area; "
+				    "offset active");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 4 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 4 - Reserved");
 		}
-                break;		
+		break;
 
-	case 0x50:	/* Format 5 - Data Check with displacement information */
+	case 0x50:		/* Format 5 - Data Check with displacement information */
 		switch (msg_no) {
 		case 0x00:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the "
-                                      "home address area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the "
+				    "home address area");
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the count area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the count area");
 			break;
 		case 0x02:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the key area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the key area");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the data area");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the data area");
 			break;
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the "
-                                      "home address area; offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the "
+				    "home address area; offset active");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the count area; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the count area; "
+				    "offset active");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the key area; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the key area; "
+				    "offset active");
 			break;
 		case 0x0B:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Data Check in the data area; "
-                                      "offset active");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Data Check in the data area; "
+				    "offset active");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 5 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 5 - Reserved");
 		}
-                break;		
+		break;
 
-	case 0x60:	/* Format 6 - Usage Statistics/Overrun Errors */
+	case 0x60:		/* Format 6 - Usage Statistics/Overrun Errors */
 		switch (msg_no) {
 		case 0x00:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel A");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel A");
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel B");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel B");
 			break;
 		case 0x02:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel C");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel C");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel D");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel D");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel E");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel E");
 			break;
 		case 0x05:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel F");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel F");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel G");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel G");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Overrun on channel H");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Overrun on channel H");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 6 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 6 - Reserved");
 		}
-                break;		
+		break;
 
-	case 0x70:	/* Format 7 - Device Connection Control Checks */
+	case 0x70:		/* Format 7 - Device Connection Control Checks */
 		switch (msg_no) {
 		case 0x00:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - RCC initiated by a connection "
-                                      "check alert");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - RCC initiated by a connection "
+				    "check alert");
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - RCC 1 sequence not "
-                                      "successful");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - RCC 1 sequence not "
+				    "successful");
 			break;
 		case 0x02:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - RCC 1 and RCC 2 sequences not "
-                                      "successful");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - RCC 1 and RCC 2 sequences not "
+				    "successful");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Invalid tag-in during "
-                                      "selection sequence");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Invalid tag-in during "
+				    "selection sequence");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - extra RCC required");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - extra RCC required");
 			break;
 		case 0x05:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Invalid DCC selection "
-                                      "response or timeout");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Invalid DCC selection "
+				    "response or timeout");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Missing end operation; device "
-                                      "transfer complete");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Missing end operation; device "
+				    "transfer complete");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Missing end operation; device "
-                                      "transfer incomplete");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Missing end operation; device "
+				    "transfer incomplete");
 			break;
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Invalid tag-in for an "
-                                      "immediate command sequence");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Invalid tag-in for an "
+				    "immediate command sequence");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Invalid tag-in for an "
-                                      "extended command sequence");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Invalid tag-in for an "
+				    "extended command sequence");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - 3990 microcode time out when "
-                                      "stopping selection");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - 3990 microcode time out when "
+				    "stopping selection");
 			break;
 		case 0x0B:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - No response to selection "
-                                      "after a poll interruption");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - No response to selection "
+				    "after a poll interruption");
 			break;
 		case 0x0C:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Permanent path error (DASD "
-                                      "controller not available)");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Permanent path error (DASD "
+				    "controller not available)");
 			break;
 		case 0x0D:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - DASD controller not available"
-                                      " on disconnected command chain");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - DASD controller not available"
+				    " on disconnected command chain");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 7 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 7 - Reserved");
 		}
-                break;		
+		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:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - Error correction code "
-                                      "hardware fault");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - Error correction code "
+				    "hardware fault");
 			break;
 		case 0x03:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - Unexpected end operation "
-                                      "response code");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - Unexpected end operation "
+				    "response code");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - End operation with transfer "
-                                      "count not zero");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - End operation with transfer "
+				    "count not zero");
 			break;
 		case 0x05:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - End operation with transfer "
-                                      "count zero");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - End operation with transfer "
+				    "count zero");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - DPS checks after a system "
-                                      "reset or selective reset");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - DPS checks after a system "
+				    "reset or selective reset");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - DPS cannot be filled");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - DPS cannot be filled");
 			break;
 		case 0x08:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - Short busy time-out during "
-                                      "device selection");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - Short busy time-out during "
+				    "device selection");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - DASD controller failed to "
-                                      "set or reset the long busy latch");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - DASD controller failed to "
+				    "set or reset the long busy latch");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - No interruption from device "
-                                      "during a command chain");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - No interruption from device "
+				    "during a command chain");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 8 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 8 - Reserved");
 		}
-                break;		
+		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:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 9 - Device check-2 error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 9 - Device check-2 error");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 9 - Head address did not compare");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 9 - Head address did not compare");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 9 - Track physical address did "
-                                      "not compare while oriented");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 9 - Track physical address did "
+				    "not compare while oriented");
 			break;
 		case 0x0E:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 9 - Cylinder address did not "
-                                      "compare");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 9 - Cylinder address did not "
+				    "compare");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT 9 - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT 9 - Reserved");
 		}
-                break;		
+		break;
 
 	case 0xF0:		/* Format F - Cache Storage Checks */
 		switch (msg_no) {
 		case 0x00:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Operation Terminated");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Operation Terminated");
 			break;
 		case 0x01:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Subsystem Processing Error");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Subsystem Processing Error");
 			break;
 		case 0x02:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Cache or nonvolatile storage "
-                                      "equipment failure");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Cache or nonvolatile storage "
+				    "equipment failure");
 			break;
 		case 0x04:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Caching terminated");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Caching terminated");
 			break;
 		case 0x06:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Cache fast write access not "
-                                      "authorized");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Cache fast write access not "
+				    "authorized");
 			break;
 		case 0x07:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Track format incorrect");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Track format incorrect");
 			break;
 		case 0x09:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Caching reinitiated");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Caching reinitiated");
 			break;
 		case 0x0A:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Nonvolatile storage "
-                                      "terminated");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Nonvolatile storage "
+				    "terminated");
 			break;
 		case 0x0B:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Volume is suspended duplex");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Volume is suspended duplex");
 			break;
 		case 0x0C:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Subsystem status connot be "
-                                      "determined");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Subsystem status connot be "
+				    "determined");
 			break;
 		case 0x0D:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - Caching status reset to "
-                                      "default");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - Caching status reset to "
+				    "default");
 			break;
 		case 0x0E:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT F - DASD Fast Write inhibited");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT F - DASD Fast Write inhibited");
 			break;
 		default:
-                        DASD_MESSAGE (KERN_WARNING, device, "%s",
-                                      "FORMAT D - Reserved");
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "FORMAT D - Reserved");
 		}
-                break;		
+		break;
 
 	default:	/* unknown message format - should not happen */
+		break;
+	}			/* end switch message format */
 
-	} /* end switch message format */
-
-} /* end dasd_3990_handle_env_data */
+}				/* end dasd_3990_handle_env_data */
 
 /*
  * DASD_3990_ERP_COM_REJ
@@ -1391,44 +1134,41 @@
  *   Handles 24 byte 'Command Reject' error.
  *
  * PARAMETER
- *   erp                current erp_head
- *   sense              current sense data
+ *   erp		current erp_head
+ *   sense		current sense data
  * 
  * RETURN VALUES
- *   erp                'new' erp_head - pointer to new ERP 
+ *   erp		'new' erp_head - pointer to new ERP 
  */
-ccw_req_t *
-dasd_3990_erp_com_rej (ccw_req_t *erp,
-		       char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_com_rej(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
 
-        erp->function = dasd_3990_erp_com_rej;
+	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_DEBUG, device, "%s",
-                              "Command Reject - environmental data present");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Command Reject - environmental data present");
 
-		dasd_3990_handle_env_data (erp,
-                                           sense);
+		dasd_3990_handle_env_data(erp, sense);
 
 		erp->retries = 5;
 
 	} else {
 		/* fatal error -  set status to FAILED */
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "Command Reject - Fatal error");
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Command Reject - Fatal error");
 
-                erp = dasd_3990_erp_cleanup (erp,
-                                             CQR_STATUS_FAILED);
+		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 	}
 
 	return erp;
 
-} /* end dasd_3990_erp_com_rej */
+}				/* end dasd_3990_erp_com_rej */
 
 /*
  * DASD_3990_ERP_BUS_OUT 
@@ -1437,38 +1177,37 @@
  *   Handles 24 byte 'Bus Out Parity Check' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_bus_out (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_bus_out(dasd_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;
-
-        } else {
-
-                /* 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);
-                
-        }
+	/* 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;
+
+	} else {
+
+		/* issue a message and wait for 'device ready' interrupt */
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "bus out parity error or BOPC requested by "
+			    "channel");
+
+		dasd_3990_erp_block_queue(erp, 60*HZ);
+
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_bus_out */
+}				/* end dasd_3990_erp_bus_out */
 
 /*
  * DASD_3990_ERP_EQUIP_CHECK
@@ -1477,13 +1216,12 @@
  *   Handles 24 byte 'Equipment Check' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_equip_check (ccw_req_t *erp,
-			   char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_equip_check(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
@@ -1492,48 +1230,46 @@
 
 	if (sense[1] & SNS1_WRITE_INHIBITED) {
 
-		DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Write inhibited path encountered");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Write inhibited path encountered");
 
 		/* vary path offline */
-		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");
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Path should be varied off-line. "
+			    "This is not implemented yet \n - please report "
+			    "to linux390@de.ibm.com");
 
-		erp = dasd_3990_erp_action_1 (erp);
+		erp = dasd_3990_erp_action_1(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;
-        
-} /* end dasd_3990_erp_equip_check */
+
+		DEV_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) {
+
+		DEV_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 */
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Equipment check or processing error");
+
+		erp = dasd_3990_erp_action_5(erp);
+	}
+
+	return erp;
+
+}				/* end dasd_3990_erp_equip_check */
 
 /*
  * DASD_3990_ERP_DATA_CHECK
@@ -1542,13 +1278,12 @@
  *   Handles 24 byte 'Data Check' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_data_check (ccw_req_t *erp,
-			  char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_data_check(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
@@ -1558,43 +1293,42 @@
 	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */
 
 		/* issue message that the data has been corrected */
-		DASD_MESSAGE (KERN_EMERG, device, "%s",
-                              "Data recovered during retry with PCI "
-                              "fetch mode active");
-
-                /* not possible to handle this situation in Linux */    
-                panic("No way to inform appliction about the possibly "
-                      "incorret data");
+		DEV_MESSAGE(KERN_EMERG, device, "%s",
+			    "Data recovered during retry with PCI "
+			    "fetch mode active");
+
+		/* not possible to handle this situation in Linux */
+		panic("No way to inform appliction about the possibly "
+		      "incorret data");
 
 	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Uncorrectable data check recovered secondary "
-                              "addr of duplex pair");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Uncorrectable data check recovered secondary "
+			    "addr of duplex pair");
 
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
+		erp = dasd_3990_erp_action_4(erp, sense);
 
 	} else if (sense[1] & SNS1_PERM_ERR) {
 
-		DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Uncorrectable data check with internal "
-                              "retry exhausted");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Uncorrectable data check with internal "
+			    "retry exhausted");
 
-		erp = dasd_3990_erp_action_1 (erp);
+		erp = dasd_3990_erp_action_1(erp);
 
 	} else {
 		/* all other data checks */
-		DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Uncorrectable data check with retry count "
-                              "exhausted...");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Uncorrectable data check with retry count "
+			    "exhausted...");
 
-		erp = dasd_3990_erp_action_5 (erp);
+		erp = dasd_3990_erp_action_5(erp);
 	}
 
 	return erp;
 
-} /* end dasd_3990_erp_data_check */
+}				/* end dasd_3990_erp_data_check */
 
 /*
  * DASD_3990_ERP_OVERRUN
@@ -1603,28 +1337,27 @@
  *   Handles 24 byte 'Overrun' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_overrun (ccw_req_t *erp,
-		       char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_overrun(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_overrun;
 
-        DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                      "Overrun - service overrun or overrun"
-                      " error requested by channel");
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "Overrun - service overrun or overrun"
+		    " error requested by channel");
 
-        erp = dasd_3990_erp_action_5 (erp);
+	erp = dasd_3990_erp_action_5(erp);
 
 	return erp;
 
-} /* end dasd_3990_erp_overrun */
+}				/* end dasd_3990_erp_overrun */
 
 /*
  * DASD_3990_ERP_INV_FORMAT
@@ -1633,13 +1366,12 @@
  *   Handles 24 byte 'Invalid Track Format' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_inv_format (ccw_req_t *erp,
-			  char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_inv_format(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
@@ -1648,28 +1380,25 @@
 
 	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Track format error when destaging or "
-                              "staging data");
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Track format error when destaging or "
+			    "staging data");
 
-		dasd_3990_handle_env_data (erp,
-                                           sense);
+		dasd_3990_handle_env_data(erp, sense);
 
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
+		erp = dasd_3990_erp_action_4(erp, sense);
 
 	} else {
-		DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "Invalid Track Format - Fatal error should have "
-                              "been handled within the interrupt handler");
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Invalid Track Format - Fatal error should have "
+			    "been handled within the interrupt handler");
 
-                erp= dasd_3990_erp_cleanup (erp,
-                                            CQR_STATUS_FAILED);
-        }
+		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_inv_format */
+}				/* end dasd_3990_erp_inv_format */
 
 /*
  * DASD_3990_ERP_EOC
@@ -1678,25 +1407,23 @@
  *   Handles 24 byte 'End-of-Cylinder' error.
  *
  * PARAMETER
- *   erp                already added default erp
+ *   erp		already added default erp
  * RETURN VALUES
- *   erp                pointer to original (failed) cqr.
+ *   erp		pointer to original (failed) cqr.
  */
-ccw_req_t *
-dasd_3990_erp_EOC (ccw_req_t *default_erp,
-		   char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_EOC(dasd_ccw_req_t * default_erp, char *sense)
 {
 
 	dasd_device_t *device = default_erp->device;
 
-        DASD_MESSAGE (KERN_ERR, device, "%s",
-                      "End-of-Cylinder - must never happen");
+	DEV_MESSAGE(KERN_ERR, device, "%s",
+		    "End-of-Cylinder - must never happen");
 
-        /* implement action 7 - BUG */
-        return dasd_3990_erp_cleanup (default_erp,
-                                      CQR_STATUS_FAILED);
+	/* implement action 7 - BUG */
+	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 
-} /* end dasd_3990_erp_EOC */
+}				/* end dasd_3990_erp_EOC */
 
 /*
  * DASD_3990_ERP_ENV_DATA
@@ -1705,39 +1432,34 @@
  *   Handles 24 byte 'Environmental-Data Present' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_env_data (ccw_req_t *erp,
-			char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_env_data(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_env_data;
 
-        DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                      "Environmental data present");
+	DEV_MESSAGE(KERN_DEBUG, device, "%s", "Environmental data present");
 
-        dasd_3990_handle_env_data (erp,
-                                   sense);
+	dasd_3990_handle_env_data(erp, sense);
 
-        /* don't retry on disabled interface */
-        if (sense[7] != 0x0F) {
+	/* don't retry on disabled interface */
+	if (sense[7] != 0x0F) {
 
-                erp = dasd_3990_erp_action_4 (erp,
-                                              sense);
-        } else {
+		erp = dasd_3990_erp_action_4(erp, sense);
+	} else {
 
-                erp = dasd_3990_erp_cleanup (erp,
-                                             CQR_STATUS_IN_IO);
-        }
+		erp = dasd_3990_erp_cleanup(erp, DASD_CQR_IN_IO);
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_env_data */
+}				/* end dasd_3990_erp_env_data */
 
 /*
  * DASD_3990_ERP_NO_REC
@@ -1746,26 +1468,24 @@
  *   Handles 24 byte 'No Record Found' error.
  *
  * PARAMETER
- *   erp                already added default ERP
- *              
+ *   erp		already added default ERP
+ *		
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_no_rec (ccw_req_t *default_erp,
-		      char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_no_rec(dasd_ccw_req_t * default_erp, char *sense)
 {
 
 	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");
+	DEV_MESSAGE(KERN_ERR, device, "%s",
+		    "No Record Found - Fatal error should "
+		    "have been handled within the interrupt handler");
 
-        return dasd_3990_erp_cleanup (default_erp,
-                                      CQR_STATUS_FAILED);
+	return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 
-} /* end dasd_3990_erp_no_rec */
+}				/* end dasd_3990_erp_no_rec */
 
 /*
  * DASD_3990_ERP_FILE_PROT
@@ -1773,26 +1493,24 @@
  * DESCRIPTION
  *   Handles 24 byte 'File Protected' error.
  *   Note: Seek related recovery is not implemented because
- *         wee don't use the seek command yet.
+ *	   wee don't use the seek command yet.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp		current erp_head
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp		new erp_head - pointer to new ERP
  */
-ccw_req_t *
-dasd_3990_erp_file_prot (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_file_prot(dasd_ccw_req_t * erp)
 {
 
 	dasd_device_t *device = erp->device;
 
-        DASD_MESSAGE (KERN_ERR, device, "%s",
-                      "File Protected");
+	DEV_MESSAGE(KERN_ERR, device, "%s", "File Protected");
 
-        return dasd_3990_erp_cleanup (erp,
-                                      CQR_STATUS_FAILED);
+	return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
 
-} /* end dasd_3990_erp_file_prot */
+}				/* end dasd_3990_erp_file_prot */
 
 /*
  * DASD_3990_ERP_INSPECT_24 
@@ -1802,92 +1520,72 @@
  *   and sets up a related error recovery action.  
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created default ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created default ERP
  *
  * RETURN VALUES
- *   erp                pointer to the (addtitional) ERP
+ *   erp		pointer to the (addtitional) ERP
  */
-ccw_req_t *
-dasd_3990_erp_inspect_24 (ccw_req_t *erp,
-                          char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_inspect_24(dasd_ccw_req_t * erp, char *sense)
 {
 
-	ccw_req_t *erp_filled = NULL;
+	dasd_ccw_req_t *erp_filled = NULL;
 
-	/* Check sense for ....    */
-	/* 'Command Reject'        */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_CMD_REJECT)) {
-		erp_filled = dasd_3990_erp_com_rej (erp,
-						    sense);
+	/* Check sense for ....	   */
+	/* 'Command Reject'	   */
+	if ((erp_filled == NULL) && (sense[0] & SNS0_CMD_REJECT)) {
+		erp_filled = dasd_3990_erp_com_rej(erp, sense);
 	}
 	/* 'Intervention Required' */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_INTERVENTION_REQ)) {
-		erp_filled = dasd_3990_erp_int_req (erp);
+	if ((erp_filled == NULL) && (sense[0] & SNS0_INTERVENTION_REQ)) {
+		erp_filled = dasd_3990_erp_int_req(erp);
 	}
 	/* 'Bus Out Parity Check'  */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_BUS_OUT_CHECK)) {
-		erp_filled = dasd_3990_erp_bus_out (erp);
-	}
-	/* 'Equipment Check'       */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_EQUIPMENT_CHECK)) {
-		erp_filled = dasd_3990_erp_equip_check (erp,
-							sense);
-	}
-	/* 'Data Check'            */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_DATA_CHECK)) {
-		erp_filled = dasd_3990_erp_data_check (erp,
-						       sense);
-	}
-	/* 'Overrun'               */
-	if ((erp_filled == NULL) &&
-	    (sense[0] & SNS0_OVERRUN)) {
-		erp_filled = dasd_3990_erp_overrun (erp,
-						    sense);
+	if ((erp_filled == NULL) && (sense[0] & SNS0_BUS_OUT_CHECK)) {
+		erp_filled = dasd_3990_erp_bus_out(erp);
+	}
+	/* 'Equipment Check'	   */
+	if ((erp_filled == NULL) && (sense[0] & SNS0_EQUIPMENT_CHECK)) {
+		erp_filled = dasd_3990_erp_equip_check(erp, sense);
+	}
+	/* 'Data Check'		   */
+	if ((erp_filled == NULL) && (sense[0] & SNS0_DATA_CHECK)) {
+		erp_filled = dasd_3990_erp_data_check(erp, sense);
+	}
+	/* 'Overrun'		   */
+	if ((erp_filled == NULL) && (sense[0] & SNS0_OVERRUN)) {
+		erp_filled = dasd_3990_erp_overrun(erp, sense);
 	}
 	/* 'Invalid Track Format'  */
-	if ((erp_filled == NULL) &&
-	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
-		erp_filled = dasd_3990_erp_inv_format (erp,
-						       sense);
-	}
-	/* 'End-of-Cylinder'       */
-	if ((erp_filled == NULL) &&
-	    (sense[1] & SNS1_EOC)) {
-		erp_filled = dasd_3990_erp_EOC (erp,
-						sense);
-	}
-	/* 'Environmental Data'    */
-	if ((erp_filled == NULL) &&
-	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
-		erp_filled = dasd_3990_erp_env_data (erp,
-						     sense);
-	}
-	/* 'No Record Found'       */
-	if ((erp_filled == NULL) &&
-	    (sense[1] & SNS1_NO_REC_FOUND)) {
-		erp_filled = dasd_3990_erp_no_rec (erp,
-						   sense);
-	}
-	/* 'File Protected'        */
-	if ((erp_filled == NULL) &&
-	    (sense[1] & SNS1_FILE_PROTECTED)) {
-		erp_filled = dasd_3990_erp_file_prot (erp);
+	if ((erp_filled == NULL) && (sense[1] & SNS1_INV_TRACK_FORMAT)) {
+		erp_filled = dasd_3990_erp_inv_format(erp, sense);
+	}
+	/* 'End-of-Cylinder'	   */
+	if ((erp_filled == NULL) && (sense[1] & SNS1_EOC)) {
+		erp_filled = dasd_3990_erp_EOC(erp, sense);
+	}
+	/* 'Environmental Data'	   */
+	if ((erp_filled == NULL) && (sense[2] & SNS2_ENV_DATA_PRESENT)) {
+		erp_filled = dasd_3990_erp_env_data(erp, sense);
+	}
+	/* 'No Record Found'	   */
+	if ((erp_filled == NULL) && (sense[1] & SNS1_NO_REC_FOUND)) {
+		erp_filled = dasd_3990_erp_no_rec(erp, sense);
+	}
+	/* 'File Protected'	   */
+	if ((erp_filled == NULL) && (sense[1] & SNS1_FILE_PROTECTED)) {
+		erp_filled = dasd_3990_erp_file_prot(erp);
 	}
 	/* other (unknown) error - do default ERP */
 	if (erp_filled == NULL) {
 
-		erp_filled = erp;	
+		erp_filled = erp;
 	}
 
 	return erp_filled;
 
-} /* END dasd_3990_erp_inspect_24 */
+}				/* END dasd_3990_erp_inspect_24 */
 
 /*
  ***************************************************************************** 
@@ -1903,27 +1601,25 @@
  *   Just retry and if retry doesn't work, return with error.
  *
  * PARAMETER
- *   erp                current erp_head
- *   sense              current sense data 
+ *   erp		current erp_head
+ *   sense		current sense data 
  * RETURN VALUES
- *   erp                modified erp_head
+ *   erp		modified erp_head
  */
-ccw_req_t *
-dasd_3990_erp_action_10_32 (ccw_req_t *erp,
-                            char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_action_10_32(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
 
-        erp->retries  = 256;
-        erp->function = dasd_3990_erp_action_10_32;
+	erp->retries = 256;
+	erp->function = dasd_3990_erp_action_10_32;
 
-	DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                      "Perform logging requested");
+	DEV_MESSAGE(KERN_DEBUG, device, "%s", "Perform logging requested");
 
 	return erp;
 
-} /* end dasd_3990_erp_action_10_32 */
+}				/* end dasd_3990_erp_action_10_32 */
 
 /*
  * DASD_3990_ERP_ACTION_1B_32
@@ -1937,170 +1633,143 @@
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
- *   default_erp        already added default erp.
- *   sense              current sense data 
+ *   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
+ *   erp		new erp or 
+ *			default_erp in case of imprecise ending or error
  */
-ccw_req_t *
-dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
-                            char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_action_1B_32(dasd_ccw_req_t * default_erp, char *sense)
 {
 
-	dasd_device_t  *device = default_erp->device;
-        __u32          cpa     = 0;
-        ccw_req_t      *cqr;
-	ccw_req_t      *erp;
+	dasd_device_t *device = default_erp->device;
+	__u32 cpa = 0;
+	dasd_ccw_req_t *cqr;
+	dasd_ccw_req_t *erp;
 	DE_eckd_data_t *DE_data;
-	char           *LO_data;   /* LO_eckd_data_t */
-        ccw1_t         *ccw;
+	char *LO_data;		/* LO_eckd_data_t */
+	ccw1_t *ccw;
+
+	DEV_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;
+	}
+
+	/* for imprecise ending just do default erp */
+	if (sense[1] & 0x01) {
+
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Imprecise ending is set - just retry");
+
+		return default_erp;
+	}
+
+	/* determine the address of the CCW to be restarted */
+	/* Imprecise ending is not set -> addr from IRB-SCSW */
+	cpa = default_erp->refers->dstat->cpa;
+
+	if (cpa == 0) {
+
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Unable to determine address of the CCW "
+			    "to be restarted");
+
+		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
+	}
 
-	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;
-        }
-
-        /* for imprecise ending just do default erp */
-        if (sense[1] & 0x01) {
-
-                DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Imprecise ending is set - just retry");
-
-                return default_erp;
-        } 
-         
-        /* determine the address of the CCW to be restarted */
-        /* Imprecise ending is not set -> addr from IRB-SCSW */
-        cpa = default_erp->refers->dstat->cpa;    
-        
-        if (cpa == 0) {
-                
-                DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Unable to determine address of the CCW "
-                              "to be restarted");
-                
-                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),
-                                  device);
-
-	if (!erp) {
-
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "Unable to allocate ERP");
-                
-                return dasd_3990_erp_cleanup (default_erp,
-                                              CQR_STATUS_FAILED);
+	erp = dasd_alloc_erp_request((char *) &cqr->magic,
+				     2 + 1,/* DE/LO + TIC */
+				     sizeof (DE_eckd_data_t) +
+				     sizeof (LO_eckd_data_t), device);
+
+	if (IS_ERR(erp)) {
+		DEV_MESSAGE(KERN_ERR, device, "%s", "Unable to allocate ERP");
+		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
 	}
-        
-        /* use original DE */
+
+	/* use original DE */
 	DE_data = erp->data;
-        memcpy (DE_data, 
-                cqr->data, 
-                sizeof (DE_eckd_data_t));
-        
-        /* create LO */
+	memcpy(DE_data, cqr->data, sizeof (DE_eckd_data_t));
+
+	/* create LO */
 	LO_data = erp->data + sizeof (DE_eckd_data_t);
-        
-        if ((sense[3]  == 0x01) &&
-            (LO_data[1] & 0x01)   ){
-
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "BUG - this should not happen");
-
-                return dasd_3990_erp_cleanup (default_erp,
-                                              CQR_STATUS_FAILED);
-        }
-
-        if ((sense[7] & 0x3F) == 0x01) {
-                /* operation code is WRITE DATA -> data area orientation */
-                LO_data[0] = 0x81;
-
-        } else if ((sense[7] & 0x3F) == 0x03) {
-                /* operation code is FORMAT WRITE -> index orientation */
-                LO_data[0] = 0xC3;
-
-        } else {
-                LO_data[0] = sense[7];  /* operation */
-        }
-
-        LO_data[1] = sense[8];  /* auxiliary */
-        LO_data[2] = sense[9];  
-        LO_data[3] = sense[3];  /* count */ 
-        LO_data[4] = sense[29]; /* seek_addr.cyl */
-        LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */
-        LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */  
-
-        memcpy (&(LO_data[8]), &(sense[11]), 8);   
-
-        /* create DE ccw */    
-        ccw = erp->cpaddr;
-	memset (ccw, 0, sizeof (ccw1_t));
+
+	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
+
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "BUG - this should not happen");
+
+		return dasd_3990_erp_cleanup(default_erp, DASD_CQR_FAILED);
+	}
+
+	if ((sense[7] & 0x3F) == 0x01) {
+		/* operation code is WRITE DATA -> data area orientation */
+		LO_data[0] = 0x81;
+
+	} else if ((sense[7] & 0x3F) == 0x03) {
+		/* operation code is FORMAT WRITE -> index orientation */
+		LO_data[0] = 0xC3;
+
+	} else {
+		LO_data[0] = sense[7];	/* operation */
+	}
+
+	LO_data[1] = sense[8];	/* auxiliary */
+	LO_data[2] = sense[9];
+	LO_data[3] = sense[3];	/* count */
+	LO_data[4] = sense[29];	/* seek_addr.cyl */
+	LO_data[5] = sense[30];	/* seek_addr.cyl 2nd byte */
+	LO_data[7] = sense[31];	/* seek_addr.head 2nd byte */
+
+	memcpy(&(LO_data[8]), &(sense[11]), 8);
+
+	/* create DE ccw */
+	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;
-	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->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32)(addr_t) DE_data;
+
+	/* 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;
-	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->flags = CCW_FLAG_CC;
+	ccw->count = 16;
+	ccw->cda = (__u32)(addr_t) LO_data;
+
+	/* 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;
+	erp->refers = default_erp->refers;
+	erp->device = device;
+	erp->magic = default_erp->magic;
+	erp->lpm = 0xFF;
+	erp->expires = 0;
+	erp->retries = 256;
+	erp->status = DASD_CQR_FILLED;
+
+	/* remove the default erp */
+	dasd_free_erp_request(default_erp, device);
 
-        /* fill erp related fields */
-        erp->function = dasd_3990_erp_action_1B_32;
-	erp->refers   = default_erp->refers;
-	erp->device   = device;
-	erp->magic    = default_erp->magic;
-	erp->lpm      = 0xFF;
-	erp->expires  = 0;
-	erp->retries  = 256;
-	erp->status   = CQR_STATUS_FILLED;
-        
-        /* remove the default erp */
-        dasd_free_request (default_erp, device);
-        
 	return erp;
-        
-} /* end dasd_3990_erp_action_1B_32 */
+
+}				/* end dasd_3990_erp_action_1B_32 */
 
 /*
  * DASD_3990_UPDATE_1B
@@ -2112,116 +1781,106 @@
  *   ERP. 
  *
  * PARAMETER
- *   previous_erp       already created previous erp.
- *   sense              current sense data 
+ *   previous_erp	already created previous erp.
+ *   sense		current sense data 
  * RETURN VALUES
- *   erp                modified erp 
+ *   erp		modified erp 
  */
-ccw_req_t *
-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;
-	ccw_req_t      *erp;
-	char           *LO_data;   /* LO_eckd_data_t */
-        ccw1_t         *ccw;
-
-	DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                      "Write not finished because of unexpected condition"
-                      " - follow on");
-        
-        /* determine the original cqr */
-        cqr = previous_erp;
-
-        while (cqr->refers != NULL){
-                cqr = cqr->refers;
-        }
-         
-        /* for imprecise ending just do default erp */
-        if (sense[1] & 0x01) {
-
-                DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Imprecise ending is set - just retry");
-
-                check_then_set (&previous_erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
-
-                return previous_erp;
-        } 
-         
-        /* determine the address of the CCW to be restarted */
-        /* Imprecise ending is not set -> addr from IRB-SCSW */
-        cpa = previous_erp->dstat->cpa;    
-        
-        if (cpa == 0) {
-                
-                DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                              "Unable to determine address of the CCW "
-                              "to be restarted");
-                
-                check_then_set (&previous_erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-                
-                return previous_erp;
-        }
-        
-        erp = previous_erp;
+static dasd_ccw_req_t *
+dasd_3990_update_1B(dasd_ccw_req_t * previous_erp, char *sense)
+{
+
+	dasd_device_t *device = previous_erp->device;
+	__u32 cpa = 0;
+	dasd_ccw_req_t *cqr;
+	dasd_ccw_req_t *erp;
+	char *LO_data;		/* LO_eckd_data_t */
+	ccw1_t *ccw;
+
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "Write not finished because of unexpected condition"
+		    " - follow on");
+
+	/* determine the original cqr */
+	cqr = previous_erp;
+
+	while (cqr->refers != NULL) {
+		cqr = cqr->refers;
+	}
+
+	/* for imprecise ending just do default erp */
+	if (sense[1] & 0x01) {
+
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Imprecise ending is set - just retry");
+
+		previous_erp->status = DASD_CQR_QUEUED;
+
+		return previous_erp;
+	}
+
+	/* determine the address of the CCW to be restarted */
+	/* Imprecise ending is not set -> addr from IRB-SCSW */
+	cpa = previous_erp->dstat->cpa;
+
+	if (cpa == 0) {
+
+		DEV_MESSAGE(KERN_DEBUG, device, "%s",
+			    "Unable to determine address of the CCW "
+			    "to be restarted");
+
+		previous_erp->status = DASD_CQR_FAILED;
+
+		return previous_erp;
+	}
+
+	erp = previous_erp;
 
 	/* update the LO with the new returned sense data  */
 	LO_data = erp->data + sizeof (DE_eckd_data_t);
-        
-        if ((sense[3]  == 0x01) &&
-            (LO_data[1] & 0x01)   ){
-
-                DASD_MESSAGE (KERN_ERR, device, "%s",
-                              "BUG - this should not happen");
-
-                check_then_set (&previous_erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-                
-                return previous_erp;
-        }
-
-        if ((sense[7] & 0x3F) == 0x01) {
-                /* operation code is WRITE DATA -> data area orientation */
-                LO_data[0] = 0x81;
-
-        } else if ((sense[7] & 0x3F) == 0x03) {
-                /* operation code is FORMAT WRITE -> index orientation */
-                LO_data[0] = 0xC3;
-
-        } else {
-                LO_data[0] = sense[7];  /* operation */
-        }
-
-        LO_data[1] = sense[8];  /* auxiliary */
-        LO_data[2] = sense[9];  
-        LO_data[3] = sense[3];  /* count */ 
-        LO_data[4] = sense[29]; /* seek_addr.cyl */
-        LO_data[5] = sense[30]; /* seek_addr.cyl 2nd byte */
-        LO_data[7] = sense[31]; /* seek_addr.head 2nd byte */  
-
-        memcpy (&(LO_data[8]), &(sense[11]), 8);   
-
-        /* TIC to the failed ccw */
-        ccw = erp->cpaddr;  /* addr of DE ccw */
-        ccw++;              /* addr of LE ccw */
-        ccw++;              /* addr of TIC ccw */ 
+
+	if ((sense[3] == 0x01) && (LO_data[1] & 0x01)) {
+
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "BUG - this should not happen");
+
+		previous_erp->status = DASD_CQR_FAILED;
+
+		return previous_erp;
+	}
+
+	if ((sense[7] & 0x3F) == 0x01) {
+		/* operation code is WRITE DATA -> data area orientation */
+		LO_data[0] = 0x81;
+
+	} else if ((sense[7] & 0x3F) == 0x03) {
+		/* operation code is FORMAT WRITE -> index orientation */
+		LO_data[0] = 0xC3;
+
+	} else {
+		LO_data[0] = sense[7];	/* operation */
+	}
+
+	LO_data[1] = sense[8];	/* auxiliary */
+	LO_data[2] = sense[9];
+	LO_data[3] = sense[3];	/* count */
+	LO_data[4] = sense[29];	/* seek_addr.cyl */
+	LO_data[5] = sense[30];	/* seek_addr.cyl 2nd byte */
+	LO_data[7] = sense[31];	/* seek_addr.head 2nd byte */
+
+	memcpy(&(LO_data[8]), &(sense[11]), 8);
+
+	/* TIC to the failed ccw */
+	ccw = erp->cpaddr;	/* addr of DE ccw */
+	ccw++;			/* addr of LE ccw */
+	ccw++;			/* addr of TIC ccw */
 	ccw->cda = cpa;
 
-	check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_QUEUED);
-        
+	erp->status = DASD_CQR_QUEUED;
+
 	return erp;
-        
-} /* end dasd_3990_update_1B */
+
+}				/* end dasd_3990_update_1B */
 
 /*
  * DASD_3990_ERP_COMPOUND_RETRY 
@@ -2229,46 +1888,45 @@
  * 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.
+ *	   by the sense data. This makes enqueueing of the request
+ *	   easier.
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created ERP
  *
  * RETURN VALUES
- *   erp                modified ERP pointer
- *
- */
-void
-dasd_3990_erp_compound_retry (ccw_req_t *erp,
-                              char      *sense)
-{
-
-        switch (sense[25] & 0x03) { 
-        case 0x00:	/* no not retry */
-                erp->retries = 1; 
-                break;            
-                
-        case 0x01:	/* retry 2 times */
-                erp->retries = 2;
-                break;
-                
-        case 0x02:	/* retry 10 times */
-                erp->retries = 10;
-                break;
-                
-        case 0x03:	/* retry 256 times */
-                erp->retries = 256;
-                break;
-                
-        default:
-                BUG();
-        }
-        
-        erp->function = dasd_3990_erp_compound_retry;
-        
-} /* end dasd_3990_erp_compound_retry */
+ *   erp		modified ERP pointer
+ *
+ */
+static void
+dasd_3990_erp_compound_retry(dasd_ccw_req_t * erp, char *sense)
+{
+
+	switch (sense[25] & 0x03) {
+	case 0x00:		/* no not retry */
+		erp->retries = 1;
+		break;
+
+	case 0x01:		/* retry 2 times */
+		erp->retries = 2;
+		break;
+
+	case 0x02:		/* retry 10 times */
+		erp->retries = 10;
+		break;
+
+	case 0x03:		/* retry 256 times */
+		erp->retries = 256;
+		break;
+
+	default:
+		BUG();
+	}
+
+	erp->function = dasd_3990_erp_compound_retry;
+
+}				/* end dasd_3990_erp_compound_retry */
 
 /*
  * DASD_3990_ERP_COMPOUND_PATH 
@@ -2278,37 +1936,34 @@
  *   channel path.
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created ERP
  *
  * RETURN VALUES
- *   erp                modified ERP pointer
+ *   erp		modified ERP pointer
  *
  */
-void
-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,
-                                        CQR_STATUS_FAILED,
-                                        CQR_STATUS_ERROR);
-                        
-                }
-        }
-        
-        erp->function = dasd_3990_erp_compound_path;
+static void
+dasd_3990_erp_compound_path(dasd_ccw_req_t * erp, char *sense)
+{
+
+	if (sense[25] & DASD_SENSE_BIT_3) {
+		dasd_3990_erp_alternate_path(erp);
 
-} /* end dasd_3990_erp_compound_path */
+		if (erp->status == DASD_CQR_FAILED) {
+			/* reset the lpm and the status to be able to 
+			 * try further actions. */
+
+			erp->lpm = LPM_ANYPATH;
+
+			erp->status = DASD_CQR_ERROR;
+
+		}
+	}
+
+	erp->function = dasd_3990_erp_compound_path;
+
+}				/* end dasd_3990_erp_compound_path */
 
 /*
  * DASD_3990_ERP_COMPOUND_CODE 
@@ -2317,47 +1972,44 @@
  *   Handles the compound ERP action for retry code.
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created ERP
  *
  * RETURN VALUES
- *   erp                NEW ERP pointer
+ *   erp		NEW ERP pointer
  *
  */
-ccw_req_t *
-dasd_3990_erp_compound_code (ccw_req_t *erp,
-                             char      *sense)
-{
-        
-        if (sense[25] & DASD_SENSE_BIT_2) {
-
-                switch (sense[28]) {
-                case 0x17:
-                        /* issue a Diagnostic Control command with an 
-                         * Inhibit Write subcommand and controler modifier */
-                        erp = dasd_3990_erp_DCTL (erp,
-                                                  0x20);
-                        break;
-                        
-                case 0x25:
-                        /* wait for 5 seconds and retry again */
-                        erp->retries = 1;
-                        
-                        dasd_3990_erp_block_queue (erp,
-                                                   5);
-                        break;
-                        
-                default:
-                        /* should not happen - continue */
+static dasd_ccw_req_t *
+dasd_3990_erp_compound_code(dasd_ccw_req_t * erp, char *sense)
+{
 
-                }
-        }
+	if (sense[25] & DASD_SENSE_BIT_2) {
 
-        erp->function = dasd_3990_erp_compound_code;
+		switch (sense[28]) {
+		case 0x17:
+			/* issue a Diagnostic Control command with an 
+			 * Inhibit Write subcommand and controler modifier */
+			erp = dasd_3990_erp_DCTL(erp, 0x20);
+			break;
+			
+		case 0x25:
+			/* wait for 5 seconds and retry again */
+			erp->retries = 1;
+			
+			dasd_3990_erp_block_queue (erp, 5*HZ);
+			break;
+			
+		default:
+			/* should not happen - continue */
+			break;
+		}
+	}
 
-        return erp;
+	erp->function = dasd_3990_erp_compound_code;
 
-} /* end dasd_3990_erp_compound_code */
+	return erp;
+
+}				/* end dasd_3990_erp_compound_code */
 
 /*
  * DASD_3990_ERP_COMPOUND_CONFIG 
@@ -2368,35 +2020,33 @@
  *   Note: duplex handling is not implemented (yet).
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created ERP
  *
  * RETURN VALUES
- *   erp                modified ERP pointer
+ *   erp		modified ERP pointer
  *
  */
-void
-dasd_3990_erp_compound_config (ccw_req_t *erp,
-                               char      *sense)
+static void
+dasd_3990_erp_compound_config(dasd_ccw_req_t * erp, char *sense)
 {
 
-        if ((sense[25] & DASD_SENSE_BIT_1) && 
-            (sense[26] & DASD_SENSE_BIT_2)   ) {	
+	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;
+		/* set to suspended duplex state then restart */
+		dasd_device_t *device = erp->device;
 
-                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");
-                
-        }
+		DEV_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");
 
-        erp->function = dasd_3990_erp_compound_config;
+	}
 
-} /* end dasd_3990_erp_compound_config */
+	erp->function = dasd_3990_erp_compound_config;
+
+}				/* end dasd_3990_erp_compound_config */
 
 /*
  * DASD_3990_ERP_COMPOUND 
@@ -2406,50 +2056,44 @@
  *   compound retry was not successful.
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the current (failed) ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the current (failed) ERP
  *
  * RETURN VALUES
- *   erp                (additional) ERP pointer
+ *   erp		(additional) ERP pointer
  *
  */
-ccw_req_t *
-dasd_3990_erp_compound (ccw_req_t *erp,
-                        char      *sense)
+static dasd_ccw_req_t *
+dasd_3990_erp_compound(dasd_ccw_req_t * erp, char *sense)
 {
 
-        if ((erp->function == dasd_3990_erp_compound_retry) &&
-            (erp->status   == CQR_STATUS_ERROR            )   ) {
-                
-                dasd_3990_erp_compound_path (erp,
-                                             sense);
-        }
+	if ((erp->function == dasd_3990_erp_compound_retry) &&
+	    (erp->status == DASD_CQR_ERROR)) {
+
+		dasd_3990_erp_compound_path(erp, sense);
+	}
 
-        if ((erp->function == dasd_3990_erp_compound_path) &&
-            (erp->status   == CQR_STATUS_ERROR           )    ){
+	if ((erp->function == dasd_3990_erp_compound_path) &&
+	    (erp->status == DASD_CQR_ERROR)) {
 
-                erp = dasd_3990_erp_compound_code (erp,
-                                                   sense);
-        }
+		erp = dasd_3990_erp_compound_code(erp, sense);
+	}
 
-        if ((erp->function == dasd_3990_erp_compound_code) && 
-            (erp->status   == CQR_STATUS_ERROR           )   ) {
-                
-                dasd_3990_erp_compound_config (erp,
-                                               sense);
-        }
+	if ((erp->function == dasd_3990_erp_compound_code) &&
+	    (erp->status == DASD_CQR_ERROR)) {
 
-        /* if no compound action ERP specified, the request failed */
-        if (erp->status == CQR_STATUS_ERROR) {
+		dasd_3990_erp_compound_config(erp, sense);
+	}
 
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-        }
+	/* if no compound action ERP specified, the request failed */
+	if (erp->status == DASD_CQR_ERROR) {
 
-        return erp;
-        
-} /* end dasd_3990_erp_compound */
+		erp->status = DASD_CQR_FAILED;
+	}
+
+	return erp;
+
+}				/* end dasd_3990_erp_compound */
 
 /*
  * DASD_3990_ERP_INSPECT_32 
@@ -2459,16 +2103,15 @@
  *   and sets up a related error recovery action.  
  *
  * PARAMETER
- *   sense              sense data of the actual error
- *   erp                pointer to the currently created default ERP
+ *   sense		sense data of the actual error
+ *   erp		pointer to the currently created default ERP
  *
  * RETURN VALUES
- *   erp_filled         pointer to the ERP
+ *   erp_filled		pointer to the ERP
  *
  */
-ccw_req_t *
-dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
-                           char      *sense )
+static dasd_ccw_req_t *
+dasd_3990_erp_inspect_32(dasd_ccw_req_t * erp, char *sense)
 {
 
 	dasd_device_t *device = erp->device;
@@ -2478,8 +2121,7 @@
 	if (sense[25] & DASD_SENSE_BIT_0) {
 
 		/* compound program action codes (byte25 bit 0 == '1') */
-                dasd_3990_erp_compound_retry (erp,
-                                              sense);
+		dasd_3990_erp_compound_retry(erp, sense);
 
 	} else {
 
@@ -2487,92 +2129,85 @@
 		switch (sense[25]) {
 
 		case 0x00:	/* success */
-                        DASD_MESSAGE (KERN_DEBUG, device,
-                                      "ERP called for successful request %p"
-                                      " - NO ERP necessary",
-                                      erp);
-                        
-                        erp = dasd_3990_erp_cleanup (erp,
-                                                     CQR_STATUS_DONE);
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "ERP called for successful request %p"
+				    " - NO ERP necessary", erp);
+
+			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_DONE);
+
+			break;
 
-                        break;
-                        
 		case 0x01:	/* fatal error */
-                        DASD_MESSAGE (KERN_ERR, device, "%s",
-                                      "Fatal error should have been "
-                                      "handled within the interrupt handler");
-
-                        erp = dasd_3990_erp_cleanup (erp,
-                                                     CQR_STATUS_FAILED);
-                        break;
+			DEV_MESSAGE(KERN_ERR, device, "%s",
+				    "Fatal error should have been "
+				    "handled within the interrupt handler");
+
+			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
+			break;
 
 		case 0x02:	/* intervention required */
 		case 0x03:	/* intervention required during dual copy */
-                        erp = dasd_3990_erp_int_req (erp);
-                        break;
+			erp = dasd_3990_erp_int_req(erp);
+			break;
 
 		case 0x0F:	/* length mismatch during update write command */
-                        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");
-
-                        erp = dasd_3990_erp_cleanup (erp,
-                                                     CQR_STATUS_FAILED);
-                        break;
+			DEV_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");
+
+			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
+			break;
 
 		case 0x10:	/* logging required for other channel program */
-                        erp = dasd_3990_erp_action_10_32 (erp,
-                                                    sense);
-                        break;
+			erp = dasd_3990_erp_action_10_32(erp, sense);
+			break;
 
 		case 0x15:	/* next track outside defined extend */
-                        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");
-
-                        erp= dasd_3990_erp_cleanup (erp,
-                                                    CQR_STATUS_FAILED);
-                        break;
+			DEV_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");
+
+			erp = dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
+			break;
 
 		case 0x1B:	/* unexpected condition during write */
 
-                        erp = dasd_3990_erp_action_1B_32 (erp,
-                                                          sense);
-                        break;
+			erp = dasd_3990_erp_action_1B_32(erp, sense);
+			break;
 
 		case 0x1C:	/* invalid data */
-                        DASD_MESSAGE (KERN_EMERG, device, "%s",
-                                      "Data recovered during retry with PCI "
-                                      "fetch mode active");
-                        
-                        /* not possible to handle this situation in Linux */    
-                        panic("Invalid data - No way to inform appliction about "
-                              "the possibly incorret data");
+			DEV_MESSAGE(KERN_EMERG, device, "%s",
+				    "Data recovered during retry with PCI "
+				    "fetch mode active");
+
+			/* not possible to handle this situation in Linux */
+			panic
+			    ("Invalid data - No way to inform appliction about "
+			     "the possibly incorret data");
 			break;
 
 		case 0x1D:	/* state-change pending */
-                        DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                                      "A State change pending condition exists "
-                                      "for the subsystem or device");
+			DEV_MESSAGE(KERN_DEBUG, device, "%s",
+				    "A State change pending condition exists "
+				    "for the subsystem or device");
 
-                        erp = dasd_3990_erp_action_4 (erp,
-                                                      sense);
+			erp = dasd_3990_erp_action_4(erp, sense);
 			break;
 
 		default:	/* all others errors - default erp  */
-                        
+			break;
 		}
 	}
 
 	return erp;
 
-} /* end dasd_3990_erp_inspect_32 */
+}				/* end dasd_3990_erp_inspect_32 */
 
 /*
  ***************************************************************************** 
@@ -2588,37 +2223,35 @@
  *   the 24-byte or the 32-byte inspection routine.
  *
  * PARAMETER
- *   erp                pointer to the currently created default ERP
+ *   erp		pointer to the currently created default ERP
  * RETURN VALUES
- *   erp_new            contens was possibly modified 
+ *   erp_new		contens was possibly modified 
  */
-ccw_req_t *
-dasd_3990_erp_inspect (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_inspect(dasd_ccw_req_t * erp)
 {
 
-	ccw_req_t *erp_new = NULL;
+	dasd_ccw_req_t *erp_new = NULL;
 	/* sense data are located in the refers record of the */
-	/* already set up new ERP !                           */
+	/* already set up new ERP !			      */
 	char *sense = erp->refers->dstat->ii.sense.data;
 
 	/* distinguish between 24 and 32 byte sense data */
 	if (sense[27] & DASD_SENSE_BIT_0) {
 
 		/* inspect the 24 byte sense data */
-		erp_new = dasd_3990_erp_inspect_24 (erp,
-                                                    sense);
+		erp_new = dasd_3990_erp_inspect_24(erp, sense);
 
 	} else {
 
 		/* inspect the 32 byte sense data */
-		erp_new = dasd_3990_erp_inspect_32 (erp,
-                                                    sense);
+		erp_new = dasd_3990_erp_inspect_32(erp, sense);
 
-	} /* end distinguish between 24 and 32 byte sense data */
+	}			/* end distinguish between 24 and 32 byte sense data */
 
 	return erp_new;
 
-} /* END dasd_3990_erp_inspect */
+}				/* END dasd_3990_erp_inspect */
 
 /*
  * DASD_3990_ERP_ADD_ERP
@@ -2629,44 +2262,40 @@
  *   This erp is initialized as an default erp (retry TIC)
  *
  * PARAMETER
- *   cqr                head of the current ERP-chain (or single cqr if 
- *                      first error)
+ *   cqr		head of the current ERP-chain (or single cqr if 
+ *			first error)
  * RETURN VALUES
- *   erp                pointer to new ERP-chain head
+ *   erp		pointer to new ERP-chain head
  */
-ccw_req_t *
-dasd_3990_erp_add_erp (ccw_req_t *cqr)
+static dasd_ccw_req_t *
+dasd_3990_erp_add_erp(dasd_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, 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);
+	dasd_ccw_req_t *erp;
 
-                return cqr;
+	erp = dasd_alloc_erp_request((char *) &cqr->magic, 1, 0, cqr->device);
+	if (IS_ERR(erp)) {
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Unable to allocate ERP request");
+		cqr->status = DASD_CQR_FAILED;
+		return cqr;
 	}
 
 	/* initialize request with default TIC to current ERP/CQR */
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda      = (long)(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  = 256;
+	erp->refers = cqr;
+	erp->device = cqr->device;
+	erp->magic = cqr->magic;
+	erp->lpm = 0xFF;
+	erp->expires = 0;
+	erp->retries = 256;
 
-	erp->status = CQR_STATUS_FILLED;
+	erp->status = DASD_CQR_FILLED;
 
 	return erp;
 }
@@ -2680,30 +2309,30 @@
  *   determined based on the sense data.
  *
  * PARAMETER
- *   cqr                head of the current ERP-chain (or single cqr if 
- *                      first error)
+ *   cqr		head of the current ERP-chain (or single cqr if 
+ *			first error)
  *
  * RETURN VALUES
- *   erp                pointer to new ERP-chain head
+ *   erp		pointer to new ERP-chain head
  */
-ccw_req_t *
-dasd_3990_erp_additional_erp (ccw_req_t *cqr)
+static dasd_ccw_req_t *
+dasd_3990_erp_additional_erp(dasd_ccw_req_t * cqr)
 {
 
-	ccw_req_t *erp = NULL;
+	dasd_ccw_req_t *erp = NULL;
 
 	/* add erp and initialize with default TIC */
-	erp = dasd_3990_erp_add_erp (cqr);
+	erp = dasd_3990_erp_add_erp(cqr);
 
 	/* inspect sense, determine specific ERP if possible */
-        if (erp != cqr) {
+	if (erp != cqr) {
 
-                erp = dasd_3990_erp_inspect (erp);
-        }
+		erp = dasd_3990_erp_inspect(erp);
+	}
 
 	return erp;
 
-} /* end dasd_3990_erp_additional_erp */
+}				/* end dasd_3990_erp_additional_erp */
 
 /*
  * DASD_3990_ERP_ERROR_MATCH
@@ -2716,39 +2345,37 @@
  *   24 byte sense byte 25 and 27 is set as well.
  *
  * PARAMETER
- *   cqr1               first cqr, which will be compared with the 
- *   cqr2               second cqr.
+ *   cqr1		first cqr, which will be compared with the 
+ *   cqr2		second cqr.
  *
  * RETURN VALUES
- *   match              'boolean' for match found
- *                      returns 1 if match found, otherwise 0.
+ *   match		'boolean' for match found
+ *			returns 1 if match found, otherwise 0.
  */
-int
-dasd_3990_erp_error_match (ccw_req_t *cqr1,
-			   ccw_req_t *cqr2)
+static int
+dasd_3990_erp_error_match(dasd_ccw_req_t * cqr1, dasd_ccw_req_t * cqr2)
 {
 
 	/* check failed CCW */
-	if (cqr1->dstat->cpa !=
-	    cqr2->dstat->cpa) {
-	//	return 0;	/* CCW doesn't match */
+	if (cqr1->dstat->cpa != cqr2->dstat->cpa) {
+		//	return 0;	/* CCW doesn't match */
 	}
 
 	/* check sense data; byte 0-2,25,27 */
-	if (!((strncmp (cqr1->dstat->ii.sense.data,
-			cqr2->dstat->ii.sense.data,
-			3) == 0) &&
+	if (!((strncmp(cqr1->dstat->ii.sense.data,
+		       cqr2->dstat->ii.sense.data,
+		       3) == 0) &&
 	      (cqr1->dstat->ii.sense.data[27] ==
-	       cqr2->dstat->ii.sense.data[27]   ) &&
+	       cqr2->dstat->ii.sense.data[27]) &&
 	      (cqr1->dstat->ii.sense.data[25] ==
-	       cqr2->dstat->ii.sense.data[25]   )   )) {
+	       cqr2->dstat->ii.sense.data[25]))) {
 
 		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
@@ -2758,19 +2385,19 @@
  *   quick exit if current cqr is not an ERP (cqr->refers=NULL)
  *
  * PARAMETER
- *   cqr                failed cqr (either original cqr or already an erp)
+ *   cqr		failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp                erp-pointer to the already defined error 
- *                      recovery procedure OR
- *                      NULL if a 'new' error occurred.
+ *   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)
+static dasd_ccw_req_t *
+dasd_3990_erp_in_erp(dasd_ccw_req_t * cqr)
 {
 
-	ccw_req_t *erp_head  = cqr,	/* save erp chain head */
-                  *erp_match = NULL;	/* save erp chain head */
+	dasd_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 */
@@ -2779,21 +2406,19 @@
 
 	/* 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 */
+		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 */
 
-	} while ((cqr->refers != NULL) &&
-		 (!match             )   );
+	} while ((cqr->refers != NULL) && (!match));
 
 	if (!match) {
-		return NULL; 	/* no match was found */
+		return NULL;	/* no match was found */
 	}
 
-        return erp_match;	/* return address of matching erp */
+	return erp_match;	/* return address of matching erp */
 
-} /* END dasd_3990_erp_in_erp */
+}				/* END dasd_3990_erp_in_erp */
 
 /*
  * DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
@@ -2802,91 +2427,84 @@
  *   No retry is left for the current ERP. Check what has to be done 
  *   with the ERP.
  *     - do further defined ERP action or
- *     - wait for interrupt or  
+ *     - wait for interrupt or	
  *     - exit with permanent error
  *
  * PARAMETER
- *   erp                ERP which is in progress wiht no retry left
+ *   erp		ERP which is in progress wiht no retry left
  *
  * RETURN VALUES
- *   erp                modified/additional ERP
+ *   erp		modified/additional ERP
  */
-ccw_req_t *
-dasd_3990_erp_further_erp (ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_further_erp(dasd_ccw_req_t * erp)
 {
 
-        dasd_device_t *device = erp->device;
-        char          *sense  = erp->dstat->ii.sense.data;
-        
-        /* check for 24 byte sense ERP */
-	if ((erp->function == dasd_3990_erp_bus_out ) ||
-            (erp->function == dasd_3990_erp_action_1) ||
-            (erp->function == dasd_3990_erp_action_4)   ){
-                
-                erp = dasd_3990_erp_action_1 (erp);
-                
+	dasd_device_t *device = erp->device;
+	char *sense = erp->dstat->ii.sense.data;
+
+	/* check for 24 byte sense ERP */
+	if ((erp->function == dasd_3990_erp_bus_out) ||
+	    (erp->function == dasd_3990_erp_action_1) ||
+	    (erp->function == dasd_3990_erp_action_4)) {
+
+		erp = dasd_3990_erp_action_1(erp);
+
 	} else if (erp->function == dasd_3990_erp_action_5) {
-                
-                /* retries have not been successful */
-                /* prepare erp for retry on different channel path */
-                erp = dasd_3990_erp_action_1 (erp);
-                
-                if (!(sense[ 2] & DASD_SENSE_BIT_0)) {
-
-                        /* issue a Diagnostic Control command with an 
-                         * Inhibit Write subcommand */
-
-                        switch (sense[25]) {
-                        case 0x17:
-                        case 0x57: { /* controller */
-                                erp = dasd_3990_erp_DCTL (erp,
-                                                          0x20);
-                                break;
-                        }
-                        case 0x18:
-                        case 0x58: { /* channel path */
-                                erp = dasd_3990_erp_DCTL (erp,
-                                                          0x40);
-                                break;
-                        }
-                        case 0x19:
-                        case 0x59: { /* storage director */
-                                erp = dasd_3990_erp_DCTL (erp,
-                                                          0x80);
-                                break;
-                        }
-                        default:
-                                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_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);
+
+		/* retries have not been successful */
+		/* prepare erp for retry on different channel path */
+		erp = dasd_3990_erp_action_1(erp);
+
+		if (!(sense[2] & DASD_SENSE_BIT_0)) {
+
+			/* issue a Diagnostic Control command with an 
+			 * Inhibit Write subcommand */
+
+			switch (sense[25]) {
+			case 0x17:
+			case 0x57:{	/* controller */
+					erp = dasd_3990_erp_DCTL(erp, 0x20);
+					break;
+				}
+			case 0x18:
+			case 0x58:{	/* channel path */
+					erp = dasd_3990_erp_DCTL(erp, 0x40);
+					break;
+				}
+			case 0x19:
+			case 0x59:{	/* storage director */
+					erp = dasd_3990_erp_DCTL(erp, 0x80);
+					break;
+				}
+			default:
+				DEV_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_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_ERR, device,
-                              "no retries left for erp %p - "
-                              "set status to FAILED",
-                              erp);
+		/* no retry left and no additional special handling necessary */
+		DEV_MESSAGE(KERN_ERR, device,
+			    "no retries left for erp %p - "
+			    "set status to FAILED", erp);
 
-		check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
+		erp->status = DASD_CQR_FAILED;
 	}
 
-	return erp; 
+	return erp;
 
-} /* end dasd_3990_erp_further_erp */
+}				/* end dasd_3990_erp_further_erp */
 
 /*
  * DASD_3990_ERP_HANDLE_MATCH_ERP 
@@ -2900,343 +2518,206 @@
  *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
- *   erp_head           first ERP in ERP-chain
- *   erp                ERP that handles the actual error.
- *                      (matching erp)
+ *   erp_head		first ERP in ERP-chain
+ *   erp		ERP that handles the actual error.
+ *			(matching erp)
  *
  * RETURN VALUES
- *   erp                modified/additional ERP
+ *   erp		modified/additional ERP
  */
-ccw_req_t *
-dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head,
-				ccw_req_t *erp)
+static dasd_ccw_req_t *
+dasd_3990_erp_handle_match_erp(dasd_ccw_req_t * erp_head, dasd_ccw_req_t * erp)
 {
 
-	dasd_device_t *device   = erp_head->device;
-	ccw_req_t     *erp_done = erp_head;  /* finished req */
-        ccw_req_t     *erp_free = NULL;      /* req to be freed */    
-        
+	dasd_device_t *device = erp_head->device;
+	dasd_ccw_req_t *erp_done = erp_head;	/* finished req */
+	dasd_ccw_req_t *erp_free = NULL;	/* req to be freed */
+
 	/* loop over successful ERPs and remove them from chanq */
 	while (erp_done != erp) {
 
-                if (erp_done == NULL) 	/* end of chain reached */
-                        panic (PRINTK_HEADER "Programming error in ERP! The "
-                               "original request was lost\n");
+		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;
+		list_del(&erp_done->list);
+
+		erp_free = erp_done;
 		erp_done = erp_done->refers;
-                
+
 		/* free the finished erp request */
-		dasd_free_request (erp_free, erp_free->device);
+		dasd_free_erp_request(erp_free, erp_free->device);
 
-	} /* end while */
+	}			/* end while */
 
-        if (erp->retries > 0) {
-                
-                char *sense = erp->dstat->ii.sense.data;
-                
-                /* check for special retries */
-                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_DEBUG, device,
-                                      "%i retries left for erp %p",
-                                      erp->retries,
-                                      erp);
-                        
-                        /* handle the request again... */
-                        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 = dasd_3990_erp_further_erp (erp);
-	}
-
-        return erp;
-        
-} /* end dasd_3990_erp_handle_match_erp */
+	if (erp->retries > 0) {
 
-/*
- * DASD_3990_ERP_ACTION
- *
- * DESCRIPTION
- *   controll routine for 3990 erp actions.
- *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
- *
- * PARAMETER
- *   cqr                failed cqr (either original cqr or already an erp)
- *
- * RETURN VALUES
- *   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)
- */
-ccw_req_t *
-dasd_3990_erp_action (ccw_req_t *cqr)
-{
+		char *sense = erp->dstat->ii.sense.data;
 
-	ccw_req_t     *erp    = NULL;
-	dasd_device_t *device = cqr->device;
-        __u32         cpa     = cqr->dstat->cpa;    
+		/* check for special retries */
+		if (erp->function == dasd_3990_erp_action_4) {
 
-#ifdef ERP_DEBUG 
-        DASD_MESSAGE (KERN_DEBUG, device,
-                      "entering 3990 ERP for "
-                      "0x%04X on sch %d = /dev/%s ",
-                      device->devinfo.devno,
-                      device->devinfo.irq,
-                      device->name);
+			erp = dasd_3990_erp_action_4(erp, sense);
 
-	/* print current erp_chain */
-        DASD_MESSAGE (KERN_DEBUG, device, "%s",
-                      "ERP chain at BEGINNING of ERP-ACTION");
-        {
-                ccw_req_t *temp_erp = NULL;
-                for (temp_erp = cqr; 
-                     temp_erp != NULL; 
-                     temp_erp = temp_erp->refers){
-
-                        DASD_MESSAGE (KERN_DEBUG, device,
-                                      "      erp %p refers to %p",
-                                      temp_erp,
-                                      temp_erp->refers);
-                }
-        } 
-#endif /* ERP_DEBUG */
+		} else if (erp->function == dasd_3990_erp_action_1B_32) {
 
-	/* double-check if current erp/cqr was successfull */
-	if ((cqr->dstat->cstat == 0x00                                 ) &&
-	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))   ) {
+			erp = dasd_3990_update_1B(erp, sense);
 
-                DASD_MESSAGE (KERN_DEBUG, device,
-                              "ERP called for successful request %p"
-                              " - NO ERP necessary",
-                              cqr);
-                
-                check_then_set (&cqr->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_DONE);
+		} else if (erp->function == dasd_3990_erp_int_req) {
 
-		return cqr;
-	}
-	/* check if sense data are available */
-	if (!cqr->dstat->ii.sense.data) {
-		DASD_MESSAGE (KERN_DEBUG, device,
-			"ERP called witout sense data avail ..."
-			"request %p - NO ERP possible",
-			cqr);
-
-                check_then_set (&cqr->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
-
-		return cqr; 
+			erp = dasd_3990_erp_int_req(erp);
 
-	}
+		} else {
+			/* simple retry	  */
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "%i retries left for erp %p",
+				    erp->retries, erp);
 
-	/* check if error happened before */
-	erp = dasd_3990_erp_in_erp (cqr);
+			/* handle the request again... */
+			erp->status = DASD_CQR_QUEUED;
+		}
 
-	if (erp == NULL) {
-		/* no matching erp found - set up erp */
-		erp = dasd_3990_erp_additional_erp (cqr);
 	} else {
-		/* matching erp found - set all leading erp's to DONE */
-		erp = dasd_3990_erp_handle_match_erp (cqr, 
-                                                      erp);
+		/* no retry left - check for further necessary action	 */
+		/* if no further actions, handle rest as permanent error */
+		erp = dasd_3990_erp_further_erp(erp);
 	}
 
-#ifdef ERP_DEBUG
-	/* 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 refers to %p",
-                                      temp_erp,
-                                      temp_erp->refers);
-                }
-        }
-#endif /* ERP_DEBUG */
-
-        if (erp->status == CQR_STATUS_FAILED) {
-
-                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();
-                }
-
-        }
-
 	return erp;
 
-} /* end dasd_3990_erp_action */
+}				/* end dasd_3990_erp_handle_match_erp */
 
 /*
- * DASD_3990_ERP_POSTACTION
+ * DASD_3990_ERP_ACTION
  *
  * 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.
+ *   controll routine for 3990 erp actions.
+ *   Has to be called with the queue lock (namely the s390_irq_lock) acquired.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   cqr		failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   cqr                pointer to the original CQR
+ *   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)
  */
-ccw_req_t *
-dasd_3990_erp_postaction (ccw_req_t *erp)
+dasd_ccw_req_t *
+dasd_3990_erp_action(dasd_ccw_req_t * cqr)
 {
 
-	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;
+	dasd_ccw_req_t *erp = NULL;
+	dasd_device_t *device = cqr->device;
+	__u32 cpa = cqr->dstat->cpa;
 
 #ifdef ERP_DEBUG
-
 	/* print current erp_chain */
-	printk (KERN_DEBUG PRINTK_HEADER
-		"3990 ERP postaction called for erp chain:\n");
+	DEV_MESSAGE(KERN_DEBUG, device, "%s",
+		    "ERP chain at BEGINNING of ERP-ACTION");
 	{
-		ccw_req_t *temp_erp = NULL;
+		dasd_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);
+		for (temp_erp = cqr;
+		     temp_erp != NULL; temp_erp = temp_erp->refers) {
+
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "	   erp %p refers to %p",
+				    temp_erp, temp_erp->refers);
 		}
 	}
+#endif				/* ERP_DEBUG */
 
-#endif /* ERP_DEBUG */
-
-	/* free all ERPs - but NOT the original cqr */
-	while (erp->refers != NULL) {
+	/* double-check if current erp/cqr was successfull */
+	if ((cqr->dstat->cstat == 0x00) &&
+	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
 
-		free_erp = erp;
-		erp      = erp->refers;
+		DEV_MESSAGE(KERN_DEBUG, device,
+			    "ERP called for successful request %p"
+			    " - NO ERP necessary", cqr);
 
-		/* remove the request from the device queue */
-		dasd_chanq_deq (&device->queue,
-                                free_erp);
+		cqr->status = DASD_CQR_DONE;
 
-		/* free the finished erp request */
-		dasd_free_request (free_erp, free_erp->device);
+		return cqr;
 	}
+	/* check if sense data are available */
+	if (!cqr->dstat->ii.sense.data) {
+		DEV_MESSAGE(KERN_DEBUG, device,
+			    "ERP called witout sense data avail ..."
+			    "request %p - NO ERP possible", cqr);
 
-	/* save ptr to original cqr */
-	cqr = erp;
+		cqr->status = DASD_CQR_FAILED;
 
-	/* set corresponding status to original cqr */
-	if (success) {
+		return cqr;
 
-		check_then_set (&cqr->status, 
-                                CQR_STATUS_ERROR,
-				CQR_STATUS_DONE);
-	} else {
+	}
 
-		check_then_set (&cqr->status,
-				CQR_STATUS_ERROR, 
-                                CQR_STATUS_FAILED);
+	/* check if error happened before */
+	erp = dasd_3990_erp_in_erp(cqr);
+
+	if (erp == NULL) {
+		/* no matching erp found - set up erp */
+		erp = dasd_3990_erp_additional_erp(cqr);
+	} else {
+		/* matching erp found - set all leading erp's to DONE */
+		erp = dasd_3990_erp_handle_match_erp(cqr, erp);
 	}
 
 #ifdef ERP_DEBUG
 	/* print current erp_chain */
-	printk (KERN_DEBUG PRINTK_HEADER
-		"3990 ERP postaction finished with remaining chain:\n");
+	DEV_MESSAGE(KERN_DEBUG, device, "%s", "ERP chain at END of ERP-ACTION");
 	{
-		ccw_req_t *temp_erp = NULL;
+		dasd_ccw_req_t *temp_erp = NULL;
+		for (temp_erp = erp;
+		     temp_erp != NULL; temp_erp = temp_erp->refers) {
+
+			DEV_MESSAGE(KERN_DEBUG, device,
+				    "	   erp %p refers to %p",
+				    temp_erp, temp_erp->refers);
+		}
+	}
+#endif				/* ERP_DEBUG */
 
-		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);
+	if (erp->status == DASD_CQR_FAILED)
+		dasd_log_ccw(erp, 1, cpa);
+
+	/* enqueue added ERP request */
+	if ((erp != cqr) && (erp->status == DASD_CQR_FILLED)) {
+		erp->status = DASD_CQR_QUEUED;
+		list_add(&erp->list, &device->ccw_queue);
+	} else {
+		if ((erp->status == DASD_CQR_FILLED) || (erp != cqr)) {
+			/* something strange happened - log the error and throw a BUG() */
+			DEV_MESSAGE(KERN_ERR, device, "%s",
+				    "Problems with ERP chain!!! BUG");
+
+			/* print current erp_chain */
+			DEV_MESSAGE(KERN_DEBUG, device, "%s",
+				    "ERP chain at END of ERP-ACTION");
+			{
+				dasd_ccw_req_t *temp_erp = NULL;
+				for (temp_erp = erp;
+				     temp_erp != NULL;
+				     temp_erp = temp_erp->refers) {
+
+					DEV_MESSAGE(KERN_DEBUG, device,
+						    "	   erp %p (function %p)"
+						    " refers to %p",
+						    temp_erp,
+						    temp_erp->function,
+						    temp_erp->refers);
+				}
+			}
+			BUG();
 		}
+
 	}
-#endif /* ERP_DEBUG */
 
-	return cqr;
+	return erp;
 
-} /* end dasd_3990_erp_postaction */
+}				/* end dasd_3990_erp_action */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
@@ -3252,7 +2733,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_3990_erp.h b/drivers/s390/block/dasd_3990_erp.h
--- a/drivers/s390/block/dasd_3990_erp.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/block/dasd_3990_erp.h	Sat Jun  8 22:31:36 2002
@@ -10,16 +10,16 @@
 #ifndef DASD_3990_ERP_H
 #define DASD_3990_ERP_H
 
-dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *);
+dasd_era_t dasd_3990_erp_examine(dasd_ccw_req_t *, devstat_t *);
 
-ccw_req_t *dasd_3990_erp_action (ccw_req_t *);
-ccw_req_t *dasd_2105_erp_action (ccw_req_t *);
+dasd_ccw_req_t *dasd_3990_erp_action(dasd_ccw_req_t *);
+dasd_ccw_req_t *dasd_2105_erp_action(ccw_req_t *);
 
-void dasd_3990_erp_restart_queue (unsigned long);
+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 char modifier;	/* Subcommand modifier		       */
 	unsigned short res;	/* reserved */
 } __attribute__ ((packed)) DCTL_data_t;
 
diff -Nru a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
--- a/drivers/s390/block/dasd_9336_erp.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/block/dasd_9336_erp.c	Sat Jun  8 22:31:36 2002
@@ -5,14 +5,10 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <asm/ccwcache.h>
+#define PRINTK_HEADER "dasd_erp(9336)"
+
 #include "dasd_int.h"
-#include "dasd_9336_erp.h"
 
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#define PRINTK_HEADER "dasd_erp(9336)"
-#endif				/* PRINTK_HEADER */
 
 /*
  * DASD_9336_ERP_EXAMINE 
@@ -26,16 +22,17 @@
  *   'Chapter 7. 9336 Sense Data'.
  *
  * RETURN VALUES
- *   dasd_era_none      no error 
- *   dasd_era_fatal     for all fatal (unrecoverable errors)
- *   dasd_era_recover   for all others.
+ *   dasd_era_none	no error 
+ *   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(dasd_ccw_req_t * cqr, devstat_t * stat)
 {
 	/* 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;
@@ -56,7 +53,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_9336_erp.h b/drivers/s390/block/dasd_9336_erp.h
--- a/drivers/s390/block/dasd_9336_erp.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd_9336_erp.h	Sat Jun  8 22:31:37 2002
@@ -10,6 +10,6 @@
 #ifndef DASD_9336_ERP_H
 #define DASD_9336_ERP_H
 
-dasd_era_t dasd_9336_erp_examine (ccw_req_t *, devstat_t *);
+dasd_era_t dasd_9336_erp_examine(dasd_ccw_req_t *, devstat_t *);
 
 #endif				/* DASD_3990_ERP_H */
diff -Nru a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
--- a/drivers/s390/block/dasd_9343_erp.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/s390/block/dasd_9343_erp.c	Sat Jun  8 22:31:43 2002
@@ -5,18 +5,15 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <asm/ccwcache.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)
+#include "dasd_int.h"
+
+dasd_era_t
+dasd_9343_erp_examine(dasd_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 -Nru a/drivers/s390/block/dasd_9343_erp.h b/drivers/s390/block/dasd_9343_erp.h
--- a/drivers/s390/block/dasd_9343_erp.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/block/dasd_9343_erp.h	Sat Jun  8 22:31:36 2002
@@ -10,8 +10,8 @@
 #ifndef DASD_9343_ERP_H
 #define DASD_9343_ERP_H
 
-dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *);
+dasd_era_t dasd_9343_erp_examine(dasd_ccw_req_t *, devstat_t *);
 
-ccw_req_t *dasd_9343_erp_action (ccw_req_t *);
+dasd_ccw_req_t *dasd_9343_erp_action(dasd_ccw_req_t *);
 
 #endif				/* DASD_9343_ERP_H */
diff -Nru a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/block/dasd_devmap.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,531 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd_devmap.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
+ *
+ * Device mapping and dasd= parameter parsing functions. All devmap
+ * functions may not be called from interrupt context. In particular
+ * dasd_get_device is a no-no from interrupt context.
+ *
+ * 05/04/02 split from dasd.c, code restructuring.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+
+#include <asm/debug.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* This is ugly... */
+#define PRINTK_HEADER "dasd_devmap:"
+
+#include "dasd_int.h"
+
+/*
+ * Parameter parsing functions for dasd= parameter. The syntax is:
+ *   <devno>		: (0x)?[0-9a-fA-F]+
+ *   <feature>		: ro
+ *   <feature_list>	: \(<feature>(:<feature>)*\)
+ *   <range>		: <devno>(-<devno>)?<feature_list>?
+ *   <dasd_module>	: dasd_diag_mod|dasd_eckd_mod|dasd_fba_mod
+ *
+ *   <dasd>		: autodetect|probeonly|<range>(,<range>)*
+ */
+
+int dasd_probeonly =  0;	/* is true, when probeonly mode is active */
+int dasd_autodetect = 0;	/* is true, when autodetection is active */
+
+/*
+ * 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.
+ */
+static char *dasd[256];
+
+/*
+ * Single spinlock to protect devmap structures and lists.
+ */
+static spinlock_t dasd_devmap_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Hash lists for devmap structures.
+ */
+static struct list_head dasd_devindex_hashlists[256];
+static struct list_head dasd_devno_hashlists[256];
+int dasd_max_devindex;
+
+#ifndef MODULE
+/*
+ * The parameter parsing functions for builtin-drivers are called
+ * before kmalloc works. Store the pointers to the parameters strings
+ * into dasd[] for later processing.
+ */
+static int __init
+dasd_call_setup(char *str)
+{
+	static int count = 0;
+
+	if (count < 256)
+		dasd[count++] = str;
+	return 1;
+}
+
+__setup ("dasd=", dasd_call_setup);
+#endif	/* #ifndef MODULE */
+
+/*
+ * Read a device number from a string. The number is always in hex,
+ * a leading 0x is accepted.
+ */
+int
+dasd_devno(char *str, char **endp)
+{
+	/* remove leading '0x' */
+	if (*str == '0') {
+		str++;
+		if (*str == 'x')
+			str++;
+	}
+	/* We require at least one hex digit */
+	if (!isxdigit(*str))
+		return -EINVAL;
+	return simple_strtoul(str, endp, 16);
+}
+
+/*
+ * Read colon separated list of dasd features. Currently there is
+ * only one: "ro" for read-only devices. The default feature set
+ * is empty (value 0).
+ */
+int
+dasd_feature_list(char *str, char **endp)
+{
+	int features, len, rc;
+
+	rc = 0;
+	if (*str != '(') {
+		*endp = str;
+		return DASD_FEATURE_DEFAULT;
+	}
+	features = 0;
+	while (1) {
+		for (len = 0; 
+		     str[len] && str[len] != ':' && str[len] != ')'; len++);
+		if (len == 2 && !strncmp(str, "ro", 2))
+			features |= DASD_FEATURE_READONLY;
+		else {
+			MESSAGE(KERN_WARNING,
+				"unsupported feature: %*s, "
+				"ignoring setting", len, str);
+			rc = -EINVAL;
+		}
+		str += len;
+		if (*str != ':')
+			break;
+		str++;
+	}
+	if (*str != ')') {
+		MESSAGE(KERN_WARNING, "%s",
+			"missing ')' in dasd parameter string\n");
+		rc = -EINVAL;
+	} else
+		str++;
+	*endp = str;
+	if (rc != 0)
+		return rc;
+	return features;
+}
+
+/*
+ * Read comma separated list of dasd ranges.
+ */
+static inline int
+dasd_ranges_list(char *str)
+{
+	int from, to, features, rc;
+
+	while (1) {
+		to = from = dasd_devno(str, &str);
+		if (*str == '-') {
+			str++;
+			to = dasd_devno(str, &str);
+		}
+		features = dasd_feature_list(str, &str);
+		/* Negative numbers in from/to/features indicate errors */
+		if (from >= 0 && to >= 0 && features >= 0) {
+			rc = dasd_add_range(from, to, features);
+			if (rc)
+				return rc;
+		}
+		if (*str != ',')
+			break;
+		str++;
+	}
+	if (*str != '\0') {
+		MESSAGE(KERN_WARNING,
+			"junk at end of dasd parameter string: %s\n", str);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * Parse a single dasd= parameter.
+ */
+static int
+dasd_parameter(char *str)
+{
+	if (strcmp ("autodetect", str) == 0) {
+		dasd_autodetect = 1;
+		MESSAGE (KERN_INFO, "%s",
+			 "turning to autodetection mode");
+		return 0;
+	}
+	if (strcmp ("probeonly", str) == 0) {
+		dasd_probeonly = 1;
+		MESSAGE(KERN_INFO, "%s",
+			"turning to probeonly mode");
+		return 0;
+	}
+	/* turn off autodetect mode and scan for dasd ranges */
+	dasd_autodetect = 0;
+	return dasd_ranges_list(str);
+}
+
+/*
+ * Parse parameters stored in dasd[] and dasd_disciplines[].
+ */
+int
+dasd_parse(void)
+{
+	int rc, i;
+
+	rc = 0;
+	for (i = 0; i < 256; i++) {
+		if (dasd[i] == NULL)
+			break;
+		rc = dasd_parameter(dasd[i]);
+		if (rc) {
+			DBF_EVENT(DBF_ALERT, "%s", "invalid range found");
+			break;
+		}
+	}
+	return rc;
+}
+
+/*
+ * Add a range of devices and creates the corresponding devreg_t
+ * structures. The order of the ranges added through this function
+ * will define the kdevs for the individual devices. 
+ */
+int
+dasd_add_range(int from, int to, int features)
+{
+	int devindex;
+	int devno;
+
+	if (from > to) {
+		MESSAGE(KERN_ERR,
+			"Invalid device range %04x-%04x", from, to);
+		return -EINVAL;
+	}
+	spin_lock(&dasd_devmap_lock);
+	for (devno = from; devno <= to; devno++) {
+		dasd_devmap_t *devmap, *tmp;
+		struct list_head *l;
+
+		devmap = NULL;
+		/* Find previous devmap for device number i */
+		list_for_each(l, &dasd_devno_hashlists[devno & 255]) {
+			tmp = list_entry(l, dasd_devmap_t, devno_list);
+			if (tmp->devno == devno) {
+				devmap = tmp;
+				break;
+			}
+		}
+		if (devmap == NULL) {
+			/* This devno is new. */
+			devmap = (dasd_devmap_t *)
+				kmalloc(sizeof(dasd_devmap_t), GFP_KERNEL);
+			if (devmap == NULL)
+				return -ENOMEM;
+			devindex = dasd_max_devindex++;
+			devmap->devindex = devindex;
+			devmap->devno = devno;
+			devmap->features = features;
+			devmap->devreg = NULL;
+			devmap->device = NULL;
+			list_add(&devmap->devindex_list,
+				 &dasd_devindex_hashlists[devindex & 255]);
+			list_add(&devmap->devno_list,
+				 &dasd_devno_hashlists[devno & 255]);
+		}
+		if (devmap->devreg == NULL) {
+			/* The devreg is missing. */
+			devmap->devreg = (devreg_t *)
+				kmalloc(sizeof(devreg_t), GFP_KERNEL);
+			if (devmap->devreg == NULL)
+				return -ENOMEM;
+			memset(devmap->devreg, sizeof(devreg_t), 0);
+			devmap->devreg->ci.devno = devno;
+			devmap->devreg->flag = DEVREG_TYPE_DEVNO;
+			devmap->devreg->oper_func = dasd_oper_handler;
+			s390_device_register(devmap->devreg);
+		}
+	}
+	spin_unlock(&dasd_devmap_lock);
+	return 0;
+}
+
+/*
+ * Removes the devreg_t structures for a range of devices. This does
+ * NOT remove the range itself. The mapping between devno and kdevs
+ * for the devices is remembered until dasd_forget_ranges() is called.
+ */
+static int
+dasd_clear_range(int from, int to)
+{
+	int devno;
+
+	if (from > to) {
+		MESSAGE(KERN_ERR,
+			"Invalid device range %04x-%04x", from, to);
+		return -EINVAL;
+	}
+	spin_lock(&dasd_devmap_lock);
+	for (devno = from; devno <= to; devno++) {
+		struct list_head *l;
+		dasd_devmap_t *devmap = NULL;
+		/* Find previous devmap for device number i */
+		list_for_each(l, &dasd_devno_hashlists[devno & 255]) {
+			devmap = list_entry(l, dasd_devmap_t, devno_list);
+			if (devmap->devno == devno)
+				break;
+		}
+		if (devmap == NULL)
+			continue;
+		if (devmap->device != NULL)
+			BUG();
+		if (devmap->devreg == NULL)
+			continue;
+		s390_device_unregister(devmap->devreg);
+		kfree(devmap->devreg);
+		devmap->devreg = NULL;
+	}
+	spin_unlock(&dasd_devmap_lock);
+	return 0;
+}
+
+/*
+ * Forget all about the device numbers added so far.
+ * This may only be called at module unload or system shutdown.
+ */
+static void
+dasd_forget_ranges(void)
+{
+	int i;
+
+	spin_lock(&dasd_devmap_lock);
+	for (i = 0; i < 256; i++) {
+		struct list_head *l, *next;
+		dasd_devmap_t *devmap;
+		list_for_each_safe(l, next, &dasd_devno_hashlists[i]) {
+			devmap = list_entry(l, dasd_devmap_t, devno_list);
+			if (devmap->device != NULL)
+				BUG();
+			if (devmap->devreg != NULL) {
+				s390_device_unregister(devmap->devreg);
+				kfree(devmap->devreg);
+				devmap->devreg = NULL;
+			}
+			list_del(&devmap->devindex_list);
+			list_del(&devmap->devno_list);
+			kfree(devmap);
+		}
+	}
+	spin_unlock(&dasd_devmap_lock);
+}
+
+/*
+ * Find the devmap structure from a devno. Can be removed as soon
+ * as big minors are available.
+ */
+dasd_devmap_t *
+dasd_devmap_from_devno(int devno)
+{
+	struct list_head *l;
+	dasd_devmap_t *devmap, *tmp;
+		
+	devmap = NULL;
+	spin_lock(&dasd_devmap_lock);
+	/* Find devmap for device with device number devno */
+	list_for_each(l, &dasd_devno_hashlists[devno&255]) {
+		tmp = list_entry(l, dasd_devmap_t, devno_list);
+		if (tmp->devno == devno) {
+			/* Found the device, return devmap */
+			devmap = tmp;
+			break;
+		}
+	}
+	spin_unlock(&dasd_devmap_lock);
+	return devmap;
+}
+
+/*
+ * Find the devmap for a device by its device index. Can be removed
+ * as soon as big minors are available.
+ */
+dasd_devmap_t *
+dasd_devmap_from_devindex(int devindex)
+{
+	struct list_head *l;
+	dasd_devmap_t *devmap, *tmp;
+		
+	devmap = NULL;
+	spin_lock(&dasd_devmap_lock);
+	/* Find devmap for device with device index devindex */
+	list_for_each(l, &dasd_devindex_hashlists[devindex & 255]) {
+		tmp = list_entry(l, dasd_devmap_t, devindex_list);
+		if (tmp->devindex == devindex) {
+			/* Found the device, return devno */
+			devmap = tmp;
+			break;
+		}
+	}
+	spin_unlock(&dasd_devmap_lock);
+	return devmap;
+}
+
+/*
+ * Find the devmap for a device by its irq line.
+ */
+dasd_devmap_t *
+dasd_devmap_from_irq(int irq)
+{
+	struct list_head *l;
+	dasd_devmap_t *devmap, *tmp;
+	int i;
+
+	devmap = NULL;
+	spin_lock(&dasd_devmap_lock);
+	for (i = 0; (i < 256) && (devmap == NULL); i++) {
+		list_for_each(l, &dasd_devno_hashlists[i & 255]) {
+			tmp = list_entry(l, dasd_devmap_t, devno_list);
+			if (tmp->device != NULL &&
+			    tmp->device->devinfo.irq == irq) {
+				devmap = tmp;
+				break;
+			}
+		}
+	}
+	spin_unlock(&dasd_devmap_lock);
+	return devmap;
+}
+
+/*
+ * Find the devmap for a device corresponding to a kdev.
+ */
+dasd_devmap_t *
+dasd_devmap_from_kdev(kdev_t kdev)
+{
+	int devindex;
+
+	/* Find the devindex for kdev. */
+	devindex = dasd_gendisk_major_index(major(kdev));
+	if (devindex < 0)
+		/* No such major -> no devmap */
+		return NULL;
+	devindex += minor(kdev) >> DASD_PARTN_BITS;
+
+	/* Now find the devmap by the devindex. */
+	return dasd_devmap_from_devindex(devindex);
+}
+
+/*
+ * Find the device structure for device number devno. If it does not
+ * exists yet, allocate it. Increase the reference counter in the device
+ * structure and return a pointer to it.
+ */
+dasd_device_t *
+dasd_get_device(dasd_devmap_t *devmap)
+{
+	dasd_device_t *device;
+
+	spin_lock(&dasd_devmap_lock);
+	device = devmap->device;
+	if (device != NULL)
+		atomic_inc(&device->ref_count);
+	spin_unlock(&dasd_devmap_lock);
+	if (device != NULL)
+		return device;
+
+	device = dasd_alloc_device(devmap);
+	if (IS_ERR(device))
+		return device;
+
+	spin_lock(&dasd_devmap_lock);
+	if (devmap->device != NULL) {
+		/* Someone else was faster. */
+		dasd_free_device(device);
+		device = devmap->device;
+	} else
+		devmap->device = device;
+	atomic_inc(&device->ref_count);
+	spin_unlock(&dasd_devmap_lock);
+	return device;
+}
+
+/*
+ * Decrease the reference counter of a devices structure. If the
+ * reference counter reaches zero and the device status is
+ * DASD_STATE_NEW the device structure is freed. 
+ */
+void
+dasd_put_device(dasd_devmap_t *devmap)
+{
+	dasd_device_t *device;
+
+	spin_lock(&dasd_devmap_lock);
+	device = devmap->device;
+	if (atomic_dec_return(&device->ref_count) == 0 &&
+	    device->state == DASD_STATE_NEW) {
+		devmap->device = NULL;
+		dasd_free_device(device);
+	}
+	spin_unlock(&dasd_devmap_lock);
+}
+
+int
+dasd_devmap_init(void)
+{
+	int i;
+
+	/* Initialize devmap structures. */
+	dasd_max_devindex = 0;
+	for (i = 0; i < 256; i++) {
+		INIT_LIST_HEAD(&dasd_devindex_hashlists[i]);
+		INIT_LIST_HEAD(&dasd_devno_hashlists[i]);
+	}
+	return 0;
+
+}
+
+void
+dasd_devmap_exit(void)
+{
+	dasd_forget_ranges();
+}
+
+EXPORT_SYMBOL(dasd_devmap_from_devno);
+EXPORT_SYMBOL(dasd_devmap_from_devindex);
+EXPORT_SYMBOL(dasd_devmap_from_irq);
+EXPORT_SYMBOL(dasd_devmap_from_kdev);
+EXPORT_SYMBOL(dasd_get_device);
+EXPORT_SYMBOL(dasd_put_device);
diff -Nru a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
--- a/drivers/s390/block/dasd_diag.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/s390/block/dasd_diag.c	Sat Jun  8 22:31:35 2002
@@ -10,25 +10,26 @@
  * 07/13/00 Added fixup sections for diagnoses ans saved some registers
  * 07/14/00 fixed constraints in newly generated inline asm
  * 10/05/00 adapted to 'new' DASD driver
- *          fixed return codes of dia250()
- *          fixed partition handling and HDIO_GETGEO
+ *	    fixed return codes of dia250()
+ *	    fixed partition handling and HDIO_GETGEO
+ * 2002/01/04 Created 2.4-2.5 compatibility mode
+ * 05/04/02 code restructuring.
  */
 
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <asm/debug.h>
-
 #include <linux/slab.h>
-#include <linux/hdreg.h>	/* HDIO_GETGEO                      */
-#include <linux/blk.h>
-#include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include <linux/hdreg.h>	/* HDIO_GETGEO			    */
 
+#include <asm/dasd.h>
+#include <asm/debug.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
+#include <asm/s390_ext.h>
+#include <asm/todclk.h>
 
 #include "dasd_int.h"
 #include "dasd_diag.h"
@@ -36,74 +37,81 @@
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER DASD_NAME"(diag):"
+#define PRINTK_HEADER "dasd(diag):"
 
-dasd_discipline_t dasd_diag_discipline;
+static dasd_discipline_t dasd_diag_discipline;
 
-typedef struct
-    dasd_diag_private_t {
+typedef struct dasd_diag_private_t {
 	dasd_diag_characteristics_t rdc_data;
 	diag_rw_io_t iob;
 	diag_init_io_t iib;
-	unsigned long *label;
+	unsigned int pt_block;
 } dasd_diag_private_t;
 
+typedef struct dasd_diag_req_t {
+	int block_count;
+	diag_bio_t bio[0];
+} dasd_diag_req_t;
+
+
 static __inline__ int
-dia210 (void *devchar)
+dia210(void *devchar)
 {
 	int rc;
 
-	__asm__ __volatile__ ("    diag  %1,0,0x210\n"
-			      "0:  ipm   %0\n"
-			      "    srl   %0,28\n"
-			      "1:\n"
-			      ".section .fixup,\"ax\"\n"
-			      "2:  lhi   %0,3\n"
-			      "    bras  1,3f\n"
-			      "    .long 1b\n"
-			      "3:  l     1,0(1)\n"
-			      "    br    1\n"
-			      ".previous\n"
-			      ".section __ex_table,\"a\"\n"
-			      "    .align 4\n"
-			      "    .long 0b,2b\n" ".previous\n":"=d" (rc)
-			      :"d" ((void *) __pa (devchar))
-			      :"1");
+	__asm__ __volatile__("	  diag	%1,0,0x210\n"
+			     "0:  ipm	%0\n"
+			     "	  srl	%0,28\n"
+			     "1:\n"
+			     ".section .fixup,\"ax\"\n"
+			     "2:  lhi	%0,3\n"
+			     "	  bras	1,3f\n"
+			     "	  .long 1b\n"
+			     "3:  l	1,0(1)\n"
+			     "	  br	1\n"
+			     ".previous\n"
+			     ".section __ex_table,\"a\"\n"
+			     "	  .align 4\n"
+			     "	  .long 0b,2b\n" ".previous\n":"=d"(rc)
+			     :"d"((void *) __pa(devchar))
+			     :"1");
 	return rc;
 }
 
 static __inline__ int
-dia250 (void *iob, int cmd)
+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"
-			      "1:\n"
-			      ".section .fixup,\"ax\"\n"
-			      "2:  lhi   %0,3\n"
-			      "    bras  1,3f\n"
-			      "    .long 1b\n"
-			      "3:  l     1,0(1)\n"
-			      "    br    1\n"
-			      ".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");
+	__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"
+			     "	  bras	1,3f\n"
+			     "	  .long 1b\n"
+			     "3:  l	1,0(1)\n"
+			     "	  br	1\n"
+			     ".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;
 }
 
 static __inline__ int
-mdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size)
+mdsk_init_io(dasd_device_t * device, int blocksize, int offset, int size)
 {
-	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
-	diag_init_io_t *iib = &private->iib;
+	dasd_diag_private_t *private;
+	diag_init_io_t *iib;
 	int rc;
 
-	memset (iib, 0, sizeof (diag_init_io_t));
+	private = (dasd_diag_private_t *) device->private;
+	iib = &private->iib;
+	memset(iib, 0, sizeof (diag_init_io_t));
 
 	iib->dev_nr = device->devinfo.devno;
 	iib->block_size = blocksize;
@@ -111,452 +119,432 @@
 	iib->start_block = 0;
 	iib->end_block = size;
 
-	rc = dia250 (iib, INIT_BIO);
+	rc = dia250(iib, INIT_BIO);
 
 	return rc & 3;
 }
 
 static __inline__ int
-mdsk_term_io (dasd_device_t * device)
+mdsk_term_io(dasd_device_t * device)
 {
-	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
-	diag_init_io_t *iib = &private->iib;
+	dasd_diag_private_t *private;
+	diag_init_io_t *iib;
 	int rc;
 
-	memset (iib, 0, sizeof (diag_init_io_t));
+	private = (dasd_diag_private_t *) device->private;
+	iib = &private->iib;
+	memset(iib, 0, sizeof (diag_init_io_t));
 	iib->dev_nr = device->devinfo.devno;
-	rc = dia250 (iib, TERM_BIO);
+	rc = dia250(iib, TERM_BIO);
 	return rc & 3;
 }
 
-int
-dasd_start_diag (ccw_req_t * cqr)
+static int
+dasd_start_diag(dasd_ccw_req_t * cqr)
 {
-	int rc;
-	dasd_device_t *device = cqr->device;
+	dasd_device_t *device;
 	dasd_diag_private_t *private;
-	diag_rw_io_t *iob;
+	dasd_diag_req_t *dreq;
+	int rc;
 
+	device = cqr->device;
 	private = (dasd_diag_private_t *) device->private;
-	iob = &private->iob;
+	dreq = (dasd_diag_req_t *) cqr->data;
+
+	private->iob.dev_nr = device->devinfo.devno;
+	private->iob.key = 0;
+	private->iob.flags = 2;	/* do asynchronous io */
+	private->iob.block_count = dreq->block_count;
+	private->iob.interrupt_params = (u32) cqr;
+	private->iob.bio_list = __pa(dreq->bio);
 
-	iob->dev_nr = device->devinfo.devno;
-	iob->key = 0;
-	iob->flags = 2;
-	iob->block_count = cqr->cplength >> 1;
-	iob->interrupt_params = (u32) cqr;
-	iob->bio_list = __pa (cqr->cpaddr);
+	cqr->startclk = get_clock();
 
-	asm volatile ("STCK %0":"=m" (cqr->startclk));
-	rc = dia250 (iob, RW_BIO);
+	rc = dia250(&private->iob, RW_BIO);
 	if (rc > 8) {
-		PRINT_WARN ("dia250 returned CC %d\n", rc);
-		check_then_set (&cqr->status,
-				CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
+		MESSAGE(KERN_WARNING, "dia250 returned CC %d", rc);
+		cqr->status = DASD_CQR_ERROR;
 	} else if (rc == 0) {
-		check_then_set (&cqr->status,
-				CQR_STATUS_QUEUED, CQR_STATUS_DONE);
-		dasd_schedule_bh (device);
+		cqr->status = DASD_CQR_DONE;
+		dasd_schedule_bh(device);
 	} else {
-		check_then_set (&cqr->status,
-				CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+		cqr->status = DASD_CQR_IN_IO;
 		rc = 0;
 	}
 	return rc;
 }
 
-void
-dasd_ext_handler (struct pt_regs *regs, __u16 code)
+static 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);
+	dasd_ccw_req_t *cqr, *next;
 	dasd_device_t *device;
-	int done_fast_io = 0;
-	int devno;
-        unsigned long flags;
-
+	unsigned long long expires;
+	unsigned long flags;
+	char status;
+	int ip, cpu;
+
+	/*
+	 * Get the external interruption subcode. VM stores
+	 * this in the 'cpu address' field associated with
+	 * the external interrupt. For diag 250 the subcode
+	 * needs to be 3.
+	 */
+	if ((S390_lowcore.cpu_addr & 0xff00) != 0x0300)
+		return;
+	status = *((char *) &S390_lowcore.ext_params + 5);
+	ip = S390_lowcore.ext_params;
 
+	cpu = smp_processor_id();
 	irq_enter(cpu, -1);
 
 	if (!ip) {		/* no intparm: unsolicited interrupt */
-		printk (KERN_WARNING PRINTK_HEADER
-			"caught unsolicited interrupt\n");
+		MESSAGE(KERN_DEBUG, "%s", "caught unsolicited interrupt");
 		irq_exit(cpu, -1);
 		return;
 	}
-	if (ip & 0x80000001) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"caught spurious interrupt with parm %08x\n", ip);
-		irq_exit(cpu, -1);
-		return;
-	}
-	cqr = (ccw_req_t *) ip;
+	cqr = (dasd_ccw_req_t *) ip;
 	device = (dasd_device_t *) cqr->device;
-
-	devno = device->devinfo.devno;
-	if (device == NULL) {
-		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));
-	}
-	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"0x%04X : /dev/%s (%d:%d)"
-			" magic number of ccw_req_t 0x%08X doesn't match"
-			" discipline 0x%08X\n",
-			devno, device->name,
-			MAJOR (device->kdev), MINOR (device->kdev),
-			cqr->magic, *(int *) (&device->discipline->name));
+	if (strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+		DEV_MESSAGE(KERN_WARNING, device,
+			    " magic number of dasd_ccw_req_t 0x%08X doesn't"
+			    " match discipline 0x%08X",
+			    cqr->magic, *(int *) (&device->discipline->name));
 		irq_exit(cpu, -1);
 		return;
 	}
 
-        /* get irq lock to modify request queue */
-        s390irq_spin_lock_irqsave (device->devinfo.irq, 
-                                   flags);
-
-	asm volatile ("STCK %0":"=m" (cqr->stopclk));
-
-	switch (status) {
-	case 0x00:
-		check_then_set (&cqr->status,
-				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;
+	/* get irq lock to modify request queue */
+	spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+
+	cqr->stopclk = get_clock();
+
+	expires = 0;
+	if (status == 0) {
+		cqr->status = DASD_CQR_DONE;
+		/* Start first request on queue if possible -> fast_io. */
+		if (!list_empty(&device->ccw_queue)) {
+			next = list_entry(device->ccw_queue.next,
+					  dasd_ccw_req_t, list);
+			if (next->status == DASD_CQR_QUEUED) {
+				if (dasd_start_diag(next) == 0)
+					expires = next->expires;
+				else
+					MESSAGE(KERN_WARNING, "%s",
+						"Interrupt fastpath failed!");
 			}
 		}
-		break;
-	case 0x01:
-	case 0x02:
-	case 0x03:
-	default:
-		check_then_set (&cqr->status,
-				CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-		break;
-	}
+	} else 
+		cqr->status = DASD_CQR_FAILED;
 
-        s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
-                                        flags);
+	if (expires != 0)
+		dasd_set_timer(device, expires);
+	else
+		dasd_clear_timer(device);
+	dasd_schedule_bh(device);
 
-	wake_up (&device->wait_q);
-	dasd_schedule_bh (device);
+	spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq), flags);
 	irq_exit(cpu, -1);
 
 }
 
 static int
-dasd_diag_check_characteristics (struct dasd_device_t *device)
+dasd_diag_check_device(dasd_device_t *device)
 {
-	int rc = 0;
-	int bsize;
-	int label_block;
 	dasd_diag_private_t *private;
 	dasd_diag_characteristics_t *rdc_data;
-	ccw_req_t *cqr;
+	diag_bio_t bio;
 	long *label;
-	int sb;
+	int sb, bsize;
+	int rc;
 
-	if (device == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
-	}
-	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;
+	if (private == NULL) {
+		private = kmalloc(sizeof(dasd_diag_private_t), GFP_KERNEL);
+		if (private == NULL) {
+			MESSAGE(KERN_WARNING, "%s",
+				"memory allocation failed for private data");
+			return -ENOMEM;
+		}
+		device->private = (void *) private;
+	}
+	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
-
 	rdc_data->dev_nr = device->devinfo.devno;
 	rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
 
-        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) {
-                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);
-#endif
+	rc = dia210(rdc_data);
+	if (rc)
+		return -ENOTSUPP;
+
 	/* Figure out position of label block */
-	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 {
-                BUG();
+	switch (private->rdc_data.vdev_class) {
+	case DEV_CLASS_FBA:
+		private->pt_block = 1;
+		break;
+	case DEV_CLASS_ECKD:
+		private->pt_block = 2;
+		break;
+	default:
+		return -ENOTSUPP;
 	}
-	private->label = (long *) get_free_page (GFP_KERNEL);
-	label = private->label;
-	mdsk_term_io (device);	/* first terminate all outstanding operations */
+
+	DBF_EVENT(DBF_INFO,
+		  "%04X: %04X on real %04X/%02X",
+		  rdc_data->dev_nr,
+		  rdc_data->vdev_type,
+		  rdc_data->rdev_type, rdc_data->rdev_model);
+
+	/* terminate all outstanding operations */
+	mdsk_term_io(device);
+
 	/* figure out blocksize of device */
+	label = (long *) get_free_page(GFP_KERNEL);
+	if (label == NULL)  {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+		return -ENOMEM;
+	}
 	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 = 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);
-                        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 = device->sizes.pt_block + 1;
-		bio->buffer = __pa (private->label);
-		cqr->device = device;
-		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->bio_list = __pa (bio);
-		rc = dia250 (iob, RW_BIO);
-		if (rc == 0) {
-			if (label[3] != bsize ||
-                            label[0] != 0xc3d4e2f1 ||	/* != CMS1 */
-                            label[13] == 0 ){
-                                rc = -EMEDIUMTYPE;
-				goto fail;
-			}
+		mdsk_init_io(device, bsize, 0, 64);
+		memset(&bio, 0, sizeof (diag_bio_t));
+		bio.type = MDSK_READ_REQ;
+		bio.block_number = private->pt_block + 1;
+		bio.buffer = __pa(label);
+		memset(&private->iob, 0, sizeof (diag_rw_io_t));
+		private->iob.dev_nr = rdc_data->dev_nr;
+		private->iob.key = 0;
+		private->iob.flags = 0;	/* do synchronous io */
+		private->iob.block_count = 1;
+		private->iob.interrupt_params = 0;
+		private->iob.bio_list = __pa(&bio);
+		if (dia250(&private->iob, RW_BIO) == 0)
 			break;
-		}
-		mdsk_term_io (device);
+		mdsk_term_io(device);
 	}
-        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++;
-	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);
-        rc = 0;
-	goto out;
- fail:
-        if ( rc ) {
-                kfree (device->private);
-                device->private = NULL;
-        }
- out:
+	if (bsize <= PAGE_SIZE && label[3] == bsize &&
+	    label[0] == 0xc3d4e2f1 && label[13] != 0) {
+		device->blocks = label[7];
+		device->bp_block = bsize;
+		device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+		for (sb = 512; sb < bsize; sb = sb << 1)
+			device->s2b_shift++;
+		
+		DEV_MESSAGE(KERN_INFO, device,
+			    "capacity (%dkB blks): %ldkB",
+			    (device->bp_block >> 10),
+			    (device->blocks << device->s2b_shift) >> 1);
+		rc = 0;
+	} else
+		rc = -EMEDIUMTYPE;
+	free_page((long) label);
 	return rc;
 }
 
 static int
-dasd_diag_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
+dasd_diag_fill_geometry(dasd_device_t *device, struct hd_geometry *geo)
 {
-	int rc = 0;
-	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
-	unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
-	unsigned long tracks = sectors >> 6;
-	unsigned long trk_rem = sectors & ((1 << 6) - 1);	/* 64k per track */
-	unsigned long cyls = tracks >> 4;
-	unsigned long cyls_rem = tracks & ((1 << 4) - 1);	/* 16 head per cyl */
-
-	switch (device->sizes.bp_block) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-		break;
-	default:
+	if (dasd_check_blocksize(device->bp_block) != 0)
 		return -EINVAL;
-	}
-	geo->cylinders = cyls;
+	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->sizes.s2b_shift;
-	return rc;
+	geo->sectors = 128 >> device->s2b_shift;
+	return 0;
 }
 
 static dasd_era_t
-dasd_diag_examine_error (ccw_req_t * cqr, devstat_t * stat)
+dasd_diag_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat)
 {
 	return dasd_era_fatal;
 }
 
-static ccw_req_t *
-dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
+static dasd_erp_fn_t
+dasd_diag_erp_action(dasd_ccw_req_t * cqr)
 {
-	ccw_req_t *rw_cp = NULL;
-	struct buffer_head *bh;
-	int rw_cmd;
-	int noblk = req->nr_sectors >> device->sizes.s2b_shift;
-	int byt_per_blk = device->sizes.bp_block;
-	int block;
-	diag_bio_t *bio;
-	int bhct;
-	long size;
-
-	if (!noblk) {
-		PRINT_ERR ("No blocks to read/write...returning\n");
-		return NULL;
-	}
-	if (req->cmd == READ) {
+	return dasd_default_erp_action;
+}
+
+static dasd_erp_fn_t
+dasd_diag_erp_postaction(dasd_ccw_req_t * cqr)
+{
+	return dasd_default_erp_postaction;
+}
+
+static dasd_ccw_req_t *
+dasd_diag_build_cp(dasd_device_t * device, struct request *req)
+{
+	dasd_ccw_req_t *cqr;
+	dasd_diag_req_t *dreq;
+	diag_bio_t *dbio;
+	struct bio *bio;
+	struct bio_vec *bv;
+	char *dst;
+	int count, datasize;
+	sector_t recid, first_rec, last_rec;
+	unsigned blksize, off;
+	unsigned char rw_cmd;
+	int i;
+
+	if (rq_data_dir(req) == READ)
 		rw_cmd = MDSK_READ_REQ;
-	} else if (req->cmd == WRITE) {
+	else if (rq_data_dir(req) == WRITE)
 		rw_cmd = MDSK_WRITE_REQ;
+	else
+		return ERR_PTR(-EINVAL);
+	blksize = device->bp_block;
+	/* Calculate record id of first and last block. */
+	first_rec = req->sector >> device->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	/* Check struct bio and count the number of blocks for the request. */
+	count = 0;
+	rq_for_each_bio(bio, req) {
+		bio_for_each_segment(bv, bio, i) {
+			if (bv->bv_len & (blksize - 1))
+				/* Fba can only do full blocks. */
+				return ERR_PTR(-EINVAL);
+			count += bv->bv_len >> (device->s2b_shift + 9);
+		}
 	}
-	bhct = 0;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size < byt_per_blk)
-                        BUG();
-                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
-	}
+	/* Paranoia. */
+	if (count != last_rec - first_rec + 1)
+		return ERR_PTR(-EINVAL);
 	/* Build the request */
-	rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device);
-	if (!rw_cp) {
-		return NULL;
-	}
-	bio = (diag_bio_t *) (rw_cp->cpaddr);
-
-	block = req->sector >> device->sizes.s2b_shift;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-                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->req = req;
-	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
-	return rw_cp;
+	datasize = sizeof(dasd_diag_req_t) + count*sizeof(diag_bio_t);
+	cqr = dasd_smalloc_request(dasd_diag_discipline.name, 0,
+				   datasize, device);
+	if (IS_ERR(cqr))
+		return cqr;
+	
+	dreq = (dasd_diag_req_t *) cqr->data;
+	dreq->block_count = count;
+	dbio = dreq->bio;
+	recid = first_rec;
+	rq_for_each_bio(bio, req) {
+		bio_for_each_segment(bv, bio, i) {
+			dst = kmap(bv->bv_page) + bv->bv_offset;
+			for (off = 0; off < bv->bv_len; off += blksize) {
+				memset(dbio, 0, sizeof (diag_bio_t));
+				dbio->type = rw_cmd;
+				dbio->block_number = recid + 1;
+				dbio->buffer = __pa(dst);
+				dbio++;
+				dst += blksize;
+				recid++;
+			}
+		}
+	}
+	cqr->buildclk = get_clock();
+	cqr->device = device;
+	cqr->expires = 50 * HZ;	/* 50 seconds */
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
 }
 
 static int
-dasd_diag_fill_info (dasd_device_t * device, dasd_information_t * info)
+dasd_diag_fill_info(dasd_device_t * device, dasd_information2_t * info)
 {
-	int rc = 0;
+	dasd_diag_private_t *private;
+
+	private = (dasd_diag_private_t *) device->private;
+	info->label_block = private->pt_block;
 	info->FBA_layout = 1;
+	info->format = DASD_FORMAT_LDL;
 	info->characteristics_size = sizeof (dasd_diag_characteristics_t);
-	memcpy (info->characteristics,
-		&((dasd_diag_private_t *) device->private)->rdc_data,
-		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;
+	return 0;
 }
 
-static char *
-dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
+static void
+dasd_diag_dump_sense(dasd_device_t *device, dasd_ccw_req_t * req)
 {
-	char *page = (char *) get_free_page (GFP_KERNEL);
-	int len;
+	char *page;
+
+	page = (char *) get_free_page(GFP_KERNEL);
 	if (page == NULL) {
-		return NULL;
+		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
+		return;
 	}
-	len = sprintf (page, KERN_WARNING PRINTK_HEADER
-		       "device %04X on irq %d: I/O status report:\n",
-		       device->devinfo.devno, device->devinfo.irq);
+	sprintf(page, KERN_WARNING PRINTK_HEADER
+		"device %04X on irq %d: I/O status report:\n",
+		device->devinfo.devno, device->devinfo.irq);
+
+	MESSAGE(KERN_ERR, "Sense data:\n%s", page);
 
-	return page;
+	free_page((unsigned long) page);
 }
 
-dasd_discipline_t dasd_diag_discipline = {
-        owner: THIS_MODULE,
+/*
+ * max_blocks is dependent on the amount of storage that is available
+ * in the static io buffer for each device. Currently each device has
+ * 8192 bytes (=2 pages). dasd diag is only relevant for 31 bit.
+ * The dasd_ccw_req_t has 96 bytes, the dasd_diag_req_t has 8 bytes and
+ * the diag_bio_t for each block has 16 bytes. 
+ * That makes:
+ * (8192 - 96 - 8) / 16 = 505.5 blocks at maximum.
+ * We want to fit two into the available memory so that we can immediatly
+ * start the next request if one finishes off. That makes 252.75 blocks
+ * for one request. Give a little safety and the result is 240.
+ */
+static dasd_discipline_t dasd_diag_discipline = {
+	owner:THIS_MODULE,
 	name:"DIAG",
 	ebcname:"DIAG",
-	max_blocks:PAGE_SIZE / sizeof (diag_bio_t),
-	check_characteristics:dasd_diag_check_characteristics,
+	max_blocks:240,
+	check_device:dasd_diag_check_device,
 	fill_geometry:dasd_diag_fill_geometry,
 	start_IO:dasd_start_diag,
 	examine_error:dasd_diag_examine_error,
-	build_cp_from_req:dasd_diag_build_cp_from_req,
+	erp_action:dasd_diag_erp_action,
+	erp_postaction:dasd_diag_erp_postaction,
+	build_cp:dasd_diag_build_cp,
 	dump_sense:dasd_diag_dump_sense,
-	int_handler:dasd_ext_handler,
 	fill_info:dasd_diag_fill_info,
 };
 
 int
-dasd_diag_init (void)
+dasd_diag_init(void)
 {
-	int rc = 0;
-	if (MACHINE_IS_VM) {
-		printk (KERN_INFO PRINTK_HEADER
-			"%s discipline initializing\n",
+	if (!MACHINE_IS_VM) {
+		MESSAGE(KERN_INFO,
+			"Machine is not VM: %s discipline not initializing",
 			dasd_diag_discipline.name);
-		ASCEBC (dasd_diag_discipline.ebcname, 4);
-		ctl_set_bit (0, 9);
-		register_external_interrupt (0x2603, dasd_ext_handler);
-		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);
-		rc = -EINVAL;
+		return -EINVAL;
 	}
-	return rc;
+	ASCEBC(dasd_diag_discipline.ebcname, 4);
+	ctl_set_bit(0, 9);
+	register_external_interrupt(0x2603, dasd_ext_handler);
+	dasd_discipline_add(&dasd_diag_discipline);
+	return 0;
 }
 
 void
-dasd_diag_cleanup (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_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",
+	if (!MACHINE_IS_VM) {
+		MESSAGE(KERN_INFO,
+			"Machine is not VM: %s discipline not initializing",
 			dasd_diag_discipline.name);
+		return;
 	}
+	dasd_discipline_del(&dasd_diag_discipline);
+	unregister_external_interrupt(0x2603, dasd_ext_handler);
+	ctl_clear_bit(0, 9);
 }
 
 #ifdef MODULE
 int
-init_module (void)
+init_module(void)
 {
-	int rc = 0;
-	rc = dasd_diag_init ();
-	return rc;
+	return dasd_diag_init();
 }
 
 void
-cleanup_module (void)
+cleanup_module(void)
 {
-	dasd_diag_cleanup ();
-	return;
+	dasd_diag_cleanup();
 }
 #endif
 
@@ -574,7 +562,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
--- a/drivers/s390/block/dasd_diag.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd_diag.h	Sat Jun  8 22:31:37 2002
@@ -10,13 +10,12 @@
 #define MDSK_WRITE_REQ 0x01
 #define MDSK_READ_REQ  0x02
 
-#define INIT_BIO        0x00
-#define RW_BIO          0x01
-#define TERM_BIO        0x02
-
-#define DEV_CLASS_FBA   0x01
-#define DEV_CLASS_ECKD  0x04
-#define DEV_CLASS_CKD   0x04
+#define INIT_BIO	0x00
+#define RW_BIO		0x01
+#define TERM_BIO	0x02
+
+#define DEV_CLASS_FBA	0x01
+#define DEV_CLASS_ECKD	0x04
 
 typedef struct dasd_diag_characteristics_t {
 	u16 dev_nr;
@@ -29,7 +28,7 @@
 	u8 rdev_type;
 	u8 rdev_model;
 	u8 rdev_features;
-} __attribute__ ((packed, aligned (4)))
+} __attribute__ ((packed, aligned(4)))
 
     dasd_diag_characteristics_t;
 
@@ -40,7 +39,7 @@
 	u32 block_number;
 	u32 alet;
 	u32 buffer;
-} __attribute__ ((packed, aligned (8)))
+} __attribute__ ((packed, aligned(8)))
 
     diag_bio_t;
 
@@ -52,7 +51,7 @@
 	u32 start_block;
 	u32 end_block;
 	u32 spare2[6];
-} __attribute__ ((packed, aligned (8)))
+} __attribute__ ((packed, aligned(8)))
 
     diag_init_io_t;
 
@@ -67,9 +66,9 @@
 	u32 bio_list;
 	u32 interrupt_params;
 	u32 spare3[5];
-} __attribute__ ((packed, aligned (8)))
+} __attribute__ ((packed, aligned(8)))
 
     diag_rw_io_t;
 
-int dasd_diag_init (void);
-void dasd_diag_cleanup (void);
+int dasd_diag_init(void);
+void dasd_diag_cleanup(void);
diff -Nru a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
--- a/drivers/s390/block/dasd_eckd.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/s390/block/dasd_eckd.c	Sat Jun  8 22:31:35 2002
@@ -1,10 +1,12 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-                    Carsten Otte <Cotte@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com> 
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
+ *
  * History of changes (starts July 2000)
  * 07/11/00 Enabled rotational position sensing
  * 07/14/00 Reorganized the format process for better ERP
@@ -17,23 +19,25 @@
  * 10/10/00 now dequeuing init_cqr before freeing *ouch*
  * 26/10/00 fixed ITPM20144ASC (problems when accesing a device formatted by VIF)
  * 01/23/01 fixed kmalloc statement in dump_sense to be GFP_ATOMIC
- *          fixed partition handling and HDIO_GETGEO
+ *	    fixed partition handling and HDIO_GETGEO
+ * 2002/01/04 Created 2.4-2.5 compatibility mode
+ * 05/04/02 code restructuring.
  */
 
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
-#include <linux/hdreg.h>	/* HDIO_GETGEO                      */
-#include <linux/blk.h>
+#include <linux/hdreg.h>	/* HDIO_GETGEO			    */
 
 #include <asm/debug.h>
-#include <asm/ccwcache.h>
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
+#include <asm/todclk.h>
+#include <asm/uaccess.h>
 
 #include "dasd_int.h"
 #include "dasd_eckd.h"
@@ -41,8 +45,7 @@
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER DASD_NAME"(eckd):"
-#undef CDL_PRINTK
+#define PRINTK_HEADER "dasd(eckd):"
 
 #define ECKD_C0(i) (i->home_bytes)
 #define ECKD_F(i) (i->formula)
@@ -55,259 +58,255 @@
 #define ECKD_F7(i) (i->factor7)
 #define ECKD_F8(i) (i->factor8)
 
-dasd_discipline_t dasd_eckd_discipline;
+static dasd_discipline_t dasd_eckd_discipline;
 
-typedef struct
-dasd_eckd_private_t {
+typedef struct dasd_eckd_private_t {
 	dasd_eckd_characteristics_t rdc_data;
 	dasd_eckd_confdata_t conf_data;
 	eckd_count_t count_area[5];
+	int init_cqr_status;
 	int uses_cdl;
+	attrib_data_t attrib;	/* e.g. cache operations */
 } dasd_eckd_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
 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_TYPE_DEVCHARS),
-                oper_func:dasd_oper_handler
-        },
+		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:0x9343}},
-                flag:(DEVREG_MATCH_CU_TYPE | 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_TYPE_DEVCHARS),
+		oper_func:dasd_oper_handler
+	}
 };
 #endif
 
-int sizes_trk0[] = { 28, 148, 84 };
+static const int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
 
 static inline unsigned int
-round_up_multiple (unsigned int no, unsigned int mult)
+round_up_multiple(unsigned int no, unsigned int mult)
 {
 	int rem = no % mult;
 	return (rem ? no - rem + mult : no);
 }
 
 static inline unsigned int
-ceil_quot (unsigned int d1, unsigned int d2)
+ceil_quot(unsigned int d1, unsigned int d2)
 {
 	return (d1 + (d2 - 1)) / d2;
 }
 
 static inline int
-bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,	/* key length */
-		  int dl /* data length */ )
+bytes_per_record(dasd_eckd_characteristics_t *rdc, int kl, int dl)
 {
-	int bpr = 0;
+	unsigned int fl1, fl2, int1, int2;
+	int bpr;
+
 	switch (rdc->formula) {
-	case 0x01:{
-			unsigned int fl1, fl2;
-			fl1 = round_up_multiple (ECKD_F2 (rdc) + dl,
-						 ECKD_F1 (rdc));
-			fl2 = round_up_multiple (kl ? ECKD_F2 (rdc) + kl : 0,
-						 ECKD_F1 (rdc));
-			bpr = fl1 + fl2;
-			break;
-		}
-	case 0x02:{
-			unsigned int fl1, fl2, int1, int2;
-			int1 = ceil_quot (dl + ECKD_F6 (rdc),
-					  ECKD_F5 (rdc) << 1);
-			int2 = ceil_quot (kl + ECKD_F6 (rdc),
-					  ECKD_F5 (rdc) << 1);
-			fl1 = round_up_multiple (ECKD_F1 (rdc) *
-						 ECKD_F2 (rdc) +
-						 (dl + ECKD_F6 (rdc) +
-						  ECKD_F4 (rdc) * int1),
-						 ECKD_F1 (rdc));
-			fl2 = round_up_multiple (ECKD_F1 (rdc) *
-						 ECKD_F3 (rdc) +
-						 (kl + ECKD_F6 (rdc) +
-						  ECKD_F4 (rdc) * int2),
-						 ECKD_F1 (rdc));
-			bpr = fl1 + fl2;
-			break;
-		}
+	case 0x01:
+		fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
+		fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
+					ECKD_F1(rdc));
+		bpr = fl1 + fl2;
+		break;
+	case 0x02:
+		int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
+		int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
+		fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
+					ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
+					ECKD_F1(rdc));
+		fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
+					ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
+					ECKD_F1(rdc));
+		bpr = fl1 + fl2;
+		break;
 	default:
-		INTERNAL_ERROR ("unknown formula%d\n", rdc->formula);
+		MESSAGE(KERN_ERR, "unknown formula%d", rdc->formula);
+		bpr = 0;
+		break;
 	}
 	return bpr;
 }
 
 static inline unsigned int
-bytes_per_track (dasd_eckd_characteristics_t * rdc)
+bytes_per_track(dasd_eckd_characteristics_t *rdc)
 {
 	return *(unsigned int *) (rdc->byte_per_track) >> 8;
 }
 
 static inline unsigned int
-recs_per_track (dasd_eckd_characteristics_t * rdc,
-		unsigned int kl, unsigned int dl)
+recs_per_track(dasd_eckd_characteristics_t * rdc,
+	       unsigned int kl, unsigned int dl)
 {
-	int rpt = 0;
-	int dn;
+	int dn, kn;
+
 	switch (rdc->dev_type) {
 	case 0x3380:
 		if (kl)
-			return 1499 / (15 +
-				       7 + ceil_quot (kl + 12, 32) +
-				       ceil_quot (dl + 12, 32));
+			return 1499 / (15 + 7 + ceil_quot(kl + 12, 32) +
+				       ceil_quot(dl + 12, 32));
 		else
-			return 1499 / (15 + ceil_quot (dl + 12, 32));
+			return 1499 / (15 + ceil_quot(dl + 12, 32));
 	case 0x3390:
-		dn = ceil_quot (dl + 6, 232) + 1;
+		dn = ceil_quot(dl + 6, 232) + 1;
 		if (kl) {
-			int kn = ceil_quot (kl + 6, 232) + 1;
-			return 1729 / (10 +
-				       9 + ceil_quot (kl + 6 * kn, 34) +
-				       9 + ceil_quot (dl + 6 * dn, 34));
+			kn = ceil_quot(kl + 6, 232) + 1;
+			return 1729 / (10 + 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;
+		dn = ceil_quot(dl + 6, 232) + 1;
 		if (kl) {
-			int kn = ceil_quot (kl + 6, 232) + 1;
-			return 1420 / (18 +
-				       7 + ceil_quot (kl + 6 * kn, 34) +
-				       ceil_quot (dl + 6 * dn, 34));
+			kn = ceil_quot(kl + 6, 232) + 1;
+			return 1420 / (18 + 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;
+	return 0;
 }
 
-static inline int
-define_extent (ccw1_t * de_ccw,
-	       DE_eckd_data_t * data,
-	       int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr)
+static inline void
+define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk,
+	      int cmd, dasd_device_t * device)
 {
-        int rc=0;
+	dasd_eckd_private_t *private;
 	ch_t geo, beg, end;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
 
-	geo.cyl = private->rdc_data.no_cyl;
-	geo.head = private->rdc_data.trk_per_cyl;
-	beg.cyl = trk / geo.head;
-	beg.head = trk % geo.head;
-	end.cyl = totrk / geo.head;
-	end.head = totrk % geo.head;
+	private = (dasd_eckd_private_t *) device->private;
 
-	memset (de_ccw, 0, sizeof (ccw1_t));
-	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
-	de_ccw->count = 16;
-	if ((rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device))) 
-                return rc;
+	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
+	ccw->flags = 0;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa(data);
 
-	memset (data, 0, sizeof (DE_eckd_data_t));
+	memset(data, 0, sizeof (DE_eckd_data_t));
 	switch (cmd) {
 	case DASD_ECKD_CCW_READ_HOME_ADDRESS:
 	case DASD_ECKD_CCW_READ_RECORD_ZERO:
 	case DASD_ECKD_CCW_READ:
 	case DASD_ECKD_CCW_READ_MT:
-	case DASD_ECKD_CCW_READ_CKD:	/* Fallthrough */
+	case DASD_ECKD_CCW_READ_CKD:
 	case DASD_ECKD_CCW_READ_CKD_MT:
 	case DASD_ECKD_CCW_READ_KD:
 	case DASD_ECKD_CCW_READ_KD_MT:
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->mask.perm = 0x1;
-		data->attributes.operation = 0x3;	/* enable seq. caching */
+		data->attributes.operation = private->attrib.operation;
 		break;
 	case DASD_ECKD_CCW_WRITE:
 	case DASD_ECKD_CCW_WRITE_MT:
 	case DASD_ECKD_CCW_WRITE_KD:
 	case DASD_ECKD_CCW_WRITE_KD_MT:
 		data->mask.perm = 0x02;
-		data->attributes.operation = 0x3;	/* enable seq. caching */
+		data->attributes.operation = private->attrib.operation;
 		break;
 	case DASD_ECKD_CCW_WRITE_CKD:
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
-		data->attributes.operation = 0x1;	/* format through cache */
+		data->attributes.operation = DASD_BYPASS_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;
 		data->mask.auth = 0x1;
-		data->attributes.operation = 0x1;	/* format through cache */
+		data->attributes.operation = DASD_BYPASS_CACHE;
 		break;
 	default:
-		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+		MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd);
 		break;
 	}
-	data->attributes.mode = 0x3;
+
+	data->attributes.mode = 0x3;	/* ECKD */
+
 	if (private->rdc_data.cu_type == 0x2105
-	    && !(private->uses_cdl && trk < 2)
-	    ) {
-		data->reserved |= 0x40;
+	    && !(private->uses_cdl && trk < 2))
+		data->ga_extended |= 0x40;
+
+	geo.cyl = private->rdc_data.no_cyl;
+	geo.head = private->rdc_data.trk_per_cyl;
+	beg.cyl = trk / geo.head;
+	beg.head = trk % geo.head;
+	end.cyl = totrk / geo.head;
+	end.head = totrk % geo.head;
+
+	/* check for sequential prestage - enhance cylinder range */
+	if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
+	    data->attributes.operation == DASD_SEQ_ACCESS) {
+
+		if (end.cyl + private->attrib.nr_cyl < geo.cyl) {
+			end.cyl += private->attrib.nr_cyl;
+			DBF_DEV_EVENT(DBF_NOTICE, device,
+				      "Enhanced DE Cylinder from  %x to %x",
+				      (totrk / geo.head), end.cyl);
+		} else {
+			end.cyl = (geo.cyl - 1);
+			DBF_DEV_EVENT(DBF_NOTICE, device,
+				      "Enhanced DE Cylinder from  %x to "
+				      "End of device %x",
+				      (totrk / geo.head), end.cyl);
+		}
 	}
+
 	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 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, 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 = 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);
-#endif
-	memset (lo_ccw, 0, sizeof (ccw1_t));
-	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
-	lo_ccw->count = 16;
-	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;
+static inline void
+locate_record(ccw1_t *ccw, LO_eckd_data_t *data, int trk,
+	      int rec_on_trk, int no_rec, int cmd,
+	      dasd_device_t * device, int reclen)
+{
+	dasd_eckd_private_t *private;
+	int sector;
+	int dn, d;
+				
+	private = (dasd_eckd_private_t *) device->private;
+
+	DBF_EVENT(DBF_INFO,
+		  "Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d",
+		  trk, rec_on_trk, no_rec, cmd, reclen);
+
+	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
+	ccw->flags = 0;
+	ccw->count = 16;
+	ccw->cda = (__u32) __pa(data);
+
+	memset(data, 0, sizeof (LO_eckd_data_t));
+	sector = 0;
+	if (rec_on_trk) {
+		switch (private->rdc_data.dev_type) {
+		case 0x3390:
+			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:
+			d = 7 + ceil_quot(reclen + 12, 32);
+			sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
+			break;
+		}
+	}
+	data->sector = sector;
 	data->count = no_rec;
 	switch (cmd) {
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -360,593 +359,557 @@
 		data->operation.operation = 0x06;
 		break;
 	case DASD_ECKD_CCW_ERASE:
-                data->length = reclen;
-                data->auxiliary.last_bytes_used = 0x1;
+		data->length = reclen;
+		data->auxiliary.last_bytes_used = 0x1;
 		data->operation.operation = 0x0b;
 		break;
 	default:
-		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
+		MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd);
 	}
-	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
-	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
+	data->seek_addr.cyl = data->search_arg.cyl =
+		trk / private->rdc_data.trk_per_cyl;
+	data->seek_addr.head = data->search_arg.head =
+		trk % private->rdc_data.trk_per_cyl;
 	data->search_arg.record = rec_on_trk;
-        return rc;
 }
 
-static int
-dasd_eckd_id_check (s390_dev_info_t * info)
+/*
+ * Returns 1 if the block is one of the special blocks that needs
+ * to get read/written with the KD variant of the command.
+ * That is DASD_ECKD_READ_KD_MT instead of DASD_ECKD_READ_MT and
+ * DASD_ECKD_WRITE_KD_MT instead of DASD_ECKD_WRITE_MT.
+ * Luckily the KD variants differ only by one bit (0x08) from the
+ * normal variant. So don't wonder about code like:
+ * if (dasd_eckd_cdl_special(blk_per_trk, recid))
+ *         ccw->cmd_code |= 0x8;
+ */
+static inline int
+dasd_eckd_cdl_special(int blk_per_trk, int recid)
+{
+	if (recid < 3)
+		return 1;
+	if (recid < blk_per_trk)
+		return 0;
+	if (recid < 2 * blk_per_trk)
+		return 1;
+	return 0;
+}
+
+/*
+ * Returns the record size for the special blocks of the cdl format.
+ * Only returns something useful if dasd_eckd_cdl_special is true
+ * for the recid.
+ */
+static inline int
+dasd_eckd_cdl_reclen(int recid)
+{
+	if (recid < 3)
+		return sizes_trk0[recid];
+	return LABEL_SIZE;
+}
+
+static inline int
+dasd_eckd_id_check(s390_dev_info_t * info)
 {
 	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;
 	return -ENODEV;
 }
 
-static int
-dasd_eckd_check_characteristics (struct dasd_device_t *device)
+static inline int
+dasd_eckd_check_characteristics(dasd_device_t *device)
 {
-	int rc = 0;
-	void *conf_data;
+	dasd_eckd_private_t *private;
 	void *rdc_data;
+	void *conf_data;
 	int conf_len;
-	dasd_eckd_private_t *private;
+	int rc;
 
-	if (device == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"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;
-	}
 	private = (dasd_eckd_private_t *) device->private;
+	if (private == NULL) {
+		private = kmalloc(sizeof(dasd_eckd_private_t),
+				  GFP_KERNEL | GFP_DMA);
+		if (private == NULL) {
+			MESSAGE(KERN_WARNING, "%s",
+				"memory allocation failed for private data");
+			return -ENOMEM;
+		}
+		device->private = (void *) private;
+	}
+	/* Invalidate status of initial analysis. */
+	private->init_cqr_status = -1;
+	/* Set default cache operations. */
+	private->attrib.operation = DASD_SEQ_ACCESS;
+	private->attrib.nr_cyl = 0x02;
+
+	/* Read Device Characteristics */
 	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);
-                goto fail;
-        }
-	printk (KERN_INFO PRINTK_HEADER
-		"%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 = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,
-                             LPM_ANYPATH);
-
-        if (rc == -EOPNOTSUPP) {
-                rc = 0; /* this one is ok */
-        }
+	rc = read_dev_chars(device->devinfo.irq, &rdc_data, 64);
 	if (rc) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Read configuration data returned error %d\n", rc);
-                goto fail;
-	}
-        if (conf_data == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No configuration data retrieved\n");
-                goto out; /* no errror */
-	} 
-        if (conf_len != sizeof (dasd_eckd_confdata_t)) {
-		printk (KERN_WARNING PRINTK_HEADER
+		MESSAGE(KERN_WARNING,
+			"Read device characteristics returned error %d", rc);
+		return rc;
+	}
+
+	DEV_MESSAGE(KERN_INFO, device,
+		    "%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
+		    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);
+
+	/* Read Configuration Data */
+	rc = read_conf_data(device->devinfo.irq,
+			    &conf_data, &conf_len, LPM_ANYPATH);
+	if (rc && rc != -EOPNOTSUPP) {	/* -EOPNOTSUPP is ok */
+		MESSAGE(KERN_WARNING,
+			"Read configuration data returned error %d", rc);
+		return rc;
+	}
+	if (conf_data == NULL) {
+		MESSAGE(KERN_WARNING, "%s", "No configuration data retrieved");
+		return 0;	/* no errror */
+	}
+	if (conf_len != sizeof (dasd_eckd_confdata_t)) {
+		MESSAGE(KERN_WARNING,
 			"sizes of configuration data mismatch"
-                        "%d (read) vs %ld (expected)\n",
+			"%d (read) vs %ld (expected)",
 			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;
+		return 0;	/* no errror */
+	}
+	memcpy(&private->conf_data, conf_data, sizeof (dasd_eckd_confdata_t));
+
+	DEV_MESSAGE(KERN_INFO, device,
+		    "%04X/%02X(CU:%04X/%02X): Configuration data read",
+		    private->rdc_data.dev_type,
+		    private->rdc_data.dev_model,
+		    private->rdc_data.cu_type,
+		    private->rdc_data.cu_model.model);
+	return 0;
 }
 
-static inline int
-dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
+static int
+dasd_eckd_check_device(struct dasd_device_t *device)
 {
-	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;
+	int rc;
+
+	rc = dasd_eckd_id_check(&device->devinfo);
+	if (rc)
+		return rc;
+	return dasd_eckd_check_characteristics(device);
 }
 
-static ccw_req_t *
-dasd_eckd_init_analysis (struct dasd_device_t *device)
+static dasd_ccw_req_t *
+dasd_eckd_analysis_ccw(struct dasd_device_t *device)
 {
-	ccw_req_t *cqr = NULL;
-	ccw1_t *ccw;
-	DE_eckd_data_t *DE_data;
+	dasd_eckd_private_t *private;
+	eckd_count_t *count_data;
 	LO_eckd_data_t *LO_data;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
-	eckd_count_t *count_data = private->count_area;
+	dasd_ccw_req_t *cqr;
+	ccw1_t *ccw;
+	int cplength, datasize;
+	int i;
 
-	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");
-                goto out;
-	}
-	DE_data = cqr->data;
-	LO_data = cqr->data + sizeof (DE_eckd_data_t);
+	private = (dasd_eckd_private_t *) device->private;
+
+	cplength = 8;
+	datasize = sizeof(DE_eckd_data_t) + 2*sizeof(LO_eckd_data_t);
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   cplength, datasize, device);
+	if (IS_ERR(cqr))
+		return cqr;
 	ccw = cqr->cpaddr;
-	if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
-                goto clear_cqr;
-        }        
-	ccw->flags |= CCW_FLAG_CC;
-	ccw++;
-	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;
-	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++;
+	/* Define extent for the first 3 tracks. */
+	define_extent(ccw++, cqr->data, 0, 2,
+		      DASD_ECKD_CCW_READ_COUNT, device);
+	LO_data = cqr->data + sizeof (DE_eckd_data_t);
+	/* Locate record for the first 4 records on track 0. */
+	ccw[-1].flags |= CCW_FLAG_CC;
+	locate_record(ccw++, LO_data++, 0, 0, 4,
+		      DASD_ECKD_CCW_READ_COUNT, device, 0);
+
+	count_data = private->count_area;
+	for (i = 0; i < 4; i++) {
+		ccw[-1].flags |= CCW_FLAG_CC;
+		ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+		ccw->flags = 0;
+		ccw->count = 8;
+		ccw->cda = (__u32)(addr_t) count_data;
+		ccw++;
+		count_data++;
+	}
+
+	/* Locate record for the first record on track 2. */
+	ccw[-1].flags |= CCW_FLAG_CC;
+	locate_record(ccw++, LO_data++, 2, 0, 1,
+		      DASD_ECKD_CCW_READ_COUNT, device, 0);
+	/* Read count ccw. */
+	ccw[-1].flags |= CCW_FLAG_CC;
 	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->flags = 0;
 	ccw->count = 8;
-	if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
-                goto clear_cqr;
-        }
+	ccw->cda = (__u32)(addr_t) count_data;
+
 	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:
+	cqr->status = DASD_CQR_FILLED;
 	return cqr;
 }
 
+/*
+ * This is the callback function for the init_analysis cqr. It saves
+ * the status of the initial analysis ccw before it frees it and kicks
+ * the device to continue the startup sequence. This will call
+ * dasd_eckd_do_analysis again (if the devices has not been marked
+ * for deletion in the meantime).
+ */
+static void
+dasd_eckd_analysis_callback(dasd_ccw_req_t *init_cqr, void *data)
+{
+	dasd_eckd_private_t *private;
+	dasd_device_t *device;
+
+	device = init_cqr->device;
+	private = (dasd_eckd_private_t *) device->private;
+	private->init_cqr_status = init_cqr->status;
+	dasd_sfree_request(init_cqr, device);
+	dasd_kick_device(device);
+}
+
 static int
-dasd_eckd_do_analysis (struct dasd_device_t *device)
+dasd_eckd_start_analysis(struct dasd_device_t *device)
 {
-	int sb, rpt;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	eckd_count_t *count_area = NULL;
-	char *cdl_msg;
-        int status;
-	int i;
+	dasd_eckd_private_t *private;
+	dasd_ccw_req_t *init_cqr;
+
+	private = (dasd_eckd_private_t *) device->private;
+	init_cqr = dasd_eckd_analysis_ccw(device);
+	if (IS_ERR(init_cqr))
+		return PTR_ERR(init_cqr);
+	init_cqr->callback = dasd_eckd_analysis_callback;
+	init_cqr->callback_data = NULL;
+	init_cqr->expires = 5*HZ;
+	dasd_add_request_head(init_cqr);
+	return -EAGAIN;
+}
+
+static int
+dasd_eckd_end_analysis(struct dasd_device_t *device)
+{
+	dasd_eckd_private_t *private;
+	eckd_count_t *count_area;
+	unsigned int sb, blk_per_trk;
+	int status, i;
+
+	private = (dasd_eckd_private_t *) device->private;
+	status = private->init_cqr_status;
+	private->init_cqr_status = -1;
+	if (status != DASD_CQR_DONE) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "volume analysis returned unformatted disk");
+		return -EMEDIUMTYPE;
+	}
+
 	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;
-        }
+	/* Calculate number of blocks/records per track. */
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
 	/* Check Track 0 for Compatible Disk Layout */
+	count_area = NULL;
 	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))) {
+		if (private->count_area[i].kl != 4 ||
+		    private->count_area[i].dl != dasd_eckd_cdl_reclen(i) - 4) {
 			private->uses_cdl = 0;
 			break;
 		}
 	}
-	if (i == 3) {
+	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)) {
+			     private->count_area[0].dl))
 				break;
-			}
 		}
-		if (i == 5) {
+		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;
-		}
-	}
-	if (device->sizes.bp_block == 0) {
-		DASD_MESSAGE (KERN_WARNING, device, "%s",
-			      "Volume has incompatible disk layout");
+		if (private->count_area[3].record == 1)
+			DEV_MESSAGE(KERN_WARNING, device, "%s",
+				    "Trk 0: no records after VTOC!");
+	}
+	if (count_area != NULL && count_area->kl == 0) {
+		/* we found notthing violating our disk layout */
+		if (dasd_check_blocksize(count_area->dl) == 0)
+			device->bp_block = count_area->dl;
+	}
+	if (device->bp_block == 0) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "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;
-	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));
-	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);
+	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	for (sb = 512; sb < device->bp_block; sb = sb << 1)
+		device->s2b_shift++;
+
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, device->bp_block);
+	device->blocks = (private->rdc_data.no_cyl *
+			  private->rdc_data.trk_per_cyl *
+			  blk_per_trk);
+
+	DEV_MESSAGE(KERN_INFO, device,
+		    "(%dkB blks): %dkB at %dkB/trk %s",
+		    (device->bp_block >> 10),
+		    ((private->rdc_data.no_cyl *
+		      private->rdc_data.trk_per_cyl *
+		      blk_per_trk * (device->bp_block >> 9)) >> 1),
+		    ((blk_per_trk * device->bp_block) >> 10), 
+		    private->uses_cdl ?
+		    "compatible disk layout" : "linux disk layout");
+
 	return 0;
 }
 
 static int
-dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
+dasd_eckd_do_analysis(struct dasd_device_t *device)
+{
+	dasd_eckd_private_t *private;
+
+	private = (dasd_eckd_private_t *) device->private;
+	if (private->init_cqr_status < 0)
+		return dasd_eckd_start_analysis(device);
+	else
+		return dasd_eckd_end_analysis(device);
+}
+
+static int
+dasd_eckd_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
 {
 	int rc = 0;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	switch (device->sizes.bp_block) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-            geo->sectors = recs_per_track (&(private->rdc_data), 
-                                           0, device->sizes.bp_block);
-            break;
-	default:
-            break;
+	dasd_eckd_private_t *private;
+
+	private = (dasd_eckd_private_t *) device->private;
+	if (dasd_check_blocksize(device->bp_block) == 0) {
+		geo->sectors = recs_per_track(&private->rdc_data,
+					      0, device->bp_block);
 	}
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
 	return rc;
 }
 
-static ccw_req_t *
-dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
+static dasd_ccw_req_t *
+dasd_eckd_format_device(dasd_device_t * device, format_data_t * fdata)
 {
+	dasd_eckd_private_t *private;
+	dasd_ccw_req_t *fcp;
+	eckd_count_t *ect;
+	ccw1_t *ccw;
+	void *data;
+	int rpt, cyl, head;
+	int cplength, datasize;
 	int i;
-	ccw_req_t *fcp = NULL;
-	DE_eckd_data_t *DE_data = NULL;
-	LO_eckd_data_t *LO_data = NULL;
-	eckd_count_t *ct_data = NULL;
-	eckd_count_t *r0_data = NULL;
-	eckd_home_t *ha_data = NULL;
-	ccw1_t *last_ccw = NULL;
-	void *last_data = NULL;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-
-	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);
-        
-	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 (fdata->blksize) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
+
+	private = (dasd_eckd_private_t *) device->private;
+	rpt = recs_per_track(&private->rdc_data, 0, fdata->blksize);
+	cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
+	head = fdata->start_unit % private->rdc_data.trk_per_cyl;
+
+	/* Sanity checks. */
+	if (fdata->start_unit >=
+	    (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) {
+		DEV_MESSAGE(KERN_INFO, device, "Track no %d too big!",
+			    fdata->start_unit);
+		return ERR_PTR(-EINVAL);
+	}
+	if (fdata->start_unit > fdata->stop_unit) {
+		DEV_MESSAGE(KERN_INFO, device, "Track %d reached! ending.",
+			    fdata->start_unit);
+		return ERR_PTR(-EINVAL);
+	}
+	if (dasd_check_blocksize(fdata->blksize) != 0) {
+		MESSAGE(KERN_WARNING, "Invalid blocksize %d...terminating!",
+			fdata->blksize);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/*
+	 * fdata->intensity is a bit string that tells us what to do:
+	 *   Bit 0: write record zero
+	 *   Bit 1: write home address, currently not supported
+	 *   Bit 2: invalidate tracks
+	 *   Bit 3: use OS/390 compatible disk layout (cdl)
+	 * Only some bit combinations do make sense.
+	 */
+	switch (fdata->intensity) {
+	case 0x00:	/* Normal format */
+	case 0x08:	/* Normal format, use cdl. */
+		cplength = 2 + rpt;
+		datasize = sizeof(DE_eckd_data_t) + sizeof(LO_eckd_data_t) +
+			rpt * sizeof(eckd_count_t);
+		break;
+	case 0x01:	/* Write record zero and format track. */
+	case 0x09:	/* Write record zero and format track, use cdl. */
+		cplength = 3 + rpt;
+		datasize = sizeof(DE_eckd_data_t) + sizeof(LO_eckd_data_t) +
+			sizeof(eckd_count_t) + rpt * sizeof(eckd_count_t);
+		break;
+	case 0x04:	/* Invalidate track. */
+	case 0x0c:	/* Invalidate track, use cdl. */
+		cplength = 3;
+		datasize = sizeof(DE_eckd_data_t) + sizeof(LO_eckd_data_t) +
+			sizeof(eckd_count_t);
 		break;
 	default:
-		printk (KERN_WARNING PRINTK_HEADER
-			"Invalid blocksize %d...terminating!\n", fdata->blksize);
-		return NULL;
+		MESSAGE(KERN_WARNING, "Invalid flags 0x%x.", fdata->intensity);
+		return ERR_PTR(-EINVAL);
 	}
-	switch (fdata->intensity) {
-	case 0x00:
-	case 0x01:
-	case 0x03:
-	case 0x04:		/* make track invalid */
-	case 0x08:
-	case 0x09:
-	case 0x0b:
-	case 0x0c:
+	/* Allocate the format ccw request. */
+	fcp = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   cplength, datasize, device);
+	if (IS_ERR(fcp))
+		return fcp;
+
+	data = fcp->data;
+	ccw = fcp->cpaddr;
+
+	switch (fdata->intensity & ~0x08) {
+	case 0x00: /* Normal format. */
+		define_extent(ccw++, (DE_eckd_data_t *) data,
+			      fdata->start_unit, fdata->start_unit,
+			      DASD_ECKD_CCW_WRITE_CKD, device);
+		data += sizeof(DE_eckd_data_t);
+		ccw[-1].flags |= CCW_FLAG_CC;
+		locate_record(ccw++, (LO_eckd_data_t *) data,
+			      fdata->start_unit, 0, rpt,
+			      DASD_ECKD_CCW_WRITE_CKD, device,
+			      fdata->blksize);
+		data += sizeof(LO_eckd_data_t);
+		break;
+	case 0x01: /* Write record zero + format track. */
+		define_extent(ccw++, (DE_eckd_data_t *) data,
+			      fdata->start_unit, fdata->start_unit,
+			      DASD_ECKD_CCW_WRITE_RECORD_ZERO,
+			      device);
+		data += sizeof(DE_eckd_data_t);
+		ccw[-1].flags |= CCW_FLAG_CC;
+		locate_record(ccw++, (LO_eckd_data_t *) data,
+			      fdata->start_unit, 0, rpt + 1,
+			      DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
+			      device->bp_block);
+		data += sizeof(LO_eckd_data_t);
+		break;
+	case 0x04: /* Invalidate track. */
+		define_extent(ccw++, (DE_eckd_data_t *) data,
+			      fdata->start_unit, fdata->start_unit,
+			      DASD_ECKD_CCW_WRITE_CKD, device);
+		data += sizeof(DE_eckd_data_t);
+		ccw[-1].flags |= CCW_FLAG_CC;
+		locate_record(ccw++, (LO_eckd_data_t *) data,
+			      fdata->start_unit, 0, 1,
+			      DASD_ECKD_CCW_WRITE_CKD, device, 8);
+		data += sizeof(LO_eckd_data_t);
 		break;
-	default:
-		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) ?
-	    (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",
-			      fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity);
-	}
-	if ((fdata->intensity & ~0x8) & 0x04) {
-		wrccws = 1;
-		rpt = 1;
-	} else {
-		if (fdata->intensity & 0x1) {
-			wrccws++;
-			datasize += sizeof (eckd_count_t);
-		}
-		if (fdata->intensity & 0x2) {
-			wrccws++;
-			datasize += sizeof (eckd_home_t);
-		}
 	}
-	fcp = dasd_alloc_request (dasd_eckd_discipline.name,
-				 wrccws + 2 + 1,
-				 datasize + rpt * sizeof (eckd_count_t),
-                                 device );
-	if (fcp != NULL) {
-		fcp->device = device;
-		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 (fdata->intensity & 0x2) {
-			ha_data = (eckd_home_t *) last_data;
-			last_data = (void *) (ha_data + 1);
-		}
-		if (fdata->intensity & 0x1) {
-			r0_data = (eckd_count_t *) last_data;
-			last_data = (void *) (r0_data + 1);
-		}
-		ct_data = (eckd_count_t *) last_data;
-
-		last_ccw = fcp->cpaddr;
-
-		switch (fdata->intensity & ~0x08) {
-		case 0x03:
-			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++;
-			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:
-			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++;
-			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 0x04:
-                        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++;
-			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", fdata->intensity);
-			return NULL;
-		}
-		if (fdata->intensity & 0x02) {
-			PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity);
-			return NULL;
-		}
-		if (fdata->intensity & 0x01) {	/* write record zero */
-			r0_data->cyl = cyl;
-			r0_data->head = head;
-			r0_data->record = 0;
-			r0_data->kl = 0;
-			r0_data->dl = 8;
-			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
-			last_ccw->count = 8;
-			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
-			if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
-                                goto clear_fcp;
-                        }
-			last_ccw++;
-		}
-		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->count = 8;
-			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++;
+	if (fdata->intensity & 0x01) {	/* write record zero */
+		ect = (eckd_count_t *) data;
+		data += sizeof(eckd_count_t);
+		ect->cyl = cyl;
+		ect->head = head;
+		ect->record = 0;
+		ect->kl = 0;
+		ect->dl = 8;
+		ccw[-1].flags |= CCW_FLAG_CC;
+		ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
+		ccw->flags = CCW_FLAG_SLI;
+		ccw->count = 8;
+		ccw->cda = (__u32)(addr_t) ect;
+	}
+	if (fdata->intensity & 0x04) {	/* erase track */
+		ect = (eckd_count_t *) data;
+		data += sizeof(eckd_count_t);
+		ect->cyl = cyl;
+		ect->head = head;
+		ect->record = 1;
+		ect->kl = 0;
+		ect->dl = 0;
+		ccw[-1].flags |= CCW_FLAG_CC;
+		ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+		ccw->flags = CCW_FLAG_SLI;
+		ccw->count = 8;
+		ccw->cda = (__u32)(addr_t) ect;
+	} else {		/* write remaining records */
+		for (i = 0; i < rpt; i++) {
+			ect = (eckd_count_t *) data;
+			data += sizeof(eckd_count_t);
+			ect->cyl = cyl;
+			ect->head = head;
+			ect->record = i + 1;
+			ect->kl = 0;
+			ect->dl = fdata->blksize;
+			/* Check for special tracks 0-1 when formatting CDL */
+			if ((fdata->intensity & 0x08) &&
+			    fdata->start_unit == 0) {
+				if (i < 3) {
+					ect->kl = 4;
+					ect->dl = sizes_trk0[i] - 4;
+				} 
+			}
+			if ((fdata->intensity & 0x08) &&
+			    fdata->start_unit == 1) {
+				ect->kl = 44;
+				ect->dl = LABEL_SIZE - 44;
 			}
+			ccw[-1].flags |= CCW_FLAG_CC;
+			ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+			ccw->flags = CCW_FLAG_SLI;
+			ccw->count = 8;
+			ccw->cda = (__u32)(addr_t) ect;
 		}
-		(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:
+	}
+	fcp->device = device;
+	fcp->retries = 2;	/* set retry counter to enable ERP */
+	fcp->status = DASD_CQR_FILLED;
 	return fcp;
 }
 
 static dasd_era_t
-dasd_eckd_examine_error (ccw_req_t * cqr, devstat_t * stat)
+dasd_eckd_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat)
 {
 	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.cu_type) {
 	case 0x3990:
 	case 0x2105:
-		return dasd_3990_erp_examine (cqr, stat);
+		return dasd_3990_erp_examine(cqr, stat);
 	case 0x9343:
-		return dasd_9343_erp_examine (cqr, stat);
+		return dasd_9343_erp_examine(cqr, stat);
 	default:
-		printk (KERN_WARNING PRINTK_HEADER
-			"default (unknown CU type) - RECOVERABLE return \n");
+		MESSAGE(KERN_WARNING, "%s",
+			"default (unknown CU type) - RECOVERABLE return");
 		return dasd_era_recover;
 	}
 }
 
-static dasd_erp_action_fn_t
-dasd_eckd_erp_action (ccw_req_t * cqr)
+static dasd_erp_fn_t
+dasd_eckd_erp_action(dasd_ccw_req_t * cqr)
 {
 	dasd_device_t *device = (dasd_device_t *) cqr->device;
 
@@ -961,414 +924,501 @@
 	}
 }
 
-static dasd_erp_postaction_fn_t
-dasd_eckd_erp_postaction (ccw_req_t * cqr)
+static dasd_erp_fn_t
+dasd_eckd_erp_postaction(dasd_ccw_req_t * cqr)
 {
 	return dasd_default_erp_postaction;
 }
 
-
-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
-}
-
-
-static ccw_req_t *
-dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
+static dasd_ccw_req_t *
+dasd_eckd_build_cp(dasd_device_t * device, struct request *req)
 {
-	ccw_req_t *rw_cp = NULL;
-	int rw_cmd;
-	int bhct;
-	long size;
-	ccw1_t *ccw;
-	DE_eckd_data_t *DE_data;
+	dasd_eckd_private_t *private;
+	unsigned long *idaws;
 	LO_eckd_data_t *LO_data;
-	struct buffer_head *bh;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	int byt_per_blk = device->sizes.bp_block;
-	int shift = device->sizes.s2b_shift;
-	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;
-	int recid = req->sector >> shift;
-	int locate4k_set = 0;
-	int nlocs = 0;
-
-	if (req->cmd == READ) {
-		rw_cmd = DASD_ECKD_CCW_READ_MT;
-	} else if (req->cmd == WRITE) {
-		rw_cmd = DASD_ECKD_CCW_WRITE_MT;
-	} else {
-		PRINT_ERR ("Unknown command %d\n", req->cmd);
-		return NULL;
-	}
-	/* Build the request */
-	/* 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)
-                        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;
-	}
-	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),
-                                    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;
-	if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) {
-                goto clear_rw_cp;
-        }
-	ccw->flags |= CCW_FLAG_CC;
-	for (bh = req->bh; bh != NULL;) {
-                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 */
-                                        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, 
-                                                       1, cmd, device,
-                                                           dasd_eckd_cdl_reclen(device, recid), rw_cp)) {
-                                                goto clear_rw_cp;
-                                        }
-                                } else {
-                                        // Do a locate record for standard blocks */
-                                        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;
-                                }
-                                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;
-	rw_cp->expires = 5 * TOD_MIN;	/* 5 minutes */
-	rw_cp->req = req;
-	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);
-        goto out;
- clear_rw_cp:
-        dasd_free_request (rw_cp, device);
-        rw_cp=NULL;
- out:
-	return rw_cp;
-}
+	dasd_ccw_req_t *cqr;
+	ccw1_t *ccw;
+	struct bio *bio;
+	struct bio_vec *bv;
+	char *dst;
+	unsigned int blksize, blk_per_trk, off;
+	int count, cidaw, cplength, datasize;
+	sector_t recid, first_rec, last_rec;
+	unsigned char cmd, rcmd;
+	int i;
 
-#if 0
-int
-dasd_eckd_cleanup_request (ccw_req_t * cqr)
-{
-	int ret = 0;
-	struct request *req = cqr->req;
-	dasd_device_t *device = cqr->device;
-	int byt_per_blk = device->sizes.bp_block;
-
-	for (bh = req->bh; bh != NULL;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-				ccw++;
-				ccw->flags |= CCW_FLAG_CC;
-				ccw->cmd_code = rw_cmd;
-				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw,
-						    __pa (bh->b_data + size));
+	private = (dasd_eckd_private_t *) device->private;
+	if (rq_data_dir(req) == READ)
+		cmd = DASD_ECKD_CCW_READ_MT;
+	else if (rq_data_dir(req) == WRITE)
+		cmd = DASD_ECKD_CCW_WRITE_MT;
+	else
+		return ERR_PTR(-EINVAL);
+	/* Calculate number of blocks/records per track. */
+	blksize = device->bp_block;
+	blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+	/* Calculate record id of first and last block. */
+	first_rec = req->sector >> device->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	/* Check struct bio and count the number of blocks for the request. */
+	count = 0;
+	cidaw = 0;
+	rq_for_each_bio(bio, req) {
+		bio_for_each_segment(bv, bio, i) {
+			if (bv->bv_len & (blksize - 1))
+				/* Eckd can only do full blocks. */
+				return ERR_PTR(-EINVAL);
+			count += bv->bv_len >> (device->s2b_shift + 9);
+#if defined(CONFIG_ARCH_S390X)
+			cidaw += idal_nr_words(kmap(bv->bv_page) +
+					       bv->bv_offset, bv->bv_len);
+#endif
+		}
+	}
+	/* Paranoia. */
+	if (count != last_rec - first_rec + 1)
+		return ERR_PTR(-EINVAL);
+	/* 1x define extent + 1x locate record + number of blocks */
+	cplength = 2 + count;
+	/* 1x define extent + 1x locate record + cidaws*sizeof(long) */
+	datasize = sizeof(DE_eckd_data_t) + sizeof(LO_eckd_data_t) +
+		cidaw * sizeof(unsigned long);
+	/* Find out the number of additional locate record ccws for cdl. */
+	if (private->uses_cdl && first_rec < 2*blk_per_trk) {
+		if (last_rec >= 2*blk_per_trk)
+			count = 2*blk_per_trk - first_rec;
+		cplength += count;
+		datasize += count*sizeof(LO_eckd_data_t);
+	}
+	/* Allocate the ccw request. */
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   cplength, datasize, device);
+	if (IS_ERR(cqr))
+		return cqr;
+	ccw = cqr->cpaddr;
+	/* First ccw is define extent. */
+	define_extent(ccw++, cqr->data, first_rec / blk_per_trk, 
+		      last_rec / blk_per_trk, cmd, device);
+	/* Build locate_record+read/write/ccws. */
+	idaws = (unsigned long *) (cqr->data + sizeof(DE_eckd_data_t));
+	LO_data = (LO_eckd_data_t *) (idaws + cidaw);
+	recid = first_rec;
+	if (private->uses_cdl == 0 || recid > 2*blk_per_trk) {
+		/* Only standard blocks so there is just one locate record. */
+		ccw[-1].flags |= CCW_FLAG_CC;
+		locate_record(ccw++, LO_data++,
+			      recid / blk_per_trk, recid % blk_per_trk + 1,
+			      last_rec - recid + 1, cmd, device, blksize);
+	}
+	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+		dst = kmap(bv->bv_page) + bv->bv_offset;
+		for (off = 0; off < bv->bv_len; off += blksize) {
+			rcmd = cmd;
+			count = blksize;
+			/* Locate record for cdl special block ? */
+			if (private->uses_cdl && recid < 2*blk_per_trk) {
+				if (dasd_eckd_cdl_special(blk_per_trk, recid)){
+					rcmd |= 0x8;
+					count = dasd_eckd_cdl_reclen(recid);
+					if (count < blksize)
+						memset(dst + count, 0xe5,
+						       blksize - count);
+				}
+				ccw[-1].flags |= CCW_FLAG_CC;
+				locate_record(ccw++, LO_data++,
+					      recid / blk_per_trk,
+					      recid % blk_per_trk + 1,
+					      1, rcmd, device, count);
+			}
+			/* Locate record for standard blocks ? */
+			if (private->uses_cdl && recid == 2*blk_per_trk) {
+				ccw[-1].flags |= CCW_FLAG_CC;
+				locate_record(ccw++, LO_data++,
+					      recid / blk_per_trk,
+					      recid % blk_per_trk + 1,
+					      last_rec - recid + 1,
+					      cmd, device, count);
 			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-				ccw++;
-				ccw->flags |= CCW_FLAG_DC;
-				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;
+			/* Read/write ccw. */
+			ccw[-1].flags |= CCW_FLAG_CC;
+			ccw->cmd_code = rcmd;
+			ccw->count = count;
+			if (idal_is_needed(dst, blksize)) {
+				ccw->cda = (__u32)(addr_t) idaws;
+				ccw->flags = CCW_FLAG_IDA;
+				idaws = idal_create_words(idaws, dst, blksize);
+			} else {
+				ccw->cda = (__u32)(addr_t) dst;
+				ccw->flags = 0;
 			}
+			ccw++;
+			dst += blksize;
+			recid++;
 		}
 	}
-	return ret;
+	cqr->device = device;
+	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
+	cqr->lpm = LPM_ANYPATH;
+	cqr->retries = 2;
+	cqr->buildclk = get_clock();
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
+}
+
+static int
+dasd_eckd_fill_info(dasd_device_t * device, dasd_information2_t * info)
+{
+	dasd_eckd_private_t *private;
+
+	private = (dasd_eckd_private_t *) device->private;
+	info->label_block = 2;
+	info->FBA_layout = private->uses_cdl ? 0 : 1;
+	info->format = private->uses_cdl ? DASD_FORMAT_CDL : DASD_FORMAT_LDL;
+	info->characteristics_size = sizeof(dasd_eckd_characteristics_t);
+	memcpy(info->characteristics, &private->rdc_data,
+	       sizeof(dasd_eckd_characteristics_t));
+	info->confdata_size = sizeof (dasd_eckd_confdata_t);
+	memcpy(info->configuration_data, &private->conf_data,
+	       sizeof (dasd_eckd_confdata_t));
+	return 0;
 }
-#endif
 
 /*
- * DASD_ECKD_RESERVE
- *
- * DESCRIPTION
- *    Buils a channel programm to reserve a device.
- *    Options are set to 'synchronous wait for interrupt' and
- *    'timeout the request'. This leads to an terminate IO if 
- *    the interrupt is outstanding for a certain time. 
+ * SECTION: ioctl functions for eckd devices.
  */
-ccw_req_t *
-dasd_eckd_reserve (struct dasd_device_t * device)
+
+/*
+ * Release device ioctl.
+ * Buils a channel programm to releases a prior reserved 
+ * (see dasd_eckd_reserve) device.
+ */
+static int dasd_eckd_release(void *inp, int no, long args)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
+	int rc;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1, 0, device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
-		return NULL;
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+		dasd_put_device(devmap);
+		return -ENOMEM;
 	}
-	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
-	cqr->device  = device;
+	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
+	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
-	cqr->status  = CQR_STATUS_FILLED;
-	return cqr; 
+	cqr->expires = 10 * HZ;
+	cqr->status = DASD_CQR_FILLED;
+
+	rc = dasd_sleep_on_immediatly(cqr);
+
+	dasd_kfree_request(cqr, cqr->device);
+	dasd_put_device(devmap);
+	return rc;
 }
 
 /*
- * DASD_ECKD_RELEASE
- *
- * DESCRIPTION
- *    Buils a channel programm to releases a prior reserved 
- *    (see dasd_eckd_reserve) device.
+ * Reserve device ioctl.
+ * Options are set to 'synchronous wait for interrupt' and
+ * 'timeout the request'. This leads to an terminate IO if 
+ * the interrupt is outstanding for a certain time. 
  */
-ccw_req_t *
-dasd_eckd_release (struct dasd_device_t * device)
+static int dasd_eckd_reserve(void *inp, int no, long args)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
+	int rc;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1, 0, device);
+
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
-		return NULL;
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+		dasd_put_device(devmap);
+		return -ENOMEM;
 	}
-	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RELEASE;
-	cqr->device  = device;
+	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_RESERVE;
+	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
-	cqr->status  = CQR_STATUS_FILLED;
-	return cqr;
+	cqr->expires = 10 * HZ;
+	cqr->status = DASD_CQR_FILLED;
 
+	rc = dasd_sleep_on_immediatly(cqr);
+
+	if (rc == -EIO) {
+		/* Request got an eror or has been timed out. */
+		dasd_eckd_release(inp, no, args);
+	}
+	dasd_kfree_request(cqr, cqr->device);
+	dasd_put_device(devmap);
+	return rc;
 }
 
 /*
- * DASD_ECKD_STEAL_LOCK
- *
- * DESCRIPTION
- *    Buils a channel programm to break a device's reservation. 
- *    (unconditional reserve)
+ * Steal lock ioctl - unconditional reserve device.
+ * Buils a channel programm to break a device's reservation. 
+ * (unconditional reserve)
  */
-ccw_req_t *
-dasd_eckd_steal_lock (struct dasd_device_t * device)
+static int dasd_eckd_steal_lock(void *inp, int no, long args)
 {
-	ccw_req_t *cqr =
-	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_ccw_req_t *cqr;
+	int rc;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1, 0, device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
-		return NULL;
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+		dasd_put_device(devmap);
+		return -ENOMEM;
 	}
 	cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SLCK;
-	cqr->device  = device;
+	cqr->device = device;
 	cqr->retries = 0;
-	cqr->expires = 10 * TOD_SEC;
-        cqr->options = (DOIO_WAIT_FOR_INTERRUPT | DOIO_TIMEOUT); /* timeout reqest */
-	cqr->status  = CQR_STATUS_FILLED;
-	return cqr;
-}
+	cqr->expires = 10 * HZ;
+	cqr->status = DASD_CQR_FILLED;
 
-static inline ccw1_t *
-dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
-{
-	ccw1_t *cp;
+	rc = dasd_sleep_on_immediatly(cqr);
 
-	cp = cqr->cpaddr;
-	do {
-		if (cp->cmd_code == cmd)
-			return cp;
-		if (cp->cmd_code == CCW_CMD_TIC) {
-			cp = (ccw1_t *) (long) cp->cda;
-			continue;
-		}
-		if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
-			cp++;
-			continue;
-		}
-		break;
-	} while (1);
-	return NULL;
+	if (rc == -EIO) {
+		/* Request got an eror or has been timed out. */
+		dasd_eckd_release(inp, no, args);
+	}
+	dasd_kfree_request(cqr, cqr->device);
+	dasd_put_device(devmap);
+	return rc;
 }
 
-static ccw_req_t *
-dasd_eckd_merge_cp (dasd_device_t * device)
+/*
+ * Read performance statistics
+ */
+static int dasd_eckd_performance(void *inp, int no, long args)
 {
-	return NULL;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_psf_prssd_data_t *prssdp;
+	dasd_rssd_perf_stats_t *stats;
+	dasd_ccw_req_t *cqr;
+	ccw1_t *ccw;
+	int rc;
+
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	cqr = dasd_smalloc_request(dasd_eckd_discipline.name,
+				   1 /* PSF */  + 1 /* RSSD */ ,
+				   (sizeof (dasd_psf_prssd_data_t) +
+				    sizeof (dasd_rssd_perf_stats_t)), device);
+	if (cqr == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory to allocate initialization request");
+		dasd_put_device(devmap);
+		return -ENOMEM;
+	}
+	cqr->device = device;
+	cqr->retries = 0;
+	cqr->expires = 10 * HZ;
+
+	/* Prepare for Read Subsystem Data */
+	prssdp = (dasd_psf_prssd_data_t *) cqr->data;
+	memset(prssdp, 0, sizeof (dasd_psf_prssd_data_t));
+	prssdp->order = PSF_ORDER_PRSSD;
+	prssdp->suborder = 0x01;	/* Perfomance Statistics */
+	prssdp->varies[1] = 0x01;	/* Perf Statistics for the Subsystem */
+
+	ccw = cqr->cpaddr;
+	ccw->cmd_code = DASD_ECKD_CCW_PSF;
+	ccw->count = sizeof (dasd_psf_prssd_data_t);
+	ccw->flags |= CCW_FLAG_CC;
+	ccw->cda = (__u32)(addr_t) prssdp;
+
+	/* Read Subsystem Data - Performance Statistics */
+	stats = (dasd_rssd_perf_stats_t *) (prssdp + 1);
+	memset(stats, 0, sizeof (dasd_rssd_perf_stats_t));
+
+	ccw->cmd_code = DASD_ECKD_CCW_RSSD;
+	ccw->count = sizeof (dasd_rssd_perf_stats_t);
+	ccw->cda = (__u32)(addr_t) stats;
+
+	cqr->status = DASD_CQR_FILLED;
+	rc = dasd_sleep_on(cqr);
+	if (rc == 0) {
+		/* Prepare for Read Subsystem Data */
+		prssdp = (dasd_psf_prssd_data_t *) cqr->data;
+		stats = (dasd_rssd_perf_stats_t *) (prssdp + 1);
+		rc = copy_to_user((long *) args, (long *) stats,
+				  sizeof(dasd_rssd_perf_stats_t));
+	}
+	dasd_sfree_request(cqr, cqr->device);
+	dasd_put_device(devmap);
+	return rc;
 }
 
-static int
-dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
+/*
+ * Set attributes (cache operations)
+ * Stores the attributes for cache operation to be used in Define Extend (DE).
+ */
+static int dasd_eckd_set_attrib(void *inp, int no, long args)
 {
-	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;
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_eckd_private_t *private;
+	attrib_data_t attrib;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (!args)
+		return -EINVAL;
+
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	if (copy_from_user(&attrib, (void *) args, sizeof (attrib_data_t))) {
+		dasd_put_device(devmap);
+		return -EFAULT;
+	}
+
+	private = (dasd_eckd_private_t *) device->private;
+
+	DBF_DEV_EVENT(DBF_ERR, device,
+		      "cache operation mode got "
+		      "%x (%i cylinder prestage)",
+		      attrib.operation, attrib.nr_cyl);
+
+	private->attrib = attrib;
+
+	DBF_DEV_EVENT(DBF_ERR, device,
+		      "cache operation mode set to "
+		      "%x (%i cylinder prestage)",
+		      private->attrib.operation, private->attrib.nr_cyl);
+	dasd_put_device(devmap);
+	return 0;
 }
 
-static char*
-dasd_eckd_dump_sense (struct dasd_device_t *device, 
-                      ccw_req_t            *req)
+static void
+dasd_eckd_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
 {
 
-	char *page = (char *) get_free_page (GFP_ATOMIC);
-	devstat_t *stat = &device->dev_status;
-	char *sense = stat->ii.sense.data;
+	char *page, *sense;
+	ccw1_t *act;
 	int len, sl, sct;
 
+	page = (char *) get_free_page(GFP_ATOMIC);
 	if (page == NULL) {
-                printk (KERN_ERR PRINTK_HEADER
-                        "No memory to dump sense data\n");
-		return NULL;
-	}
-
-	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_ERR PRINTK_HEADER
-			"in req: %p CS: 0x%02X DS: 0x%02X\n",
-			req, stat->cstat, stat->dstat);
-	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);
+		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
+		return;
 	}
-	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+	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_ERR PRINTK_HEADER
+		       "in req: %p CS: 0x%02X DS: 0x%02X\n", req,
+		       device->dev_status.cstat, device->dev_status.dstat);
+	len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+		       "Failing CCW: %p\n", 
+		       (void *) (addr_t) device->dev_status.cpa);
+	act = req->cpaddr;
+	do {
+		DBF_EVENT(DBF_INFO,
+			  "CCW %p: %08X %08X",
+			  act, ((int *) act)[0], ((int *) act)[1]);
+		DBF_EVENT(DBF_INFO,
+			  "DAT: %08X %08X %08X %08X",
+			  ((int *) (addr_t) act->cda)[0],
+			  ((int *) (addr_t) act->cda)[1],
+			  ((int *) (addr_t) act->cda)[2],
+			  ((int *) (addr_t) act->cda)[3]);
+	} while (act++->flags & (CCW_FLAG_CC | CCW_FLAG_DC));
+	sense = device->dev_status.ii.sense.data;
+	if (device->dev_status.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
 		for (sl = 0; sl < 4; sl++) {
-			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
-					"Sense(hex) %2d-%2d:",
-					(8 * sl), ((8 * sl) + 7));
+			len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+				       "Sense(hex) %2d-%2d:",
+				       (8 * sl), ((8 * sl) + 7));
 
 			for (sct = 0; sct < 8; sct++) {
-				len += sprintf (page + len, " %02x",
-						sense[8 * sl + sct]);
+				len += sprintf(page + len, " %02x",
+					       sense[8 * sl + sct]);
 			}
-			len += sprintf (page + len, "\n");
+			len += sprintf(page + len, "\n");
 		}
 
 		if (sense[27] & DASD_SENSE_BIT_0) {
 			/* 24 Byte Sense Data */
-			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");
+			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_ERR PRINTK_HEADER
-					"32 Byte: Format: %x Exception class %x\n",
-					sense[6] & 0x0f, sense[22] >> 4);
+			len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+				       "32 Byte: Format: %x "
+				       "Exception class %x\n",
+				       sense[6] & 0x0f, sense[22] >> 4);
 		}
 	}
 
-        printk ("Sense data:\n%s", 
-                page);
+	MESSAGE(KERN_ERR, "Sense data:\n%s", page);
 
-        free_page ((unsigned long) page);
-        
-	return NULL;
+	free_page((unsigned long) page);
 }
 
-
-dasd_discipline_t dasd_eckd_discipline = {
-        owner: THIS_MODULE,
+/*
+ * max_blocks is dependent on the amount of storage that is available
+ * in the static io buffer for each device. Currently each device has
+ * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
+ * 24 bytes, the dasd_ccw_req_t has 136 bytes and each block can use
+ * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
+ * addition we have one define extent ccw + 16 bytes of data and one
+ * locate record ccw + 16 bytes of data. That makes:
+ * (8192 - 24 - 136 - 8 - 16 - 8 - 16) / 16 = 499 blocks at maximum.
+ * We want to fit two into the available memory so that we can immediatly
+ * start the next request if one finishes off. That makes 249.5 blocks
+ * for one request. Give a little safety and the result is 240.
+ */
+static dasd_discipline_t dasd_eckd_discipline = {
+	owner:THIS_MODULE,
 	name:"ECKD",
 	ebcname:"ECKD",
-	max_blocks:255,
-	id_check:dasd_eckd_id_check,
-	check_characteristics:dasd_eckd_check_characteristics,
-	init_analysis:dasd_eckd_init_analysis,
+	max_blocks:240,
+	check_device:dasd_eckd_check_device,
 	do_analysis:dasd_eckd_do_analysis,
 	fill_geometry:dasd_eckd_fill_geometry,
 	start_IO:dasd_start_IO,
@@ -1377,77 +1427,73 @@
 	examine_error:dasd_eckd_examine_error,
 	erp_action:dasd_eckd_erp_action,
 	erp_postaction:dasd_eckd_erp_postaction,
-	build_cp_from_req:dasd_eckd_build_cp_from_req,
+	build_cp:dasd_eckd_build_cp,
 	dump_sense:dasd_eckd_dump_sense,
-	int_handler:dasd_int_handler,
-	reserve:dasd_eckd_reserve,
-	release:dasd_eckd_release,
-        steal_lock:dasd_eckd_steal_lock,
-	merge_cp:dasd_eckd_merge_cp,
 	fill_info:dasd_eckd_fill_info,
 };
 
 int
-dasd_eckd_init (void)
+dasd_eckd_init(void)
 {
-	int rc = 0;
-	printk (KERN_INFO PRINTK_HEADER
-		"%s discipline initializing\n", dasd_eckd_discipline.name);
-	ASCEBC (dasd_eckd_discipline.ebcname, 4);
-	dasd_discipline_add (&dasd_eckd_discipline);
+	int i;
+	printk("sizeof(dasd_ccw_req_t) = %li\n",
+	       sizeof(dasd_ccw_req_t));
+	dasd_ioctl_no_register(THIS_MODULE, BIODASDSATTR,
+			       dasd_eckd_set_attrib);
+	dasd_ioctl_no_register(THIS_MODULE, BIODASDPSRD,
+			       dasd_eckd_performance);
+	dasd_ioctl_no_register(THIS_MODULE, BIODASDRLSE,
+			       dasd_eckd_release);
+	dasd_ioctl_no_register(THIS_MODULE, BIODASDRSRV,
+			       dasd_eckd_reserve);
+	dasd_ioctl_no_register(THIS_MODULE, BIODASDSLCK,
+			       dasd_eckd_steal_lock);
+
+	ASCEBC(dasd_eckd_discipline.ebcname, 4);
+	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]);
-		}
-	}
-#endif				/* CONFIG_DASD_DYNAMIC */
-	return rc;
+	for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++)
+			s390_device_register(&dasd_eckd_known_devices[i]);
+#endif
+	return 0;
 }
 
 void
-dasd_eckd_cleanup (void)
+dasd_eckd_cleanup(void)
 {
-	printk (KERN_INFO PRINTK_HEADER
-		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
+	int i;
+
 #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]);
-		}
-	}
+	for (i = 0; i < sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++)
+		s390_device_unregister(&dasd_eckd_known_devices[i]);
 #endif				/* CONFIG_DASD_DYNAMIC */
-	dasd_discipline_del (&dasd_eckd_discipline);
+
+	dasd_discipline_del(&dasd_eckd_discipline);
+
+	dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSATTR,
+				 dasd_eckd_set_attrib);
+	dasd_ioctl_no_unregister(THIS_MODULE, BIODASDPSRD,
+				 dasd_eckd_performance);
+	dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRLSE,
+				 dasd_eckd_release);
+	dasd_ioctl_no_unregister(THIS_MODULE, BIODASDRSRV,
+				 dasd_eckd_reserve);
+	dasd_ioctl_no_unregister(THIS_MODULE, BIODASDSLCK,
+				 dasd_eckd_steal_lock);
 }
 
 #ifdef MODULE
 int
-init_module (void)
+init_module(void)
 {
-	int rc = 0;
-	rc = dasd_eckd_init ();
-	return rc;
+	return dasd_eckd_init();
 }
 
 void
-cleanup_module (void)
+cleanup_module(void)
 {
-	dasd_eckd_cleanup ();
-	return;
+	dasd_eckd_cleanup();
 }
 #endif
 
@@ -1465,7 +1511,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
--- a/drivers/s390/block/dasd_eckd.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/block/dasd_eckd.h	Sat Jun  8 22:31:37 2002
@@ -1,78 +1,74 @@
 #ifndef DASD_ECKD_H
 #define DASD_ECKD_H
 
-#include "dasd_3990_erp.h"
-#include "dasd_9343_erp.h"
-
-#define DASD_ECKD_CCW_WRITE 0x05
-#define DASD_ECKD_CCW_READ 0x06
+/*******************************************************************************
+ * SECTION: CCW Definitions
+ ******************************************************************************/
+#define DASD_ECKD_CCW_WRITE		 0x05
+#define DASD_ECKD_CCW_READ		 0x06
 #define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
-#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
-#define DASD_ECKD_CCW_WRITE_CKD 0x1d
-#define DASD_ECKD_CCW_READ_CKD 0x1e
-#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
-#define DASD_ECKD_CCW_WRITE_MT 0x85
-#define DASD_ECKD_CCW_READ_MT 0x86
-#define DASD_ECKD_CCW_WRITE_KD_MT 0x8d
-#define DASD_ECKD_CCW_READ_KD_MT 0x8e
-#define DASD_ECKD_CCW_RELEASE 0x94
-#define DASD_ECKD_CCW_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
-#define DASD_ECKD_CCW_RESERVE 0xB4
-#define DASD_ECKD_CCW_SLCK 0x14	/* steal lock - unconditional reserve */
+#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_SLCK		 0x14
+#define DASD_ECKD_CCW_WRITE_RECORD_ZERO	 0x15
+#define DASD_ECKD_CCW_READ_RECORD_ZERO	 0x16
+#define DASD_ECKD_CCW_WRITE_CKD		 0x1d
+#define DASD_ECKD_CCW_READ_CKD		 0x1e
+#define DASD_ECKD_CCW_PSF		 0x27
+#define DASD_ECKD_CCW_RSSD		 0x3e
+#define DASD_ECKD_CCW_LOCATE_RECORD	 0x47
+#define DASD_ECKD_CCW_DEFINE_EXTENT	 0x63
+#define DASD_ECKD_CCW_WRITE_MT		 0x85
+#define DASD_ECKD_CCW_READ_MT		 0x86
+#define DASD_ECKD_CCW_WRITE_KD_MT	 0x8d
+#define DASD_ECKD_CCW_READ_KD_MT	 0x8e
+#define DASD_ECKD_CCW_RELEASE		 0x94
+#define DASD_ECKD_CCW_READ_CKD_MT	 0x9e
+#define DASD_ECKD_CCW_WRITE_CKD_MT	 0x9d
+#define DASD_ECKD_CCW_RESERVE		 0xB4
+
+/*
+ *Perform Subsystem Function / Sub-Orders
+ */
+#define PSF_ORDER_PRSSD			 0x18
+
+/*******************************************************************************
+ * SECTION: Type Definitions
+ ******************************************************************************/
 
-typedef
-    struct eckd_count_t {
+typedef struct eckd_count_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
 	__u8 kl;
 	__u16 dl;
-} __attribute__ ((packed))
-
-    eckd_count_t;
+} __attribute__ ((packed)) eckd_count_t;
 
-typedef
-    struct ch_t {
+typedef struct ch_t {
 	__u16 cyl;
 	__u16 head;
-} __attribute__ ((packed))
-
-    ch_t;
+} __attribute__ ((packed)) ch_t;
 
-typedef
-    struct chs_t {
+typedef struct chs_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed))
+} __attribute__ ((packed)) chs_t;
 
-    chs_t;
-
-typedef
-    struct chr_t {
+typedef struct chr_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
-} __attribute__ ((packed))
-
-    chr_t;
+} __attribute__ ((packed)) chr_t;
 
-typedef
-    struct geom_t {
+typedef struct geom_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed))
-
-    geom_t;
+} __attribute__ ((packed)) geom_t;
 
 typedef struct eckd_home_t {
 	__u8 skip_control[14];
@@ -83,12 +79,9 @@
 	__u8 reserved;
 	__u8 key_length;
 	__u8 reserved2[2];
-} __attribute__ ((packed))
+} __attribute__ ((packed)) eckd_home_t;
 
-    eckd_home_t;
-
-typedef
-    struct DE_eckd_data_t {
+typedef struct DE_eckd_data_t {
 	struct {
 		unsigned char perm:2;	/* Permissions on this extent */
 		unsigned char reserved:1;
@@ -105,16 +98,13 @@
 	} __attribute__ ((packed)) attributes;
 	__u16 short blk_size;	/* Blocksize */
 	__u16 fast_write_id;
-	__u8 unused;
-	__u8 reserved;
+	__u8 ga_additional;	/* Global Attributes Additional */
+	__u8 ga_extended;	/* Global Attributes Extended	*/
 	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 {
+typedef struct LO_eckd_data_t {
 	struct {
 		unsigned char orientation:2;
 		unsigned char operation:6;
@@ -130,12 +120,9 @@
 	chr_t search_arg;
 	__u8 sector;
 	__u16 length;
-} __attribute__ ((packed))
-
-    LO_eckd_data_t;
+} __attribute__ ((packed)) LO_eckd_data_t;
 
-typedef
-    struct dasd_eckd_characteristics_t {
+typedef struct dasd_eckd_characteristics_t {
 	__u16 cu_type;
 	struct {
 		unsigned char support:2;
@@ -205,9 +192,7 @@
 	__u8 factor8;
 	__u8 reserved2[3];
 	__u8 reserved3[10];
-} __attribute__ ((packed))
-
-    dasd_eckd_characteristics_t;
+} __attribute__ ((packed)) dasd_eckd_characteristics_t;
 
 typedef struct dasd_eckd_confdata_t {
 	struct {
@@ -324,10 +309,19 @@
 		__u8 log_dev_address;
 		unsigned char reserved2[12];
 	} __attribute__ ((packed)) neq;
-} __attribute__ ((packed))
+} __attribute__ ((packed)) dasd_eckd_confdata_t;
 
-    dasd_eckd_confdata_t;
+/*
+ * Perform Subsystem Function - Prepare for Read Subsystem Data	 
+ */
+typedef struct dasd_psf_prssd_data_t {
+	unsigned char order;
+	unsigned char flags;
+	unsigned char reserved[4];
+	unsigned char suborder;
+	unsigned char varies[9];
+} __attribute__ ((packed)) dasd_psf_prssd_data_t;
 
-int dasd_eckd_init (void);
-void dasd_eckd_cleanup (void);
+int dasd_eckd_init(void);
+void dasd_eckd_cleanup(void);
 #endif				/* DASD_ECKD_H */
diff -Nru a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/block/dasd_erp.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,271 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
+ *
+ * 05/04/02 split from dasd.c, code restructuring.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+
+#include <asm/debug.h>
+#include <asm/ebcdic.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* This is ugly... */
+#define PRINTK_HEADER "dasd_erp:"
+
+#include "dasd_int.h"
+
+dasd_ccw_req_t *
+dasd_alloc_erp_request(char *magic, int cplength, int datasize,
+		       dasd_device_t * device)
+{
+	unsigned long flags;
+	dasd_ccw_req_t *cqr;
+	char *data;
+	int size;
+
+	/* Sanity checks */
+	if ( magic == NULL || datasize > PAGE_SIZE ||
+	     (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
+		BUG();
+	debug_text_event ( dasd_debug_area, 1, "ALLC");
+	debug_text_event ( dasd_debug_area, 1, magic);
+	debug_int_event ( dasd_debug_area, 1, cplength);
+	debug_int_event ( dasd_debug_area, 1, datasize);
+
+	size = (sizeof(dasd_ccw_req_t) + 7L) & -8L;
+	if (cplength > 0)
+		size += cplength * sizeof(ccw1_t);
+	if (datasize > 0)
+		size += datasize;
+	spin_lock_irqsave(&device->mem_lock, flags);
+	cqr = (dasd_ccw_req_t *) dasd_alloc_chunk(&device->erp_chunks, size);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	if (cqr == NULL)
+		return ERR_PTR(-ENOMEM);
+	memset(cqr, 0, sizeof(dasd_ccw_req_t));
+	data = (char *) cqr + ((sizeof(dasd_ccw_req_t) + 7L) & -8L);
+	cqr->cpaddr = NULL;
+	if (cplength > 0) {
+		cqr->cpaddr = (ccw1_t *) data;
+		data += cplength*sizeof(ccw1_t);
+		memset(cqr->cpaddr, 0, cplength*sizeof(ccw1_t));
+	}
+	cqr->data = NULL;
+	if (datasize > 0) {
+		cqr->data = data;
+ 		memset(cqr->data, 0, datasize);
+	}
+	strncpy((char *) &cqr->magic, magic, 4);
+	ASCEBC((char *) &cqr->magic, 4);
+	atomic_inc(&device->ref_count);
+	return cqr;
+}
+
+void
+dasd_free_erp_request(dasd_ccw_req_t * cqr, dasd_device_t * device)
+{
+	unsigned long flags;
+
+	if (cqr->dstat != NULL)
+		kfree(cqr->dstat);
+	debug_text_event(dasd_debug_area, 1, "FREE");
+	debug_int_event(dasd_debug_area, 1, (long) cqr);
+	spin_lock_irqsave(&device->mem_lock, flags);
+	dasd_free_chunk(&device->erp_chunks, cqr);
+	spin_unlock_irqrestore(&device->mem_lock, flags);
+	atomic_dec(&device->ref_count);
+}
+
+/*
+ * DESCRIPTION
+ *   sets up the default-ERP dasd_ccw_req_t, namely one, which performs a TIC
+ *   to the original channel program with a retry counter of 16
+ *
+ * PARAMETER
+ *   cqr		failed CQR
+ *
+ * RETURN VALUES
+ *   erp		CQR performing the ERP
+ */
+dasd_ccw_req_t *
+dasd_default_erp_action(dasd_ccw_req_t * cqr)
+{
+	dasd_device_t *device;
+	dasd_ccw_req_t *erp;
+
+	MESSAGE(KERN_DEBUG, "%s", "Default ERP called... ");
+	device = cqr->device;
+	erp = dasd_alloc_erp_request((char *) &cqr->magic, 1, 0, device);
+	if (IS_ERR(erp)) {
+		DEV_MESSAGE(KERN_ERR, device, "%s",
+			    "Unable to allocate request for default ERP");
+		cqr->status = DASD_CQR_FAILED;
+		cqr->stopclk = get_clock();
+		return cqr;
+	}
+
+	erp->cpaddr->cmd_code = CCW_CMD_TIC;
+	erp->cpaddr->cda = (__u32) (addr_t) cqr->cpaddr;
+	erp->function = dasd_default_erp_action;
+	erp->refers = cqr;
+	erp->device = device;
+	erp->magic = cqr->magic;
+	erp->retries = 16;
+	erp->status = DASD_CQR_FILLED;
+
+	list_add(&erp->list, &device->ccw_queue);
+	erp->status = DASD_CQR_QUEUED;
+
+	return erp;
+
+}				/* end dasd_default_erp_action */
+
+/*
+ * DESCRIPTION
+ *   Frees all ERPs of the current ERP Chain and set the status
+ *   of the original CQR either to DASD_CQR_DONE if ERP was successful
+ *   or to DASD_CQR_FAILED if ERP was NOT successful.
+ *   NOTE: This function is only called if no discipline postaction
+ *	   is available
+ *
+ * PARAMETER
+ *   erp		current erp_head
+ *
+ * RETURN VALUES
+ *   cqr		pointer to the original CQR
+ */
+dasd_ccw_req_t *
+dasd_default_erp_postaction(dasd_ccw_req_t * cqr)
+{
+	dasd_device_t *device;
+	int success;
+
+	if (cqr->refers == NULL || cqr->function == NULL)
+		BUG();
+
+	device = cqr->device;
+	success = cqr->status == DASD_CQR_DONE;
+
+	/* free all ERPs - but NOT the original cqr */
+	while (cqr->refers != NULL) {
+		dasd_ccw_req_t *refers;
+
+		refers = cqr->refers;
+		/* remove the request from the device queue */
+		list_del(&cqr->list);
+		/* free the finished erp request */
+		dasd_free_erp_request(cqr, device);
+		cqr = refers;
+	}
+
+	/* set corresponding status to original cqr */
+	if (success)
+		cqr->status = DASD_CQR_DONE;
+	else {
+		cqr->status = DASD_CQR_FAILED;
+		cqr->stopclk = get_clock();
+	}
+
+	return cqr;
+
+}				/* end default_erp_postaction */
+
+/*
+ * Print the hex dump of the memory used by a request. This includes
+ * all error recovery ccws that have been chained in from of the 
+ * real request.
+ */
+static inline void
+hex_dump_memory(dasd_device_t *device, void *data, int len)
+{
+	int *pint;
+
+	pint = (int *) data;
+	while (len > 0) {
+		DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
+			    pint, pint[0], pint[1], pint[2], pint[3]);
+		pint += 4;
+		len -= 16;
+	}
+}
+
+void
+dasd_log_ccw(dasd_ccw_req_t * cqr, int caller, __u32 cpa)
+{
+	dasd_device_t *device;
+	dasd_ccw_req_t *lcqr;
+	ccw1_t *ccw;
+	int cplength;
+
+	device = cqr->device;
+	/* dump sense data */
+	if (device->discipline && device->discipline->dump_sense)
+		device->discipline->dump_sense(device, cqr);
+
+	/* log the channel program */
+	for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
+		DEV_MESSAGE(KERN_ERR, device,
+			    "(%s) ERP chain report for req: %p",
+			    caller == 0 ? "EXAMINE" : "ACTION", lcqr);
+		hex_dump_memory(device, lcqr, sizeof(dasd_ccw_req_t));
+
+		cplength = 1;
+		ccw = lcqr->cpaddr;
+		while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
+			cplength++;
+
+		if (cplength > 40) {	/* log only parts of the CP */
+			DEV_MESSAGE(KERN_ERR, device, "%s",
+				    "Start of channel program:");
+			hex_dump_memory(device, lcqr->cpaddr,
+					40*sizeof(ccw1_t));
+
+			DEV_MESSAGE(KERN_ERR, device, "%s",
+				    "End of channel program:");
+			hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
+					10*sizeof(ccw1_t));
+		} else {	/* log the whole CP */
+			DEV_MESSAGE(KERN_ERR, device, "%s",
+				    "Channel program (complete):");
+			hex_dump_memory(device, lcqr->cpaddr,
+					cplength*sizeof(ccw1_t));
+		}
+
+		if (lcqr != cqr)
+			continue;
+
+		/*
+		 * Log bytes arround failed CCW but only if we did
+		 * not log the whole CP of the CCW is outside the
+		 * logged CP. 
+		 */
+		if (cplength > 40 ||
+		    ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
+		     (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
+			
+			DEV_MESSAGE(KERN_ERR, device,
+				    "Failed CCW (%p) (area):",
+				    (void *) (long) cpa);
+			hex_dump_memory(device, cqr->cpaddr - 10,
+					20*sizeof(ccw1_t));
+		}
+	}
+
+}				/* end log_erp_chain */
+
+EXPORT_SYMBOL(dasd_default_erp_action);
+EXPORT_SYMBOL(dasd_default_erp_postaction);
+EXPORT_SYMBOL(dasd_alloc_erp_request);
+EXPORT_SYMBOL(dasd_free_erp_request);
+EXPORT_SYMBOL(dasd_log_ccw);
diff -Nru a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
--- a/drivers/s390/block/dasd_fba.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/block/dasd_fba.c	Sat Jun  8 22:31:51 2002
@@ -4,7 +4,9 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- *          fixed partition handling and HDIO_GETGEO
+ *	    fixed partition handling and HDIO_GETGEO
+ * 2002/01/04 Created 2.4-2.5 compatibility mode
+ * 05/04/02 code restructuring.
  */
 
 #include <linux/config.h>
@@ -13,35 +15,31 @@
 #include <asm/debug.h>
 
 #include <linux/slab.h>
-#include <linux/hdreg.h>	/* HDIO_GETGEO                      */
-#include <linux/blk.h>
+#include <linux/hdreg.h>	/* HDIO_GETGEO			    */
 
-#include <asm/ccwcache.h>
 #include <asm/idals.h>
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
+#include <asm/todclk.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
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER DASD_NAME"(fba):"
+#define PRINTK_HEADER "dasd(fba):"
 
 #define DASD_FBA_CCW_WRITE 0x41
 #define DASD_FBA_CCW_READ 0x42
 #define DASD_FBA_CCW_LOCATE 0x43
 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63
 
-dasd_discipline_t dasd_fba_discipline;
+static dasd_discipline_t dasd_fba_discipline;
 
-typedef struct
-    dasd_fba_private_t {
+typedef struct dasd_fba_private_t {
 	dasd_fba_characteristics_t rdc_data;
 } dasd_fba_private_t;
 
@@ -49,62 +47,61 @@
 static
 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 int
-define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
-	       int blksize, int beg, int nr, ccw_req_t* cqr,
-               dasd_device_t* device)
+
+static inline void
+define_extent(ccw1_t * ccw, DE_fba_data_t *data, int rw,
+	      int blksize, int beg, int nr)
 {
-        int rc=0;
-	memset (DE_data, 0, sizeof (DE_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
+	ccw->flags = 0;
 	ccw->count = 16;
-	if ((rc=dasd_set_normalized_cda (ccw, __pa (DE_data), cqr, device)))
-                return rc;
+	ccw->cda = (__u32) __pa(data);
+	memset(data, 0, sizeof (DE_fba_data_t));
 	if (rw == WRITE)
-		(DE_data->mask).perm = 0x0;
+		(data->mask).perm = 0x0;
 	else if (rw == READ)
-		(DE_data->mask).perm = 0x1;
+		(data->mask).perm = 0x1;
 	else
-		DE_data->mask.perm = 0x2;
-	DE_data->blk_size = blksize;
-	DE_data->ext_loc = beg;
-	DE_data->ext_end = nr - 1;
-        return rc;
+		data->mask.perm = 0x2;
+	data->blk_size = blksize;
+	data->ext_loc = beg;
+	data->ext_end = nr - 1;
 }
 
 static inline void
-locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
-	       int block_ct, ccw_req_t* cqr, dasd_device_t* device)
+locate_record(ccw1_t * ccw, LO_fba_data_t *data, int rw,
+	      int block_nr, int block_ct)
 {
-	memset (LO_data, 0, sizeof (LO_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_LOCATE;
+	ccw->flags = 0;
 	ccw->count = 8;
-	dasd_set_normalized_cda (ccw, __pa (LO_data), cqr, device);
+	ccw->cda = (__u32) __pa(data);
+	memset(data, 0, sizeof (LO_fba_data_t));
 	if (rw == WRITE)
-		LO_data->operation.cmd = 0x5;
+		data->operation.cmd = 0x5;
 	else if (rw == READ)
-		LO_data->operation.cmd = 0x6;
+		data->operation.cmd = 0x6;
 	else
-		LO_data->operation.cmd = 0x8;
-	LO_data->blk_nr = block_nr;
-	LO_data->blk_ct = block_ct;
+		data->operation.cmd = 0x8;
+	data->blk_nr = block_nr;
+	data->blk_ct = block_ct;
 }
 
-static int
-dasd_fba_id_check (s390_dev_info_t * info)
+static inline int
+dasd_fba_id_check(s390_dev_info_t * info)
 {
 	if (info->sid_data.cu_type == 0x3880)
 		if (info->sid_data.dev_type == 0x3370)
@@ -115,290 +112,292 @@
 	return -ENODEV;
 }
 
-static int
-dasd_fba_check_characteristics (struct dasd_device_t *device)
+static inline int
+dasd_fba_check_characteristics(struct dasd_device_t *device)
 {
-	int rc = -ENODEV;
-	void *rdc_data;
 	dasd_fba_private_t *private;
+	void *rdc_data;
+	int rc;
 
-	if (device == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"Null device pointer passed to characteristics checker\n");
-                return -ENODEV;
-	}
-	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");
-                rc = -ENOMEM;
-                goto fail;
-	}
 	private = (dasd_fba_private_t *) device->private;
+	if (private == NULL) {
+		private = kmalloc(sizeof(dasd_fba_private_t), GFP_KERNEL);
+		if (private == NULL) {
+			MESSAGE(KERN_WARNING, "%s",
+				"memory allocation failed for private data");
+			return -ENOMEM;
+		}
+		device->private = (void *) private;
+	}
+	/* Read Device Characteristics */
 	rdc_data = (void *) &(private->rdc_data);
-	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 32);
+	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);
-                goto fail;
+		MESSAGE(KERN_WARNING,
+			"Read device characteristics returned error %d", rc);
+		return rc;
 	}
-	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,
-		(private->rdc_data.blk_bdsa *
-		 (private->rdc_data.blk_size >> 9)) >> 11,
-		private->rdc_data.blk_size);
-        goto out;
- fail:
-        if ( rc ) {
-                kfree(device->private);
-                device->private = NULL;
-        }
-        
- out:
-	return rc;
+
+	DEV_MESSAGE(KERN_INFO, device,
+		    "%04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)",
+		    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;
 }
 
 static int
-dasd_fba_do_analysis (struct dasd_device_t *device)
+dasd_fba_check_device(struct dasd_device_t *device)
 {
-	int rc = 0;
-	int sb;
-	dasd_fba_private_t *private = (dasd_fba_private_t *) device->private;
-	int bs = private->rdc_data.blk_size;
-
-	memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-	switch (bs) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-		device->sizes.bp_block = bs;
-		break;
-	default:
-		printk (KERN_INFO PRINTK_HEADER
-			"/dev/%s (%04X): unknown blocksize %d\n",
-			device->name, device->devinfo.devno, bs);
-		return -EMEDIUMTYPE;
-	}
-	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < bs; sb = sb << 1)
-		device->sizes.s2b_shift++;
+	int rc;
+
+	rc = dasd_fba_id_check(&device->devinfo);
+	if (rc)
+		return rc;
+	return dasd_fba_check_characteristics(device);
+}
 
-	device->sizes.blocks = (private->rdc_data.blk_bdsa);
-	device->sizes.pt_block = 1;
+static int
+dasd_fba_do_analysis(struct dasd_device_t *device)
+{
+	dasd_fba_private_t *private;
+	int sb, rc;
 
-	return rc;
+	private = (dasd_fba_private_t *) device->private;
+	rc = dasd_check_blocksize(private->rdc_data.blk_size);
+	if (rc) {
+		DEV_MESSAGE(KERN_INFO, device, "unknown blocksize %d",
+			    private->rdc_data.blk_size);
+		return rc;
+	}
+	device->blocks = private->rdc_data.blk_bdsa;
+	device->bp_block = private->rdc_data.blk_size;
+	device->s2b_shift = 0;	/* bits to shift 512 to get a block */
+	for (sb = 512; sb < private->rdc_data.blk_size; sb = sb << 1)
+		device->s2b_shift++;
+	return 0;
 }
 
 static int
-dasd_fba_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
+dasd_fba_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
 {
-	int rc = 0;
-	unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
-	unsigned long tracks = sectors >> 6;
-	unsigned long cyls = tracks >> 4;
-
-	switch (device->sizes.bp_block) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-		break;
-	default:
+	if (dasd_check_blocksize(device->bp_block) != 0)
 		return -EINVAL;
-	}
-	geo->cylinders = cyls;
+	geo->cylinders = (device->blocks << device->s2b_shift) >> 10;
 	geo->heads = 16;
-	geo->sectors = 128 >> device->sizes.s2b_shift;
-	return rc;
+	geo->sectors = 128 >> device->s2b_shift;
+	return 0;
 }
 
 static dasd_era_t
-dasd_fba_examine_error (ccw_req_t * cqr, devstat_t * stat)
+dasd_fba_examine_error(dasd_ccw_req_t * cqr, devstat_t * stat)
 {
-	dasd_device_t *device = (dasd_device_t *) cqr->device;
+	dasd_device_t *device;
+
+	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:
-		return dasd_3370_erp_examine (cqr, stat);
+		return dasd_3370_erp_examine(cqr, stat);
 	case 0x9336:
-		return dasd_9336_erp_examine (cqr, stat);
+		return dasd_9336_erp_examine(cqr, stat);
 	default:
 		return dasd_era_recover;
 	}
 }
 
-static dasd_erp_action_fn_t
-dasd_fba_erp_action (ccw_req_t * cqr)
+static dasd_erp_fn_t
+dasd_fba_erp_action(dasd_ccw_req_t * cqr)
 {
 	return dasd_default_erp_action;
 }
 
-static dasd_erp_postaction_fn_t
-dasd_fba_erp_postaction (ccw_req_t * cqr)
+static dasd_erp_fn_t
+dasd_fba_erp_postaction(dasd_ccw_req_t * cqr)
 {
 	if (cqr->function == dasd_default_erp_action)
 		return dasd_default_erp_postaction;
-	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n", cqr->function);
+
+	MESSAGE(KERN_WARNING, "unknown ERP action %p", cqr->function);
+
 	return NULL;
 }
 
-static ccw_req_t *
-dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req)
+static dasd_ccw_req_t *
+dasd_fba_build_cp(dasd_device_t * device, struct request *req)
 {
-	ccw_req_t *rw_cp = NULL;
-	int rw_cmd;
-	int bhct, i = 0;
-	long size;
-	ccw1_t *ccw;
-	DE_fba_data_t *DE_data;
+	dasd_fba_private_t *private;
+	unsigned long *idaws;
 	LO_fba_data_t *LO_data;
-	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) {
-		rw_cmd = DASD_FBA_CCW_WRITE;
-	} else {
-		PRINT_ERR ("Unknown command %d\n", req->cmd);
-		return NULL;
+	dasd_ccw_req_t *cqr;
+	ccw1_t *ccw;
+	struct bio *bio;
+	struct bio_vec *bv;
+	char *dst;
+	int count, cidaw, cplength, datasize;
+	sector_t recid, first_rec, last_rec;
+	unsigned int blksize, off;
+	unsigned char cmd;
+	int i;
+
+	private = (dasd_fba_private_t *) device->private;
+	if (rq_data_dir(req) == READ) {
+		cmd = DASD_FBA_CCW_READ;
+	} else if (rq_data_dir(req) == WRITE) {
+		cmd = DASD_FBA_CCW_WRITE;
+	} else
+		return ERR_PTR(-EINVAL);
+	blksize = device->bp_block;
+	/* Calculate record id of first and last block. */
+	first_rec = req->sector >> device->s2b_shift;
+	last_rec = (req->sector + req->nr_sectors - 1) >> device->s2b_shift;
+	/* Check struct bio and count the number of blocks for the request. */
+	count = 0;
+	cidaw = 0;
+	rq_for_each_bio(bio, req) {
+		bio_for_each_segment(bv, bio, i) {
+			if (bv->bv_len & (blksize - 1))
+				/* Fba can only do full blocks. */
+				return ERR_PTR(-EINVAL);
+			count += bv->bv_len >> (device->s2b_shift + 9);
+#if defined(CONFIG_ARCH_S390X)
+			cidaw += idal_nr_words(kmap(bv->bv_page) +
+					       bv->bv_offset, bv->bv_len);
+#endif
+		}
+	}
+	/* Paranoia. */
+	if (count != last_rec - first_rec + 1)
+		return ERR_PTR(-EINVAL);
+	/* 1x define extent + 1x locate record + number of blocks */
+	cplength = 2 + count;
+	/* 1x define extent + 1x locate record */
+	datasize = sizeof(DE_fba_data_t) + sizeof(LO_fba_data_t) +
+		cidaw * sizeof(unsigned long);
+	/*
+	 * Find out number of additional locate record ccws if the device
+	 * can't do data chaining.
+	 */
+	if (private->rdc_data.mode.bits.data_chain == 0) {
+		cplength += count - 1;
+		datasize += (count - 1)*sizeof(LO_fba_data_t);
 	}
-	/* Build the request */
-	/* count hs to prevent errors, when bh smaller than block */
-        bh = req -> bh;
-	bhct = 0;
-        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;
+	/* Allocate the ccw request. */
+	cqr = dasd_smalloc_request(dasd_fba_discipline.name,
+				   cplength, datasize, device);
+	if (IS_ERR(cqr))
+		return cqr;
+	ccw = cqr->cpaddr;
+	/* First ccw is define extent. */
+	define_extent(ccw++, cqr->data, rq_data_dir(req),
+		      device->bp_block, req->sector, req->nr_sectors);
+	/* Build locate_record + read/write ccws. */
+	idaws = (unsigned long *) (cqr->data + sizeof(DE_fba_data_t));
+	LO_data = (LO_fba_data_t *) (idaws + cidaw);
+	/* Locate record for all blocks for smart devices. */
+	if (private->rdc_data.mode.bits.data_chain != 0) {
+		ccw[-1].flags |= CCW_FLAG_CC;
+		locate_record(ccw++, LO_data++, rq_data_dir(req), 0, count);
+	}
+	recid = first_rec;
+	rq_for_each_bio(bio, req) bio_for_each_segment(bv, bio, i) {
+		dst = kmap(bv->bv_page) + bv->bv_offset;
+		for (off = 0; off < bv->bv_len; off += blksize) {
+			/* Locate record for stupid devices. */
+			if (private->rdc_data.mode.bits.data_chain == 0) {
+				ccw[-1].flags |= CCW_FLAG_CC;
+				locate_record(ccw, LO_data++,
+					      rq_data_dir(req),
+					      recid - first_rec, 1);
+				ccw->flags = CCW_FLAG_CC;
+				ccw++;
+			} else {
+				if (recid > first_rec)
+					ccw[-1].flags |= CCW_FLAG_DC;
+				else
+					ccw[-1].flags |= CCW_FLAG_CC;
+			}
+			ccw->cmd_code = cmd;
+			ccw->count = device->bp_block;
+			if (idal_is_needed(dst, blksize)) {
+				ccw->cda = (__u32)(addr_t) idaws;
+				ccw->flags = CCW_FLAG_IDA;
+				idaws = idal_create_words(idaws, dst, blksize);
+			} else {
+				ccw->cda = (__u32)(addr_t) dst;
+				ccw->flags = 0;
+			}
+			ccw++;
+			dst += blksize;
+			recid++;
+		}
 	}
-	DE_data = rw_cp->data;
-	LO_data = rw_cp->data + sizeof (DE_fba_data_t);
-	ccw = rw_cp->cpaddr;
-
-	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;
-        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;
-                        }
-                }
-                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;
+	cqr->device = device;
+	cqr->expires = 5 * 60 * HZ;	/* 5 minutes */
+	cqr->status = DASD_CQR_FILLED;
+	return cqr;
 }
 
 static int
-dasd_fba_fill_info (dasd_device_t * device, dasd_information_t * info)
+dasd_fba_fill_info(dasd_device_t * device, dasd_information2_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->format = DASD_FORMAT_LDL;
+	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;
+	return 0;
 }
 
-
-static char *
-dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
+static void
+dasd_fba_dump_sense(struct dasd_device_t *device, dasd_ccw_req_t * req)
 {
-	char *page = (char *) get_free_page (GFP_KERNEL);
-	int len;
+	char *page;
+
+	page = (char *) get_free_page(GFP_KERNEL);
 	if (page == NULL) {
-		return NULL;
+		MESSAGE(KERN_ERR, "%s", "No memory to dump sense data");
+		return;
 	}
-	len = sprintf (page, KERN_WARNING PRINTK_HEADER
-		       "device %04X on irq %d: I/O status report:\n",
-		       device->devinfo.devno, device->devinfo.irq);
+	sprintf(page, KERN_WARNING PRINTK_HEADER
+		"device %04X on irq %d: I/O status report:\n",
+		device->devinfo.devno, device->devinfo.irq);
+
+	MESSAGE(KERN_ERR, "Sense data:\n%s", page);
 
-	return page;
+	free_page((unsigned long) page);
 }
 
-dasd_discipline_t dasd_fba_discipline = {
-        owner: THIS_MODULE,
+/*
+ * max_blocks is dependent on the amount of storage that is available
+ * in the static io buffer for each device. Currently each device has
+ * 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
+ * 24 bytes, the dasd_ccw_req_t has 136 bytes and each block can use
+ * up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
+ * addition we have one define extent ccw + 16 bytes of data and a 
+ * locate record ccw for each block (stupid devices!) + 16 bytes of data.
+ * That makes:
+ * (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
+ * We want to fit two into the available memory so that we can immediatly
+ * start the next request if one finishes off. That makes 100.1 blocks
+ * for one request. Give a little safety and the result is 96.
+ */
+static dasd_discipline_t dasd_fba_discipline = {
+	owner:THIS_MODULE,
 	name:"FBA ",
 	ebcname:"FBA ",
-	max_blocks:((PAGE_SIZE >> 1) / sizeof (ccw1_t) - 1),
-	id_check:dasd_fba_id_check,
-	check_characteristics:dasd_fba_check_characteristics,
+	max_blocks:96,
+	check_device:dasd_fba_check_device,
 	do_analysis:dasd_fba_do_analysis,
 	fill_geometry:dasd_fba_fill_geometry,
 	start_IO:dasd_start_IO,
@@ -406,72 +405,51 @@
 	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,
+	build_cp:dasd_fba_build_cp,
 	dump_sense:dasd_fba_dump_sense,
-	int_handler:dasd_int_handler,
 	fill_info:dasd_fba_fill_info,
 };
 
 int
-dasd_fba_init (void)
+dasd_fba_init(void)
 {
-	int rc = 0;
-	printk (KERN_INFO PRINTK_HEADER
-		"%s discipline initializing\n", dasd_fba_discipline.name);
-	ASCEBC (dasd_fba_discipline.ebcname, 4);
-	dasd_discipline_add (&dasd_fba_discipline);
+	int i;
+
+	ASCEBC(dasd_fba_discipline.ebcname, 4);
+	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;
+	for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++)
+		s390_device_register(&dasd_fba_known_devices[i]);
+#endif
+	return 0;
 }
 
 void
-dasd_fba_cleanup( void ) {
-        printk ( KERN_INFO PRINTK_HEADER
-                 "%s discipline cleaning up\n", dasd_fba_discipline.name);
-#ifdef CONFIG_DASD_DYNAMIC
-        {
+dasd_fba_cleanup(void)
+{
 	int i;
-        for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
-                s390_device_unregister(&dasd_fba_known_devices[i]);
-        }
-        }
-#endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_del(&dasd_fba_discipline);
+
+#ifdef CONFIG_DASD_DYNAMIC
+	for (i = 0; i < sizeof(dasd_fba_known_devices) / sizeof(devreg_t); i++)
+		s390_device_unregister(&dasd_fba_known_devices[i]);
+#endif
+	dasd_discipline_del(&dasd_fba_discipline);
 }
 
 #ifdef MODULE
 int
-init_module (void)
+init_module(void)
 {
-	int rc = 0;
-	rc = dasd_fba_init ();
-	return rc;
+	return dasd_fba_init();
 }
 
 void
-cleanup_module (void)
+cleanup_module(void)
 {
-	dasd_fba_cleanup ();
-	return;
+	dasd_fba_cleanup();
 }
 #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
@@ -486,7 +464,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h
--- a/drivers/s390/block/dasd_fba.h	Sat Jun  8 22:31:52 2002
+++ b/drivers/s390/block/dasd_fba.h	Sat Jun  8 22:31:52 2002
@@ -71,6 +71,6 @@
 
     dasd_fba_characteristics_t;
 
-int dasd_fba_init (void);
-void dasd_fba_cleanup (void);
+int dasd_fba_init(void);
+void dasd_fba_cleanup(void);
 #endif				/* DASD_FBA_H */
diff -Nru a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/block/dasd_genhd.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,397 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd_ioctl.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
+ *
+ * Dealing with devices registered to multiple major numbers.
+ *
+ * 05/04/02 split from dasd.c, code restructuring.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/fs.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* This is ugly... */
+#define PRINTK_HEADER "dasd_gendisk:"
+
+#include "dasd_int.h"
+
+static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head dasd_major_info = LIST_HEAD_INIT(dasd_major_info);
+
+struct major_info {
+	struct list_head list;
+	struct gendisk gendisk;	/* actually contains the major number */
+};
+
+/*
+ * Returns the queue corresponding to a device behind a kdev.
+ */
+static request_queue_t *
+dasd_get_queue(kdev_t kdev)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	request_queue_t *queue;
+
+	devmap = dasd_devmap_from_kdev(kdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return NULL;
+	queue = device->request_queue;
+	dasd_put_device(devmap);
+	return queue;
+}
+
+/*
+ * Register major number for the dasd driver. Call with DASD_MAJOR to
+ * setup the static dasd device major 94 or with 0 to allocated a major
+ * dynamically.
+ */
+static int
+dasd_register_major(int major)
+{
+	struct major_info *mi;
+	struct hd_struct *gd_part;
+	devfs_handle_t *gd_de_arr, *gd_label_arr;
+	int *gd_sizes;
+	char *gd_flags;
+	int new_major, rc;
+
+	rc = 0;
+	/* Allocate major info structure. */
+	mi = kmalloc(sizeof(struct major_info), GFP_KERNEL);
+
+	/* Allocate gendisk arrays. */
+	gd_de_arr = kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t),
+			    GFP_KERNEL);
+	gd_flags = kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
+	gd_label_arr = kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t),
+			       GFP_KERNEL);
+	gd_part = kmalloc(sizeof (struct hd_struct) << MINORBITS, GFP_ATOMIC);
+	gd_sizes = kmalloc(sizeof(int) << MINORBITS, GFP_ATOMIC);
+
+	/* Check if one of the allocations failed. */
+	if (mi == NULL || gd_de_arr == NULL || gd_flags == NULL ||
+	    gd_label_arr == NULL || gd_part == NULL || gd_sizes == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"Cannot get memory to allocate another "
+			"major number");
+		rc = -ENOMEM;
+		goto out_error;
+	}
+
+	/* Register block device. */
+	new_major = devfs_register_blkdev(major, "dasd",
+					  &dasd_device_operations);
+	if (new_major < 0) {
+		MESSAGE(KERN_WARNING,
+			"Cannot register to major no %d, rc = %d", major, rc);
+		rc = new_major;
+		goto out_error;
+	}
+	if (major != 0)
+		new_major = major;
+
+	/* Initialize major info structure. */
+	memset(mi, 0, sizeof(struct major_info));
+	mi->gendisk.major = new_major;
+	mi->gendisk.major_name = "dasd";
+	mi->gendisk.minor_shift = DASD_PARTN_BITS;
+	mi->gendisk.nr_real = DASD_PER_MAJOR;
+	mi->gendisk.fops = &dasd_device_operations;
+	mi->gendisk.de_arr = gd_de_arr;
+	mi->gendisk.flags = gd_flags;
+	mi->gendisk.label_arr = gd_label_arr;
+	mi->gendisk.part = gd_part;
+	mi->gendisk.sizes = gd_sizes;
+
+	/* Initialize the gendisk arrays. */
+	memset(gd_de_arr, 0, DASD_PER_MAJOR * sizeof(devfs_handle_t));
+	memset(gd_flags, 0, DASD_PER_MAJOR * sizeof (char));
+	memset(gd_label_arr, 0, DASD_PER_MAJOR * sizeof(devfs_handle_t));
+	memset(gd_part, 0, sizeof (struct hd_struct) << MINORBITS);
+	memset(gd_sizes, 0, sizeof(int) << MINORBITS);
+
+	/* Setup block device pointers for the new major. */
+	blk_dev[new_major].queue = dasd_get_queue;
+	blk_size[new_major] = gd_sizes;
+
+	/* Insert the new major info structure into dasd_major_info list. */
+	spin_lock(&dasd_major_lock);
+	list_add_tail(&mi->list, &dasd_major_info);
+	spin_unlock(&dasd_major_lock);
+
+	/* Make the gendisk known. */
+	add_gendisk(&mi->gendisk);
+	return 0;
+
+	/* Something failed. Do the cleanup and return rc. */
+out_error:
+	/* We rely on kfree to do the != NULL check. */
+	kfree(gd_sizes);
+	kfree(gd_part);
+	kfree(gd_label_arr);
+	kfree(gd_flags);
+	kfree(gd_de_arr);
+	kfree(mi);
+	return rc;
+}
+
+static void
+dasd_unregister_major(struct major_info * mi)
+{
+	int *bs;
+	int major, rc;
+
+	if (mi == NULL)
+		return;
+
+	/* Remove gendisk information. */
+	del_gendisk(&mi->gendisk);
+
+	/* Delete the major info from dasd_major_info. */
+	spin_lock(&dasd_major_lock);
+	list_del(&mi->list);
+	spin_unlock(&dasd_major_lock);
+
+	/* Clear block device pointers. */
+	major = mi->gendisk.major;
+	blk_dev[major].queue = NULL;
+	bs = blk_size[major];
+	blk_clear(major);
+
+	rc = devfs_unregister_blkdev(major, "dasd");
+	if (rc < 0)
+		MESSAGE(KERN_WARNING,
+			"Cannot unregister from major no %d, rc = %d",
+			major, rc);
+
+	/* Free memory. */
+	kfree(bs);
+	kfree(mi->gendisk.part);
+	kfree(mi->gendisk.label_arr);
+	kfree(mi->gendisk.flags);
+	kfree(mi->gendisk.de_arr);
+	kfree(mi);
+}
+
+/*
+ * Dynamically allocate a new major for dasd devices.
+ */
+int
+dasd_gendisk_new_major(void)
+{
+	int rc;
+	
+	rc = dasd_register_major(0);
+	if (rc)
+		DBF_EXC(DBF_ALERT, "%s", "out of major numbers!");
+	return rc;
+}
+
+/*
+ * Return pointer to gendisk structure by kdev.
+ */
+struct gendisk *
+dasd_gendisk_from_major(int major)
+{
+	struct list_head *l;
+	struct major_info *mi;
+	struct gendisk *gdp;
+
+	spin_lock(&dasd_major_lock);
+	gdp = NULL;
+	list_for_each(l, &dasd_major_info) {
+		mi = list_entry(l, struct major_info, list);
+		if (mi->gendisk.major == major) {
+			gdp = &mi->gendisk;
+			break;
+		}
+	}
+	spin_unlock(&dasd_major_lock);
+	return gdp;
+}
+
+/*
+ * Return pointer to gendisk structure by devindex.
+ */
+struct gendisk *
+dasd_gendisk_from_devindex(int devindex)
+{
+	struct list_head *l;
+	struct major_info *mi;
+	struct gendisk *gdp;
+
+	spin_lock(&dasd_major_lock);
+	gdp = NULL;
+	list_for_each(l, &dasd_major_info) {
+		mi = list_entry(l, struct major_info, list);
+		if (devindex < DASD_PER_MAJOR) {
+			gdp = &mi->gendisk;
+			break;
+		}
+		devindex -= DASD_PER_MAJOR;
+	}
+	spin_unlock(&dasd_major_lock);
+	return gdp;
+}
+
+/*
+ * Return devindex of first device using a specifiy major number.
+ */
+int dasd_gendisk_major_index(int major)
+{
+	struct list_head *l;
+	struct major_info *mi;
+	int devindex, rc;
+
+	spin_lock(&dasd_major_lock);
+	rc = -EINVAL;
+	devindex = 0;
+	list_for_each(l, &dasd_major_info) {
+		mi = list_entry(l, struct major_info, list);
+		if (mi->gendisk.major == major) {
+			rc = devindex;
+			break;
+		}
+		devindex += DASD_PER_MAJOR;
+	}
+	spin_unlock(&dasd_major_lock);
+	return rc;
+}
+
+
+/*
+ * This one is needed for naming 18000+ possible dasd devices.
+ *   dasda - dasdz : 26 devices
+ *   dasdaa - dasdzz : 676 devices, added up = 702
+ *   dasdaaa - dasdzzz : 17576 devices, added up = 18278
+ * This function is called from the partition detection code (see disk_name)
+ * via the genhd_dasd_name hook. As mentioned in partition/check.c this
+ * is ugly...
+ */
+int
+dasd_device_name(char *str, int index, int partition, struct gendisk *hd)
+{
+	struct list_head *l;
+	int len, found;
+
+	/* Check if this is on of our gendisk structures. */
+	found = 0;
+	spin_lock(&dasd_major_lock);
+	list_for_each(l, &dasd_major_info) {
+		struct major_info *mi;
+		mi = list_entry(l, struct major_info, list);
+		if (&mi->gendisk == hd) {
+			found = 1;
+			break;
+		}
+		index += DASD_PER_MAJOR;
+	}
+	spin_unlock(&dasd_major_lock);
+	if (!found)
+		/* Not one of our structures. Can't be a dasd. */
+		return -EINVAL;
+	len = sprintf(str, "dasd");
+	if (index > 25) {
+		if (index > 701)
+			len += sprintf(str + len, "%c",
+				       'a' + (((index - 702) / 676) % 26));
+		len += sprintf(str + len, "%c",
+			       'a' + (((index - 26) / 26) % 26));
+	}
+	len += sprintf(str + len, "%c", 'a' + (index % 26));
+
+	if (partition > DASD_PARTN_MASK)
+		return -EINVAL;
+	if (partition)
+		len += sprintf(str + len, "%d", partition);
+	return 0;
+}
+
+/*
+ * Register disk to genhd. This will trigger a partition detection.
+ */
+void
+dasd_setup_partitions(dasd_device_t * device)
+{
+	grok_partitions(device->kdev, device->blocks << device->s2b_shift);
+}
+
+/*
+ * Remove all inodes in the system for a device and make the
+ * partitions unusable by setting their size to zero.
+ */
+void
+dasd_destroy_partitions(dasd_device_t * device)
+{
+	struct gendisk *gdp;
+	int minor, i;
+
+	gdp = dasd_gendisk_from_major(major(device->kdev));
+	if (gdp == NULL)
+		return;
+
+	wipe_partitions(device->kdev);
+
+	/* FIXME: do we really need that */
+	minor = minor(device->kdev);
+	for (i = 0; i < (1 << DASD_PARTN_BITS); i++)
+		gdp->sizes[minor + i] = 0;
+
+	/*
+	 * This is confusing. The funcions is devfs_register_partitions
+	 * but the 1 as third parameter makes it do an unregister...
+	 * FIXME: there must be a better way to get rid of the devfs entries
+	 */
+	devfs_register_partitions(gdp, minor(device->kdev), 1);
+}
+
+extern int (*genhd_dasd_name)(char *, int, int, struct gendisk *);
+extern int (*genhd_dasd_ioctl) (struct inode *inp, struct file *filp,
+                                unsigned int no, unsigned long data);
+
+int
+dasd_gendisk_init(void)
+{
+	int rc;
+
+	/* Register to static dasd major 94 */
+	rc = dasd_register_major(DASD_MAJOR);
+	if (rc != 0) {
+		MESSAGE(KERN_WARNING,
+			"Couldn't register successfully to "
+			"major no %d", DASD_MAJOR);
+		return rc;
+	}
+	genhd_dasd_name = dasd_device_name;
+        genhd_dasd_ioctl = dasd_ioctl;
+	return 0;
+
+}
+
+void
+dasd_gendisk_exit(void)
+{
+	struct list_head *l, *n;
+
+	genhd_dasd_ioctl = NULL;
+	genhd_dasd_name = NULL;
+	spin_lock(&dasd_major_lock);
+	list_for_each_safe(l, n, &dasd_major_info)
+		dasd_unregister_major(list_entry(l, struct major_info, list));
+	spin_unlock(&dasd_major_lock);
+}
diff -Nru a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
--- a/drivers/s390/block/dasd_int.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/block/dasd_int.h	Sat Jun  8 22:31:51 2002
@@ -1,135 +1,75 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@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
+ * 2002/01/04 Created 2.4-2.5 compatibility mode
+ * 05/04/02 code restructuring.
  */
 
 #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);
+#ifdef __KERNEL__
 
-#define DASD_NAME "dasd"
 #define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+#define DASD_PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
 
+/*
+ * States a dasd device can have:
+ *   new: the dasd_device_t structure is allocated.
+ *   known: the discipline for the device is identified.
+ *   basic: the device can do basic i/o.
+ *   accept: the device is analysed (format is known).
+ *   ready: partition detection is done and the device is can do block io.
+ *   online: the device accepts requests from the block device queue.
+ *
+ * Things to do for startup state transitions:
+ *   new -> known: find discipline for the device and create devfs entries.
+ *   known -> basic: request irq line for the device.
+ *   basic -> accept: do the initial analysis, e.g. format detection.
+ *   accept-> ready: do block device setup and detect partitions.
+ *   ready -> online: schedule the device tasklet.
+ * Things to do for shutdown state transitions:
+ *   online -> ready: just set the new device state.
+ *   ready -> accept: flush requests from the block device layer and
+ *                    clear partition information.
+ *   accept -> basic: reset format information.
+ *   basic -> known: terminate all requests and free irq.
+ *   known -> new: remove devfs entries and forget discipline.
+ */
 
-#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_NEW	  0
 #define DASD_STATE_KNOWN  1
-#define DASD_STATE_ACCEPT 2
-#define DASD_STATE_INIT   3
+#define DASD_STATE_BASIC  2
+#define DASD_STATE_ACCEPT 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/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 <linux/interrupt.h>
+#include <asm/debug.h>
+#include <asm/dasd.h>
+#include <asm/idals.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_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, \
-	nr_real:D_PER_MAJOR, \
-        fops:&dasd_device_operations, 
-static inline struct request * 
-dasd_next_request( request_queue_t *queue ) 
-{
-        return elv_next_request(queue);
-}
-static inline void 
-dasd_dequeue_request( request_queue_t * q, struct request *req )
-{
-        blkdev_dequeue_request (req);
-}
-#endif
+#define CONFIG_DASD_DYNAMIC
 
-/* 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;
+/*
+ * SECTION: Type definitions
+ */
+typedef int (*dasd_ioctl_fn_t) (void *inp, int no, long args);
 
 typedef struct {
 	struct list_head list;
@@ -139,10 +79,10 @@
 } dasd_ioctl_list_t;
 
 typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover              */
+	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_recover = 2	/* recovery action recommended	     */
 } dasd_era_t;
 
 /* BIT DEFINITIONS FOR SENSE DATA */
@@ -151,112 +91,114 @@
 #define DASD_SENSE_BIT_2 0x20
 #define DASD_SENSE_BIT_3 0x10
 
-#define check_then_set(where,from,to) \
+/*
+ * SECTION: MACROs for klogd and s390 debug feature (dbf)
+ */
+#define DBF_DEV_EVENT(d_level, d_device, d_str, d_data...) \
 do { \
-        if ((*(where)) != (from) ) { \
-                printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
-                BUG(); \
-        } \
-        (*(where)) = (to); \
-} while (0)
+	debug_sprintf_event(d_device->debug_area, \
+			    d_level, \
+			    d_str "\n", \
+			    d_data); \
+} while(0)
 
-#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+#define DBF_DEV_EXC(d_level, d_device, d_str, d_data...) \
 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 ); \
+	debug_sprintf_exception(d_device->debug_area, \
+				d_level, \
+				d_str "\n", \
+				d_data); \
 } 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);\
+#define DBF_EVENT(d_level, d_str, d_data...)\
+do { \
+	debug_sprintf_event(dasd_debug_area, \
+			    d_level,\
+			    d_str "\n", \
+			    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);\
+
+#define DBF_EXC(d_level, d_str, d_data...)\
+do { \
+	debug_sprintf_exception(dasd_debug_area, \
+				d_level,\
+				d_str "\n", \
+				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);\
+/* definition of dbf debug levels */
+#define	DBF_EMERG	0	/* system is unusable			*/
+#define	DBF_ALERT	1	/* action must be taken immediately	*/
+#define	DBF_CRIT	2	/* critical conditions			*/
+#define	DBF_ERR		3	/* error conditions			*/
+#define	DBF_WARNING	4	/* warning conditions			*/
+#define	DBF_NOTICE	5	/* normal but significant condition	*/
+#define	DBF_INFO	6	/* informational			*/
+#define	DBF_DEBUG	6	/* debug-level messages			*/
+
+/* messages to be written via klogd and dbf */
+#define DEV_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+do { \
+	printk(d_loglevel PRINTK_HEADER " /dev/%-7s(%3d:%3d),%04x@%02x: " \
+	       d_string "\n", d_device->name, \
+	       major(d_device->kdev), minor(d_device->kdev), \
+	       d_device->devinfo.devno, d_device->devinfo.irq, \
+	       d_args); \
+	DBF_DEV_EVENT(DBF_ALERT, d_device, d_string, d_args); \
 } 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);\
+
+#define MESSAGE(d_loglevel,d_string,d_args...)\
+do { \
+	printk(d_loglevel PRINTK_HEADER " " d_string "\n", d_args); \
+	DBF_EVENT(DBF_ALERT, d_string, d_args); \
 } while(0)
 
 struct dasd_device_t;
-struct request;
+
+typedef struct dasd_ccw_req_t {
+	unsigned int magic;		/* Eye catcher */
+        struct list_head list;		/* list_head for request queueing. */
+
+	/* Where to execute what... */
+	struct dasd_device_t *device;	/* device the request is for */
+	ccw1_t *cpaddr;			/* address of channel program */
+	char status;	        	/* status of this request */
+	short retries;			/* A retry counter */
+
+	/* ... and how */
+	int options;			/* options for execution */
+	int expires;			/* expiration period in jiffies */
+	char lpm;               	/* logical path mask */
+	void *data;			/* pointer to data area */
+
+	/* these are important for recovering erroneous requests          */
+	devstat_t *dstat;		/* device status in case of an error */
+	struct dasd_ccw_req_t *refers;	/* ERP-chain queueing. */
+	void *function; 		/* originating ERP action */
+
+	unsigned long long buildclk;	/* TOD-clock of request generation */
+	unsigned long long startclk;	/* TOD-clock of request start */
+	unsigned long long stopclk;	/* TOD-clock of request interrupt */
+	unsigned long long endclk;	/* TOD-clock of request termination */
+
+        /* Callback that is called after reaching final status. */
+        void (*callback)(struct dasd_ccw_req_t *, void *data);
+        void *callback_data;
+} dasd_ccw_req_t;
 
 /* 
- * signatures for the functions of dasd_discipline_t 
- * make typecasts much easier
+ * dasd_ccw_req_t -> status can be:
  */
-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_steal_lock_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);
+#define DASD_CQR_FILLED   0x00	/* request is ready to be processed */
+#define DASD_CQR_QUEUED   0x01	/* request is queued to be processed */
+#define DASD_CQR_IN_IO    0x02	/* request is currently in IO */
+#define DASD_CQR_DONE     0x03	/* request is completed successfully */
+#define DASD_CQR_ERROR    0x04	/* request is completed with error */
+#define DASD_CQR_FAILED   0x05	/* request is finally failed */
+#define DASD_CQR_PENDING  0x06  /* request is waiting for interrupt - ERP only */ 
 
+/* Signature for error recovery functions. */
+typedef dasd_ccw_req_t *(*dasd_erp_fn_t) (dasd_ccw_req_t * cqr);
 
 /*
  * the dasd_discipline_t is
@@ -265,108 +207,320 @@
  * 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_steal_lock_fn_t steal_lock;
-        dasd_merge_cp_fn_t merge_cp;
-        dasd_info_fn_t fill_info;
+	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 */
+
 	struct list_head list;	/* used for list of disciplines */
+
+        /*
+         * Device recognition functions. check_device is used to verify
+         * the sense data and the information returned by read device
+         * characteristics. It returns 0 if the discipline can be used
+         * for the device in question.
+         * do_analysis is used in the step from device state "basic" to
+         * state "accept". It returns 0 if the device can be made ready,
+         * it returns -EMEDIUMTYPE if the device can't be made ready or
+         * -EAGAIN if do_analysis started a ccw that needs to complete
+         * before the analysis may be repeated.
+         */
+        int (*check_device)(struct dasd_device_t *);
+	int (*do_analysis) (struct dasd_device_t *);
+
+        /*
+         * Device operation functions. build_cp creates a ccw chain for
+         * a block device request, start_io starts the request and
+         * term_IO cancels it (e.g. in case of a timeout). format_device
+         * returns a ccw chain to be used to format the device.
+         */
+	dasd_ccw_req_t *(*build_cp) (struct dasd_device_t *, struct request *);
+	int (*start_IO) (dasd_ccw_req_t *);
+	int (*term_IO) (dasd_ccw_req_t *);
+	dasd_ccw_req_t *(*format_device) (struct dasd_device_t *,
+                                          struct format_data_t *);
+
+        /*
+         * Error recovery functions. examine_error() returns a value that
+         * indicates what to do for an error condition. If examine_error()
+         * returns 'dasd_era_recover' erp_action() is called to create a 
+         * special error recovery ccw. erp_postaction() is called after
+         * an error recovery ccw has finished its execution. dump_sense
+         * is called for every error condition to print the sense data
+         * to the console.
+         */
+	dasd_era_t(*examine_error) (dasd_ccw_req_t *, devstat_t *);
+	dasd_erp_fn_t(*erp_action) (dasd_ccw_req_t *);
+	dasd_erp_fn_t(*erp_postaction) (dasd_ccw_req_t *);
+	void (*dump_sense) (struct dasd_device_t *, dasd_ccw_req_t *);
+
+        /* i/o control functions. */
+	int (*fill_geometry) (struct dasd_device_t *, struct hd_geometry *);
+	int (*fill_info) (struct dasd_device_t *, dasd_information2_t *);
 } dasd_discipline_t;
 
-#define DASD_DEFAULT_FEATURES 0
-#define DASD_FEATURE_READONLY 1
+typedef struct dasd_device_t {
+	/* Block device stuff. */
+	char name[16];			/* The device name in /dev. */
+	kdev_t kdev;
+	devfs_handle_t devfs_entry;
+	request_queue_t *request_queue;
+	spinlock_t request_queue_lock;
+	unsigned long blocks;		/* size of volume in blocks */
+	unsigned int bp_block;		/* bytes per block */
+	unsigned int s2b_shift;		/* log2 (bp_block/512) */
 
-/* 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;
+	/* Device discipline stuff. */
+	dasd_discipline_t *discipline;
+	char *private;
 
+	/* Device state and target state. */
+	int state, target;
 
+	/* Open and reference count. */
+        atomic_t ref_count;
+	atomic_t open_count;
+
+	/* ccw queue and memory for static ccw/erp buffers. */
+	struct list_head ccw_queue;
+	spinlock_t mem_lock;
+	void *ccw_mem;
+	void *erp_mem;
+	struct list_head ccw_chunks;
+	struct list_head erp_chunks;
 
-#define DASD_MAJOR_INFO_REGISTERED 1
-#define DASD_MAJOR_INFO_IS_STATIC 2
+	/* Common i/o stuff. */
+	s390_dev_info_t devinfo;
+	devstat_t dev_status;
 
-typedef struct major_info_t {
+	atomic_t tasklet_scheduled;
+        struct tasklet_struct tasklet;
+	struct tq_struct kick_tq;
+	struct timer_list timer;
+
+	debug_info_t *debug_area;
+#ifdef CONFIG_DASD_PROFILE
+	dasd_profile_info_t profile;
+#endif
+} dasd_device_t;
+
+/*
+ * dasd_devmap_t is used to store the features and the relation
+ * between device number and device index. To find a dasd_devmap_t
+ * that corresponds to a device number of a device index each
+ * dasd_devmap_t is added to two linked lists, one to search by
+ * the device number and one to search by the device index. As
+ * soon as big minor numbers are available the device index list
+ * can be removed since the device number will then be identical
+ * to the device index.
+ */
+typedef struct {
+	struct list_head devindex_list;
+	struct list_head devno_list;
+        unsigned int devindex;
+        unsigned short devno;
+        unsigned short features;
+        devreg_t *devreg;
+        dasd_device_t *device;
+} dasd_devmap_t;
+
+/*
+ * The static memory in ccw_mem and erp_mem is managed by a sorted
+ * list of free memory chunks.
+ */
+typedef struct dasd_mchunk_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;
+	unsigned long size;
+} __attribute__ ((aligned(8))) dasd_mchunk_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;
+static inline void
+dasd_init_chunklist(struct list_head *chunk_list, void *mem,
+		    unsigned long size)
+{
+	dasd_mchunk_t *chunk;
+
+	INIT_LIST_HEAD(chunk_list);
+	chunk = (dasd_mchunk_t *) mem;
+	chunk->size = size - sizeof(dasd_mchunk_t);
+	list_add(&chunk->list, chunk_list);
+}
+
+static inline void *
+dasd_alloc_chunk(struct list_head *chunk_list, unsigned long size)
+{
+	dasd_mchunk_t *chunk, *tmp;
+	struct list_head *l;
+
+	size = (size + 7L) & -8L;
+	list_for_each(l, chunk_list) {
+		chunk = list_entry(l, dasd_mchunk_t, list);
+		if (chunk->size < size)
+			continue;
+		if (chunk->size > size + sizeof(dasd_mchunk_t)) {
+			char *endaddr = (char *) (chunk + 1) + chunk->size;
+			tmp = (dasd_mchunk_t *) (endaddr - size) - 1;
+			tmp->size = size;
+			chunk->size -= size + sizeof(dasd_mchunk_t);
+			chunk = tmp;
+		} else
+			list_del(&chunk->list);
+		return (void *) (chunk + 1);
+	}
+	return NULL;
+}
+
+static inline void
+dasd_free_chunk(struct list_head *chunk_list, void *mem)
+{
+	dasd_mchunk_t *chunk, *tmp;
+	struct list_head *p, *left;
 
-int dasd_init (void);
+	chunk = (dasd_mchunk_t *)((char *) mem - sizeof(dasd_mchunk_t));
+	/* Find out the left neighbour in chunk_list. */
+	left = chunk_list;
+	list_for_each(p, chunk_list) {
+		if (list_entry(p, dasd_mchunk_t, list) > chunk)
+			break;
+		left = p;
+	}
+	/* Try to merge with right neighbour = next element from left. */
+	if (left->next != chunk_list) {
+		tmp = list_entry(left->next, dasd_mchunk_t, list);
+		if ((char *) (chunk + 1) + chunk->size == (char *) tmp) {
+			list_del(&tmp->list);
+			chunk->size += tmp->size + sizeof(dasd_mchunk_t);
+		}
+	}
+	/* Try to merge with left neighbour. */
+	if (left != chunk_list) {
+		tmp = list_entry(left, dasd_mchunk_t, list);
+		if ((char *) (tmp + 1) + tmp->size == (char *) chunk) {
+			tmp->size += chunk->size + sizeof(dasd_mchunk_t);
+			return;
+		}
+	}
+	__list_add(&chunk->list, left, left->next);
+}
+
+/*
+ * Check if bsize is in { 512, 1024, 2048, 4096 }
+ */
+static inline int
+dasd_check_blocksize(int bsize)
+{
+	if (bsize < 512 || bsize > 4096 || (bsize & (bsize - 1)) != 0)
+		return -EMEDIUMTYPE;
+	return 0;
+}
+
+/* externals in dasd.c */
+#define DASD_PROFILE_ON	 1
+#define DASD_PROFILE_OFF 0
+
+extern debug_info_t *dasd_debug_area;
+extern dasd_profile_info_t dasd_global_profile;
+extern unsigned int dasd_profile_level;
+extern struct block_device_operations dasd_device_operations;
+
+dasd_ccw_req_t *dasd_kmalloc_request(char *, int, int, dasd_device_t *); /* unused */
+dasd_ccw_req_t *dasd_smalloc_request(char *, int, int, dasd_device_t *);
+void dasd_kfree_request(dasd_ccw_req_t *, dasd_device_t *);
+void dasd_sfree_request(dasd_ccw_req_t *, dasd_device_t *);
+
+static inline int
+dasd_kmalloc_set_cda(ccw1_t *ccw, void *cda, dasd_device_t *device)
+{
+	return set_normalized_cda(ccw, cda);
+}
+
+dasd_device_t *dasd_alloc_device(dasd_devmap_t *);
+void dasd_free_device(dasd_device_t *);
+void dasd_enable_devices(int, int);
+void dasd_disable_devices(int, int);
 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 );
+void dasd_set_target_state(dasd_device_t *, int);
+void dasd_kick_device(dasd_device_t *);
 
-extern debug_info_t *dasd_debug_area;
-extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+void dasd_add_request_head(dasd_ccw_req_t *);
+void dasd_add_request_tail(dasd_ccw_req_t *); /* unused */
+int  dasd_start_IO(dasd_ccw_req_t *);
+int  dasd_term_IO(dasd_ccw_req_t *);
+int  dasd_oper_handler(int, devreg_t *);
+void dasd_schedule_bh(dasd_device_t *);
+int  dasd_sleep_on(dasd_ccw_req_t *);
+int  dasd_sleep_on_immediatly(dasd_ccw_req_t *);
+int  dasd_sleep_on_interruptible(dasd_ccw_req_t *);
+void dasd_set_timer(dasd_device_t *, int);
+void dasd_clear_timer(dasd_device_t *);
+int  dasd_cancel_req(dasd_ccw_req_t *); /* unused */
+
+/* externals in dasd_devmap.c */
+extern int dasd_max_devindex;
+extern int dasd_probeonly;
+extern int dasd_autodetect;
+
+int dasd_devmap_init(void);
+void dasd_devmap_exit(void);
+dasd_devmap_t *dasd_devmap_from_devno(int);
+dasd_devmap_t *dasd_devmap_from_devindex(int);
+dasd_devmap_t *dasd_devmap_from_irq(int);
+dasd_devmap_t *dasd_devmap_from_kdev(kdev_t);
+dasd_device_t *dasd_get_device(dasd_devmap_t *);
+void dasd_put_device(dasd_devmap_t *);
+
+int dasd_devno(char *, char **);
+int dasd_feature_list(char *, char **);
+int dasd_parse(void);
+int dasd_add_range(int, int, int);
+
+/* externals in dasd_gendisk.c */
+int  dasd_gendisk_init(void);
+void dasd_gendisk_exit(void);
+int  dasd_gendisk_new_major(void);
+int  dasd_gendisk_major_index(int);
+struct gendisk *dasd_gendisk_from_major(int);
+struct gendisk *dasd_gendisk_from_devindex(int);
+int  dasd_device_name(char *, int, int, struct gendisk *);
+void dasd_setup_partitions(dasd_device_t *);
+void dasd_destroy_partitions(dasd_device_t *);
+
+/* externals in dasd_ioctl.c */
+int  dasd_ioctl_init(void);
+void dasd_ioctl_exit(void);
+int  dasd_ioctl_no_register(struct module *, int, dasd_ioctl_fn_t);
+int  dasd_ioctl_no_unregister(struct module *, int, dasd_ioctl_fn_t);
+int  dasd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+/* externals in dasd_proc.c */
+int dasd_proc_init(void);
+void dasd_proc_exit(void);
+
+/* externals in dasd_erp.c */
+dasd_ccw_req_t *dasd_default_erp_action(dasd_ccw_req_t *);
+dasd_ccw_req_t *dasd_default_erp_postaction(dasd_ccw_req_t *);
+dasd_ccw_req_t *dasd_alloc_erp_request(char *, int, int, dasd_device_t *);
+void dasd_free_erp_request(dasd_ccw_req_t *, dasd_device_t *);
+void dasd_log_ccw(dasd_ccw_req_t *, int, __u32);
+
+/* externals in dasd_3370_erp.c */
+dasd_era_t dasd_3370_erp_examine(dasd_ccw_req_t *, devstat_t *);
+
+/* externals in dasd_3990_erp.c */
+dasd_era_t dasd_3990_erp_examine(dasd_ccw_req_t *, devstat_t *);
+dasd_ccw_req_t *dasd_3990_erp_action(dasd_ccw_req_t *);
+dasd_ccw_req_t *dasd_2105_erp_action(dasd_ccw_req_t *);
+void dasd_3990_erp_restart_queue(unsigned long);
+
+/* externals in dasd_9336_erp.c */
+dasd_era_t dasd_9336_erp_examine(dasd_ccw_req_t *, devstat_t *);
+
+/* externals in dasd_9336_erp.c */
+dasd_era_t dasd_9343_erp_examine(dasd_ccw_req_t *, devstat_t *);
+dasd_ccw_req_t *dasd_9343_erp_action(dasd_ccw_req_t *);
 
-#endif /* __KERNEL__ */
+#endif				/* __KERNEL__ */
 
 #endif				/* DASD_H */
 
@@ -384,7 +538,7 @@
  * c-label-offset: -4
  * c-continued-statement-offset: 4
  * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
+ * indent-tabs-mode: 1
  * tab-width: 8
  * End:
  */
diff -Nru a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/block/dasd_ioctl.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,596 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd_ioctl.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
+ *
+ * i/o controls for the dasd driver.
+ *
+ * 05/04/02 split from dasd.c, code restructuring.
+ */
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/blkpg.h>
+#include <linux/blk.h>
+
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* This is ugly... */
+#define PRINTK_HEADER "dasd_ioctl:"
+
+#include "dasd_int.h"
+
+/*
+ * SECTION: ioctl functions.
+ */
+static struct list_head dasd_ioctl_list = LIST_HEAD_INIT(dasd_ioctl_list);
+
+/*
+ * Find the ioctl with number no.
+ */
+static dasd_ioctl_list_t *
+dasd_find_ioctl(int no)
+{
+	struct list_head *curr;
+	list_for_each (curr, &dasd_ioctl_list) {
+		if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) {
+			return list_entry (curr, dasd_ioctl_list_t, list);
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Register ioctl with number no.
+ */
+int
+dasd_ioctl_no_register(struct module *owner, int no, dasd_ioctl_fn_t handler)
+{
+	dasd_ioctl_list_t *new;
+	if (dasd_find_ioctl(no))
+		return -EBUSY;
+	new = kmalloc(sizeof (dasd_ioctl_list_t), GFP_KERNEL);
+	if (new == NULL)
+		return -ENOMEM;
+	new->owner = owner;
+	new->no = no;
+	new->handler = handler;
+	list_add(&new->list, &dasd_ioctl_list);
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*
+ * Deregister ioctl with number no.
+ */
+int
+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 || owner != old->owner)
+		return -EINVAL;
+	list_del(&old->list);
+	kfree(old);
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+int
+dasd_ioctl(struct inode *inp, struct file *filp,
+	   unsigned int no, unsigned long data)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_ioctl_list_t *ioctl;
+	struct list_head *l;
+	const char *dir;
+	int rc;
+
+	if ((!inp) || kdev_none(inp->i_rdev))
+		return -EINVAL;
+	if ((_IOC_DIR(no) != _IOC_NONE) && (data == 0)) {
+		PRINT_DEBUG("empty data ptr");
+		return -EINVAL;
+	}
+	devmap = dasd_devmap_from_kdev(inp->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device)) {
+		MESSAGE(KERN_WARNING,
+			"No device registered as device (%d:%d)",
+			major(inp->i_rdev), minor(inp->i_rdev));
+		return -EINVAL;
+	}
+	dir = _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";
+	DBF_DEV_EVENT(DBF_DEBUG, device,
+		      "ioctl 0x%08x %s'0x%x'%d(%d) with data %8lx", no,
+		      dir, _IOC_TYPE(no), _IOC_NR(no), _IOC_SIZE(no), data);
+	/* Search for ioctl no in the ioctl list. */
+	list_for_each(l, &dasd_ioctl_list) {
+		ioctl = list_entry(l, dasd_ioctl_list_t, list);
+		if (ioctl->no == no) {
+			/* Found a matching ioctl. Call it. */
+			if (ioctl->owner) {
+				if (try_inc_mod_count(ioctl->owner) != 0)
+					continue;
+				rc = ioctl->handler(inp, no, data);
+				__MOD_DEC_USE_COUNT(ioctl->owner);
+			} else
+				rc = ioctl->handler(inp, no, data);
+			dasd_put_device(devmap);
+			return rc;
+		}
+	}
+	/* No ioctl with number no. */
+	DBF_DEV_EVENT(DBF_INFO, device,
+		      "unknown ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx", no,
+		      dir, _IOC_TYPE(no), _IOC_NR(no), _IOC_SIZE(no), data);
+	dasd_put_device(devmap);
+	return -ENOTTY;
+}
+
+static int dasd_ioctl_api_version(void *inp, int no, long args)
+{
+	int ver = DASD_API_VERSION;
+	return put_user(ver, (int *) args);
+}
+
+/*
+ * Enable device.
+ */
+static int dasd_ioctl_enable(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int devno;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	devno = device->devinfo.devno;
+	dasd_enable_devices(devno, devno);
+	dasd_put_device(devmap);
+	return 0;
+}
+
+/*
+ * Disable device.
+ */
+static int dasd_ioctl_disable(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	/*
+	 * Man this is sick. We don't do a real disable but only downgrade
+	 * the device to DASD_STATE_BASIC. The reason is that dasdfmt uses
+	 * BIODASDDISABLE to disable accesses to the device via the block
+	 * device layer but it still wants to do i/o on the device by
+	 * using the BIODASDFMT ioctl. Therefore the correct state for the
+	 * device is DASD_STATE_BASIC that allows to do basic i/o.
+	 */
+	dasd_set_target_state(device, DASD_STATE_BASIC);
+	dasd_put_device(devmap);
+	return 0;
+}
+
+/*
+ * 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
+ * devices this means CCWs are generated to format a single track.
+ */
+static int
+dasd_format(dasd_device_t * device, format_data_t * fdata)
+{
+	dasd_ccw_req_t *cqr;
+	int rc;
+
+	if (device->discipline->format_device == NULL)
+		return -EPERM;
+
+	if (atomic_read(&device->open_count) > 1) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "dasd_format: device is open! ");
+		return -EBUSY;
+	}
+
+	DBF_DEV_EVENT(DBF_NOTICE, device,
+		      "formatting units %d to %d (%d B blocks) flags %d",
+		      fdata->start_unit,
+		      fdata->stop_unit, fdata->blksize, fdata->intensity);
+
+	while (fdata->start_unit <= fdata->stop_unit) {
+		cqr = device->discipline->format_device(device, fdata);
+		if (IS_ERR(cqr))
+			return PTR_ERR(cqr);
+		rc = dasd_sleep_on_interruptible(cqr);
+		dasd_sfree_request(cqr, cqr->device);
+		if (rc) {
+			if (rc != -ERESTARTSYS)
+				DEV_MESSAGE(KERN_ERR, device,
+					    " Formatting of unit %d failed "
+					    "with rc = %d",
+					    fdata->start_unit, rc);
+			return rc;
+		}
+		fdata->start_unit++;
+	}
+	return 0;
+}
+
+/*
+ * Format device.
+ */
+static int dasd_ioctl_format(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	format_data_t fdata;
+	int partn, rc;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (!args)
+		return -EINVAL;
+	/* fdata == NULL is no longer a valid arg to dasd_format ! */
+	partn = minor(((struct inode *) inp)->i_rdev) & DASD_PARTN_MASK;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+
+	rc = 0;
+	if (devmap->features & DASD_FEATURE_READONLY)
+		rc = -EROFS;
+	else if (copy_from_user(&fdata, (void *) args, sizeof (format_data_t)))
+		rc = -EFAULT;
+	else if (partn != 0) {
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "Cannot low-level format a partition");
+		rc = -EINVAL;
+	} else
+		rc = dasd_format(device, &fdata);
+	dasd_put_device(devmap);
+	return rc;
+}
+
+#ifdef CONFIG_DASD_PROFILE
+/*
+ * Reset device profile information
+ */
+static int dasd_ioctl_reset_profile(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	memset(&device->profile, 0, sizeof (dasd_profile_info_t));
+	dasd_put_device(devmap);
+	return 0;
+}
+
+/*
+ * Return device profile information
+ */
+static int dasd_ioctl_read_profile(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int rc;
+
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	rc = 0;
+	if (copy_to_user((long *) args, (long *) &device->profile,
+			 sizeof (dasd_profile_info_t)))
+		rc = -EFAULT;
+	dasd_put_device(devmap);
+	return rc;
+}
+#else
+static int dasd_ioctl_reset_profile(void *inp, int no, long args)
+{
+	return -ENOSYS;
+}
+
+static int dasd_ioctl_read_profile(void *inp, int no, long args)
+{
+	return -ENOSYS;
+}
+#endif
+
+/*
+ * Return dasd information. Used for BIODASDINFO and BIODASDINFO2.
+ */
+static int dasd_ioctl_information(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	dasd_information2_t dasd_info;
+	unsigned long flags;
+	int rc;
+
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	if (!device->discipline->fill_info) {
+		dasd_put_device(devmap);
+		return -EINVAL;
+	}
+
+	rc = device->discipline->fill_info(device, &dasd_info);
+	if (rc) {
+		dasd_put_device(devmap);
+		return rc;
+	}
+
+	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->state;
+	
+	/*
+	 * check if device is really formatted
+	 * LDL / CDL was returned by 'fill_info'
+	 */
+	if ((device->state < DASD_STATE_READY) ||
+	    (dasd_check_blocksize(device->bp_block)))
+		dasd_info.format = DASD_FORMAT_NONE;
+	
+	dasd_info.features = devmap->features;
+	
+	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;
+#ifdef DASD_EXTENDED_PROFILING
+		{
+			struct list_head *l;
+			spin_lock_irqsave(&device->lock, flags);
+			list_for_each(l, &device->request_queue->queue_head)
+				dasd_info.req_queue_len++;
+			spin_unlock_irqrestore(&device->lock, flags);
+		}
+#endif				/* DASD_EXTENDED_PROFILING */
+		spin_lock_irqsave(get_irq_lock(device->devinfo.irq), flags);
+		list_for_each(l, &device->ccw_queue)
+			dasd_info.chanq_len++;
+		spin_unlock_irqrestore(get_irq_lock(device->devinfo.irq),
+				       flags);
+	}
+	
+	rc = 0;
+	if (copy_to_user((long *) args, (long *) &dasd_info,
+			 ((no == (unsigned int) BIODASDINFO2) ?
+			  sizeof (dasd_information2_t) :
+			  sizeof (dasd_information_t))))
+		rc = -EFAULT;
+	dasd_put_device(devmap);
+	return rc;
+}
+
+/*
+ * Set read only
+ */
+static int dasd_ioctl_set_ro(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	int major, minor;
+	int intval, i;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+	if (minor(((struct inode *) inp)->i_rdev) & DASD_PARTN_MASK)
+		// ro setting is not allowed for partitions
+		return -EINVAL;
+	if (get_user(intval, (int *) args))
+		return -EFAULT;
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	if (intval)
+		devmap->features |= DASD_FEATURE_READONLY;
+	else
+		devmap->features &= ~DASD_FEATURE_READONLY;
+	major = major(device->kdev);
+	minor = minor(device->kdev);
+	for (i = 0; i < (1 << DASD_PARTN_BITS); i++)
+		set_device_ro(mk_kdev(major, minor + i), intval);
+	dasd_put_device(devmap);
+	return 0;
+}
+
+static int dasd_ioctl_blkioctl(void *inp, int no, long args)
+{
+	return blk_ioctl(((struct inode *) inp)->i_bdev, no, args);
+}
+
+/*
+ * Return device size in number of sectors.
+ */
+static int dasd_ioctl_blkgetsize(void *inp, int no, long args)
+{
+	struct gendisk *gdp;
+	kdev_t kdev;
+	long blocks;
+
+	kdev = ((struct inode *) inp)->i_rdev;
+	gdp = dasd_gendisk_from_major(major(kdev));
+	if (gdp == NULL)
+		return -EINVAL;
+	blocks = gdp->sizes[minor(kdev)] << 1;
+	return put_user(blocks, (long *) args);
+}
+
+/*
+ * Return device size in number of sectors, 64bit version.
+ */
+static int dasd_ioctl_blkgetsize64(void *inp, int no, long args)
+{
+	struct gendisk *gdp;
+	kdev_t kdev;
+	u64 blocks;
+
+	kdev = ((struct inode *) inp)->i_rdev;
+	gdp = dasd_gendisk_from_major(major(kdev));
+	if (gdp == NULL)
+		return -EINVAL;
+	blocks = gdp->sizes[minor(kdev)] << 1;
+	return put_user(blocks << 10, (u64 *) args);
+}
+
+/*
+ * Reread partition table.
+ */
+static int dasd_ioctl_rr_partition(void *inp, int no, long args)
+{
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	devmap = dasd_devmap_from_kdev(((struct inode *) inp)->i_rdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	if (atomic_read(&device->open_count) != 1)
+		DEV_MESSAGE(KERN_WARNING, device, "%s",
+			    "BLKRRPART: device is open! expect errors.");
+	dasd_destroy_partitions(device);
+	dasd_setup_partitions(device);
+	dasd_put_device(devmap);
+	return 0;
+}
+
+/*
+ * Return disk geometry.
+ */
+static int dasd_ioctl_getgeo(void *inp, int no, long args)
+{
+	struct hd_geometry geo = { 0, };
+	dasd_devmap_t *devmap;
+	dasd_device_t *device;
+	kdev_t kdev;
+	int rc;
+
+	kdev = ((struct inode *) inp)->i_rdev;
+	devmap = dasd_devmap_from_kdev(kdev);
+	device = (devmap != NULL) ?
+		dasd_get_device(devmap) : ERR_PTR(-ENODEV);
+	if (IS_ERR(device))
+		return PTR_ERR(device);
+	rc = 0;
+	if (device != NULL && device->discipline != NULL &&
+	    device->discipline->fill_geometry != NULL) {
+		device->discipline->fill_geometry(device, &geo);
+		geo.start = get_start_sect(kdev);
+		if (copy_to_user((struct hd_geometry *) args, &geo,
+				 sizeof (struct hd_geometry)))
+			rc = -EFAULT;
+	} else
+		rc = -EINVAL;
+	dasd_put_device(devmap);
+	return rc;
+}
+
+/*
+ * List of static ioctls.
+ */
+static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] =
+{
+	{ BIODASDDISABLE, dasd_ioctl_disable },
+	{ BIODASDENABLE, dasd_ioctl_enable },
+	{ BIODASDFMT, dasd_ioctl_format },
+	{ BIODASDINFO, dasd_ioctl_information },
+	{ BIODASDINFO2, dasd_ioctl_information },
+	{ BIODASDPRRD, dasd_ioctl_read_profile },
+	{ BIODASDPRRST, dasd_ioctl_reset_profile },
+	{ BLKELVGET, dasd_ioctl_blkioctl },
+	{ BLKELVSET, dasd_ioctl_blkioctl },
+	{ BLKFLSBUF, dasd_ioctl_blkioctl },
+	{ BLKGETSIZE, dasd_ioctl_blkgetsize },
+	{ BLKGETSIZE64, dasd_ioctl_blkgetsize64 },
+	{ BLKPG, dasd_ioctl_blkioctl },
+	{ BLKROGET, dasd_ioctl_blkioctl },
+	{ BLKROSET, dasd_ioctl_set_ro },
+	{ BLKRRPART, dasd_ioctl_rr_partition },
+	{ BLKSSZGET, dasd_ioctl_blkioctl },
+	{ DASDAPIVER, dasd_ioctl_api_version },
+	{ HDIO_GETGEO, dasd_ioctl_getgeo },
+	{ -1, NULL }
+};
+
+int
+dasd_ioctl_init(void)
+{
+	int i;
+
+	for (i = 0; dasd_ioctls[i].no != -1; i++)
+		dasd_ioctl_no_register(NULL, dasd_ioctls[i].no,
+				       dasd_ioctls[i].fn);
+	return 0;
+
+}
+
+void
+dasd_ioctl_exit(void)
+{
+	int i;
+
+	for (i = 0; dasd_ioctls[i].no != -1; i++)
+		dasd_ioctl_no_unregister(NULL, dasd_ioctls[i].no,
+					 dasd_ioctls[i].fn);
+
+}
+
+EXPORT_SYMBOL(dasd_ioctl_no_register);
+EXPORT_SYMBOL(dasd_ioctl_no_unregister);
diff -Nru a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/block/dasd_proc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,469 @@
+/*
+ * File...........: linux/drivers/s390/block/dasd_proc.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Horst Hummel <Horst.Hummel@de.ibm.com>
+ *		    Carsten Otte <Cotte@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2002
+ *
+ * /proc interface for the dasd driver.
+ *
+ * 05/04/02 split from dasd.c, code restructuring.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
+
+#include <asm/debug.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+/* This is ugly... */
+#define PRINTK_HEADER "dasd_proc:"
+
+#include "dasd_int.h"
+
+typedef struct {
+	char *data;
+	int len;
+} tempinfo_t;
+
+static struct proc_dir_entry *dasd_proc_root_entry = NULL;
+static struct proc_dir_entry *dasd_devices_entry;
+static struct proc_dir_entry *dasd_statistics_entry;
+
+static ssize_t
+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;
+
+	if (*offset >= p_info->len)
+		return 0;	/* EOF */
+	len = p_info->len - *offset;
+	if (user_len < len)
+		len = user_len;
+	if (copy_to_user(user_buf, &(p_info->data[*offset]), len))
+		return -EFAULT;
+	(*offset) += len;
+	return len;		/* number of bytes "read" */
+}
+
+static int
+dasd_generic_close (struct inode *inode, struct file *file)
+{
+	tempinfo_t *info;
+
+	info = (tempinfo_t *) file->private_data;
+	file->private_data = NULL;
+	if (info) {
+		if (info->data)
+			vfree (info->data);
+		kfree (info);
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static inline char *
+dasd_get_user_string(const char *user_buf, size_t user_len)
+{
+	char *buffer;
+
+	buffer = kmalloc(user_len + 1, GFP_KERNEL);
+	if (buffer == NULL)
+		return ERR_PTR(-ENOMEM);
+	if (copy_from_user(buffer, user_buf, user_len) != 0) {
+		kfree(buffer);
+		return ERR_PTR(-EFAULT);
+	}
+	/* got the string, now strip linefeed. */
+	if (buffer[user_len - 1] == '\n')
+		buffer[user_len - 1] = 0;
+	else
+		buffer[user_len] = 0;
+	return buffer;
+}
+
+static ssize_t
+dasd_devices_write(struct file *file, const char *user_buf,
+		   size_t user_len, loff_t * offset)
+{
+	char *buffer, *str;
+	int add_or_set, device_or_range;
+	int from, to, features;
+
+	buffer = dasd_get_user_string(user_buf, user_len);
+	MESSAGE(KERN_INFO, "/proc/dasd/devices: '%s'", buffer);
+
+	/* Scan for "add " or "set ". */
+	for (str = buffer; isspace(*str); str++);
+	if (strncmp(str, "add", 3) == 0 && isspace(str[3]))
+		add_or_set = 0;
+	else if (strncmp(str, "set", 3) == 0 && isspace(str[3]))
+		add_or_set = 1;
+	else
+		goto out_error;
+	for (str = str + 4; isspace(*str); str++);
+
+	/* Scan for "device " or "range=". */
+	if (strncmp(str, "device", 6) == 0 && isspace(str[6])) {
+		device_or_range = 0;
+		for (str = str + 6; isspace(*str); str++);
+	} else if (strncmp(str, "range=", 6) == 0) {
+		device_or_range = 1;
+		str = str + 6;
+	} else
+		goto out_error;
+
+	/* Scan device number range and feature string. */
+	to = from = dasd_devno(str, &str);
+	if (*str == '-') {
+		str++;
+		to = dasd_devno(str, &str);
+	}
+	features = dasd_feature_list(str, &str);
+	/* Negative numbers in from/to/features indicate errors */
+	if (from < 0 || to < 0 || features < 0)
+		goto out_error;
+
+	if (add_or_set == 0) {
+		dasd_add_range(from, to, features);
+		dasd_enable_devices(from, to);
+	} else {
+		for (; isspace(*str); str++);
+		if (strcmp(str, "on") == 0)
+			dasd_enable_devices(from, to);
+		else if (strcmp(str, "off") == 0)
+			dasd_disable_devices(from, to);
+		else
+			goto out_error;
+	}
+	kfree(buffer);
+	return user_len;
+out_error:
+	MESSAGE(KERN_WARNING,
+		"/proc/dasd/devices: range parse error in '%s'",
+		buffer);
+	kfree(buffer);
+	return -EINVAL;
+}
+
+static inline int
+dasd_devices_print(dasd_devmap_t *devmap, char *str)
+{
+	dasd_device_t *device;
+	struct gendisk *gdp;
+	char buffer[7];
+	char *substr;
+	int minor;
+	int len;
+
+	device = dasd_get_device(devmap);
+	if (IS_ERR(device))
+		return 0;
+	/* Print device number. */
+	len = sprintf(str, "%04x", devmap->devno);
+	/* Print discipline string. */
+	if (device != NULL && device->discipline != NULL)
+		len += sprintf(str + len, "(%s)", device->discipline->name);
+	else
+		len += sprintf(str + len, "(none)");
+	/* Print kdev. */
+	gdp = dasd_gendisk_from_devindex(devmap->devindex);
+	minor = devmap->devindex % DASD_PER_MAJOR;
+	len += sprintf(str + len, " at (%3d:%3d)", gdp->major, minor);
+	/* Print device name. */
+	if (device == NULL) {
+		dasd_device_name(buffer, minor, 0, gdp);
+		substr = buffer;
+	} else
+		substr = device->name;
+	len += sprintf(str + len, " is %-7s", substr);
+	/* Print devices features. */
+	substr = (devmap->features & DASD_FEATURE_READONLY) ? "(ro)" : " ";
+	len += sprintf(str + len, "%4s: ", substr);
+	/* Print device status information. */
+	if (device == NULL) {
+		len += sprintf(str + len, "unknown");
+		dasd_put_device(devmap);
+		return len;
+	}
+	switch (device->state) {
+	case DASD_STATE_NEW:
+		len += sprintf(str + len, "new");
+		break;
+	case DASD_STATE_KNOWN:
+		len += sprintf(str + len, "detected");
+		break;
+	case DASD_STATE_BASIC:
+		len += sprintf(str + len, "basic");
+		break;
+	case DASD_STATE_ACCEPT:
+		len += sprintf(str + len, "accepted");
+		break;
+	case DASD_STATE_READY:
+	case DASD_STATE_ONLINE:
+		if (device->state < DASD_STATE_ONLINE)
+			len += sprintf(str + len, "fenced ");
+		else
+			len += sprintf(str + len, "active ");
+		if (dasd_check_blocksize(device->bp_block))
+			len += sprintf(str + len, "n/f	 ");
+		else
+			len += sprintf(str + len,
+				       "at blocksize: %d, %ld blocks, %ld MB",
+				       device->bp_block, device->blocks,
+				       ((device->bp_block >> 9) *
+					device->blocks) >> 11);
+		break;
+	default:
+		len += sprintf(str + len, "no stat");
+		break;
+	}
+	dasd_put_device(devmap);
+	return len;
+}
+
+static int
+dasd_devices_open(struct inode *inode, struct file *file)
+{
+	tempinfo_t *info;
+	int size, len;
+	int devindex;
+
+	MOD_INC_USE_COUNT;
+	info = (tempinfo_t *) kmalloc(sizeof (tempinfo_t), GFP_KERNEL);
+	if (info == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory available for data (tempinfo)");
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+
+	}
+
+	size = dasd_max_devindex * 128;
+	info->data = (char *) vmalloc (size);
+	if (size && info->data == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory available for data (info->data)");
+		kfree(info);
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+	file->private_data = (void *) info;
+
+	DBF_EVENT(DBF_NOTICE,
+		  "procfs-area: %p, size 0x%x allocated", info->data, size);
+
+	len = 0;
+	for (devindex = 0; devindex < dasd_max_devindex; devindex++) {
+		dasd_devmap_t *devmap;
+
+		devmap = dasd_devmap_from_devindex(devindex);
+		len += dasd_devices_print(devmap, info->data + len);
+		if (dasd_probeonly)
+			len += sprintf(info->data + len, "(probeonly)");
+		len += sprintf(info->data + len, "\n");
+	}
+	info->len = len;
+	if (len > size) {
+		printk("len = %i, size = %i\n", len, size);
+		BUG();
+	}
+	return 0;
+}
+
+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_generic_close,	/* close */
+};
+
+static struct inode_operations dasd_devices_inode_ops = {
+};
+
+static inline char *
+dasd_statistics_array(char *str, int *array, int shift)
+{
+	int i;
+
+	for (i = 0; i < 32; i++) {
+		str += sprintf(str, "%7d ", array[i] >> shift);
+		if (i == 15)
+			str += sprintf(str, "\n");
+	}
+	str += sprintf(str,"\n");
+	return str;
+}
+
+static int
+dasd_statistics_open(struct inode *inode, struct file *file)
+{
+	tempinfo_t *info;
+#ifdef CONFIG_DASD_PROFILE
+	dasd_profile_info_t *prof;
+	char *str;
+	int shift;
+#endif
+
+	MOD_INC_USE_COUNT;
+	info = (tempinfo_t *) kmalloc(sizeof (tempinfo_t), GFP_KERNEL);
+	if (info == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory available for data (tempinfo)");
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+
+	file->private_data = (void *) info;
+	/* FIXME! determine space needed in a better way */
+	info->data = (char *) vmalloc (PAGE_SIZE);
+
+	if (info->data == NULL) {
+		MESSAGE(KERN_WARNING, "%s",
+			"No memory available for data (info->data)");
+		kfree(info);
+		file->private_data = NULL;
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+#ifdef CONFIG_DASD_PROFILE
+	/* check for active profiling */
+	if (dasd_profile_level == DASD_PROFILE_OFF) {
+		info->len = sprintf(info->data,
+				    "Statistics are off - they might be "
+				    "switched on using 'echo set on > "
+				    "/proc/dasd/statistics'\n");
+		return 0;
+	}
+
+	prof = &dasd_global_profile;
+	/* prevent couter 'overflow' on output */
+	for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++);
+
+	str = info->data;
+	str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs);
+	str += sprintf(str, "with %d sectors(512B each)\n",
+		       prof->dasd_io_sects);
+	str += sprintf(str,
+		       "   __<4	   ___8	   __16	   __32	   __64	   _128	"
+		       "   _256	   _512	   __1k	   __2k	   __4k	   __8k	"
+		       "   _16k	   _32k	   _64k	   128k\n");
+	str += sprintf(str,
+		       "   _256	   _512	   __1M	   __2M	   __4M	   __8M	"
+		       "   _16M	   _32M	   _64M	   128M	   256M	   512M	"
+		       "   __1G	   __2G	   __4G " "   _>4G\n");
+
+	str += sprintf(str, "Histogram of sizes (512B secs)\n");
+	str = dasd_statistics_array(str, prof->dasd_io_secs, shift);
+	str += sprintf(str, "Histogram of I/O times (microseconds)\n");
+	str = dasd_statistics_array(str, prof->dasd_io_times, shift);
+	str += sprintf(str, "Histogram of I/O times per sector\n");
+	str = dasd_statistics_array(str, prof->dasd_io_timps, shift);
+	str += sprintf(str, "Histogram of I/O time till ssch\n");
+	str = dasd_statistics_array(str, prof->dasd_io_time1, shift);
+	str += sprintf(str, "Histogram of I/O time between ssch and irq\n");
+	str = dasd_statistics_array(str, prof->dasd_io_time2, shift);
+	str += sprintf(str, "Histogram of I/O time between ssch "
+			    "and irq per sector\n");
+	str = dasd_statistics_array(str, prof->dasd_io_time2ps, shift);
+	str += sprintf(str, "Histogram of I/O time between irq and end\n");
+	str = dasd_statistics_array(str, prof->dasd_io_time3, shift);
+	str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n");
+	str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift);
+
+	info->len = str - info->data;
+#else
+	info->len = sprintf(info->data,
+			    "Statistics are not activated in this kernel\n");
+#endif
+	return 0;
+}
+
+static ssize_t
+dasd_statistics_write(struct file *file, const char *user_buf,
+		      size_t user_len, loff_t * offset)
+{
+#ifdef CONFIG_DASD_PROFILE
+	char *buffer, *str;
+
+	buffer = dasd_get_user_string(user_buf, user_len);
+	MESSAGE(KERN_INFO, "/proc/dasd/statictics: '%s'", buffer);
+
+	/* check for valid verbs */
+	for (str = buffer; isspace(*str); str++);
+	if (strncmp(str, "set", 3) == 0 && isspace(str[3])) {
+		/* 'set xxx' was given */
+		for (str = str + 4; isspace(*str); str++);
+		if (strcmp(str, "on") == 0) {
+			/* switch on statistics profiling */
+			dasd_profile_level = DASD_PROFILE_ON;
+			MESSAGE(KERN_INFO, "%s", "Statictics switched on");
+		} else if (strcmp(str, "off") == 0) {
+			/* switch off and reset statistics profiling */
+			memset(&dasd_global_profile,
+			       0, sizeof (dasd_profile_info_t));
+			dasd_profile_level = DASD_PROFILE_OFF;
+			MESSAGE(KERN_INFO, "%s", "Statictics switched off");
+		} else
+			goto out_error;
+	} else if (strncmp(str, "reset", 5) == 0) {
+		/* reset the statistics */
+		memset(&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
+		MESSAGE(KERN_INFO, "%s", "Statictics reset");
+	} else
+		goto out_error;
+	kfree(buffer);
+	return user_len;
+out_error:
+	MESSAGE(KERN_WARNING, "%s",
+		"/proc/dasd/statistics: only 'set on', 'set off' "
+		"and 'reset' are supported verbs");
+	kfree(buffer);
+	return -EINVAL;
+#else
+	MESSAGE(KERN_WARNING, "%s",
+		"/proc/dasd/statistics: is not activated in this kernel");
+	return user_len;
+#endif				/* CONFIG_DASD_PROFILE */
+}
+
+static struct file_operations dasd_statistics_file_ops = {
+	read:	dasd_generic_read,	/* read */
+	write:	dasd_statistics_write,	/* write */
+	open:	dasd_statistics_open,	/* open */
+	release:dasd_generic_close,	/* close */
+};
+
+static struct inode_operations dasd_statistics_inode_ops = {
+};
+
+int
+dasd_proc_init(void)
+{
+	dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
+	dasd_devices_entry = create_proc_entry("devices",
+					       S_IFREG | S_IRUGO | S_IWUSR,
+					       dasd_proc_root_entry);
+	dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
+	dasd_devices_entry->proc_iops = &dasd_devices_inode_ops;
+	dasd_statistics_entry = create_proc_entry("statistics",
+						  S_IFREG | S_IRUGO | S_IWUSR,
+						  dasd_proc_root_entry);
+	dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
+	dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
+	return 0;
+}
+
+void
+dasd_proc_exit(void)
+{
+	remove_proc_entry("devices", dasd_proc_root_entry);
+	remove_proc_entry("statistics", dasd_proc_root_entry);
+	remove_proc_entry("dasd", &proc_root);
+}
diff -Nru a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
--- a/drivers/s390/block/xpram.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/block/xpram.c	Sat Jun  8 22:31:51 2002
@@ -158,6 +158,7 @@
 /* The following items are obtained through kmalloc() in init_module() */
 
 Xpram_Dev *xpram_devices = NULL;
+int *xpram_hardsects = NULL;
 int *xpram_offsets = NULL;   /* partition offsets */
 
 #define MIN(x,y) ((x) < (y) ? (x) : (y))
@@ -938,7 +939,6 @@
 
 	q = BLK_DEFAULT_QUEUE(major);
 	blk_init_queue (q, xpram_request);
-	blk_queue_hardsect_size(q, xpram_hardsect);
 
 	/* we want to have XPRAM_UNUSED blocks security buffer between devices */
 	mem_usable=xpram_mem_avail-(XPRAM_UNUSED*(xpram_devs-1));
@@ -978,6 +978,16 @@
 		PRINT_DEBUG(" device(%d) offset = %d kB, size = %d kB\n",i, xpram_offsets[i], xpram_sizes[i]);
 #endif
 
+	xpram_hardsects = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
+	if (!xpram_hardsects) {
+		PRINT_ERR("Not enough memory for xpram_hardsects\n");
+                PRINT_ERR("Giving up xpram\n");
+		goto fail_malloc_hardsects;
+	}
+	for (i=0; i < xpram_devs; i++) /* all the same hardsect */
+		xpram_hardsects[i] = xpram_hardsect;
+	hardsect_size[major]=xpram_hardsects;
+   
 	/* 
 	 * allocate the devices -- we can't have them static, as the number
 	 * can be specified at load time
@@ -1030,6 +1040,7 @@
 		  goto fail_devfs_register;
 		}
 #endif  /* WHY? */
+				 
 	}
 
 	return 0; /* succeed */
@@ -1042,7 +1053,10 @@
 	}
 	kfree(xpram_devices);
 	kfree (xpram_offsets);
+ fail_malloc_hardsects:
  fail_malloc_devices:
+	kfree(xpram_hardsects);
+	hardsect_size[major] = NULL;
  fail_malloc:
 	/* ???	unregister_chrdev(major, "xpram"); */
 	unregister_blkdev(major, "xpram");
@@ -1072,6 +1086,7 @@
 	int i;
 
 	/* first of all, reset all the data structures */
+	kfree(hardsect_size[major]);
 	kfree(xpram_offsets);
 	blk_clear(major);
 
diff -Nru a/drivers/s390/ccwcache.c b/drivers/s390/ccwcache.c
--- a/drivers/s390/ccwcache.c	Sat Jun  8 22:31:35 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,305 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/ccwcache.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Martin Schiwdefsky <schwidefsky@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
- 
- * History of changes
- * 11/14/00 redesign by Martin Schwidefsky
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#include <linux/spinlock.h>
-#else
-#include <asm/spinlock.h>
-#endif
-
-#include <asm/debug.h>
-#include <asm/ccwcache.h>
-#include <asm/ebcdic.h>
-
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA)
-#define CCW_CACHE_TYPE (GFP_ATOMIC | GFP_DMA)
-#else
-#define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN)
-#define CCW_CACHE_TYPE (GFP_ATOMIC)
-#define kmem_cache_destroy(x) do {} while(0)
-#endif
-
-#undef PRINTK_HEADER
-#define PRINTK_HEADER "ccwcache"
-
-/* pointer to list of allocated requests */
-static ccw_req_t *ccwreq_actual = NULL;
-static spinlock_t ccwchain_lock;
-
-/* pointer to debug area */
-static debug_info_t *debug_area = NULL;
-
-/* SECTION: Handling of the dynamically allocated kmem slabs */
-
-/* a name template for the cache-names */
-static char ccw_name_template[] = "ccwcache-\0\0\0\0"; /* fill name with zeroes! */
-/* the cache's names */
-static char ccw_cache_name[CCW_NUMBER_CACHES][sizeof(ccw_name_template)+1]; 
-/* the caches itself*/
-static kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES]; 
-
-/* SECTION: (de)allocation of ccw_req_t */
-
-/* 
- * void enchain ( ccw_req_t *request )
- * enchains the request to the ringbuffer
- */
-static inline void 
-enchain ( ccw_req_t *request )
-{
-	unsigned long flags;
-
-	/* Sanity checks */
-	if ( request == NULL )
-		BUG();
-	spin_lock_irqsave(&ccwchain_lock,flags);
-	if ( ccwreq_actual == NULL ) { /* queue empty */
-		ccwreq_actual = request;
-		request->int_prev = ccwreq_actual;
-		request->int_next = ccwreq_actual;
-	} else {
-		request->int_next = ccwreq_actual;
-		request->int_prev = ccwreq_actual->int_prev;
-		request->int_prev->int_next = request;
-		request->int_next->int_prev = request;
-	}
-	spin_unlock_irqrestore(&ccwchain_lock,flags);
-}
-
-/* 
- * void dechain ( ccw_req_t *request )
- * dechains the request from the ringbuffer
- */
-static inline void 
-dechain ( ccw_req_t *request )
-{
-	unsigned long flags;
-
-	/* Sanity checks */
-	if ( request == NULL || 
-	     request->int_next == NULL ||
-	     request->int_prev == NULL)
-		BUG();
-	/* first deallocate request from list of allocates requests */
-	spin_lock_irqsave(&ccwchain_lock,flags);
-	if ( request -> int_next == request -> int_prev ) {
-		ccwreq_actual = NULL;
-	} else {
-		if ( ccwreq_actual == request ) {
-			ccwreq_actual = request->int_next;
-		}
-		request->int_prev->int_next = request->int_next;
-		request->int_next->int_prev = request->int_prev;
-	}
-	spin_unlock_irqrestore(&ccwchain_lock,flags);
-}
-
-/* 
- * ccw_req_t *ccw_alloc_request ( int cplength, int datasize )
- * allocates a ccw_req_t, that 
- * - can hold a CP of cplength CCWS
- * - can hold additional data up to datasize 
- */
-ccw_req_t *
-ccw_alloc_request ( char *magic, int cplength, int datasize )
-{
-	ccw_req_t * request = NULL;
-        int size_needed;
-	int data_offset, ccw_offset;
-	int cachind;
-
-	/* Sanity checks */
-	if ( magic == NULL || datasize > PAGE_SIZE ||
-	     cplength == 0 || (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
-		BUG();
-	debug_text_event ( debug_area, 1, "ALLC");
-	debug_text_event ( debug_area, 1, magic);
-	debug_int_event ( debug_area, 1, cplength);
-	debug_int_event ( debug_area, 1, datasize);
-
-	/* We try to keep things together in memory */
-	size_needed = (sizeof (ccw_req_t) + 7) & -8;
-	data_offset = ccw_offset = 0;
-	if (size_needed + datasize <= PAGE_SIZE) {
-		/* Keep data with the request */
-		data_offset = size_needed;
-		size_needed += (datasize + 7) & -8;
-	}
-	if (size_needed + cplength*sizeof(ccw1_t) <= PAGE_SIZE) {
-		/* Keep CCWs with request */
-		ccw_offset = size_needed;
-		size_needed += cplength*sizeof(ccw1_t);
-	}
-
-	/* determine cache index for the requested size */
-	for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ )
-	   if ( size_needed < (SMALLEST_SLAB << cachind) ) 
-			break;
-
-	/* Try to fulfill the request from a cache */
-	if ( ccw_cache[cachind] == NULL )
-		BUG();
-	request = kmem_cache_alloc ( ccw_cache[cachind], CCW_CACHE_TYPE );
-	if (request == NULL)
-		return NULL;
-	memset ( request, 0, (SMALLEST_SLAB << cachind));
-	request->cache = ccw_cache[cachind];
-
-	/* Allocate memory for the extra data */
-	if (data_offset == 0) {
-		/* Allocated memory for extra data with kmalloc */
-	    request->data = (void *) kmalloc(datasize, CCW_CACHE_TYPE );
-		if (request->data == NULL) {
-			printk(KERN_WARNING PRINTK_HEADER 
-			       "Couldn't allocate data area\n");
-			kmem_cache_free(request->cache, request);
-			return NULL;
-		}
-	} else
-		/* Extra data already allocated with the request */
-		request->data = (void *) ((addr_t) request + data_offset);
-
-	/* Allocate memory for the channel program */
-	if (ccw_offset == 0) {
-		/* Allocated memory for the channel program with kmalloc */
-		request->cpaddr = (ccw1_t *) kmalloc(cplength*sizeof(ccw1_t),
-						     CCW_CACHE_TYPE);
-		if (request->cpaddr == NULL) {
-			printk (KERN_DEBUG PRINTK_HEADER
-				"Couldn't allocate ccw area\n");
-			if (data_offset == 0)
-				kfree(request->data);
-			kmem_cache_free(request->cache, request);
-			return NULL;
-		}
-	} else
-		/* Channel program already allocated with the request */
-		request->cpaddr = (ccw1_t *) ((addr_t) request + ccw_offset);
-
-	memset ( request->data, 0, datasize );
-	memset ( request->cpaddr, 0, cplength*sizeof(ccw1_t) );
-	strncpy ( (char *)(&request->magic), magic, 4);
-
-	ASCEBC((char *)(&request->magic),4);
-	request -> cplength = cplength;
-	request -> datasize = datasize;
-	/* enqueue request to list of allocated requests */
-	enchain(request);
-	debug_int_event ( debug_area, 1, (long)request);
-	return request;
-}
-
-/* 
- * void ccw_free_request ( ccw_req_t * )
- * deallocates the ccw_req_t, given as argument
- */
-
-void
-ccw_free_request ( ccw_req_t * request )
-{
-        int size_needed;
-
-	debug_text_event ( debug_area, 1, "FREE");
-	debug_int_event ( debug_area, 1, (long)request);
-
-	/* Sanity checks */
-	if ( request == NULL || request->cache == NULL)
-                BUG();
-
-        dechain ( request);
-	/* Free memory allocated with kmalloc
-         * make the same decisions as in ccw_alloc_requets */
-	size_needed = (sizeof (ccw_req_t) + 7) & -8;
-	if (size_needed + request->datasize <= PAGE_SIZE)
-		/* We kept the data with the request */
-		size_needed += (request->datasize + 7) & -8;
-	else
-		kfree(request->data);
-	if (size_needed + request->cplength*sizeof(ccw1_t) > PAGE_SIZE)
-		/* We kept the CCWs with request */
-                kfree(request->cpaddr);
-        kmem_cache_free(request -> cache, request);
-}
-
-/* SECTION: initialization and cleanup functions */
-
-/* 
- * ccwcache_init
- * called as an initializer function for the ccw memory management
- */
-
-int
-ccwcache_init (void)
-{
-	int rc = 0;
-	int cachind;
-
-        /* initialize variables */
-	spin_lock_init(&ccwchain_lock);
-
-	/* allocate a debug area */
-	debug_area = debug_register( "ccwcache", 2, 4,sizeof(void*));
-	if ( debug_area == NULL )
-                BUG();
-
-        debug_register_view(debug_area,&debug_hex_ascii_view);
-        debug_register_view(debug_area,&debug_raw_view);
-	debug_text_event ( debug_area, 0, "INIT");
-
-	/* First allocate the kmem caches */
-	for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
-		int slabsize = SMALLEST_SLAB << cachind;
-		debug_text_event ( debug_area, 1, "allc");
-		debug_int_event ( debug_area, 1, slabsize);
-		sprintf ( ccw_cache_name[cachind], 
-			  "%s%d%c", ccw_name_template, slabsize, 0);
-		ccw_cache[cachind] = 
-			kmem_cache_create( ccw_cache_name[cachind], 
-					   slabsize, 0,
-					   CCW_CACHE_SLAB_TYPE,
-					   NULL, NULL );
-		debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]);
-		if (ccw_cache[cachind] == NULL)
-			panic ("Allocation of CCW cache failed\n");
-	}
-	return rc;
-}
-
-/* 
- * ccwcache_cleanup
- * called as a cleanup function for the ccw memory management
- */
-
-void
-ccwcache_cleanup (void)
-{
-	int cachind;
-
-	/* Shrink the caches, if available */
-	for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
-		if ( ccw_cache[cachind] ) {
-			if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
-				ccw_cache[cachind] = NULL;
-			}
-			kmem_cache_destroy(ccw_cache[cachind]);
-		}
-	}
-	debug_unregister( debug_area );
-}
-
-EXPORT_SYMBOL(ccw_alloc_request);
-EXPORT_SYMBOL(ccw_free_request);
-
diff -Nru a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
--- a/drivers/s390/char/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/Makefile	Sat Jun  8 22:31:37 2002
@@ -2,23 +2,28 @@
 # S/390 character devices
 #
 
-export-objs	:= hwc_rw.o
+export-objs := hwc_rw.o tape.o tape34xx.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_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))
+
+tape390-objs   := tape.o tape34xx.o $(sort $(tape390-y))
+tape_3480_mod-objs := tape3480.o
+tape_3490_mod-objs := tape3490.o 
+
 
 obj-y += ctrlchar.o
 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
+obj-$(CONFIG_S390_TAPE)       += tape390.o
+obj-$(CONFIG_S390_TAPE_3480)  += tape_3480_mod.o
+obj-$(CONFIG_S390_TAPE_3490)  += tape_3490_mod.o
 
 include $(TOPDIR)/Rules.make
+
diff -Nru a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
--- a/drivers/s390/char/con3215.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/con3215.c	Sat Jun  8 22:31:36 2002
@@ -59,8 +59,6 @@
 
 struct _raw3215_info;		      /* forward declaration ... */
 
-int raw3215_condevice = -1;           /* preset console device */
-
 /*
  * Request types for a 3215 device
  */
@@ -542,7 +540,7 @@
  * Has to be called with the s390irq lock held. Can be called
  * disabled.
  */
-void raw3215_make_room(raw3215_info *raw, unsigned int length)
+static void raw3215_make_room(raw3215_info *raw, unsigned int length)
 {
 	while (RAW3215_BUFFER_SIZE - raw->count < length) {
 		/* there might be a request pending */
@@ -730,8 +728,11 @@
 	    raw->queued_read != NULL) {
 		raw->flags |= RAW3215_CLOSING;
 		add_wait_queue(&raw->empty_wait, &wait);
+#warning FIXME: use set_current_state instead of current->state=
 		current->state = TASK_INTERRUPTIBLE;
                 s390irq_spin_unlock_irqrestore(raw->irq, flags);
+		/* FIXME: what if schedule is interrupted by a signal,
+		 * shouldn't we loop here? */
 		schedule();
 		s390irq_spin_lock_irqsave(raw->irq, flags);
 		remove_wait_queue(&raw->empty_wait, &wait);
@@ -752,7 +753,7 @@
 	irq = get_irq_first();
 	count = 0;
         while (count <= number && irq != -ENODEV) {
-                if (get_dev_info(irq, &dinfo) == -ENODEV)
+                if (get_dev_info_by_irq(irq, &dinfo) == -ENODEV)
                         break;
                 if (dinfo.devno == console_device ||
                     dinfo.sid_data.cu_type == 0x3215) {
@@ -794,16 +795,16 @@
         }
 }
 
-kdev_t con3215_device(struct console *c)
+static kdev_t con3215_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, c->index + 64 );
+	return mk_kdev(TTY_MAJOR, c->index + 64 );
 }
 
 /*
  * panic() calls console_unblank before the system enters a
  * disabled, endless loop.
  */
-void con3215_unblank(void)
+static void con3215_unblank(void)
 {
 	raw3215_info *raw;
 	unsigned long flags;
@@ -843,7 +844,7 @@
 	raw3215_info *raw;
 	int retval, line;
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if ((line < 0) || (line >= NR_3215))
 		return -ENODEV;
 
@@ -1057,7 +1058,9 @@
  */
 void __init con3215_init(void)
 {
+#ifdef CONFIG_TN3215_CONSOLE
 	raw3215_info *raw;
+#endif
 	raw3215_req *req;
 	int irq;
 	int i;
diff -Nru a/drivers/s390/char/hwc.h b/drivers/s390/char/hwc.h
--- a/drivers/s390/char/hwc.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/hwc.h	Sat Jun  8 22:31:51 2002
@@ -149,6 +149,8 @@
 
 mto_t;
 
+/* FIXME: don't define static variables in a header!!! */
+#warning
 static write_hwcb_t write_hwcb_template =
 {
 	sizeof (write_hwcb_t),
@@ -180,6 +182,7 @@
 	}
 };
 
+#warning
 static mto_t mto_template =
 {
 	sizeof (mto_t),
@@ -202,6 +205,7 @@
 
 init_hwcb_t;
 
+#warning
 static init_hwcb_t init_hwcb_template =
 {
 	sizeof (init_hwcb_t),
@@ -258,6 +262,7 @@
 
 read_hwcb_t;
 
+#warning
 static read_hwcb_t read_hwcb_template =
 {
 	PAGE_SIZE,
diff -Nru a/drivers/s390/char/hwc_con.c b/drivers/s390/char/hwc_con.c
--- a/drivers/s390/char/hwc_con.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/s390/char/hwc_con.c	Sat Jun  8 22:31:35 2002
@@ -34,17 +34,11 @@
 struct console hwc_console =
 {
 
-	hwc_console_name,
-	hwc_console_write,
-	NULL,
-	hwc_console_device,
-	NULL,
-	hwc_console_unblank,
-	NULL,
-	CON_PRINTBUFFER,
-	0,
-	0,
-	NULL
+	name:hwc_console_name,
+	write:hwc_console_write,
+	device:hwc_console_device,
+	unblank:hwc_console_unblank,
+	flags:CON_PRINTBUFFER,
 };
 
 void 
@@ -54,7 +48,8 @@
 			  unsigned int count)
 {
 
-	if (console->device (console) != hwc_console.device (&hwc_console)) {
+	if (kdev_val (console->device (console)) !=
+	    kdev_val (hwc_console.device (&hwc_console))) {
 
 		hwc_printk (KERN_WARNING HWC_CON_PRINT_HEADER
 			    "hwc_console_write() called with wrong "
@@ -67,7 +62,7 @@
 kdev_t 
 hwc_console_device (struct console * c)
 {
-	return MKDEV (hwc_console_major, hwc_console_minor);
+	return mk_kdev (hwc_console_major, hwc_console_minor);
 }
 
 void 
diff -Nru a/drivers/s390/char/hwc_cpi.c b/drivers/s390/char/hwc_cpi.c
--- a/drivers/s390/char/hwc_cpi.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/hwc_cpi.c	Sat Jun  8 22:31:36 2002
@@ -11,6 +11,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/version.h>
+#include <linux/sched.h>
 #include <asm/semaphore.h>
 #include <asm/ebcdic.h>
 #include "hwc_rw.h"
diff -Nru a/drivers/s390/char/hwc_rw.c b/drivers/s390/char/hwc_rw.c
--- a/drivers/s390/char/hwc_rw.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/hwc_rw.c	Sat Jun  8 22:31:36 2002
@@ -231,6 +231,8 @@
 static unsigned long cr0_save __attribute__ ((aligned (8)));
 static unsigned char psw_mask __attribute__ ((aligned (8)));
 
+static ext_int_info_t ext_int_info_hwc;
+
 #define DELAYED_WRITE 0
 #define IMMEDIATE_WRITE 1
 
@@ -2004,7 +2006,8 @@
 
 #endif
 
-	if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
+	if (register_early_external_interrupt (0x2401, hwc_interrupt_handler,
+					       &ext_int_info_hwc) != 0)
 		panic ("Couldn't request external interrupts 0x2401");
 
 	spin_lock_init (&hwc_data.lock);
@@ -2178,6 +2181,7 @@
 					unconditional_read_2 (ext_int_param);
 					break;
 				default:
+					break;
 				}
 			}
 		}
diff -Nru a/drivers/s390/char/hwc_rw.h b/drivers/s390/char/hwc_rw.h
--- a/drivers/s390/char/hwc_rw.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/hwc_rw.h	Sat Jun  8 22:31:36 2002
@@ -61,7 +61,7 @@
 	ioctl_delim_t delim;
 } hwc_ioctls_t;
 
-static hwc_ioctls_t _hwc_ioctls;
+extern hwc_ioctls_t _hwc_ioctls;
 
 #define HWC_IOCTL_LETTER 'B'
 
diff -Nru a/drivers/s390/char/hwc_tty.c b/drivers/s390/char/hwc_tty.c
--- a/drivers/s390/char/hwc_tty.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/hwc_tty.c	Sat Jun  8 22:31:37 2002
@@ -59,7 +59,7 @@
 	      struct file *filp)
 {
 
-	if (MINOR (tty->device) - tty->driver.minor_start)
+	if (minor (tty->device) - tty->driver.minor_start)
 		return -ENODEV;
 
 	tty->driver_data = &hwc_tty_data;
@@ -78,7 +78,7 @@
 hwc_tty_close (struct tty_struct *tty,
 	       struct file *filp)
 {
-	if (MINOR (tty->device) != tty->driver.minor_start) {
+	if (minor (tty->device) != tty->driver.minor_start) {
 		printk (KERN_WARNING HWC_TTY_PRINT_HEADER
 			"do not close hwc tty because of wrong device number");
 		return;
diff -Nru a/drivers/s390/char/tape.c b/drivers/s390/char/tape.c
--- a/drivers/s390/char/tape.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/tape.c	Sat Jun  8 22:31:51 2002
@@ -1,4 +1,3 @@
-
 /***********************************************************************
  *  drivers/s390/char/tape.c
  *    tape device driver for S/390 and zSeries tapes.
@@ -6,32 +5,27 @@
  *  S390 and zSeries version
  *    Copyright (C) 2001 IBM Corporation
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Michael Holzheu <holzheu@de.ibm.com>
  *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
  ***********************************************************************
  */
 
-#include "tapedefs.h"
+#include "tapedefs.h" // kernel 2.2 compatibility defines
 
-#include <linux/config.h>
-#include <linux/stddef.h>
-#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>
-#include <asm/ebcdic.h>
-#include <linux/compatmac.h>
-#ifdef MODULE
-#include <linux/module.h>
-#endif   
-#include <asm/debug.h>
+#include <linux/stddef.h>    // defines NULL
+#include <linux/proc_fs.h>   // for /proc/tapedevices
+#include <linux/init.h>      // for kernel parameters
+#include <linux/kmod.h>      // for requesting modules
+#include <linux/spinlock.h>  // for locks
+#include <asm/types.h>       // for variable types
 #ifdef CONFIG_S390_TAPE_DYNAMIC
 #include <asm/s390dyn.h>
 #endif
 #include "tape.h"
+#ifdef CONFIG_S390_TAPE_3590
+#include "tape3590.h"
+#endif
 #ifdef CONFIG_S390_TAPE_3490
 #include "tape3490.h"
 #endif
@@ -48,175 +42,543 @@
 #include <linux/vmalloc.h>
 #endif
 #define PRINTK_HEADER "T390:"
+#define TAPE_MAX_DEVREGS        (256 / TAPE_MINORS_PER_DEV)
+
+#define TAPE_NO_IO          0
+#define TAPE_DO_IO          1
+
+#define TAPE_CIO_PRIVATE_DATA
+
+#ifdef CONFIG_KMOD
+#define tape_request_module(a) request_module(a)
+#else
+#define tape_request_module(a)
+#endif
+
+/*******************************************************************
+ * Internal Prototypes
+ *******************************************************************/
+
+static void tape_do_irq (int irq, void *int_parm, struct pt_regs *regs);
+static inline int tape_halt_io(tape_dev_t* td);
+static void tape_wait(tape_ccw_req_t* treq);
+#ifdef CONFIG_S390_TAPE_DYNAMIC
+/* functions for dyn. dev. attach/detach */
+static int tape_oper_handler ( int irq, struct _devreg *dreg);
+static void tape_noper_handler ( int irq, int status );
+#endif
+static inline void tape_disable_device(tape_dev_t* td);
+static inline int tape_enable_device(tape_dev_t* td);
+
+
+/*******************************************************************
+ * GLOBALS
+ *******************************************************************/
+
+static devreg_t          *tape_devreg[TAPE_MAX_DEVREGS];
+static int               tape_devregct=0;
+static int               tape_autoprobe = 1;
+static tape_discipline_t *tape_first_disc = NULL;
+tape_dev_t               *tape_first_dev = NULL;
+tape_frontend_t          *tape_first_front = NULL;
+char                     *tape[256] = { NULL, }; 
 
+/*
+ * Lock hirarchy:
+ * tape_discipline_lock > tape_dev_lock > td->lock
+ */
 
-/* state handling routines */
-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;
+rwlock_t   tape_dev_lock=RW_LOCK_UNLOCKED;
+static rwlock_t   tape_discipline_lock=RW_LOCK_UNLOCKED;
 
 #ifdef TAPE_DEBUG
-debug_info_t *tape_debug_area = NULL;
+debug_info_t *tape_dbf_area = NULL;
 #endif
 
-char* state_verbose[TS_SIZE]={
-    "TS_UNUSED",  "TS_IDLE", "TS_DONE", "TS_FAILED",
-    "TS_BLOCK_INIT",
-    "TS_BSB_INIT",
-    "TS_BSF_INIT",
-    "TS_DSE_INIT",
-    "TS_EGA_INIT",
-    "TS_FSB_INIT",
-    "TS_FSF_INIT",
-    "TS_LDI_INIT",
-    "TS_LBL_INIT",
-    "TS_MSE_INIT",
-    "TS_NOP_INIT",
-    "TS_RBA_INIT",
-    "TS_RBI_INIT",
-    "TS_RBU_INIT",
-    "TS_RBL_INIT",
-    "TS_RDC_INIT",
-    "TS_RFO_INIT",
-    "TS_RSD_INIT",
-    "TS_REW_INIT",
-    "TS_REW_RELEASE_INIT",
-    "TS_RUN_INIT",
-    "TS_SEN_INIT",
-    "TS_SID_INIT",
-    "TS_SNP_INIT",
-    "TS_SPG_INIT",
-    "TS_SWI_INIT",
-    "TS_SMR_INIT",
-    "TS_SYN_INIT",
-    "TS_TIO_INIT",
-    "TS_UNA_INIT",
-    "TS_WRI_INIT",
-    "TS_WTM_INIT",
-    "TS_NOT_OPER"};
+const char* tape_med_st_verbose[MS_SIZE]={
+	"UNKNOWN ",
+	"LOADED  ",
+	"UNLOADED"
+};
+
+const char* tape_state_verbose[TS_SIZE]={
+	"UNUSED",
+	"IN_USE", 
+	"INIT  ",
+	"NOT_OP"
+};
+
+const char* tape_op_verbose[TO_SIZE] = {
+	"BLK",
+	"BSB",
+	"BSF",
+	"DSE",
+	"EGA",
+	"FSB",
+	"FSF",
+	"LDI",
+	"LBL",
+	"MSE",
+	"NOP",
+	"RBA",
+	"RBI",
+	"RBU",
+	"RBL",
+	"RDC",
+	"RFO",
+	"RSD",
+	"REW",
+	"RUN",
+	"SEN",
+	"SID",
+	"SNP",
+	"SPG",
+	"SWI",
+	"SMR",
+	"SYN",
+	"TIO",
+	"UNA",
+	"WRI",
+	"WTM",
+	"MSN",
+	"LOA",
+	"RCF", /* 3590 */
+	"RAT", /* 3590 */
+	"NOT"
+};
 
-char* event_verbose[TE_SIZE]= {
-    "TE_START", "TE_DONE", "TE_FAILED", "TE_ERROR", "TE_OTHER"};
+/*******************************************************************
+ * DEVFS Functions
+ *******************************************************************/
 
-/* our root devfs handle */
 #ifdef CONFIG_DEVFS_FS
 devfs_handle_t tape_devfs_root_entry;
 
-inline void
-tape_mkdevfsroots (tape_info_t* ti) 
+/*
+ * Create devfs root entry (devno in hex) for device td
+ */
+
+static inline devfs_handle_t
+tape_mkdevfsroot (tape_dev_t* td) 
 {
     char devno [5];
-    sprintf (devno,"%04x",ti->devinfo.devno);
-    ti->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, ti);
+    sprintf (devno,"%04x",td->devinfo.devno);
+    return (td->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, td));
 }
 
-inline void
-tape_rmdevfsroots (tape_info_t* ti)
+/*
+ * Remove devfs root entry for device td
+ */
+
+static inline void
+tape_rmdevfsroot (tape_dev_t* td)
 {
-    devfs_unregister (ti->devfs_dir);
+    if (td->devfs_dir)
+            devfs_unregister (td->devfs_dir);
 }
+
 #endif
 
+/*******************************************************************
+ * PROCFS Functions
+ *******************************************************************/
+
 #ifdef CONFIG_PROC_FS
+/* functions used in tape_proc_file_ops */
+static ssize_t tape_proc_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset);
+static int tape_proc_devices_open (struct inode *inode, struct file *file);
+static int tape_proc_devices_release (struct inode *inode, struct file *file);
+
 /* our proc tapedevices entry */
-static struct proc_dir_entry *tape_devices_entry;
+static struct proc_dir_entry *tape_proc_devices;
 
 typedef struct {
 	char *data;
 	int len;
-} tempinfo_t;
+} tape_procinfo_t;
+
+static struct file_operations tape_proc_devices_file_ops =
+{
+	read:tape_proc_devices_read,	/* read */
+	open:tape_proc_devices_open,	/* open */
+	release:tape_proc_devices_release,	/* close */
+};
+
+/* 
+ * Initialize procfs stuff on startup
+ */
+
+static inline void
+tape_proc_init (void) {
+	tape_proc_devices = create_proc_entry ("tapedevices",
+						S_IFREG | S_IRUGO | S_IWUSR,
+						&proc_root);
+	if (tape_proc_devices == NULL) 
+	        goto error;
+	tape_proc_devices->proc_fops = &tape_proc_devices_file_ops;
+	tape_proc_devices->proc_iops = &tape_proc_devices_inode_ops;
+	return;
+ error:
+	PRINT_WARN ("tape: Cannot register procfs entry tapedevices\n");
+	return;
+}
 
+/*
+ * Open function for /proc/tapedevices
+ */
 
 static int
-tape_devices_open (struct inode *inode, struct file *file)
+tape_proc_devices_open (struct inode *inode, struct file *file)
 {
-    int size=80;
-    tape_info_t* ti;
-    tempinfo_t* tempinfo;
-    char* data;
-    int pos=0;
-    tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL);
-    if (!tempinfo)
-        return -ENOMEM;
-    for (ti=first_tape_info;ti!=NULL;ti=ti->next)
-        size+=80; // FIXME: Guess better!
-    data=vmalloc(size);
-    if (!data) {
-        kfree (tempinfo);
-        return -ENOMEM;
-    }
-    pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n");
-    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;
-    file->private_data= (void*) tempinfo;
-#ifdef MODULE
-    MOD_INC_USE_COUNT;
+	tape_dev_t* td;
+	tape_procinfo_t* procinfo;
+	char* data = NULL;
+	int size=0,check_size = -1;
+	int pos=0;
+	int rc=0;
+	long lockflags,lockflags2;
+	tape_ccw_req_t *treq;
+
+	MOD_INC_USE_COUNT;
+
+	procinfo = kmalloc (sizeof(tape_procinfo_t),GFP_KERNEL);
+	if (!procinfo){
+		rc = -ENOMEM;
+		MOD_DEC_USE_COUNT;
+		goto out_no_lock;
+	}
+
+	/* Find out mem size for output, ensure that after releasing lock   */
+	/* (vmalloc must not be called with interrupts disabled) no devices */
+	/* have been added/removed                                          */
+
+	do{
+		size = 100; // Headline
+		read_lock_irqsave(&tape_dev_lock,lockflags);
+
+		for (td=tape_first_dev;td!=NULL;td=td->next)
+			size+=100; // FIXME: Guess better!
+
+		if(size == check_size)
+                        break;
+
+		read_unlock_irqrestore(&tape_dev_lock,lockflags);
+
+		if(data)
+			vfree(data);
+		data=vmalloc(size);
+		if (!data) {
+                    kfree (procinfo);
+                    rc = -ENOMEM;
+                    goto out_no_lock;
+		}
+		check_size = size;
+	}while (1);
+
+	// We have the tape_dev lock now
+
+#ifdef CONFIG_S390_TAPE_CHAR
+	pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevMod\tBlkSize\tState\tOp\tMedState\n");
+#else
+	pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevMod\tState\tOp\tMedState\n");
+#endif
+
+	for (td=tape_first_dev;td!=NULL;td=td->next) {
+		s390irq_spin_lock_irqsave (td->devinfo.irq,lockflags2);
+		treq = tape_get_active_ccw_req(td);
+		pos+=sprintf(data+pos,"%d\t",td->first_minor/TAPE_MINORS_PER_DEV);
+		pos+=sprintf(data+pos,"%04X\t",td->devinfo.devno);
+		pos+=sprintf(data+pos,"%04X\t",td->devinfo.sid_data.cu_type);
+		pos+=sprintf(data+pos,"%02X\t",td->devinfo.sid_data.cu_model);
+		pos+=sprintf(data+pos,"%04X\t",td->devinfo.sid_data.dev_type);
+		pos+=sprintf(data+pos,"%02X\t",td->devinfo.sid_data.dev_model);
+#ifdef CONFIG_S390_TAPE_CHAR
+		if(td->char_data.block_size == 0)
+			pos+=sprintf(data+pos,"auto\t");
+		else
+			pos+=sprintf(data+pos,"%i\t",td->char_data.block_size);
 #endif
-    return 0;
+		pos+=sprintf(data+pos,"%s\t",((tape_state_get(td) >= 0) &&
+			(tape_state_get(td) < TS_SIZE)) ?
+			tape_state_verbose[tape_state_get (td)] : "UNKNOWN");
+		pos+=sprintf(data+pos,"%s\t",(treq != NULL) ? 
+			tape_op_verbose[treq->op] : "---");
+		pos+=sprintf(data+pos,"%s\n",tape_med_st_verbose[td->medium_state]);
+		s390irq_spin_unlock_irqrestore (td->devinfo.irq,lockflags2);
+	}
+
+	procinfo->data=data;
+	procinfo->len=pos;
+        if (pos>size) BUG(); // we've overwritten some memory
+	file->private_data= (void*) procinfo;
+	read_unlock_irqrestore(&tape_dev_lock,lockflags);
+out_no_lock:
+	return rc;
 }
 
+/*
+ * Read function for /proc/tapedevices
+ */
+
 static ssize_t
-tape_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+tape_proc_devices_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;
+	loff_t len = 0;
+	tape_procinfo_t *p_info = (tape_procinfo_t *) file->private_data;
 
 	if (*offset >= p_info->len) {
-		return 0;	/* EOF */
+		goto out; /* EOF */
 	} else {
 		len =  user_len<(p_info->len - *offset)?user_len:(p_info->len - *offset);
 		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
 			return -EFAULT;
 		(*offset) += len;
-		return len;	/* number of bytes "read" */
 	}
+out:
+	return len;
 }
 
+/*
+ * Close function for /proc/tapedevices
+ */
+
 static int
-tape_devices_release (struct inode *inode, struct file *file)
+tape_proc_devices_release (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);
-		kfree (p_info);
-	}
-#ifdef MODULE
+	tape_procinfo_t *p_info = (tape_procinfo_t *) file->private_data;
+        vfree(p_info->data);
+        kfree (p_info);
         MOD_DEC_USE_COUNT;
-#endif
 	return rc;
 }
 
-static struct file_operations tape_devices_file_ops =
+/*
+ * Cleanup all stuff registered to the procfs
+ */
+static inline void
+tape_proc_cleanup (void)
 {
-	read:tape_devices_read,	/* read */
-	open:tape_devices_open,	/* open */
-	release:tape_devices_release,	/* close */
-};
+        if (tape_proc_devices != NULL)
+		remove_proc_entry ("tapedevices", &proc_root);
+}
 
 #endif /* CONFIG_PROC_FS */
 
-/* SECTION: Parameters for tape */
-char *tape[256] = { NULL, };
+/*******************************************************************
+ * Wait/Wakeup Functions
+ *******************************************************************/
+
+static void tape_wake_up_remove(tape_ccw_req_t* treq){
+	tape_remove_ccw_req(treq->tape_dev,treq);
+	tape_free_ccw_req(treq);
+}
+ 
+static void tape_wake_up(tape_ccw_req_t* treq){
+        treq->wakeup = NULL;
+        wake_up(&treq->wq);
+}
+ 
+static void tape_wake_up_interruptible(tape_ccw_req_t* treq){
+        treq->wakeup = NULL;
+        wake_up_interruptible(&treq->wq);
+}
+ 
+#ifdef CONFIG_S390_TAPE_BLOCK
+static void tape_schedule_tapeblock(tape_ccw_req_t* treq){
+        treq->wakeup = NULL;
+        tapeblock_schedule_exec_io((tape_dev_t*)(treq->tape_dev));;
+}
+#endif
+ 
+static void tape_wait_event(tape_ccw_req_t* treq){
+        wait_event (treq->wq,(treq->wakeup == NULL));
+}
+ 
+static void tape_wait_event_interruptible(tape_ccw_req_t* treq){
+        wait_event_interruptible(treq->wq,(treq->wakeup == NULL));
+	if (signal_pending (current)) {
+		treq->rc = tape_halt_io(treq->tape_dev);
+		if(treq->rc == -ERESTARTSYS)
+		        PRINT_INFO("IO stopped on irq %d\n",treq->tape_dev->devinfo.irq); /* FIXME: only put into dbf */
+                else if(treq->rc == 0)
+		        PRINT_INFO("could not stop IO,irq was faster on irq %d\n",treq->tape_dev->devinfo.irq); /* FIXME: only put into dbf */
+                else
+			PRINT_WARN("IO error while stopping IO on irq %d\n",treq->tape_dev->devinfo.irq);
+	}
+}
+
+static void tape_wait_event_interruptible_nohaltio(tape_ccw_req_t* treq){
+	wait_event_interruptible(treq->wq,(treq->wakeup == NULL));
+}
+
+/*******************************************************************
+ * DYNAMIC ATTACH/DETACH Functions
+ *******************************************************************/
+
+static inline void
+tape_init_devregs(void)
+{
+        long lockflags;
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+	memset(tape_devreg,0,sizeof(devreg_t*) * TAPE_MAX_DEVREGS);
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+}
+
+/*
+ * Alloc a devreg for a devno
+ */
+
+static inline devreg_t *
+tape_create_devno_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;
+}
+
+/*
+ * Alloc a devreg for a cu-type 
+ */
+ 
+static inline devreg_t *
+tape_create_cu_devreg (int cu_type)
+{
+        devreg_t *devreg = kmalloc (sizeof (devreg_t), GFP_KERNEL);
+        if (devreg != NULL) {
+                memset (devreg, 0, sizeof (devreg_t));
+                devreg->ci.hc.ctype = cu_type;
+                devreg->flag = DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS;
+                devreg->oper_func = tape_oper_handler;
+        }
+        return devreg;
+}
+
+/*
+ * Create devregs for device numbers from "from" to "to"
+ */
+ 
+static inline void
+tape_create_devregs_range(int from, int to)
+{
+	int i;
+	long lockflags;
+ 
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+	for (i=from;i<=to;i++) {
+		// register for attch/detach of a devno
+		if(tape_devregct >= TAPE_MAX_DEVREGS){
+			PRINT_WARN ("Could not create devregs for devno range %04x - %04x.\n",i,to);
+			PRINT_WARN ("These devices cannot be used. Use autoprobe\n");
+			PRINT_WARN ("or specify device ranges more precisely!\n");
+			break;
+		}
+		tape_devreg[tape_devregct]=tape_create_devno_devreg(i);
+		if (tape_devreg[tape_devregct]!=NULL) {
+                        s390_device_register (tape_devreg[tape_devregct++]);
+		} else {
+                	PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n",i);
+		}
+	}
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+        return;
+}
+
+/*
+ * Create a devreg for a discipline
+ */
+
+static inline void
+tape_create_devreg_for_disc(tape_discipline_t *disc)
+{
+	int devreg_nr;
+	long lockflags;
+ 
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+	for(devreg_nr = 0; devreg_nr < TAPE_MAX_DEVREGS; devreg_nr++){
+		if(tape_devreg[devreg_nr] == NULL)
+			break;
+	}
+	if(devreg_nr == TAPE_MAX_DEVREGS){
+		PRINT_WARN ("Could not create devreg for discipline (%x), dyn. attach for this discipline deactivated.\n",disc->cu_type);
+		goto out_unlock;
+	}
+	tape_devreg[devreg_nr] = tape_create_cu_devreg(disc->cu_type);
+	if (tape_devreg[devreg_nr] != NULL) {
+		s390_device_register(tape_devreg[devreg_nr]);
+	} else {
+		PRINT_WARN("Could not alloc devreg: Out of memory\n");
+		PRINT_WARN("Dynamic attach/detach will not work!\n");
+	}
+out_unlock:
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+	return;
+}
+
+/*
+ * Free all devregs
+ */ 
+
+static inline void
+tape_delete_all_devregs(void)
+{
+	int i;
+	long lockflags;
+
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+
+	for(i = 0; i < TAPE_MAX_DEVREGS; i++){
+		if(tape_devreg[i]){
+			s390_device_unregister(tape_devreg[i]);
+			kfree(tape_devreg[i]);
+		}
+	}
+	memset(tape_devreg,0,sizeof(devreg_t*) * TAPE_MAX_DEVREGS);
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+}
+
+/*
+ * Free Devregs for a discipline
+ */
+
+static inline void
+tape_delete_devreg_for_disc(tape_discipline_t* disc)
+{
+	int i;
+	long lockflags;
+ 
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+ 
+	for(i = 0; i < TAPE_MAX_DEVREGS; i++){
+		if(tape_devreg[i]){
+			if(tape_devreg[i]->ci.hc.ctype == disc->cu_type){
+				s390_device_unregister(tape_devreg[i]);
+				kfree(tape_devreg[i]);
+				tape_devreg[i] = NULL;
+			}
+		}
+	}
+ 
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+}
+
+/*******************************************************************
+ * Module/Kernel Parameter Handling
+ *******************************************************************/
 
 #ifndef MODULE
 static char tape_parm_string[1024] __initdata = { 0, };
+
+/*
+ * Get Kernel parameters (str) seperated by ","
+ * and store them into the tape[] array
+ */
+
 static void
 tape_split_parm_string (char *str)
 {
@@ -240,13 +602,18 @@
 				count + 1);
 			break;
 		}
-		memset (tape[count], 0, len * sizeof (char));
 		memcpy (tape[count], tmp, len * sizeof (char));
 		count++;
 		tmp = end;
 	};
 }
 
+/*
+ * This function is called for each "tape=" Kernel parameter
+ * at Kernel initialization. We need tape_parm_setup because of
+ * 2.2 compatibility (At least I assume this :-))
+ */
+ 
 void __init
 tape_parm_setup (char *str, int *ints)
 {
@@ -268,424 +635,927 @@
 __setup("tape=", tape_parm_call_setup);
 #endif   /* not defined MODULE */
 
+
+/*
+ * Convert string to int
+ */
+
 static inline int
 tape_parm_strtoul (char *str, char **stra)
 {
 	char *temp = str;
 	int val;
 	if (*temp == '0') {
-		temp++;		/* strip leading zero */
+		temp++;         /* strip leading zero */
 		if (*temp == 'x')
-			temp++;	/* strip leading x */
+			temp++; /* strip leading x */
 	}
-	val = simple_strtoul (temp, &temp, 16);	/* interpret anything as hex */
+	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;
-}
+/*
+ * Parse Kernel/Module Parameters and create devregs for dynamic attach/detach
+ */ 
 
 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;
+	int from, to;
+ 
 	if (*str==NULL) {
-            /* no params present -> leave */
-            return;
+		/* 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++;
-        }
+		from = tape_parm_strtoul (temp, &temp);
+		to = from;
+		if (*temp == '-') {
+			temp++;
+			to = tape_parm_strtoul (temp, &temp);
+		}
+		tape_create_devregs_range(from,to);
+		str++;
+	}
 }
 
+/*******************************************************************
+ * Tape device (td) functions for create, free, enq, deq, enable,
+ * disable, get and put
+ *******************************************************************/
+
+/*
+ * Enable Device
+ */
 
-/* SECTION: Managing wrappers for ccwcache */
+static inline int 
+tape_enable_device(tape_dev_t* td)
+{
+#ifdef CONFIG_DEVFS_FS
+	tape_frontend_t* frontend;
+#endif
+	int rc = 0;
 
-#define TAPE_EMERGENCY_REQUESTS 16
+	if(td->discipline->setup_device(td) != 0){
+		rc = -ENOMEM;
+		goto out;
+	}
 
-static ccw_req_t *tape_emergency_req[TAPE_EMERGENCY_REQUESTS] =
-{NULL,};
-static spinlock_t tape_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+	/* Register IRQ */
 
-static void
-tape_init_emergency_req (void)
+#ifdef TAPE_CIO_PRIVATE_DATA
+	#ifdef CONFIG_S390_TAPE_DYNAMIC
+		rc = s390_request_irq_special (td->devinfo.irq, tape_do_irq,
+			tape_noper_handler,0, TAPE_MAGIC, &(td->devstat));
+	#else
+		rc = s390_request_irq (td->devinfo.irq, tape_do_irq, 0, TAPE_MAGIC, &(td->devstat));
+	#endif
+#else
+	#ifdef CONFIG_S390_TAPE_DYNAMIC
+		rc = s390_request_irq_special (td->devinfo.irq, tape_do_irq,
+			tape_noper_handler,0, (char*)td, &(td->devstat));
+	#else
+		rc = s390_request_irq (td->devinfo.irq, tape_do_irq, 0, (char*)td, &(td->devstat));
+	#endif
+#endif /* TAPE_CIO_PRIVATE_DATA */
+	if (rc){
+		PRINT_WARN ("Cannot register irq %d, rc=%d\n", td->devinfo.irq, rc);
+		td->discipline->cleanup_device(td);
+		goto out;
+	}
+	/* Create devfs entries */
+#ifdef CONFIG_DEVFS_FS
+	if (tape_mkdevfsroot(td)==NULL){
+		PRINT_WARN ("Cannot create a devfs directory for device %04x\n",td->devinfo.devno);
+		goto out_undo;
+	}
+		
+	for (frontend=tape_first_front;frontend!=NULL;frontend=frontend->next){
+		if(frontend->mkdevfstree(td) == NULL){
+			goto out_undo;
+		}
+	}
+#endif
+#ifdef TAPE_CIO_PRIVATE_DATA
+	s390_set_private_data(td->devinfo.irq,td);
+#endif
+out:
+	return rc;
+out_undo:
+        tape_disable_device(td);
+        return -ENOMEM;        
+}
+
+/*
+ * Disable Device
+ */
+
+static inline void
+tape_disable_device(tape_dev_t* td)
 {
-	int i;
-	for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) {
-		tape_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL);
+#ifdef CONFIG_DEVFS_FS
+	tape_frontend_t* frontend;
+#endif
+	td->discipline->cleanup_device(td);
+#ifdef TAPE_CIO_PRIVATE_DATA 
+	s390_set_private_data(td->devinfo.irq,NULL);
+#else
+	ioinfo[td->devinfo.irq]->irq_desc.name = NULL;
+#endif
+
+	free_irq (td->devinfo.irq, &(td->devstat)); 
+#ifdef CONFIG_DEVFS_FS
+        for (frontend=tape_first_front;frontend!=NULL;frontend=frontend->next)
+                frontend->rmdevfstree(td);
+        tape_rmdevfsroot(td);
+#endif
+	tape_state_set(td,TS_NOT_OPER);
+}
+
+/*
+ * Append Tape device (td) to our tape info list
+ * Must be called with hold tape_dev_lock
+ */
+ 
+static inline void
+tape_enq_device(tape_dev_t* td)
+{
+	tape_dev_t *temptd = NULL;
+ 
+	if (tape_first_dev == NULL) {
+		tape_first_dev = td;
+	} else {
+		temptd = tape_first_dev;
+		while (temptd->next != NULL)
+			temptd = temptd->next;
+		temptd->next = td;
+	}
+}
+ 
+/*
+ * Remove Tape device (td) from our tape info list
+ * Must be called with hold tape_dev_lock
+ */
+ 
+static inline void
+tape_deq_device(tape_dev_t* td)
+{
+	tape_dev_t* lasttd;
+ 
+	if (td==tape_first_dev) {
+		tape_first_dev=td->next;
+	} else {
+		lasttd=tape_first_dev;
+		while (lasttd->next!=td) lasttd=lasttd->next;
+		lasttd->next=td->next;
 	}
 }
 
-#ifdef MODULE // We only cleanup the emergency requests on module unload.
-static void
-tape_cleanup_emergency_req (void)
+
+/*
+ * Get Free minor number
+ * Must be called with held tape_dev_lock
+ */
+
+static inline int
+tape_get_new_minor(int devno)
 {
-	int i;
-	for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) {
-		if (tape_emergency_req[i])
-			free_page ((long) (tape_emergency_req[i]));
+	int i,tape_num = -1;
+	tape_dev_t* newtape;
+
+	if(!tape_autoprobe){
+		/* we have static device ranges, so fingure out the */
+		/* tape_num of the attached tape                    */
+		for (i=0;i<tape_devregct;i++){
+			if (tape_devreg[i]->ci.devno==devno) {
+				tape_num=TAPE_MINORS_PER_DEV*i;
+				goto out;
+			}
+		}
+	} else {
+		/* we are running in autoprobe mode, find a free */
+		/* tape_num */
+		i = 0;
+		newtape=tape_first_dev;
+		while (newtape!=NULL) {
+			if (newtape->first_minor==i) {
+				/* tape num in use. try next one */
+				i+=TAPE_MINORS_PER_DEV;
+				newtape=tape_first_dev;
+			} else {
+				/* tape num not used by newtape. look at next */
+				/* tape info */
+				newtape=newtape->next;
+			}
+		}
+		if(i>255) /* No more minor available */
+			tape_num = -1;
 		else
-			printk (KERN_WARNING PRINTK_HEADER "losing one page for 'in-use' emergency request\n");
+			tape_num = i;
 	}
+out:
+	return tape_num;
 }
-#endif
 
-ccw_req_t *
-tape_alloc_request (char *magic, int cplength, int datasize)
+
+/*
+ * Create device: Alloc, enable and enq device
+ */
+
+static inline tape_dev_t*
+tape_create_device(int irq, int devno, tape_discipline_t* disc)
 {
-	ccw_req_t *rv = NULL;
-	int i;
-	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
-		return rv;
+	int rc = 0;
+	int tape_num;
+	tape_dev_t *td;
+	long lockflags;
+
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+
+	td = kmalloc (sizeof (tape_dev_t), GFP_ATOMIC);
+	if (td == NULL) {
+		tape_sprintf_exception (tape_dbf_area,2,"ti:no mem \n");
+		PRINT_INFO ("tape: can't allocate memory for "
+			"tape info structure\n");
+		goto error;
 	}
-	if (cplength * sizeof (ccw1_t) + datasize + sizeof (ccw_req_t) > PAGE_SIZE) {
-		return NULL;
+	memset(td,0,sizeof(tape_dev_t));
+        tape_num = tape_get_new_minor(devno);
+        if(tape_num == -1){
+                PRINT_WARN("tape: could not get minor for tape %x\n",devno);
+                goto error;
+        }
+	rc = get_dev_info_by_irq (irq, &(td->devinfo));
+	if (rc == -ENODEV) {    /* end of device list */
+		goto error;
 	}
-	spin_lock (&tape_emergency_req_lock);
-	for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) {
-		if (tape_emergency_req[i] != NULL) {
-			rv = tape_emergency_req[i];
-			tape_emergency_req[i] = NULL;
+	td->discipline = disc;
+	atomic_set(&(td->use_count),1);
+	td->first_minor = tape_num;
+	td->medium_state = MS_UNKNOWN;
+	td->next = NULL;
+	td->discdata = td->treq = NULL;
+	tape_state_set (td, TS_INIT);
+	td->discdata=NULL;
+	td->last_op = TO_NOTHING;
+
+	if(td->discipline->setup_device(td) != 0)
+		goto error;
+	if(tape_enable_device(td) !=0)	
+		goto error;
+	tape_enq_device(td);
+	PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",devno,disc->cu_type,irq,tape_num/2);
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+	return td;
+error:
+	tape_sprintf_event (tape_dbf_area,3,"tsetup err: %x\n",rc);
+	if(td)
+		kfree (td);
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+	return NULL;
+}
+
+/*
+ * Free Device storage
+ */
+
+static void
+tape_free_device(tape_dev_t* td)
+{
+        if (TAPE_BUSY(td)) 
+	        BUG(); /* one should _not_ free the device when a request is pending */
+	tape_sprintf_event (tape_dbf_area,6,"free irq: %x\n",td->devinfo.irq);
+        kfree(td);
+}
+
+/*
+ * Decrement use count of tape structure
+ * if use count == 0 tape structure is freed
+ */
+ 
+inline void
+tape_put_device(tape_dev_t* td)
+{
+	if (td==NULL)
+		BUG();
+	if(atomic_dec_and_test(&(td->use_count)))
+		tape_free_device(td);
+}
+
+/*
+ * Find the tape_dev_t structure associated with member
+ * and increase use count:
+ *
+ * member:    TAPE_MEMB_IRQ, TAPE_MEMB_MINOR
+ */
+
+tape_dev_t *
+__tape_get_device_by_member(unsigned long value, int member)
+{
+	tape_dev_t *td = NULL;
+	long lockflags;
+ 
+	read_lock_irqsave(&tape_dev_lock,lockflags);
+	td = tape_first_dev;
+	while(td != NULL) {
+		switch(member){
+			case TAPE_MEMB_IRQ:
+				if(td->devinfo.irq == value)
+					goto out;
+				break;
+			case TAPE_MEMB_MINOR:
+				if((value >= td->first_minor)  && 
+				    (value < (td->first_minor + TAPE_MINORS_PER_DEV)) )
+					goto out;
+				break;
+			case TAPE_MEMB_QUEUE:
+				if(((unsigned long)(&td->blk_data.request_queue)) == value)
+					goto out;
+				break;
+			default:
+				BUG();
 		}
+		td = td->next;
 	}
-	spin_unlock (&tape_emergency_req_lock);
-	if (rv) {
-		memset (rv, 0, PAGE_SIZE);
-		rv->cache = (kmem_cache_t *) (tape_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));
+out:
+	if(td) // found!
+		atomic_inc(&(td->use_count));
+	read_unlock_irqrestore(&tape_dev_lock,lockflags);
+	return td;
+}
+
+/*
+ * Scan all irqs an create tape devices for all matching cu types
+ */
+
+static inline void
+tape_create_devs_for_disc(tape_discipline_t* disc)
+{
+	int irq,i;
+	tape_dev_t* td = NULL;
+	s390_dev_info_t dinfo;
+
+	for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
+		if(get_dev_info_by_irq (irq, &dinfo) == -ENODEV)
+			continue;
+		if(disc->cu_type != dinfo.sid_data.cu_type)
+			/* Wrong type - try next one */
+			continue;
+
+		tape_sprintf_event (tape_dbf_area,3,"det irq:  %x\n",irq);
+		tape_sprintf_event (tape_dbf_area,3,"cu     :  %x\n",disc->cu_type);
+
+
+		if(!tape_autoprobe) {
+		        for( i=0; i<tape_devregct; i++ ) {
+		                if(tape_devreg[i]->ci.devno == dinfo.devno) {
+			                td = tape_create_device(irq, dinfo.devno, disc);
+					if(!td) {
+					        PRINT_WARN( "Could not initialize tape 0x%x\n",dinfo.devno);
+						continue;
+					}
+					if(disc->init_device)
+					        disc->init_device(td); /* XXX */
+					tape_state_set (td, TS_UNUSED);
+					break;
+				}
+			}
+		}
+		else {
+		        td = tape_create_device(irq,dinfo.devno,disc);
+		  
+			if(!td){
+			        PRINT_WARN( "Could not initialize tape 0x%x\n",dinfo.devno);
+			        continue;
+			}
+			if(disc->init_device)
+			        disc->init_device(td); /* XXX */
+			tape_state_set (td, TS_UNUSED); 
+		}
 	}
-	return rv;
 }
 
-void
-tape_free_request (ccw_req_t * request)
+/*
+ * Go through our tape info list and disable, deq and free all devices with 
+ * matching cu type
+ */
+
+static inline void
+tape_delete_devs_for_disc(tape_discipline_t* disc)
 {
-	if (request->cache >= (kmem_cache_t *) tape_emergency_req &&
-	    request->cache <= (kmem_cache_t *) (tape_emergency_req + TAPE_EMERGENCY_REQUESTS)) {
-		*((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);
+	tape_dev_t *td;
+	long lockflags;
+
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+	td = tape_first_dev;
+	while (td !=NULL){
+		if(td->discipline == disc){
+			tape_deq_device(td);
+			write_unlock_irqrestore(&tape_dev_lock,lockflags);
+			tape_disable_device(td);
+			tape_put_device(td);
+			write_lock_irqsave(&tape_dev_lock,lockflags);
+			td = tape_first_dev;
+		} else {
+			td=td->next;
+		}
 	}
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
 }
+		
+/*******************************************************************
+ * TAPE Request and IO Functions
+ *******************************************************************/
 
 /*
- * Allocate a ccw request and reserve it for tape driver
+ * Allocate a new tape ccw request
  */
-inline
- ccw_req_t *
-tape_alloc_ccw_req (tape_info_t * ti, int cplength, int datasize)
+
+inline tape_ccw_req_t *
+tape_alloc_ccw_req (int cplength, int datasize,int idal_buf_size, tape_op_t operation)
 {
-	char tape_magic_id[] = "tape";
-	ccw_req_t *cqr = NULL;
+	tape_ccw_req_t* treq;
+	int kmalloc_flags;
+	if(in_interrupt())
+		kmalloc_flags = GFP_ATOMIC;
+	else
+		kmalloc_flags = GFP_KERNEL;
+
+	treq = (tape_ccw_req_t*) kmalloc(sizeof(tape_ccw_req_t),kmalloc_flags);
+	if(!treq)
+		goto error;
+	memset(treq,0,sizeof(tape_ccw_req_t));
+	treq->kernbuf_size = datasize;
+	treq->userbuf_size = datasize;
+	treq->op           = operation;
+	treq->cplength     = cplength;
+	init_waitqueue_head (&treq->wq); 
+
+	// alloc small kernel buffer
+
+	if(datasize > PAGE_SIZE)
+		BUG();
+	if(datasize > 0){
+		// the kernbuf must be below 2GB --> GFP_DMA
+		treq->kernbuf = kmalloc(datasize,kmalloc_flags | GFP_DMA); 
+		if(!treq->kernbuf)
+			goto error;
+		memset(treq->kernbuf, 0, datasize);
+	}
 
-	if (!ti)
-		return NULL;
-	cqr = tape_alloc_request (tape_magic_id, cplength, datasize);
+	// alloc idal kernel buffer
 
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-		PRINT_WARN ("empty CQR generated\n");
-#endif
+	if(idal_buf_size > 0){
+		treq->idal_buf = idalbuf_alloc(idal_buf_size);
+		if(!treq->idal_buf)
+			goto error;
 	}
-	cqr->magic = TAPE_MAGIC;	/* sets an identifier for tape driver   */
-	cqr->device = ti;	/* save pointer to tape info    */
-	return cqr;
+		
+	if(cplength < 0)
+		BUG();
+
+	// the channel program must be below 2GB --> GFP_DMA
+	treq->cpaddr = kmalloc(cplength * sizeof(ccw1_t), kmalloc_flags | GFP_DMA);
+	if(!treq->cpaddr)
+		goto error;
+	memset(treq->cpaddr, 0, cplength*sizeof(ccw1_t));
+	return treq;
+error:
+	tape_sprintf_exception (tape_dbf_area,1,"cqra nomem\n");
+	if(treq)
+		tape_free_ccw_req(treq);
+	return NULL;
 }
 
 /*
- * Find the tape_info_t structure associated with irq
+ * Free tape ccw request
  */
-static inline tape_info_t *
-tapedev_find_info (int irq)
+
+void
+tape_free_ccw_req (tape_ccw_req_t * treq)
 {
-	tape_info_t *ti;
+	if(!treq)
+                BUG();
+	if(treq->cpaddr)
+		kfree(treq->cpaddr);
+	if(treq->kernbuf)
+		kfree(treq->kernbuf);
+	if(treq->idal_buf)
+		idalbuf_free(treq->idal_buf);
+	kfree(treq);
+}
 
-	ti = first_tape_info;
-	if (ti != NULL)
-		do {
-			if (ti->devinfo.irq == irq)
-				break;
-		} while ((ti = (tape_info_t *) ti->next) != NULL);
-	return ti;
+/*
+ * Add request to request queue (At the moment queue length = 1)
+ */
+
+static inline int
+tape_add_ccw_req(tape_dev_t* td,tape_ccw_req_t* treq)
+{
+	if(td->treq)
+		return -1;
+	td->treq = treq;
+	treq->tape_dev = td;
+	return 0;
 }
 
-#define QUEUE_THRESHOLD 5
+/*
+ * Remove request from request queue (At the moment queue length = 1)
+ */
+
+int
+tape_remove_ccw_req(tape_dev_t* td,tape_ccw_req_t* treq)
+{
+	if(treq != td->treq)
+		BUG();
+	td->last_op = treq->op;
+        td->treq=NULL;
+	treq->tape_dev=NULL;
+        return 0;
+}
 
 /*
- * Tape interrupt routine, called from Ingo's I/O layer
+ * Get the active ccw request
  */
-void
-tape_irq (int irq, void *int_parm, struct pt_regs *regs)
+
+tape_ccw_req_t*
+tape_get_active_ccw_req(tape_dev_t* td)
 {
-	tape_info_t *ti = tapedev_find_info (irq);
+	return td->treq;
+}
 
-	/* analyse devstat and fire event */
-	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 (ti, TE_OTHER);
+/*
+ * Stop the active ccw request
+ */
+
+static inline int
+tape_halt_io(tape_dev_t* td)
+{
+	int retries = 0;
+	int irq = td->devinfo.irq;
+	int rc = 0;
+	long lockflags;
+	tape_ccw_req_t* treq;
+
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	treq = tape_get_active_ccw_req(td);
+	/* check if interrupt has already been processed */
+	if(!treq)
+		goto out;
+	if(treq->wakeup == NULL)
+		goto out;
+	while (retries < 5){
+		if ( retries < 2 )
+			rc = halt_IO(irq, (long)treq, treq->options);
+		else
+			rc = clear_IO(irq, (long)treq, treq->options);
+		switch (rc) {
+		case 0:         /* termination successful */
+			rc = -ERESTARTSYS;
+			goto out;
+		case -ENODEV:
+		        PRINT_INFO ("device gone, retry\n"); /* FIXME: s390dbf only */
+			break;
+		case -EIO:
+			PRINT_INFO ("I/O error, retry\n"); /* FIXME: s390dbf only */
+			break;
+		case -EBUSY:
+			PRINT_INFO ( "device busy, retry later\n"); /* FIXME: s390dbf only */
+			break;
+		default:
+			PRINT_ERR ( "line %d unknown RC=%d, please report"
+			   	    " to linux390@de.ibm.com\n", __LINE__, rc);
+			BUG ();
+		}
+		retries ++;
+	}
+out:
+	s390irq_spin_unlock_irqrestore(td->devinfo.irq, lockflags);
+	return rc;
 }
 
-int 
-tape_oper_handler ( int irq, struct _devreg *dreg) {
-    tape_info_t* ti=first_tape_info;
-    tape_info_t* newtape;
-    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;
-    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;
-    }
-    // irq is not used by tape
-    rc = get_dev_info_by_irq (irq, &dinfo);
-    if (rc == -ENODEV) {
-        retries++;
-        rc = get_dev_info_by_irq (irq, &dinfo);
-        if (retries > 5) {
-            PRINT_WARN ("No device information for new dev. could be retrieved.\n");
-            return -ENODEV;
-        }
-    }
-    disc = first_discipline;
-    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, 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  */
-    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(ti,0,sizeof(tape_info_t));
-    ti->discipline = disc;
-    disc->tape = ti;
-    tape_num=0;
-    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 (ti, irq, tape_num);
-    if (rc) {
-        kfree (ti);
-        return -ENOBUFS;
-    }
-#ifdef CONFIG_DEVFS_FS
-    for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) 
-        frontend->mkdevfstree(ti);
+
+/*
+ * The tape IO function:
+ * tape_do_io MUST be called with locked td lock!
+ */
+ 
+static inline int
+__tape_do_io(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type,int io)
+{
+	int rc = 0;
+ 
+        if ((td==NULL) || (treq==NULL)) 
+                BUG();
+
+	if(tape_state_get(td) == TS_NOT_OPER){
+		rc = -ENODEV;
+		goto out;
+	}
+	if(TAPE_BUSY(td)){
+		tape_sprintf_event (tape_dbf_area,1,"tape: IRQ - Tape busy\n");	
+		rc = -EBUSY;
+		goto out;
+	}
+	tape_add_ccw_req(td,treq);
+	switch(type){
+		case TAPE_REMOVE_REQ_ON_WAKEUP:
+			treq->wakeup = tape_wake_up_remove;
+			break;
+		case TAPE_NO_WAIT: 
+			// needed for retry
+			break; 
+		case TAPE_WAIT:
+			treq->wakeup = tape_wake_up;
+			treq->wait   = tape_wait_event;
+			break;
+		case TAPE_WAIT_INTERRUPTIBLE:
+			treq->wakeup = tape_wake_up_interruptible;
+			treq->wait   = tape_wait_event_interruptible;
+			break;
+		case TAPE_WAIT_INTERRUPTIBLE_NOHALTIO:
+			// neded for dummy load 
+			treq->wakeup = tape_wake_up_interruptible;
+			treq->wait   = tape_wait_event_interruptible_nohaltio;
+			break;
+#ifdef CONFIG_S390_TAPE_BLOCK
+		case TAPE_SCHED_BLOCK:
+			treq->wakeup = tape_schedule_tapeblock;
+			treq->wait   = NULL;
+			break;
 #endif
-    s390irq_spin_lock_irqsave (irq,lockflags);
-    if (first_tape_info == NULL) {
-        first_tape_info = ti;
-    } else {
-        newtape = first_tape_info;
-        while (newtape->next != NULL)
-            newtape = newtape->next;
-        newtape->next = ti;
-    }
-    s390irq_spin_unlock_irqrestore (irq, lockflags);
-    return 0;
+		default:
+                        BUG();
+	}
+ 
+	if(io)
+		rc = do_IO(td->devinfo.irq,treq->cpaddr,
+		(unsigned long)treq, 0x00, treq->options);
+ 
+	if(rc) {
+		tape_sprintf_event (tape_dbf_area,1,"tape: DOIO failed with er = %i\n",rc);
+		treq->wakeup = NULL;
+		treq->wait   = NULL; /*XXX ??*/
+		tape_remove_ccw_req(td,treq);
+	}
+out:
+	return rc;
+}
+
+/*
+ * Do the io request and wait for it
+ */
+
+int
+tape_do_io_and_wait(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type)
+{
+	int rc = 0;
+	long lockflags;
+        if (td==NULL) 
+                BUG();
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	rc = __tape_do_io(td,treq,type,TAPE_DO_IO);
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+	if(rc == 0)
+		tape_wait(treq);
+	return rc;
+}
+
+/*
+ * Needed for MTLOAD: Just create a wait request without doing io
+ */
+
+int
+tape_do_wait_req(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type)
+{
+	int rc = 0;
+	long lockflags;
+        if (td==NULL)
+                BUG();
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	rc = __tape_do_io(td,treq,type,TAPE_NO_IO);
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+	tape_wait(treq);
+	return rc;
+}
+
+/*
+ * Just do the io
+ */
+
+int
+tape_do_io(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type)
+{
+	int rc = 0;
+	long lockflags;
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	rc = __tape_do_io(td,treq,type,TAPE_DO_IO);
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+	return rc;
+}
+
+/*
+ * Just do the io, but we are already locked here (in irq)
+ */
+
+int
+tape_do_io_irq(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type)
+{
+        return __tape_do_io(td,treq,type,TAPE_DO_IO);
 }
 
+/*
+ * Wait for an io request
+ */
 
 static void
-tape_noper_handler ( int irq, int status ) {
-    tape_info_t *ti=first_tape_info;
-    tape_info_t *lastti;
-#ifdef CONFIG_DEVFS_FS
-    tape_frontend_t *frontend;
+tape_wait(tape_ccw_req_t* treq)
+{
+	tape_dev_t* td;
+	if(treq==NULL)
+                BUG();
+	td = treq->tape_dev;
+        if (td==NULL)
+                BUG();       
+	if(treq->wait==NULL)
+                BUG();
+        treq->wait(treq);
+	tape_remove_ccw_req(td,treq);
+}
+
+/*
+ * Tape interrupt routine, called from Ingo's I/O layer
+ */
+
+static void
+tape_do_irq (int irq, void *int_parm, struct pt_regs *regs)
+{
+	tape_dev_t *td;
+#ifdef TAPE_CIO_PRIVATE_DATA
+	td = (tape_dev_t*)s390_get_private_data(irq);
+#else
+	td = (tape_dev_t*)ioinfo[irq]->irq_desc.name;
 #endif
-    long lockflags;
-    s390irq_spin_lock_irqsave(irq,lockflags);
-    while (ti!=NULL && ti->devinfo.irq!=irq) ti=ti->next;
-    if (ti==NULL) return;
-    if (tapestate_get(ti)!=TS_UNUSED) {
-        // device is in use!
-        PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor/2);
-        tapestate_set(ti,TS_NOT_OPER);
-        ti->rc=-ENODEV; 
-	ti->wanna_wakeup=1;
-	switch (tapestate_get(ti)) {
-	case TS_REW_RELEASE_INIT:
-	    tapestate_set(ti,TS_NOT_OPER);
-	    wake_up (&ti->wq);
-	    break;
-#ifdef CONFIG_S390_TAPE_BLOCK
-	case TS_BLOCK_INIT:
-	    tapestate_set(ti,TS_NOT_OPER);
-	    schedule_tapeblock_exec_IO(ti);
-	    break;
-#endif
-	default:
-	    tapestate_set(ti,TS_NOT_OPER);
-	    wake_up_interruptible (&ti->wq);
+	if(!td) {
+		PRINT_ERR ("tape: could not get device structure for irq %d in interrupt\n",irq);
+		goto out;
 	}
-    } else {
-        // device is unused!
-        PRINT_WARN ("Tape #%d was detached.\n",ti->blk_minor/2);
-        if (ti==first_tape_info) {
-            first_tape_info=ti->next;
-        } else {
-            lastti=first_tape_info;
-            while (lastti->next!=ti) lastti=lastti->next;
-            lastti->next=ti->next;
+	if(td->devstat.dstat != 0x0c){
+		tape_sprintf_event (tape_dbf_area,3,"-- Tape Interrupthandler --\n");
+		tape_dump_sense_dbf(td);
+	}
+	if (tape_state_get(td) == TS_NOT_OPER) {
+		tape_sprintf_event (tape_dbf_area,6,"tape:device is not operational\n");
+		goto out;
+	}
+	td->discipline->irq(td);
+out:
+	return;
+}
+
+/*
+ * Oper Handler is called from Ingo's I/O layer when a new tape device is 
+ * attached. We create a new devinfo for the new device, enable and enq it.
+ */
+
+static int 
+tape_oper_handler ( int irq, struct _devreg *dreg) {
+	tape_dev_t* td=tape_first_dev;
+	int rc=0;
+	s390_dev_info_t dinfo;
+	tape_discipline_t* disc;
+	long lockflags;
+
+	td = tape_get_device_by_irq(irq);
+	if (td!=NULL) {
+		// irq is (still) used by tape. tell ingo to try again later
+		PRINT_ERR ("tape:Oper handler for irq %d called, but irq is still (internally) used.\n",irq);
+		rc = -EAGAIN;
+		goto out;
+	}
+
+	rc = get_dev_info_by_irq (irq, &dinfo);
+	if (rc == -ENODEV) {
+                PRINT_ERR ("tape: Cannot get dev info for irq %d in the oper handler.\n",irq);
+                rc = -EAGAIN;
+                goto out;
+	}
+
+	read_lock_irqsave(&tape_discipline_lock,lockflags);
+
+	disc = tape_first_disc;
+	while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
+		disc = (tape_discipline_t *) (disc->next);
+
+	if (disc == NULL){
+		PRINT_WARN ("tape: No matching discipline for cu_type %x found in the oper handler, ignoring device %04x.\n",dinfo.sid_data.cu_type,dinfo.devno);
+		rc = -ENODEV;
+		goto out_unlock;
+	}
+
+	/* Allocate tape structure  */
+	td = tape_create_device(irq,dinfo.devno,disc);
+
+	if (td == NULL) {
+		PRINT_WARN( "Could not initialize tape 0x%x\n",dinfo.devno);
+		rc = -ENOBUFS;
+		goto out_unlock;
+	} else {
+		if(disc->init_device)
+			disc->init_device(td);
+	}
+	tape_state_set (td, TS_UNUSED); 
+out_unlock:
+        read_unlock_irqrestore(&tape_discipline_lock,lockflags);
+out:
+	return rc;
+}
+
+/*
+ * Not Oper Handler is called from Ingo's IO layer, when a tape device
+ * is detached. We deq, disable and free the tape info for this device
+ */
+
+static void
+tape_noper_handler ( int irq, int status ) {
+	tape_dev_t *td;
+	long lockflags;
+	tape_ccw_req_t *treq;
+
+	td = tape_get_device_by_irq(irq);
+	if (td==NULL) {
+                PRINT_ERR("tape: not operational handler called for irq %x, but tape does not hold this irq.\n",irq);
+                goto error;
         }
-#ifdef CONFIG_DEVFS_FS
-        for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next)
-            frontend->rmdevfstree(ti);
-        tape_rmdevfsroots(ti);
-#endif
-        kfree(ti);
-    }
-    s390irq_spin_unlock_irqrestore(irq,lockflags);
-    return;
+
+	write_lock_irqsave(&tape_dev_lock,lockflags);
+	tape_deq_device(td);
+	write_unlock_irqrestore(&tape_dev_lock,lockflags);
+
+	tape_disable_device(td);
+
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	treq = tape_get_active_ccw_req(td);
+	if (treq) {
+		// device is in use!
+                treq->rc= -ENODEV;
+		if(treq->wakeup)
+			treq->wakeup (treq);
+		PRINT_WARN ("Tape #%d is detached while it was busy.\n",td->first_minor/TAPE_MINORS_PER_DEV);
+	} else {
+		// device is unused!
+		PRINT_WARN ("Tape #%d is detached now.\n",td->first_minor/TAPE_MINORS_PER_DEV);
+	}
+
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);	
+
+	/* decrement use count twice ! */	
+	tape_put_device(td);
+	tape_put_device(td);
+error:
+	return;
 }
 
+/*
+ * Write sense data to dbf
+ */
 
-void
-tape_dump_sense (devstat_t * stat)
+void tape_dump_sense_dbf(tape_dev_t* td)
 {
-#ifdef TAPE_DEBUG
-        int sl;
-#endif
-#if 0
+	devstat_t *stat = &td->devstat;
+	const char* op;
+	if(TAPE_BUSY(td))
+		op = tape_op_verbose[tape_get_active_ccw_req(td)->op];
+	else
+		op = "---";
+	tape_sprintf_event (tape_dbf_area,3,"DSTAT : %02x   CSTAT: %02x\n",stat->dstat,stat->cstat);
+	tape_sprintf_event (tape_dbf_area,3,"DEVICE: %04x OP   : %s\n",td->devinfo.devno,op);
+	tape_sprintf_event (tape_dbf_area,3,"%08x %08x\n",*((unsigned int*)&stat->ii.sense.data[0]),*((unsigned int*)&stat->ii.sense.data[4]));
+	tape_sprintf_event (tape_dbf_area,3,"%08x %08x\n",*((unsigned int*)&stat->ii.sense.data[8]),*((unsigned int*)&stat->ii.sense.data[12]));
+	tape_sprintf_event (tape_dbf_area,3,"%08x %08x\n",*((unsigned int*)&stat->ii.sense.data[16]),*((unsigned int*)&stat->ii.sense.data[20]));
+	tape_sprintf_event (tape_dbf_area,3,"%08x %08x\n",*((unsigned int*)&stat->ii.sense.data[24]),*((unsigned int*)&stat->ii.sense.data[28]));
+}
 
-	PRINT_WARN ("------------I/O resulted in unit check:-----------\n");
-	for (sl = 0; sl < 4; sl++) {
-		PRINT_WARN ("Sense:");
-		for (sct = 0; sct < 8; sct++) {
-			PRINT_WARN (" %2d:0x%02X", 8 * sl + sct,
-				    stat->ii.sense.data[8 * sl + sct]);
-		}
-		PRINT_WARN ("\n");
-	}
+/*
+ * Write sense data to console/dbf
+ */
+
+void
+tape_dump_sense (tape_dev_t* td)
+{
+	devstat_t *stat = &td->devstat;
+#if 1 /* XXX */
+	PRINT_INFO ("-------------------------------------------------\n");
+	PRINT_INFO ("DSTAT : %02x  CSTAT: %02x  CPA: %04x\n",stat->dstat,stat->cstat,stat->cpa);
+	PRINT_INFO ("DEVICE: %04x\n",td->devinfo.devno);
+	if(TAPE_BUSY(td))
+		PRINT_INFO("OP    : %s\n",tape_op_verbose[tape_get_active_ccw_req(td)->op]);
+		
 	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],
@@ -706,215 +1576,203 @@
 		    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]);
-#endif
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"SENSE:");
-        for (sl=0;sl<31;sl++) {
-            debug_int_event (tape_debug_area,3,stat->ii.sense.data[sl]);
-        }
-        debug_int_exception (tape_debug_area,3,stat->ii.sense.data[31]);
+	PRINT_INFO ("--------------------------------------------------\n");
 #endif
 }
 
+/*******************************************************************
+ * TAPE Discipline functions
+ *******************************************************************/
+
 /*
- * Setup tape_info_t structure of a tape device
+ * Register backend discipline
  */
+
 int
-tape_setup (tape_info_t * ti, int irq, int minor)
+tape_register_discipline(tape_discipline_t *disc)
 {
+        tape_discipline_t *disc_ptr;
 	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;
+        disc->next = NULL;
+
+	write_lock_irqsave(&tape_discipline_lock,lockflags);
+
+        if (tape_first_disc == NULL) {
+            tape_first_disc = disc;
+        } else {
+                for(disc_ptr = tape_first_disc; disc_ptr->next!=NULL; disc_ptr=(tape_discipline_t*)disc_ptr->next);
+                disc_ptr->next = disc;
         }
-	rc = get_dev_info_by_irq (irq, &(ti->devinfo));
-	if (rc == -ENODEV) {	/* end of device list */
-		return rc;
-	}
-	ti->rew_minor = minor;
-	ti->nor_minor = minor + 1;
-	ti->blk_minor = minor;
-#ifdef CONFIG_DEVFS_FS
-        tape_mkdevfsroots(ti);
-#endif
-	/* Register IRQ */
-#ifdef CONFIG_S390_TAPE_DYNAMIC
-        rc = s390_request_irq_special (irq, tape_irq, tape_noper_handler,0, "tape", &(ti->devstat));
-#else
-	rc = s390_request_irq (irq, tape_irq, 0, "tape", &(ti->devstat));
-#endif
-	s390irq_spin_lock_irqsave (irq, lockflags);
-	ti->next = NULL;
-	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);
-        ti->discdata=NULL;
-	ti->discipline->setup_assist (ti);
-        ti->wanna_wakeup=0;
-	s390irq_spin_unlock_irqrestore (irq, lockflags);
-	return rc;
+
+	tape_create_devs_for_disc(disc);
+	if(tape_autoprobe)
+		tape_create_devreg_for_disc(disc);
+
+	write_unlock_irqrestore(&tape_discipline_lock,lockflags);
+        return 0;
 }
 
 /*
- *      tape_init will register the driver for each tape.
+ * Unregister backend discipline
  */
-int
-tape_init (void)
+
+void 
+tape_unregister_discipline(tape_discipline_t* disc)
 {
+	tape_discipline_t* lastdisc;
 	long lockflags;
-	s390_dev_info_t dinfo;
-	tape_discipline_t *disc;
-	tape_info_t *ti = NULL, *tempti = NULL;
-        char *opt_char,*opt_block,*opt_3490,*opt_3480;
-	int irq = 0, rc, retries = 0, tape_num = 0;
-        static int initialized=0;
 
-        if (initialized) // Only init the devices once
-            return 0;
-        initialized=1;
+	write_lock_irqsave(&tape_discipline_lock,lockflags);
 
-#ifdef TAPE_DEBUG
-        tape_debug_area = debug_register ( "tape", 3, 2, 10);
-        debug_register_view(tape_debug_area,&debug_hex_ascii_view);
-        debug_text_event (tape_debug_area,3,"begin init");
-#endif /* TAPE_DEBUG */
+	tape_delete_devs_for_disc(disc);
+	if(tape_autoprobe)
+		tape_delete_devreg_for_disc(disc);
+
+	if (disc==tape_first_disc) {
+		tape_first_disc=disc->next;
+        } else {
+		lastdisc=tape_first_disc;
+		while (lastdisc->next!=disc) lastdisc=lastdisc->next;
+		lastdisc->next=disc->next;
+	}
+	
+	disc->shutdown();
+
+	write_unlock_irqrestore(&tape_discipline_lock,lockflags);
+}
+
+/*
+ * Cleanup all registered disciplines
+ */
+
+static inline void
+tape_cleanup_disciplines (void) 
+{
+        long lockflags;
+        tape_discipline_t* disc;
+	/* Unregister all backend disciplines - this also deletes the devices */
+
+	write_lock_irqsave(&tape_discipline_lock,lockflags);
+        disc=tape_first_disc;
+        while (disc != NULL) {
+		write_unlock_irqrestore(&tape_discipline_lock,lockflags);
+		tape_unregister_discipline(disc);
+		kfree(disc);
+		write_lock_irqsave(&tape_discipline_lock,lockflags);
+		disc=tape_first_disc; 
+        }
+	write_unlock_irqrestore(&tape_discipline_lock,lockflags);
+}
+
+
+/*******************************************************************
+ * TAPE Init Functions
+ *******************************************************************/
+
+/*
+ *      tape_print_banner will be called on initialisation and print a nice banner
+ */
+
+static inline void 
+tape_print_banner (void) 
+{
+        char *opt_char,*opt_block;
 
         /* print banner */        
-        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";
+        PRINT_WARN ("IBM zSeries Tape Device Driver (v%d.%02d).\n",TAPE_VERSION_MAJOR,TAPE_VERSION_MINOR);
+        PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000 - 2001\n");
+        opt_char=opt_block="not present";
 #ifdef CONFIG_S390_TAPE_CHAR
         opt_char="built in";
 #endif
 #ifdef CONFIG_S390_TAPE_BLOCK
         opt_block="built in";
 #endif
-#ifdef CONFIG_S390_TAPE_3480
-        opt_3480="built in";
-#endif
-#ifdef CONFIG_S390_TAPE_3490
-        opt_3490="built in";
-#endif
         /* print feature info */
         PRINT_WARN ("character device frontend   : %s\n",opt_char);
         PRINT_WARN ("block device frontend       : %s\n",opt_block);
-        PRINT_WARN ("support for 3480 compatible : %s\n",opt_3480);
-        PRINT_WARN ("support for 3490 compatible : %s\n",opt_3490);
-        
+}
+
+/*
+ *      tape_init will register the driver for each tape.
+ */
+
+int
+tape_init (void)
+{
+        static int initialized=0;
+
+        if (initialized) // Only init the devices once
+            return 0;
+        initialized=1;
+
+	tape_init_devregs();
+#ifdef TAPE_DEBUG
+        tape_dbf_area = debug_register ( "tape", 2, 2, 3*sizeof(long));
+        debug_register_view(tape_dbf_area,&debug_sprintf_view);
+        tape_sprintf_event (tape_dbf_area,3,"begin init\n");
+#endif /* TAPE_DEBUG */
+	tape_print_banner();
 #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
-        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) {
-            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 {
-            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
 #ifdef CONFIG_DEVFS_FS
         tape_devfs_root_entry=devfs_mk_dir (NULL, "tape", NULL);
-#endif CONFIG_DEVFS_FS
+#endif /* CONFIG_DEVFS_FS */
 
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"dev detect");
-#endif /* TAPE_DEBUG */
+        tape_sprintf_event (tape_dbf_area,3,"dev detect\n");
 	/* Allocate the tape structures */
-        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);
-		disc = first_discipline;
-		while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
-                    disc = (tape_discipline_t *) (disc->next);
-		if ((disc == NULL) || (rc == -ENODEV))
-                    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;
-                    }
-                    tape_num += 2;
-                    s390irq_spin_unlock_irqrestore (irq, lockflags);
-		}
-            }
-        }
-            
-	/* Allocate local buffer for the ccwcache       */
-	tape_init_emergency_req ();
+        if (*tape!=NULL) { /* if parameters are present */
+		PRINT_INFO ("Using ranges supplied in parameters, disabling autoprobe mode.\n");
+		tape_parm_parse (tape);
+		tape_autoprobe = 0;
+	} else {
+		PRINT_INFO ("No parameters supplied, enabling autoprobe mode for all supported devices.\n");
+		tape_autoprobe = 1;
+	}
 #ifdef CONFIG_PROC_FS
-	tape_devices_entry = create_proc_entry ("tapedevices",
-						S_IFREG | S_IRUGO | S_IWUSR,
-						&proc_root);
-	tape_devices_entry->proc_fops = &tape_devices_file_ops;
+	tape_proc_init();
 #endif /* CONFIG_PROC_FS */
+#ifdef  CONFIG_S390_TAPE_3480 
+	tape_register_discipline(tape3480_init());
+#else
+#ifndef CONFIG_S390_TAPE
+	tape_request_module("tape_3480_mod");
+#endif
+#endif /* CONFIG_S390_TAPE_3480 */
+
+#ifdef CONFIG_S390_TAPE_3490
+        tape_register_discipline(tape3490_init());
+#else
+#ifndef CONFIG_S390_TAPE
+        tape_request_module("tape_3490_mod");
+#endif
+#endif /* CONFIG_S390_TAPE_3490 */
 
+#ifdef CONFIG_S390_TAPE_3590
+        tape_register_discipline(tape3590_init());
+#else
+#ifndef CONFIG_S390_TAPE
+        tape_request_module("tape_3590_mod");
+#endif
+#endif /* CONFIG_S390_TAPE_3590 */
 	return 0;
 }
 
+/*******************************************************************
+ * TAPE Module functions
+ *******************************************************************/
+
 #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_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and Michael Holzheu (cotte@de.ibm.com,holzheu@de.ibm.com)");
+MODULE_DESCRIPTION("Linux on zSeries channel attached tape device driver");
 MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s");
 
+/*
+ * The famous init_module
+ */
+
 int
 init_module (void)
 {
@@ -927,161 +1785,128 @@
         return 0;
 }
 
-void
-cleanup_module (void)
+/*
+ * Cleanup the frontends
+ */
+static inline void
+tape_cleanup_frontends(void) 
 {
-        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 */
 
-        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:");
-                debug_int_event (tape_debug_area,6,temp->devinfo.irq);
-#endif /* TAPE_DEBUG */
-		free_irq (temp->devinfo.irq, &(temp->devstat));
-                if (temp->discdata) kfree (temp->discdata);
-                if (temp->kernbuf) kfree (temp->kernbuf);
-                if (temp->cqr) tape_free_request(temp->cqr);
-#ifdef CONFIG_DEVFS_FS
-                for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next)
-                    frontend->rmdevfstree(temp);
-                tape_rmdevfsroots(temp);
-#endif
-		kfree (temp);
-	}
-#ifdef CONFIG_DEVFS_FS
-        devfs_unregister (tape_devfs_root_entry);
-#endif CONFIG_DEVFS_FS
-#ifdef CONFIG_PROC_FS
-	remove_proc_entry ("tapedevices", &proc_root);
-#endif 
+	/* Now get rid of the frontends */
 #ifdef CONFIG_S390_TAPE_CHAR
 	tapechar_uninit();
 #endif
 #ifdef CONFIG_S390_TAPE_BLOCK
         tapeblock_uninit();
 #endif
-        frontend=first_frontend;
+        frontend=tape_first_front;
 	while (frontend != NULL) {
 		tempfe = frontend;
 		frontend = frontend->next;
 		kfree (tempfe);
 	}
-        disc=first_discipline;
-	while (disc != NULL) {
-                if (*tape)
-                    disc->shutdown(0);
-                else
-                    disc->shutdown(1);
-		tempdi = disc;
-		disc = disc->next;
-		kfree (tempdi);
-	}
-	/* Deallocate the local buffer for the ccwcache         */
-	tape_cleanup_emergency_req ();
+}
+
+
+/*
+ * Cleanup module
+ */
+
+void
+cleanup_module (void)
+{
+        tape_sprintf_event (tape_dbf_area,6,"cleaup mod");
+	tape_cleanup_disciplines();
+#ifdef CONFIG_DEVFS_FS
+	devfs_unregister (tape_devfs_root_entry); /* devfs checks for NULL */
+#endif CONFIG_DEVFS_FS
+#ifdef CONFIG_PROC_FS
+	tape_proc_cleanup();
+#endif 
+	tape_cleanup_frontends();
+	/* Deallocate devregs in case of not autoprobe */
+	if(!tape_autoprobe)
+		tape_delete_all_devregs();
 #ifdef TAPE_DEBUG
-        debug_unregister (tape_debug_area);
+        debug_unregister (tape_dbf_area);
 #endif /* TAPE_DEBUG */
 }
 #endif				/* MODULE */
 
+
+/*******************************************************************
+ * TAPE Tapestate functions
+ *******************************************************************/
+
 inline void
-tapestate_set (tape_info_t * ti, int newstate)
+tape_state_set (tape_dev_t * td, tape_state_t newstate)
 {
-    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");
-#endif /* TAPE_DEBUG */
+    if (td->tape_state == TS_NOT_OPER) {
+        tape_sprintf_event(tape_dbf_area,3,"ts_set err: not oper\n");
     } else {
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,4,"ts. dev:  ");
-        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 (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) &&
+        tape_sprintf_event(tape_dbf_area,4,"ts. dev:  %x\n",td->first_minor);
+        tape_sprintf_event(tape_dbf_area,4,"old ts:   %s\n",(((tape_state_get (td) < TO_SIZE) && (tape_state_get (td) >=0 )) ?  tape_state_verbose[tape_state_get (td)] : "UNKNOWN TS"));
+        tape_sprintf_event(tape_dbf_area,4,"%s\n", 
+			(((tape_state_get (td) < TO_SIZE) &&
+			(tape_state_get (td) >=0 )) ?
+			tape_state_verbose[tape_state_get (td)] :
+			"UNKNOWN TS"));
+        tape_sprintf_event (tape_dbf_area,4,"new ts:   \n");
+        tape_sprintf_event (tape_dbf_area,4,"%s\n",(((newstate < TO_SIZE) &&
                                               (newstate >= 0)) ?
-                                             state_verbose[newstate] :
+                                             tape_state_verbose[newstate] :
                                              "UNKNOWN TS"));
-#endif /* TAPE_DEBUG */
-	ti->tape_state = newstate;
+	td->tape_state = newstate;
     }
 }
 
-inline int
-tapestate_get (tape_info_t * ti)
+inline tape_state_t
+tape_state_get (tape_dev_t * td)
 {
-	return (ti->tape_state);
+	return (td->tape_state);
 }
 
-void
-tapestate_event (tape_info_t * ti, int event)
+inline void
+tape_med_state_set(tape_dev_t * td, tape_medium_state_t newstate)
 {
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"te! dev:  ");
-        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(ti) >= 0) &&
-                                            (tapestate_get(ti) < TS_SIZE)) ?
-                         state_verbose[tapestate_get (ti)] :
-                         "TS UNKNOWN");
-#endif /* TAPE_DEBUG */    
-        if (event == TE_ERROR) { 
-            ti->discipline->error_recovery(ti);
-        } else {
-            if ((event >= 0) &&
-                (event < TE_SIZE) &&
-                (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 */
-		ti->discipline->default_handler (ti);
-            }
-        }
-}
-
-/*
- * 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:
- */
+	if(td->medium_state == newstate)
+		goto out;
+	switch(newstate){
+		case MS_UNLOADED:
+			PRINT_INFO("(%x): Tape is unloaded\n",td->devstat.devno);
+			break;
+		case MS_LOADED:
+			PRINT_INFO("(%x): Tape has been mounted\n",td->devstat.devno);
+			break;
+		default:
+			// print nothing
+			break;
+	}
+	td->medium_state = newstate;
+out:
+	return;
+}
+	
+
+/*******************************************************************
+ * TAPE Exported Functions 
+ *******************************************************************/
+
+EXPORT_SYMBOL(tape_register_discipline);
+EXPORT_SYMBOL(tape_unregister_discipline);
+EXPORT_SYMBOL(tape_dbf_area);
+EXPORT_SYMBOL(tape_alloc_ccw_req);
+EXPORT_SYMBOL(tape_free_ccw_req); 
+EXPORT_SYMBOL(tape_state_set);
+EXPORT_SYMBOL(tape_state_get);
+EXPORT_SYMBOL(tape_med_state_set);
+EXPORT_SYMBOL(tape_state_verbose);
+EXPORT_SYMBOL(tape_op_verbose);
+EXPORT_SYMBOL(tape_dump_sense);
+EXPORT_SYMBOL(tape_dump_sense_dbf);
+EXPORT_SYMBOL(tape_do_io);
+EXPORT_SYMBOL(tape_do_io_irq);
+EXPORT_SYMBOL(tape_do_io_and_wait);
+EXPORT_SYMBOL(tape_remove_ccw_req);
+EXPORT_SYMBOL(tape_get_active_ccw_req);
diff -Nru a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
--- a/drivers/s390/char/tape.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/tape.h	Sat Jun  8 22:31:51 2002
@@ -1,7 +1,7 @@
 /***************************************************************************
  *
  *  drivers/s390/char/tape.h
- *    tape device driver for 3480/3490E tapes.
+ *    tape device driver for 3480/3490E/3590 tapes.
  *
  *  S390 and zSeries version
  *    Copyright (C) 2001 IBM Corporation
@@ -12,192 +12,368 @@
  */
 
 #ifndef _TAPE_H
-
 #define _TAPE_H
+
 #include <linux/config.h>
 #include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/mtio.h>
+#include <asm/debug.h>
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+#include "tape_idalbuf.h"
 
-#define  MAX_TAPES                     7        /* Max tapes supported is 7*/
-#define TAPE_MAGIC 0xE3C1D7C5       /* is ebcdic-"TAPE" */
+#define TAPE_VERSION_MAJOR 1
+#define TAPE_VERSION_MINOR 10
+#define TAPE_MAGIC "tape"
+#define TAPE_BUSY(td) (td->treq != NULL)
+#define TAPE_MINORS_PER_DEV 2       /* two minors per device */
+
+#define TAPE_MERGE_RC(treq,rc) \
+	if( ((rc) == 0) && ((treq)->rc != 0) ) \
+		rc = (treq)->rc;
+
+typedef enum{
+	TAPE_NO_WAIT,
+	TAPE_WAIT,
+	TAPE_WAIT_INTERRUPTIBLE,
+	TAPE_WAIT_INTERRUPTIBLE_NOHALTIO,
+	TAPE_REMOVE_REQ_ON_WAKEUP,
+	TAPE_SCHED_BLOCK,
+} tape_wait_t;
 
 typedef enum {
-    TS_UNUSED=0, TS_IDLE, TS_DONE, TS_FAILED,
-    TS_BLOCK_INIT,
-    TS_BSB_INIT,
-    TS_BSF_INIT,
-    TS_DSE_INIT,
-    TS_EGA_INIT,
-    TS_FSB_INIT,
-    TS_FSF_INIT,
-    TS_LDI_INIT,
-    TS_LBL_INIT,
-    TS_MSE_INIT,
-    TS_NOP_INIT,
-    TS_RBA_INIT,
-    TS_RBI_INIT,
-    TS_RBU_INIT,
-    TS_RBL_INIT,
-    TS_RDC_INIT,
-    TS_RFO_INIT,
-    TS_RSD_INIT,
-    TS_REW_INIT,
-    TS_REW_RELEASE_INIT,
-    TS_RUN_INIT,
-    TS_SEN_INIT,
-    TS_SID_INIT,
-    TS_SNP_INIT,
-    TS_SPG_INIT,
-    TS_SWI_INIT,
-    TS_SMR_INIT,
-    TS_SYN_INIT,
-    TS_TIO_INIT,
-    TS_UNA_INIT,
-    TS_WRI_INIT,
-    TS_WTM_INIT,
-    TS_NOT_OPER,
-    TS_SIZE } tape_stat;
-
-struct _tape_info_t; //Forward declaration
+	MS_UNKNOWN,
+	MS_LOADED,
+	MS_UNLOADED,
+	MS_SIZE
+} tape_medium_state_t;
 
 typedef enum {
-    TE_START=0, TE_DONE, TE_FAILED, TE_ERROR, TE_OTHER,
-    TE_SIZE } tape_events;
+	TS_UNUSED=0,
+	TS_IN_USE,
+	TS_INIT,
+	TS_NOT_OPER,
+	TS_SIZE
+} tape_state_t;
 
-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* 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*);
+typedef enum {
+	TO_BLOCK,
+	TO_BSB,
+	TO_BSF,
+	TO_DSE,
+	TO_EGA,
+	TO_FSB,
+	TO_FSF,
+	TO_LDI,
+	TO_LBL,
+	TO_MSE,
+	TO_NOP,
+	TO_RBA,
+	TO_RBI,
+	TO_RBU,
+	TO_RBL,
+	TO_RDC,
+	TO_RFO,
+	TO_RSD,
+	TO_REW,
+	TO_RUN,
+	TO_SEN,
+	TO_SID,
+	TO_SNP,
+	TO_SPG,
+	TO_SWI,
+	TO_SMR,
+	TO_SYN,
+	TO_TIO,
+	TO_UNA,
+	TO_WRI,
+	TO_WTM,
+	TO_MSEN,
+	TO_LOAD,
+	TO_READ_CONFIG, /* 3590 */
+	TO_READ_ATTMSG, /* 3590 */
+	TO_NOTHING,
+	TO_DIS,
+	TO_SIZE
+} tape_op_t;
+
+#define TAPE_INTERRUPTIBLE_OP(op) \
+	(op == MTEOM) || \
+	(op == MTRETEN)
+
+struct _tape_dev_t; //Forward declaration
+
+/* The tape device list lock */
+extern rwlock_t   tape_dev_lock;
+
+/* Tape CCW request */
+ 
+typedef struct _tape_ccw_req_t{
+	wait_queue_head_t wq;
+	ccw1_t*           cpaddr;
+	size_t            cplength;
+	int               options;
+	void*             kernbuf;
+	size_t            kernbuf_size;
+	idalbuf_t*        idal_buf;
+	void*             userbuf;
+	size_t            userbuf_size; 
+	tape_op_t op;
+	void   (*wakeup)(struct _tape_ccw_req_t* treq);
+	void   (*wait)(struct _tape_ccw_req_t* treq);
+        struct _tape_dev_t* tape_dev;  // Pointer for back reference
+	int rc;
+	struct _tape_ccw_req_t* recover;
+} tape_ccw_req_t;
+
+/* Callback typedefs */
+
+typedef void (*tape_disc_shutdown_t) (void);
+typedef void (*tape_event_handler_t) (struct _tape_dev_t*);
+typedef tape_ccw_req_t* (*tape_reqgen_ioctl_t)(struct _tape_dev_t* td,int op,int count,int* rc);
+typedef tape_ccw_req_t* (*tape_reqgen_bread_t)(struct request* req,struct _tape_dev_t* td,int tapeblock_major);
+typedef void (*tape_reqgen_enable_loc_t) (tape_ccw_req_t*);
+typedef void (*tape_free_bread_t)(tape_ccw_req_t*);
+typedef tape_ccw_req_t* (*tape_reqgen_rw_t)(const char* data,size_t count,struct _tape_dev_t* td);
+typedef int (*tape_setup_device_t) (struct _tape_dev_t*);
+typedef void (*tape_cleanup_device_t) (struct _tape_dev_t*);
+typedef int (*tape_disc_ioctl_overl_t)(struct _tape_dev_t*, unsigned int,unsigned long);
 #ifdef CONFIG_DEVFS_FS
-typedef void (*tape_devfs_handler_t) (struct _tape_info_t*);
+typedef devfs_handle_t (*tape_devfs_constructor_t) (struct _tape_dev_t*);
+typedef void (*tape_devfs_destructor_t) (struct _tape_dev_t*);
 #endif
-typedef tape_event_handler_t tape_event_table_t[TS_SIZE][TE_SIZE];
+
+/* Tape Discipline */
+
 typedef struct _tape_discipline_t {
-    unsigned int cu_type;
-    tape_setup_assist_t setup_assist;
-    tape_event_handler_t error_recovery;
-    tape_reqgen_t bread;
-    tape_freeblock_t free_bread;
-    tape_rwblock_t write_block;
-    tape_freeblock_t free_write_block;
-    tape_rwblock_t read_block;
-    tape_freeblock_t free_read_block;
-    tape_ccwgen_t mtfsf;
-    tape_ccwgen_t mtbsf;
-    tape_ccwgen_t mtfsr;
-    tape_ccwgen_t mtbsr;
-    tape_ccwgen_t mtweof;
-    tape_ccwgen_t mtrew;
-    tape_ccwgen_t mtoffl;
-    tape_ccwgen_t mtnop;
-    tape_ccwgen_t mtbsfm;
-    tape_ccwgen_t mtfsfm;
-    tape_ccwgen_t mteom;
-    tape_ccwgen_t mterase;
-    tape_ccwgen_t mtsetdensity;
-    tape_ccwgen_t mtseek;
-    tape_ccwgen_t mttell;
-    tape_ccwgen_t mtsetdrvbuffer;
-    tape_ccwgen_t mtlock;
-    tape_ccwgen_t mtunlock;
-    tape_ccwgen_t mtload;
-    tape_ccwgen_t mtunload;
-    tape_ccwgen_t mtcompression;
-    tape_ccwgen_t mtsetpart;
-    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;
-    struct _tape_info_t* tape; /* pointer for backreference */
-    void* next;
+	struct module               *owner;
+	unsigned int                cu_type;
+	tape_setup_device_t         setup_device;
+	tape_cleanup_device_t       cleanup_device;
+	tape_event_handler_t        init_device;
+	tape_event_handler_t        process_eov;
+	tape_event_handler_t        irq;
+	tape_reqgen_bread_t         bread;
+	tape_free_bread_t           free_bread;
+	tape_reqgen_enable_loc_t    bread_enable_locate;
+	tape_reqgen_rw_t            write_block;
+	tape_reqgen_rw_t            read_block;
+	tape_reqgen_ioctl_t         ioctl;
+	tape_disc_shutdown_t        shutdown;
+	tape_disc_ioctl_overl_t     discipline_ioctl_overload;
+	void*                       next;
 } tape_discipline_t  __attribute__ ((aligned(8)));
 
+/* Frontend */
+
 typedef struct _tape_frontend_t {
-    tape_setup_assist_t device_setup;
+	tape_setup_device_t device_setup;
 #ifdef CONFIG_DEVFS_FS
-    tape_devfs_handler_t mkdevfstree;
-    tape_devfs_handler_t rmdevfstree;
+	tape_devfs_constructor_t mkdevfstree;
+	tape_devfs_destructor_t rmdevfstree;
 #endif
-    void* next;
+	void* next;
 } tape_frontend_t  __attribute__ ((aligned(8)));
 
+/* Char Frontend Data */
 
-typedef struct _tape_info_t {
-    wait_queue_head_t wq;
-    s390_dev_info_t devinfo;             /* device info from Common I/O */
-    int     wanna_wakeup;
-    int     rew_minor;                  /* minor number for the rewinding tape */
-    int     nor_minor;                  /* minor number for the nonrewinding tape */
-    int     blk_minor;                  /* minor number for the block device */
-    devstat_t devstat;	           /* contains irq, devno, status */
-    size_t  block_size;             /* block size of tape        */
-    int    drive_type;              /* Code indicating type of drive */
-    struct file *rew_filp;	           /* backpointer to file structure */
-    struct file *nor_filp;
-    struct file *blk_filp;
-    int tape_state;  /* State of the device. See tape_stat */
-    int rc;          /* Return code. */
-    tape_discipline_t* discipline;
-    request_queue_t request_queue;
-    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;
-#ifdef CONFIG_DEVFS_FS
-    devfs_handle_t devfs_dir;             /* devfs handle for tape/DEVNO directory */
-    devfs_handle_t devfs_char_dir;        /* devfs handle for tape/DEVNO/char directory */
-    devfs_handle_t devfs_block_dir;       /* devfs handle for tape/DEVNO/block directory */
-    devfs_handle_t devfs_nonrewinding;    /* devfs handle for tape/DEVNO/char/nonrewinding device */
-    devfs_handle_t devfs_rewinding;       /* devfs handle for tape/DEVNO/char/rewinding device */
-    devfs_handle_t devfs_disc;            /* devfs handle for tape/DEVNO/block/disc device */
-#endif
-    void* discdata;
-    void* kernbuf;
-    void* userbuf;
-    void*  next;
-} tape_info_t  __attribute__ ((aligned(8)));
+typedef struct _tape_char_front_data_t{
+	int     block_size;               /* block size of tape */
+#ifdef CONFIG_DEVFS_FS
+	devfs_handle_t devfs_char_dir;    /* tape/DEVNO/char dir */
+	devfs_handle_t devfs_nonrewinding;/* tape/DEVNO/char/nonrewinding */
+	devfs_handle_t devfs_rewinding;   /* tape/DEVNO/char/rewinding */
+#endif /* CONFIG_DEVFS_FS */
+} tape_char_data_t;
+
+/* Block Frontend Data */
+
+typedef struct _tape_blk_front_data_t{
+	request_queue_t request_queue;
+	struct request* current_request;
+	int blk_retries;
+	long position;
+	atomic_t bh_scheduled;
+	struct tq_struct bh_tq;
+#ifdef CONFIG_DEVFS_FS
+	devfs_handle_t devfs_block_dir;    /* tape/DEVNO/block dir */
+	devfs_handle_t devfs_disc;         /* tape/DEVNO/block/disc */
+#endif /* CONFIG_DEVFS_FS */
+} tape_blk_data_t;
+
+/* Tape Info */
+ 
+typedef struct _tape_dev_t {
+	atomic_t use_count;            /* Reference count, when == 0 delete */
+	int      first_minor;          /* each tape device has two minors */
+	s390_dev_info_t devinfo;       /* device info from Common I/O */
+	devstat_t devstat;             /* contains irq, devno, status */
+	struct file *filp;             /* backpointer to file structure */
+	int tape_state;                /* State of the device. See tape_stat */
+	int medium_state;              /* loaded, unloaded, unkown etc. */
+	tape_discipline_t* discipline; /* The used discipline */
+	void* discdata;                /* discipline specific data */
+	tape_ccw_req_t* treq;          /* Active Tape request */
+	tape_op_t last_op;             /* Last Tape operation */
+	void*  next;                   /* ptr to next tape_dev */
+#ifdef CONFIG_DEVFS_FS
+	devfs_handle_t devfs_dir;      /* toplevel devfs dir */
+#endif /* CONFIG_DEVFS_FS */
+	tape_char_data_t  char_data;   /* Character dev frontend data */
+	tape_blk_data_t   blk_data;    /* Block dev frontend data */
+} tape_dev_t  __attribute__ ((aligned(8)));
+
+/* tape functions */
+
+#define TAPE_MEMB_IRQ       0
+#define TAPE_MEMB_MINOR     1
+#define TAPE_MEMB_QUEUE     2
 
-/* tape initialisation functions */
-int tape_init(void);
-int tape_setup (tape_info_t * ti, int irq, int minor);
+tape_dev_t* __tape_get_device_by_member(unsigned long value, int member);
 
-/* functoins for alloc'ing ccw stuff */
-inline  ccw_req_t * tape_alloc_ccw_req (tape_info_t* ti, int cplength, int datasize);
-void tape_free_request (ccw_req_t * request);
+/*
+ * Search for tape structure with specific minor number
+ */
+ 
+static inline tape_dev_t *
+tape_get_device_by_minor(int minor)
+{
+        return __tape_get_device_by_member(minor, TAPE_MEMB_MINOR);
+}
 
-/* a function for dumping device sense info */
-void tape_dump_sense (devstat_t * stat);
+/*
+ * Search for tape structure with specific IRQ
+ */
+ 
+static inline tape_dev_t *
+tape_get_device_by_irq(int irq)
+{
+        return __tape_get_device_by_member(irq, TAPE_MEMB_IRQ);
+}
 
-#ifdef CONFIG_S390_TAPE_DYNAMIC
-/* functions for dyn. dev. attach/detach */
-int tape_oper_handler ( int irq, struct _devreg *dreg);
-#endif
+/*
+ * Search for tape structure with specific queue
+ */
 
-/* functions for handling the status of a device */
-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];
+static inline tape_dev_t*
+tape_get_device_by_queue(void* queue)
+{
+	return __tape_get_device_by_member((unsigned long)queue, TAPE_MEMB_QUEUE);
+}
 
-/****************************************************************************/
+/*
+ * Increment use count of tape structure
+ */
+ 
+static inline void
+tape_get_device(tape_dev_t* td)
+{
+        if (td!=NULL)
+                atomic_inc(&(td->use_count));
+}
+
+void tape_put_device(tape_dev_t* td);
+
+/* Discipline functions */
+int tape_register_discipline(tape_discipline_t* disc);
+void tape_unregister_discipline(tape_discipline_t* disc);
 
-/* Some linked lists for storing plugins and devices */
-extern tape_info_t *first_tape_info;
-extern tape_discipline_t *first_discipline;
-extern tape_frontend_t *first_frontend;
+/* tape initialisation functions */
+int tape_init(void);
+
+/* a function for dumping device sense info */
+void tape_dump_sense (tape_dev_t* td);
+void tape_dump_sense_dbf(tape_dev_t* td);
+ 
+/* functions for handling the status of a device */
+inline void tape_state_set (tape_dev_t* td, tape_state_t newstate);
+inline tape_state_t tape_state_get (tape_dev_t* td);
+inline void tape_med_state_set(tape_dev_t* td, tape_medium_state_t newstate);
+
+/* functions for alloc'ing ccw and IO stuff */
+inline  tape_ccw_req_t* tape_alloc_ccw_req(int cplength,int datasize,int idal_buf_size, tape_op_t op);
+void tape_free_ccw_req (tape_ccw_req_t * request);
+int tape_do_io(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type);
+int tape_do_io_irq(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type);
+int tape_do_io_and_wait(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type);
+int tape_do_wait_req(tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type);
+int tape_remove_ccw_req(tape_dev_t* td,tape_ccw_req_t* treq);
+tape_ccw_req_t* tape_get_active_ccw_req(tape_dev_t* td);
 
 /* The debug area */
 #ifdef TAPE_DEBUG
-extern debug_info_t *tape_debug_area;
+        extern debug_info_t *tape_dbf_area;
+        #define tape_sprintf_event debug_sprintf_event
+        #define tape_sprintf_exception debug_sprintf_exception
+#else
+        #define tape_sprintf_event
+        #define tape_sprintf_exception
 #endif
+
+/* functions for building ccws */
+static inline ccw1_t* 
+__ccwprep(ccw1_t* ccw, __u8 cmd_code, __u8 flags, __u16 memsize, void* cda,int ccw_count)
+{
+	int i;
+#ifdef CONFIG_ARCH_S390X
+        if ((unsigned long)cda >= (1UL<<31)){
+                printk("cda: %p\n",cda);
+	        BUG();
+        }
+#endif /* CONFIG_ARCH_S390X */
+	for(i = 0 ; i < ccw_count; i++){
+        	ccw[i].cmd_code = cmd_code;
+		ccw[i].flags |= CCW_FLAG_CC;
+		ccw[i].count = memsize;
+		if(cda == 0)
+			ccw[i].cda = (unsigned long)&(ccw[i].cmd_code);
+		else
+			ccw[i].cda = (unsigned long)cda;
+	}
+        ccw[ccw_count-1].flags = flags;
+	return &ccw[ccw_count];
+};
+
+extern inline ccw1_t*
+tape_ccw_cc(ccw1_t *ccw,__u8 cmd_code,__u16 memsize,void* cda,int ccw_count)
+{
+        return __ccwprep(ccw,cmd_code,CCW_FLAG_CC,memsize,cda,ccw_count);
+}
+ 
+extern inline ccw1_t*
+tape_ccw_end(ccw1_t *ccw,__u8 cmd_code,__u16 memsize,void* cda,int ccw_count)
+{
+        return __ccwprep(ccw,cmd_code,0,memsize,cda,ccw_count);
+}
+
+extern inline ccw1_t*
+tape_ccw_cc_idal(ccw1_t *ccw,__u8 cmd_code,idalbuf_t* idal)
+{
+	ccw->cmd_code = cmd_code;
+	ccw->flags    = CCW_FLAG_CC;
+	idalbuf_set_normalized_cda(ccw,idal);
+	return ccw++;
+}
+
+extern inline ccw1_t*
+tape_ccw_end_idal(ccw1_t *ccw,__u8 cmd_code,idalbuf_t* idal)
+{
+        ccw->cmd_code = cmd_code;
+        ccw->flags    = 0;
+        idalbuf_set_normalized_cda(ccw,idal);
+        return ccw++;
+}
+
+/* Global vars */
+extern const char* tape_state_verbose[TS_SIZE];
+extern const char* tape_op_verbose[TO_SIZE];
+
+/* Some linked lists for storing plugins and devices */
+extern tape_dev_t *tape_first_dev;
+extern tape_frontend_t *tape_first_front;
 
 #endif /* for ifdef tape.h */
diff -Nru a/drivers/s390/char/tape3480.c b/drivers/s390/char/tape3480.c
--- a/drivers/s390/char/tape3480.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/tape3480.c	Sat Jun  8 22:31:36 2002
@@ -13,144 +13,84 @@
 
 #include "tapedefs.h"
 #include <linux/version.h>
-#include <asm/ccwcache.h>	/* CCW allocations      */
-#include <asm/s390dyn.h>
-#include <asm/debug.h>
 #include <linux/compatmac.h>
 #include "tape.h"
 #include "tape34xx.h"
 #include "tape3480.h"
 
-tape_event_handler_t tape3480_event_handler_table[TS_SIZE][TE_SIZE] =
-{
-    /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
-	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
-	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
-	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
-	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
-	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},		/* TS_RBA_INIT */
-	{NULL, tape34xx_rbi_init_done, NULL, NULL, NULL},	/* TS_RBI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SPG_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SWI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SMR_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
-        {NULL, NULL, NULL, NULL, NULL}};     /* TS_NOT_OPER */
-
-devreg_t tape3480_devreg = {
-    ci:
-    {hc:
-     {ctype:0x3480}},
-    flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS,
-    oper_func:tape_oper_handler
-};
+#ifdef CONFIG_S390_TAPE_3480_MODULE
+static tape_discipline_t* disc;
 
+void
+init_module(void)
+{
+        disc = tape3480_init();
+        if (disc!= NULL) 
+		tape_register_discipline(disc);
+}
 
 void
-tape3480_setup_assist (tape_info_t * ti)
+cleanup_module(void)
+{
+	if (disc!=NULL){
+		tape_unregister_discipline(disc);
+		kfree(disc);
+	}
+}
+#endif /* CONFIG_S390_TAPE_3480_MODULE */
+
+int
+tape3480_setup_device(tape_dev_t * td)
 {
 	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,ti->blk_minor);
-#endif /* TAPE_DEBUG */
-	while (data == NULL)
-		data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL);
+	tape_sprintf_event (tape_dbf_area,6,"3480 dsetup:  %x\n",td->first_minor);
+	data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL | GFP_DMA);
+	if(data == NULL)
+		return -1;
 	data->modeset_byte = 0x00;
-	ti->discdata = (void *) data;
+	td->discdata = (void *) data;
+	return 0;
 }
 
+void
+tape3480_cleanup_device(tape_dev_t * td)
+{
+	if(td->discdata){
+		kfree(td->discdata);
+		td->discdata = NULL;
+	}
+}
 
 void
-tape3480_shutdown (int autoprobe) {
-    if (autoprobe)
-	s390_device_unregister(&tape3480_devreg);
+tape3480_shutdown (void) {
 }
 
 tape_discipline_t *
-tape3480_init (int autoprobe)
+tape3480_init (void)
 {
 	tape_discipline_t *disc;
-#ifdef TAPE_DEBUG
-    debug_text_event (tape_debug_area,3,"3480 init");
-#endif /* TAPE_DEBUG */
-	disc = kmalloc (sizeof (tape_discipline_t), GFP_KERNEL);
+	tape_sprintf_event (tape_dbf_area,3,"3480 init\n");
+	disc = kmalloc (sizeof (tape_discipline_t), GFP_ATOMIC);
 	if (disc == NULL) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,3,"disc:nomem");
-#endif /* TAPE_DEBUG */
+	        tape_sprintf_exception (tape_dbf_area,3,"disc:nomem\n");
 		return disc;
 	}
+	disc->owner = THIS_MODULE;
 	disc->cu_type = 0x3480;
-	disc->setup_assist = tape3480_setup_assist;
-	disc->error_recovery = tape34xx_error_recovery;
+	disc->setup_device = tape3480_setup_device;
+	disc->cleanup_device = tape3480_cleanup_device;
+	disc->init_device = NULL;
+	disc->process_eov = tape34xx_process_eov;
+	disc->irq = tape34xx_irq;
 	disc->write_block = tape34xx_write_block;
-	disc->free_write_block = tape34xx_free_write_block;
 	disc->read_block = tape34xx_read_block;
-	disc->free_read_block = tape34xx_free_read_block;
-	disc->mtfsf = tape34xx_mtfsf;
-	disc->mtbsf = tape34xx_mtbsf;
-	disc->mtfsr = tape34xx_mtfsr;
-	disc->mtbsr = tape34xx_mtbsr;
-	disc->mtweof = tape34xx_mtweof;
-	disc->mtrew = tape34xx_mtrew;
-	disc->mtoffl = tape34xx_mtoffl;
-	disc->mtnop = tape34xx_mtnop;
-	disc->mtbsfm = tape34xx_mtbsfm;
-	disc->mtfsfm = tape34xx_mtfsfm;
-	disc->mteom = tape34xx_mteom;
-	disc->mterase = tape34xx_mterase;
-	disc->mtsetdensity = tape34xx_mtsetdensity;
-	disc->mtseek = tape34xx_mtseek;
-	disc->mttell = tape34xx_mttell;
-	disc->mtsetdrvbuffer = tape34xx_mtsetdrvbuffer;
-	disc->mtlock = tape34xx_mtlock;
-	disc->mtunlock = tape34xx_mtunlock;
-	disc->mtload = tape34xx_mtload;
-	disc->mtunload = tape34xx_mtunload;
-	disc->mtcompression = tape34xx_mtcompression;
-	disc->mtsetpart = tape34xx_mtsetpart;
-	disc->mtmkpart = tape34xx_mtmkpart;
-	disc->mtiocget = tape34xx_mtiocget;
-	disc->mtiocpos = tape34xx_mtiocpos;
+	disc->ioctl = tape34xx_ioctl;
 	disc->shutdown = tape3480_shutdown;
 	disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
-	disc->event_table = &tape3480_event_handler_table;
-	disc->default_handler = tape34xx_default_handler;
 	disc->bread = tape34xx_bread;
 	disc->free_bread = tape34xx_free_bread;
-	disc->tape = NULL;	/* pointer for backreference */
+	disc->bread_enable_locate = tape34xx_bread_enable_locate;
 	disc->next = NULL;
-	if (autoprobe)
-	    s390_device_register(&tape3480_devreg);
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,3,"3480 regis");
-#endif /* TAPE_DEBUG */
+	tape_sprintf_event (tape_dbf_area,3,"3480 regis\n");
 	return disc;
 }
diff -Nru a/drivers/s390/char/tape3480.h b/drivers/s390/char/tape3480.h
--- a/drivers/s390/char/tape3480.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/tape3480.h	Sat Jun  8 22:31:51 2002
@@ -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 (int);
+tape_discipline_t * tape3480_init (void);
 #endif // _TAPE3480_H
diff -Nru a/drivers/s390/char/tape3490.c b/drivers/s390/char/tape3490.c
--- a/drivers/s390/char/tape3490.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/s390/char/tape3490.c	Sat Jun  8 22:31:52 2002
@@ -13,144 +13,85 @@
 
 #include "tapedefs.h"
 #include <linux/version.h>
-#include <asm/ccwcache.h>	/* CCW allocations      */
-#include <asm/s390dyn.h>
-#include <asm/debug.h>
 #include <linux/compatmac.h>
 #include "tape.h"
 #include "tape34xx.h"
 #include "tape3490.h"
 
-tape_event_handler_t tape3490_event_handler_table[TS_SIZE][TE_SIZE] =
-{
-    /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
-	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
-	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
-	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
-	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
-	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},		/* TS_RBA_INIT */
-	{NULL, tape34xx_rbi_init_done, NULL, NULL, NULL},	/* TS_RBI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SPG_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SWI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SMR_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
-        {NULL, NULL, NULL, NULL, NULL}};     /* TS_NOT_OPER */
-
-devreg_t tape3490_devreg = {
-    ci:
-    {hc:
-     {ctype:0x3490}},
-    flag:DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS,
-    oper_func:tape_oper_handler
-};
+#ifdef CONFIG_S390_TAPE_3490_MODULE 
+static tape_discipline_t* disc;
 
 void
-tape3490_setup_assist (tape_info_t * ti)
+init_module(void)
+{
+        disc = tape3490_init();
+	if (disc!=NULL) 
+		tape_register_discipline(disc);
+}
+ 
+void
+cleanup_module(void)
+{
+	if (disc!=NULL){
+		tape_unregister_discipline(disc);
+		kfree(disc);
+	}
+}
+#endif /* CONFIG_S390_TAPE_3490_MODULE */
+
+int
+tape3490_setup_device (tape_dev_t * td)
 {
 	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,ti->blk_minor);
-#endif /* TAPE_DEBUG */
-	while (data == NULL)
-		data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL);
+	tape_sprintf_event (tape_dbf_area,1,"3490 dsetup: %x\n",td->first_minor);
+	data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL | GFP_DMA);
+	if(data == NULL)
+		return -1;
 	data->modeset_byte = 0x00;
-	ti->discdata = (void *) data;
+	td->discdata = (void *) data;
+	return 0;
 }
 
+void
+tape3490_cleanup_device(tape_dev_t * td)
+{
+	if(td->discdata){
+		kfree(td->discdata);
+		td->discdata = NULL;
+	}
+}
 
 void
-tape3490_shutdown (int autoprobe) {
-    if (autoprobe)
-	s390_device_unregister(&tape3490_devreg);
+tape3490_shutdown (void) {
 }
 
 
 tape_discipline_t *
-tape3490_init (int autoprobe)
+tape3490_init (void)
 {
 	tape_discipline_t *disc;
-#ifdef TAPE_DEBUG
-    debug_text_event (tape_debug_area,3,"3490 init");
-#endif /* TAPE_DEBUG */
-	disc = kmalloc (sizeof (tape_discipline_t), GFP_KERNEL);
+	tape_sprintf_event (tape_dbf_area,3,"3490 init\n");
+	disc = kmalloc (sizeof (tape_discipline_t), GFP_ATOMIC);
 	if (disc == NULL) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,3,"disc:nomem");
-#endif /* TAPE_DEBUG */
+	        tape_sprintf_exception (tape_dbf_area,3,"disc:nomem\n");
 		return disc;
 	}
+	disc->owner = THIS_MODULE;
 	disc->cu_type = 0x3490;
-	disc->setup_assist = tape3490_setup_assist;
-	disc->error_recovery = tape34xx_error_recovery;
+	disc->setup_device = tape3490_setup_device;
+	disc->cleanup_device = tape3490_cleanup_device;
+	disc->init_device = NULL;
+	disc->process_eov = tape34xx_process_eov;
+	disc->irq = tape34xx_irq;
 	disc->write_block = tape34xx_write_block;
-	disc->free_write_block = tape34xx_free_write_block;
 	disc->read_block = tape34xx_read_block;
-	disc->free_read_block = tape34xx_free_read_block;
-	disc->mtfsf = tape34xx_mtfsf;
-	disc->mtbsf = tape34xx_mtbsf;
-	disc->mtfsr = tape34xx_mtfsr;
-	disc->mtbsr = tape34xx_mtbsr;
-	disc->mtweof = tape34xx_mtweof;
-	disc->mtrew = tape34xx_mtrew;
-	disc->mtoffl = tape34xx_mtoffl;
-	disc->mtnop = tape34xx_mtnop;
-	disc->mtbsfm = tape34xx_mtbsfm;
-	disc->mtfsfm = tape34xx_mtfsfm;
-	disc->mteom = tape34xx_mteom;
-	disc->mterase = tape34xx_mterase;
-	disc->mtsetdensity = tape34xx_mtsetdensity;
-	disc->mtseek = tape34xx_mtseek;
-	disc->mttell = tape34xx_mttell;
-	disc->mtsetdrvbuffer = tape34xx_mtsetdrvbuffer;
-	disc->mtlock = tape34xx_mtlock;
-	disc->mtunlock = tape34xx_mtunlock;
-	disc->mtload = tape34xx_mtload;
-	disc->mtunload = tape34xx_mtunload;
-	disc->mtcompression = tape34xx_mtcompression;
-	disc->mtsetpart = tape34xx_mtsetpart;
-	disc->mtmkpart = tape34xx_mtmkpart;
-	disc->mtiocget = tape34xx_mtiocget;
-	disc->mtiocpos = tape34xx_mtiocpos;
+	disc->ioctl = tape34xx_ioctl;
 	disc->shutdown = tape3490_shutdown;
 	disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
-	disc->event_table = &tape3490_event_handler_table;
-	disc->default_handler = tape34xx_default_handler;
 	disc->bread = tape34xx_bread;
 	disc->free_bread = tape34xx_free_bread;
-	disc->tape = NULL;	/* pointer for backreference */
+	disc->bread_enable_locate = tape34xx_bread_enable_locate;
 	disc->next = NULL;
-	if (autoprobe)
-	    s390_device_register(&tape3490_devreg);
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,3,"3490 regis");
-#endif /* TAPE_DEBUG */
+	tape_sprintf_event (tape_dbf_area,3,"3490 regis\n");
 	return disc;
 }
diff -Nru a/drivers/s390/char/tape3490.h b/drivers/s390/char/tape3490.h
--- a/drivers/s390/char/tape3490.h	Sat Jun  8 22:31:52 2002
+++ b/drivers/s390/char/tape3490.h	Sat Jun  8 22:31:52 2002
@@ -1,4 +1,3 @@
-
 /***************************************************************************
  *
  *  drivers/s390/char/tape3490.h
@@ -20,5 +19,5 @@
 typedef struct _tape3490_disc_data_t {
     __u8 modeset_byte;
 } tape3490_disc_data_t  __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3490_init (int);
+tape_discipline_t * tape3490_init (void);
 #endif // _TAPE3490_H
diff -Nru a/drivers/s390/char/tape34xx.c b/drivers/s390/char/tape34xx.c
--- a/drivers/s390/char/tape34xx.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/tape34xx.c	Sat Jun  8 22:31:36 2002
@@ -6,6 +6,7 @@
  *  S390 and zSeries version
  *    Copyright (C) 2001 IBM Corporation
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Michael Holzheu <holzheu@de.ibm.com>
  *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
  ****************************************************************************
@@ -17,1805 +18,660 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <asm/types.h>
-#include <asm/uaccess.h>
-#include <linux/stat.h>
-#include <linux/proc_fs.h>
-#include <asm/ccwcache.h> 
-#include <asm/idals.h>  
-#ifdef CONFIG_S390_TAPE_DYNAMIC
-#include <asm/s390dyn.h>
-#endif
-#include <asm/debug.h>
 #include <linux/compatmac.h>
 #include "tape.h"
 #include "tape34xx.h"
+#include <asm/idals.h>
+#include <asm/ebcdic.h>
+#include <asm/tape390.h>
 
-#define PRINTK_HEADER "T34xx:"
+#define PRINTK_HEADER "T3xxx:"
 
-tape_event_handler_t tape34xx_event_handler_table[TS_SIZE][TE_SIZE] =
+/*
+ * Done Handler is called when dev stat = DEVICE-END (successfull operation)
+ */
+
+void tape34xx_done_handler(tape_dev_t* td)
 {
-    /* {START , DONE, FAILED, ERROR, OTHER } */
-	{NULL, tape34xx_unused_done, NULL, NULL, NULL},	/* TS_UNUSED */
-	{NULL, tape34xx_idle_done, NULL, NULL, NULL},	/* TS_IDLE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_DONE */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_FAILED */
-	{NULL, tape34xx_block_done, NULL, NULL, NULL},		/* TS_BLOCK_INIT */
-	{NULL, tape34xx_bsb_init_done, NULL, NULL, NULL},	/* TS_BSB_INIT */
-	{NULL, tape34xx_bsf_init_done, NULL, NULL, NULL},	/* TS_BSF_INIT */
-	{NULL, tape34xx_dse_init_done, NULL, NULL, NULL},	/* TS_DSE_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_EGA_INIT */
-	{NULL, tape34xx_fsb_init_done, NULL, NULL, NULL},	/* TS_FSB_INIT */
-	{NULL, tape34xx_fsf_init_done, NULL, NULL, NULL},	/* TS_FSF_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_LDI_INIT */
-	{NULL, tape34xx_lbl_init_done, NULL, NULL, NULL},	/* TS_LBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_MSE_INIT */
-	{NULL, tape34xx_nop_init_done, NULL, NULL, NULL},	/* TS_NOP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBA_INIT */
-	{NULL, tape34xx_rbi_init_done, NULL, NULL, NULL},	/* TS_RBI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBU_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RBL_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RDC_INIT */
-	{NULL, tape34xx_rfo_init_done, NULL, NULL, NULL},	/* TS_RFO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_RSD_INIT */
-	{NULL, tape34xx_rew_init_done, NULL, NULL, NULL},	/* TS_REW_INIT */
-	{NULL, tape34xx_rew_release_init_done, NULL, NULL, NULL},	/* TS_REW_RELEASE_IMIT */
-	{NULL, tape34xx_run_init_done, NULL, NULL, NULL},	/* TS_RUN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SEN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SID_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SNP_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SPG_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SWI_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SMR_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_SYN_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_TIO_INIT */
-	{NULL, NULL, NULL, NULL, NULL},		/* TS_UNA_INIT */
-	{NULL, tape34xx_wri_init_done, NULL, NULL, NULL},	/* TS_WRI_INIT */
-	{NULL, tape34xx_wtm_init_done, NULL, NULL, NULL},	/* TS_WTM_INIT */
-	{NULL, NULL, NULL, NULL, NULL}};        /* TS_NOT_OPER */
+	__u8 *data = NULL;
+	int i;
+	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
 
+	tape_sprintf_event (tape_dbf_area,6,"%s\n",tape_op_verbose[treq->op]);
+	tape_sprintf_event (tape_dbf_area,6,"done\n");
 
-int
-tape34xx_ioctl_overload (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
-{
-	return -EINVAL;		// no additional ioctls
+	treq->rc = 0;
+	switch(treq->op){
+		case TO_BSB:
+		case TO_BSF:
+		case TO_DSE:
+		case TO_FSB:
+		case TO_FSF:
+		case TO_LBL:
+		case TO_RFO:
+		case TO_RBA:
+		case TO_REW:
+		case TO_WRI:
+		case TO_WTM: 
+		case TO_BLOCK:
+		case TO_LOAD:
+	        case TO_DIS:
+			tape_med_state_set(td,MS_LOADED);
+			break;
+		case TO_NOP:
+			break;
+		case TO_RUN:
+			tape_med_state_set(td,MS_UNLOADED);
+                        break;
+		case TO_RBI:
+			data = treq->kernbuf;
+			tape_sprintf_event (tape_dbf_area,6,"data: %04x %04x\n",*((unsigned int*)&data[0]),*((unsigned int*)&data[4]));
+			i = 0;
+			i = data[3];
+			i += 256 * data[2];
+			i += 65536 * (data[1] & 0x3F);
+			memcpy(data,&i,4);
+			tape_med_state_set(td,MS_LOADED);
+			break;
+		default:
+			tape_sprintf_exception (tape_dbf_area,3,"TE UNEXPEC\n");
+			tape34xx_default_handler (td);
+			return;
+	}
+	
+	if(treq->wakeup)
+		treq->wakeup (treq);
+	return;
+}
 
+/*
+ * This function is called, when no request is outstanding and we get an
+ * interrupt
+ */
+
+void tape34xx_unsolicited_irq(tape_dev_t* td)
+{
+	if(td->devstat.dstat == 0x85 /* READY */) {
+		// A medium was inserted in the drive!
+		tape_sprintf_event (tape_dbf_area,6,"xuud med\n");
+		tape_med_state_set(td,MS_LOADED);
+	} else {
+		tape_sprintf_event (tape_dbf_area,3,"unsol.irq! dev end: %x\n",td->devinfo.irq);
+		PRINT_WARN ("Unsolicited IRQ (Device End) caught.\n");
+		tape_dump_sense (td);
+        }
 }
 
-ccw_req_t *
-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 (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xwbl nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	mem = kmalloc (count, GFP_KERNEL);
-	if (!mem) {
-		tape_free_request (cqr);
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xwbl nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	if (copy_from_user (mem, data, count)) {
-		kfree (mem);
-		tape_free_request (cqr);
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xwbl segf.");
-#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 *) ti->discdata)->modeset_byte)));
-	ccw++;
 
-	ccw->cmd_code = WRITE_CMD;
-	ccw->flags = 0;
-	ccw->count = count;
-	set_normalized_cda (ccw, (unsigned long) mem);
-	if ((ccw->cda) == 0) {
-		kfree (mem);
-		tape_free_request (cqr);
-		return NULL;
-	}
-	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 */
-	return cqr;
-}
+/*
+ * tape34xx_display 
+ */
 
-void 
-tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti)
+int
+tape34xx_display (tape_dev_t* td, unsigned long arg)
 {
-	unsigned long lockflags;
-	ccw1_t *ccw;
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	ccw = cqr->cpaddr;
-	ccw++;
-	clear_normalized_cda (ccw);
-	kfree (ti->kernbuf);
-	tape_free_request (cqr);
-	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 */
-}
+        struct display_struct d_struct;
+        tape_ccw_req_t *treq = NULL;
+        ccw1_t *ccw = NULL;
+        int ds = 17;           /* datasize  */
+        int ccw_cnt = 2;       /* ccw count */
+        int op = TO_DIS;       /* tape operation */
+        int i = 0, rc = -1;
+
+        rc = copy_from_user(&d_struct, (char *)arg, sizeof(d_struct));
+        if (rc != 0)
+                goto error;
+
+        treq=tape_alloc_ccw_req(ccw_cnt, ds, 0, op);
+        if (!treq)
+	        goto error;
+
+        ((unsigned char *)treq->kernbuf)[0] = d_struct.cntrl;
+
+        for (i = 0; i < 8; i++) {
+                ((unsigned char *)treq->kernbuf)[i+1] = d_struct.message1[i];
+                ((unsigned char *)treq->kernbuf)[i+9] = d_struct.message2[i];
+        }
+
+        ASCEBC (((unsigned char*)treq->kernbuf) + 1, 16);
+
+        ccw = treq->cpaddr;
+        ccw = tape_ccw_cc(ccw, LOAD_DISPLAY, 17, treq->kernbuf, 1);
+        ccw = tape_ccw_end(ccw,NOP,0,0,1);
 
-ccw_req_t *
-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 (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xrbl nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	mem = kmalloc (count, GFP_KERNEL);
-	if (!mem) {
-		tape_free_request (cqr);
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xrbl 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
+        tape_do_io_and_wait(td,treq,TAPE_WAIT_INTERRUPTIBLE);
+    
+        tape_free_ccw_req(treq);
 
-	ccw->cmd_code = READ_FORWARD;
-	ccw->flags = 0;
-	ccw->count = count;
-	set_normalized_cda (ccw, (unsigned long) mem);
-	if ((ccw->cda) == 0) {
-		kfree (mem);
-		tape_free_request (cqr);
-		return NULL;
-	}
-	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;
-}
+        return(0);
 
-ccw_req_t *
-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 = ti->cqr;
-	ccw = cqr->cpaddr;
-	ccw++;
-	count=ccw->count;
-	// free old cqr.
-	clear_normalized_cda (ccw);
-	tape_free_request (cqr);
-	// build new cqr
-	cqr = tape_alloc_ccw_req (ti, 3, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xrop 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
+ error:
+	return -EINVAL;
 
-	ccw->cmd_code = READ_BACKWARD;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = count;
-	set_normalized_cda (ccw, (unsigned long) ti->kernbuf);
-	if ((ccw->cda) == 0) {
-		tape_free_request (cqr);
-		return NULL;
-	}
-	ccw++;
-	ccw->cmd_code = FORSPACEBLOCK;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 1;
-	ccw->cda = (unsigned long)ccw;
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 1;
-	ccw->cda = (unsigned long)ccw;
-	tapestate_set (ti, TS_RBA_INIT);
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"xrop ccwg");
-#endif /* TAPE_DEBUG */
-	return cqr;
 }
 
-void 
-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 (ti->devinfo.irq, lockflags);
-	ccw = cqr->cpaddr;
-	ccw++;
-	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 (ti->devinfo.irq, lockflags);
-	clear_normalized_cda (ccw);
-	kfree (ti->kernbuf);
-	tape_free_request (cqr);
-	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 */
-}
 
 /*
- * The IOCTL interface is implemented in the following section,
- * excepted the MTRESET, MTSETBLK which are handled by tapechar.c
- */
-/*
- * MTFSF: Forward space over 'count' file marks. The tape is positioned
- * at the EOT (End of Tape) side of the file mark.
+ * ioctl_overload 
  */
-ccw_req_t *
-tape34xx_mtfsf (tape_info_t * ti, int count)
+
+int
+tape34xx_ioctl_overload (tape_dev_t* td, unsigned int cmd, unsigned long arg)
 {
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsf parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsf 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = FORSPACEFILE;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
+        if (cmd == TAPE390_DISPLAY)
+	        return tape34xx_display(td, arg);
+	else
+                return -EINVAL;		// no additional ioctls
 }
 
+
+/*******************************************************************
+ * Request creating functions:
+ *******************************************************************/
+
 /*
+ * 34xx IOCTLS
+ *
+ * MTFSF: Forward space over 'count' file marks. The tape is positioned
+ * at the EOT (End of Tape) side of the file mark.
+ *
  * MTBSF: Backward space over 'count' file marks. The tape is positioned at
  * the EOT (End of Tape) side of the last skipped file mark.
- */
-ccw_req_t *
-tape34xx_mtbsf (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsf parm");
-#endif /* TAPE_DEBUG */
-	        return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsf 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = BACKSPACEFILE;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTFSR: Forward space over 'count' tape blocks (blocksize is set
  * via MTSETBLK.
- */
-ccw_req_t *
-tape34xx_mtfsr (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsr parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsr 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = FORSPACEBLOCK;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTBSR: Backward space over 'count' tape blocks.
  * (blocksize is set via MTSETBLK.
- */
-ccw_req_t *
-tape34xx_mtbsr (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsr parm");
-#endif /* TAPE_DEBUG */   
-	        return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsr 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = BACKSPACEBLOCK;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTWEOF: Write 'count' file marks at the current position.
- */
-ccw_req_t *
-tape34xx_mtweof (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xweo parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xweo 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = WRITETAPEMARK;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 1;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTREW: Rewind the tape.
- */
-ccw_req_t *
-tape34xx_mtrew (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 3, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xrew 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = REWIND;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTOFFL: Rewind the tape and put the drive off-line.
  * Implement 'rewind unload'
- */
-ccw_req_t *
-tape34xx_mtoffl (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 3, 32);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xoff 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = REWIND_UNLOAD;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 1;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = SENSE;
-	ccw->flags = 0;
-	ccw->count = 32;
-	ccw->cda = (unsigned long) cqr->cpaddr;
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTNOP: 'No operation'.
- */
-ccw_req_t *
-tape34xx_mtnop (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 1, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xnop nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	ccw = cqr->cpaddr;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) ccw->cmd_code;
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTBSFM: Backward space over 'count' file marks.
  * The tape is positioned at the BOT (Begin Of Tape) side of the
  * last skipped file mark.
- */
-ccw_req_t *
-tape34xx_mtbsfm (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsm parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbsm 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = BACKSPACEFILE;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTFSFM: Forward space over 'count' file marks.
  * The tape is positioned at the BOT (Begin Of Tape) side
  * of the last skipped file mark.
- */
-ccw_req_t *
-tape34xx_mtfsfm (tape_info_t * ti, int count)
-{
-	long lockflags;
-	int i;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count == 0) || (count > 510)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsm parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xfsm 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	for (i = 0; i < count; i++) {
-		ccw->cmd_code = FORSPACEFILE;
-		ccw->flags = CCW_FLAG_CC;
-		ccw->count = 0;
-		ccw->cda = (unsigned long) (&(ccw->cmd_code));
-		ccw++;
-	}
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTEOM: positions at the end of the portion of the tape already used
  * for recordind data. MTEOM positions after the last file mark, ready for
  * appending another file.
  * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
- */
-ccw_req_t *
-tape34xx_mteom (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 4, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xeom 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = FORSPACEFILE;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = CCW_CMD_TIC;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (cqr->cpaddr);
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTERASE: erases the tape.
- */
-ccw_req_t *
-tape34xx_mterase (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 5, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xera 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = REWIND;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = ERASE_GAP;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = DATA_SEC_ERASE;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTSETDENSITY: set tape density.
- */
-ccw_req_t *
-tape34xx_mtsetdensity (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xden 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 *) 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 (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 */
-	return cqr;
-}
-
-/*
+ *
  * MTSEEK: seek to the specified block.
- */
-ccw_req_t *
-tape34xx_mtseek (tape_info_t * ti, int count)
-{
-	long lockflags;
-	__u8 *data;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((data = kmalloc (4 * sizeof (__u8), GFP_KERNEL)) == NULL) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xsee nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	data[0] = 0x01;
-	data[1] = data[2] = data[3] = 0x00;
-	if (count >= 4194304) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xsee parm");
-#endif /* TAPE_DEBUG */
-		kfree(data);
-		return NULL;
-	}
-	if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)	// IDRC on
-
-		data[1] = data[1] | 0x80;
-	data[3] += count % 256;
-	data[2] += (count / 256) % 256;
-	data[1] += (count / 65536);
-#ifdef TAPE_DEBUG
-	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 (ti, 3, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xsee nomem");
-#endif /* TAPE_DEBUG */
-		kfree (data);
-		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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = LOCATE;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 4;
-	set_normalized_cda (ccw, (unsigned long) data);
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTTELL: Tell block. Return the number of block relative to current file.
- */
-ccw_req_t *
-tape34xx_mttell (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	void *mem;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xtel nomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	mem = kmalloc (8, GFP_KERNEL);
-	if (!mem) {
-		tape_free_request (cqr);
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xtel 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 *) 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 (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 */
-	return cqr;
-}
-
-/*
+ *
  * MTSETDRVBUFFER: Set the tape drive buffer code to number.
  * Implement NOP.
- */
-ccw_req_t *
-tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xbuf 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 *) 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 (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 */
-	return cqr;
-}
-
-/*
+ *
  * MTLOCK: Locks the tape drive door.
  * Implement NOP CCW command.
- */
-ccw_req_t *
-tape34xx_mtlock (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xloc 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 *) 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 (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 */
-	return cqr;
-}
-
-/*
+ *
  * MTUNLOCK: Unlocks the tape drive door.
  * Implement the NOP CCW command.
- */
-ccw_req_t *
-tape34xx_mtunlock (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xulk 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 *) 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 (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 */
-	return cqr;
-}
-
-/*
+ *
  * MTLOAD: Loads the tape.
- * 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 * ti, int count)
-{
-         return NULL;
-}
-
-/*
+ * 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
+ *
  * MTUNLOAD: Rewind the tape and unload it.
- */
-ccw_req_t *
-tape34xx_mtunload (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 3, 32);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xunl 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 *) ti->discdata)->modeset_byte)));
-	ccw++;
-	ccw->cmd_code = REWIND_UNLOAD;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 1;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	ccw++;
-	ccw->cmd_code = SENSE;
-	ccw->flags = 0;
-	ccw->count = 32;
-	ccw->cda = (unsigned long) cqr->cpaddr;
-	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 */
-	return cqr;
-}
-
-/*
+ *
  * MTCOMPRESSION: used to enable compression.
  * Sets the IDRC on/off.
- */
-ccw_req_t *
-tape34xx_mtcompression (tape_info_t * ti, int count)
-{
-	long lockflags;
-	ccw_req_t *cqr;
-	ccw1_t *ccw;
-	if ((count < 0) || (count > 1)) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xcom parm");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
-	if (count == 0)
-		((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x00;		// IDRC off
+ *
+ * MTSTPART: Move the tape head at the partition with the number 'count'.
+ * Implement the NOP CCW command.
+ *
+ * MTMKPART: .... dummy .
+ * Implement the NOP CCW command.
+ *
+ * MTIOCGET: query the tape drive status.
+ *
+ * MTIOCPOS: query the tape position.
+ *
+ */ 
 
-	else
-		((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x08;		// IDRC on
+tape_ccw_req_t *
+tape34xx_ioctl(tape_dev_t* td, int mtcmd,int count, int* rc)
+{
+	tape_ccw_req_t *treq = NULL;
+        ccw1_t *ccw = NULL;
+	int ds = 0;   /* datasize  */
+	int ccw_cnt;  /* ccw count */
+	int op = -1;  /* tape operation */
+
+	tape_sprintf_event(tape_dbf_area,6,"34xxioctl: op(%x) count(%x)\n",mtcmd,count);
+	/* Preprocessing */
+
+	switch(mtcmd){
+		case MTLOAD:   *rc = -EINVAL; goto error;
+		case MTIOCGET: *rc = -EINVAL; goto error;
+		case MTIOCPOS: *rc = -EINVAL; goto error;
+
+		case MTFSF:          op=TO_FSF; ccw_cnt=count+2; ds=0; break;
+		case MTBSF:          op=TO_BSF; ccw_cnt=count+2; ds=0; break;
+		case MTFSR:          op=TO_FSB; ccw_cnt=count+2; ds=0; break;
+		case MTBSR:          op=TO_BSB; ccw_cnt=count+2; ds=0; break;
+		case MTWEOF:         op=TO_WTM; ccw_cnt=count+2; ds=0; break;
+		case MTREW:          op=TO_REW; ccw_cnt=3;       ds=0; break;
+		case MTOFFL:         op=TO_RUN; ccw_cnt=3;       ds=0; break;
+		case MTNOP:          op=TO_NOP; ccw_cnt=2;       ds=0; break; 
+		case MTBSFM:         op=TO_BSF; ccw_cnt=count+2; ds=0; break;
+		case MTFSFM:         op=TO_FSF; ccw_cnt=count+2; ds=0; break;
+		case MTEOM:          op=TO_FSF; ccw_cnt=4;       ds=0; break;
+		case MTERASE:        op=TO_DSE; ccw_cnt=5;       ds=0; break;
+		case MTSETDENSITY:   op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTSEEK:         op=TO_LBL; ccw_cnt=3;       ds=4; break;
+		case MTTELL:         op=TO_RBI; ccw_cnt=3;       ds=8; break;
+		case MTSETDRVBUFFER: op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTLOCK:         op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTUNLOCK:       op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTUNLOAD:       op=TO_RUN; ccw_cnt=3;       ds=32; break;
+		case MTCOMPRESSION:  op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTSETPART:      op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		case MTMKPART:       op=TO_NOP; ccw_cnt=3;       ds=0; break;
+		default:
+			PRINT_ERR( "IOCTL %x not implemented\n",op );
+			*rc = -EINVAL;
+			goto error;
+	}
+
+	if (ccw_cnt > 510) {
+		tape_sprintf_exception (tape_dbf_area,6,"wrng parm\n");
+		*rc = -EINVAL;
+		goto error;
+	}
+
+	treq=tape_alloc_ccw_req(ccw_cnt,ds,0,op);
+        if (!treq){
+		*rc = -ENOSPC;
+                goto error;
+	}
+	ccw = treq->cpaddr;
+
+	/* setup first ccw */
+	ccw = tape_ccw_cc(ccw,MODE_SET_DB,1,&MOD_BYTE,1);
+
+	/* setup middle ccw(s) */
+
+	switch(mtcmd){
+		case MTFSF:
+                	ccw = tape_ccw_cc(ccw,FORSPACEFILE,0,0,count);
+			break;
+		case MTBSF:
+			ccw = tape_ccw_cc(ccw,BACKSPACEFILE,0,0,count);
+			break;
+		case MTFSR:
+			ccw = tape_ccw_cc(ccw,FORSPACEBLOCK,0,0,count);
+			break;
+		case MTBSR:
+			ccw = tape_ccw_cc(ccw,BACKSPACEBLOCK,0,0,count);
+			break;
+		case MTWEOF:
+			ccw = tape_ccw_cc(ccw,WRITETAPEMARK,0,0,count); // this operation does _always_ write only one tape mark :(
+			break;
+		case MTREW:
+			ccw = tape_ccw_cc(ccw,REWIND,0,0,1);
+			break;
+		case MTOFFL:
+			ccw = tape_ccw_cc(ccw,REWIND_UNLOAD,0,0,1);
+			break;
+		case MTUNLOCK:
+		case MTLOCK:
+		case MTSETDRVBUFFER:
+		case MTSETDENSITY:
+		case MTSETPART:
+		case MTMKPART:
+		case MTNOP:
+			ccw = tape_ccw_cc(ccw,NOP,0,0,1);
+			break;
+		case MTBSFM:
+			ccw = tape_ccw_cc(ccw,BACKSPACEFILE,0,0,count);
+			break;
+		case MTFSFM:
+			ccw = tape_ccw_cc(ccw,FORSPACEFILE,0,0,count);
+			break;
+		case MTEOM:
+			ccw = tape_ccw_cc(ccw,FORSPACEFILE,0,0,1);
+			ccw = tape_ccw_cc(ccw,NOP,0,0,1);
+			break;
+		case MTERASE:
+			ccw = tape_ccw_cc(ccw,REWIND,0,0,1);
+			ccw = tape_ccw_cc(ccw,ERASE_GAP,0,0,1);
+			ccw = tape_ccw_cc(ccw,DATA_SEC_ERASE,0,0,1);
+			break;
+		case MTTELL:
+			ccw = tape_ccw_cc(ccw,READ_BLOCK_ID,8,treq->kernbuf,1);
+			break;
+		case MTUNLOAD:
+			ccw = tape_ccw_cc(ccw,REWIND_UNLOAD,0,0,1);
+			break;
+		case MTCOMPRESSION:
+			if((count < 0) || (count > 1)){
+				tape_sprintf_exception (tape_dbf_area,6,"xcom parm\n");
+				goto error;
+			}
+			if(count == 0){
+				PRINT_INFO( "(%x) Compression switched off\n", td->devstat.devno);
+				MOD_BYTE = 0x00; // IDRC off
+			} else {
+				PRINT_INFO( "(%x) Compression switched on\n", td->devstat.devno);
+				MOD_BYTE = 0x08; // IDRC on
+			}
+			ccw = tape_ccw_cc(ccw,NOP,0,0,1);
+			break; // Modset does the job
+		case MTSEEK:
+			{
+			__u8* data = treq->kernbuf;
+			data[0] = 0x01;
+			data[1] = data[2] = data[3] = 0x00;
+			if (count >= 4194304){
+				tape_sprintf_exception(tape_dbf_area,6,"xsee parm\n");
+				*rc = -EINVAL;
+				goto error;
+			}
+			if(MOD_BYTE && 0x08)
+				data[1] = data[1] | 0x80;
 
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xcom 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 *) 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 (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 */
-	return cqr;
+			data[3] += count % 256;
+			data[2] += (count / 256) % 256;
+			data[1] += (count / 65536);
+			ccw = tape_ccw_cc(ccw,LOCATE,4,treq->kernbuf,1);
+			break;
+			}
+		default:
+			PRINT_WARN( "IOCTL %x not implemented\n",op );
+			*rc = -EINVAL;
+			goto error;
+
+        }
+
+	/* setup last ccw */
+
+	switch(mtcmd){
+		case MTEOM:
+			ccw = tape_ccw_end(ccw,CCW_CMD_TIC,0,treq->cpaddr,1);
+			break;
+		case MTUNLOAD:
+			ccw = tape_ccw_end(ccw,SENSE,32,treq->kernbuf,1);
+			break;
+		default:
+			ccw = tape_ccw_end(ccw,NOP,0,0,1);
+			break;
+	}
+	*rc = 0;
+	return treq;
+error:
+	if (treq)
+	        tape_free_ccw_req(treq);
+	return NULL;
 }
 
 /*
- * MTSTPART: Move the tape head at the partition with the number 'count'.
- * Implement the NOP CCW command.
+ * Write Block 
  */
-ccw_req_t *
-tape34xx_mtsetpart (tape_info_t * ti, int count)
+
+tape_ccw_req_t *
+tape34xx_write_block (const char *data, size_t count, tape_dev_t* td)
 {
-	long lockflags;
-	ccw_req_t *cqr;
+	tape_ccw_req_t *treq = NULL;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xspa 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 *) 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 (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 */
-	return cqr;
+	treq = tape_alloc_ccw_req (2, 0, count,TO_WRI);
+	if (!treq)
+		goto error;
+	if (idalbuf_copy_from_user (treq->idal_buf, data, count)) {
+	        tape_sprintf_exception (tape_dbf_area,6,"xwbl segf.\n");
+		goto error;
+	}
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw,MODE_SET_DB,1,&MOD_BYTE,1);
+	ccw = tape_ccw_end_idal(ccw,WRITE_CMD,treq->idal_buf);
+	treq->userbuf = (void *) data;
+	tape_sprintf_event (tape_dbf_area,6,"xwbl ccwg\n");
+	return treq;
+error:
+	tape_sprintf_exception (tape_dbf_area,6,"xwbl fail\n");
+	if (treq)
+	        tape_free_ccw_req(treq);
+	return NULL;
 }
 
 /*
- * MTMKPART: .... dummy .
- * Implement the NOP CCW command.
+ * Read Block
  */
-ccw_req_t *
-tape34xx_mtmkpart (tape_info_t * ti, int count)
+
+tape_ccw_req_t *
+tape34xx_read_block (const char *data, size_t count, tape_dev_t* td)
 {
-	long lockflags;
-	ccw_req_t *cqr;
+	tape_ccw_req_t *treq = NULL;
 	ccw1_t *ccw;
-	cqr = tape_alloc_ccw_req (ti, 2, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xnpa 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 *) 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 (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 */
-	return cqr;
+	/* we have to alloc 4 ccws in order to be able to transform request */
+	/* into a read backward request in error case                       */
+	treq = tape_alloc_ccw_req (4, 0, count,TO_RFO);
+	if (!treq) 
+		goto error;
+	treq->userbuf = (void*)data;
+	treq->userbuf_size = count;
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw,MODE_SET_DB,1,&MOD_BYTE,1);
+	ccw = tape_ccw_end_idal(ccw,READ_FORWARD,treq->idal_buf);
+	tape_sprintf_event (tape_dbf_area,6,"xrbl ccwg\n");
+	return treq;
+error:
+	tape_sprintf_exception (tape_dbf_area,6,"xrbl fail");
+	if (treq)
+	        tape_free_ccw_req(treq);
+	return NULL;
 }
 
 /*
- * MTIOCGET: query the tape drive status.
+ * Read Opposite Error Recovery Function:
+ * Used, when Read Forward does not work
  */
-ccw_req_t *
-tape34xx_mtiocget (tape_info_t * ti, int count)
+
+tape_ccw_req_t *
+tape34xx_read_opposite (tape_dev_t* td)
 {
-	return NULL;
+	ccw1_t *ccw;
+	tape_ccw_req_t* treq = tape_get_active_ccw_req(td);
+	if (treq==NULL) // no request to recover?
+		BUG();
+
+	// transform read forward request into read backward request.
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw,MODE_SET_DB,1,&MOD_BYTE,1);
+	ccw = tape_ccw_cc_idal(ccw,READ_BACKWARD,treq->idal_buf);
+	ccw = tape_ccw_cc(ccw,FORSPACEBLOCK,0,0,1);
+	ccw = tape_ccw_end(ccw,NOP,0,0,1);
+	treq->op = TO_RBA;
+	tape_sprintf_event (tape_dbf_area,6,"xrop ccwg");
+	return treq;
 }
 
 /*
- * MTIOCPOS: query the tape position.
+ * Tape Block READ
  */
-ccw_req_t *
-tape34xx_mtiocpos (tape_info_t * ti, int count)
-{
-	return NULL;
-}
 
-ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* ti,int tapeblock_major) {
-	ccw_req_t *cqr;
+tape_ccw_req_t * tape34xx_bread (struct request *req,tape_dev_t* td,int tapeblock_major) {
+	tape_ccw_req_t *treq;
 	ccw1_t *ccw;
 	__u8 *data;
-	kdev_t dev = mk_kdev(tapeblock_major, ti->blk_minor);
-	struct block_device *bdev = bdget(kdev_t_to_nr(dev));
-	unsigned bsize = block_size(bdev);
-	int s2b = bsize/queue_hardsect_size(&ti->request_queue);
-	int realcount;
+	int s2b = blksize_size[tapeblock_major][td->first_minor]/hardsect_size[tapeblock_major][td->first_minor];
+	int realcount = 0;
 	int size,bhct = 0;
 	struct buffer_head* bh;
-	bdput(bdev);
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > bsize)
-			for (size = 0; size < bh->b_size; size += bsize)
+		if (bh->b_size > blksize_size[tapeblock_major][td->first_minor])
+			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][td->first_minor])
 				bhct++;
 		else
 			bhct++;
 	}
-	if ((data = kmalloc (4 * sizeof (__u8), GFP_ATOMIC)) == NULL) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,3,"xBREDnomem");
-#endif /* TAPE_DEBUG */
-		return NULL;
-	}
+	tape_sprintf_event (tape_dbf_area,6,"xBREDid:");
+	treq = tape_alloc_ccw_req (2+bhct+1, 4,0,TO_BLOCK);
+	if (!treq) {
+		tape_sprintf_exception (tape_dbf_area,6,"xBREDnomem\n");
+                goto error;
+        }
+
+	data = treq->kernbuf;
 	data[0] = 0x01;
 	data[1] = data[2] = data[3] = 0x00;
 	realcount=req->sector/s2b;
-	if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)	// IDRC on
-
+	if (MOD_BYTE & 0x08)	// IDRC on
 		data[1] = data[1] | 0x80;
 	data[3] += realcount % 256;
 	data[2] += (realcount / 256) % 256;
 	data[1] += (realcount / 65536);
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"xBREDid:");
-	debug_int_event (tape_debug_area,6,realcount);
-#endif /* TAPE_DEBUG */
-	cqr = tape_alloc_ccw_req (ti, 2+bhct+1, 0);
-	if (!cqr) {
-#ifdef TAPE_DEBUG
-	        debug_text_exception (tape_debug_area,6,"xBREDnomem");
-#endif /* TAPE_DEBUG */
-		kfree(data);
-		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 *) 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);
-	}
-	ti->position=realcount+req->nr_sectors/s2b;
+	tape_sprintf_event (tape_dbf_area,6,"realcount = %i\n",realcount);
+
+	ccw = treq->cpaddr;
+	ccw = tape_ccw_cc(ccw,MODE_SET_DB,1,&MOD_BYTE,1);
+	if (realcount!=td->blk_data.position)
+		ccw = tape_ccw_cc(ccw,LOCATE,4,treq->kernbuf,1);
+	else
+		ccw = tape_ccw_cc(ccw,NOP,0,0,1);
+	td->blk_data.position=realcount+req->nr_sectors/s2b;
 	for (bh=req->bh;bh!=NULL;) {
-	        ccw->flags = CCW_FLAG_CC;
-		if (bh->b_size >= bsize) {
-			for (size = 0; size < bh->b_size; size += bsize) {
-			        ccw++;
+		if (bh->b_size >= blksize_size[tapeblock_major][td->first_minor]) {
+			for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][td->first_minor]){
 				ccw->flags = CCW_FLAG_CC;
 				ccw->cmd_code = READ_FORWARD;
-				ccw->count = bsize;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
+				ccw->count = blksize_size[tapeblock_major][td->first_minor];
+				set_normalized_cda(ccw,__pa(bh->b_data+size));
+				ccw++;
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < bsize;) {
-				ccw++;
-				ccw->flags = CCW_FLAG_DC;
-				ccw->cmd_code = READ_FORWARD;
-				ccw->count = bh->b_size;
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-			}
-			if (size != bsize) {
-				PRINT_WARN ("Cannot fulfill small request %d vs. %d (%ld sects)\n",
-					    size,
-					    bsize,
-					    req->nr_sectors);
-				kfree(data);
-				tape_free_request (cqr);
-				return NULL;
-			}
+		    BUG();
 		}
 	}
-	ccw -> flags &= ~(CCW_FLAG_DC);
-	ccw -> flags |= (CCW_FLAG_CC);
-	ccw++;
-	ccw->cmd_code = NOP;
-	ccw->flags = 0;
-	ccw->count = 0;
-	ccw->cda = (unsigned long) (&(ccw->cmd_code));
-	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* 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) ||
-	    (ccw->cmd_code == LOCATE) ||
-	    (ccw->cmd_code == READ_FORWARD))
-	    clear_normalized_cda(ccw);
-    tape_free_request(cqr);
-    kfree(ti->kernbuf);
-    ti->kernbuf=NULL;
-}
-
-/* event handlers */
-void
-tape34xx_default_handler (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-    debug_text_event (tape_debug_area,6,"xdefhandle");
-#endif /* TAPE_DEBUG */
-	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 (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 * ti)
-{
-	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", ti->rew_minor / 2);
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,3,"xuuh nomed");
-#endif /* TAPE_DEBUG */
-		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",
-			    ti->rew_minor / 2);
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,3,"xuuh medchg");
-#endif
-		/* nothing to do. chan end & dev end will be reported when io is finished */
-	} else {
-#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 (ti) < TS_SIZE) && 
-						     (tapestate_get (ti) >= 0)) ?
-				  state_verbose[tapestate_get (ti)] : 
-				  "TS UNKNOWN");
-#endif /* TAPE_DEBUG */
-		tape34xx_default_handler (ti);
-	}
-}
-
-void
-tape34xx_unused_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,"xuui med");
-#endif /* TAPE_DEBUG */
-	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,ti->devinfo.irq);
-#endif /* TAPE_DEBUG */
-	PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
-	tape_dump_sense (&ti->devstat);
-    }
-}
-
-
-void
-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,ti->devinfo.irq);
-#endif /* TAPE_DEBUG */
-	PRINT_WARN ("Unsolicited IRQ (Device End) caught in idle state.\n");
-	tape_dump_sense (&ti->devstat);
-    }
-}
-
-void
-tape34xx_block_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"x:bREQdone");
-#endif /* TAPE_DEBUG */
-	tapestate_set(ti,TS_DONE);
-	schedule_tapeblock_exec_IO(ti);
-}
-
-void
-tape34xx_bsf_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"bsf done");
-#endif
-	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 * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"dse done");
-#endif
-	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 * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"fsf done");
-#endif
-	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 * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"fsb done");
-#endif
-	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 * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"bsb done");
-#endif
-	tapestate_set (ti, TS_DONE);
-	ti->rc = 0;
-	ti->wanna_wakeup=1;
-	wake_up (&ti->wq);
-}
-
-void
-tape34xx_lbl_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"lbl done");
-#endif
-	tapestate_set (ti, TS_DONE);
-	ti->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
-	ti->wanna_wakeup=1;
-	wake_up (&ti->wq);
-}
-
-void
-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 (ti, TS_DONE);
-	ti->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
-	ti->wanna_wakeup=1;
-	wake_up (&ti->wq);
+	ccw = tape_ccw_end(ccw,NOP,0,0,1);
+	tape_sprintf_event (tape_dbf_area,6,"xBREDccwg\n");
+	return treq;
+error:
+	tape_sprintf_exception (tape_dbf_area,6,"xBREDccwg fail");
+	if (treq)
+	        tape_free_ccw_req(treq);
+	return NULL;
 }
 
-void
-tape34xx_rfo_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"rfo done");
-#endif
-	tapestate_set (ti, TS_DONE);
-	ti->rc = 0;
-	ti->wanna_wakeup=1;
-	wake_up (&ti->wq);
+void tape34xx_free_bread (tape_ccw_req_t* treq) {
+	ccw1_t* ccw;
+	for (ccw=(ccw1_t*)treq->cpaddr;ccw->flags & CCW_FLAG_CC;ccw++)
+	if (ccw->cmd_code == READ_FORWARD)
+		clear_normalized_cda(ccw);
+	tape_free_ccw_req(treq); 
 }
 
-void
-tape34xx_rbi_init_done (tape_info_t * ti)
-{
-	__u8 *data;
-#ifdef TAPE_DEBUG
-	int i;
-#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
-	ti->wanna_wakeup=1;
-	wake_up_interruptible (&ti->wq);
-}
+// FIXME: Comment?
 
-void
-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 (ti, TS_DONE);
-	ti->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
-	ti->wanna_wakeup=1;
-	wake_up_interruptible (&ti->wq);
+void tape34xx_bread_enable_locate (tape_ccw_req_t * treq) {
+	ccw1_t *ccw;
+	if (treq==NULL) BUG();
+	ccw=treq->cpaddr;
+	ccw++;
+	ccw = tape_ccw_cc(ccw,LOCATE,4,treq->kernbuf,1);
+	return;
 }
 
-void
-tape34xx_rew_release_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"rewR done");
-#endif
-	tapestate_set (ti, TS_DONE);
-	ti->rc = 0;
-	//s390irq_spin_unlock(tape->devinfo.irq);
-	ti->wanna_wakeup=1;
-	wake_up (&ti->wq);
-}
+/*******************************************************************
+ * Event Handlers
+ *******************************************************************/
 
-void
-tape34xx_run_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"rew done");
-#endif
-	tapestate_set (ti, TS_DONE);
-	ti->rc = 0;
-	ti->wanna_wakeup=1;
-	wake_up_interruptible (&ti->wq);
-}
+/*
+ * Default Handler is called, when an unexpected IRQ comes in
+ */
 
 void
-tape34xx_wri_init_done (tape_info_t * ti)
+tape34xx_default_handler (tape_dev_t * td)
 {
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,6,"wri done");
-#endif
-	//BH: use irqsave
-	//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);
+	tape_ccw_req_t* treq = tape_get_active_ccw_req(td);
+	tape_sprintf_event (tape_dbf_area,6,"xdefhandle\n");
+	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 op is: %s",tape_op_verbose[treq->op]);
+	tape_dump_sense (td);
+	treq->rc = -EIO;
+	if(treq->wakeup)
+		treq->wakeup (treq);
 }
 
-void
-tape34xx_wtm_init_done (tape_info_t * ti)
-{
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"wtm done");
-#endif
-	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.  */
 
-/* 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* ti)
+tape34xx_error_recovery (tape_dev_t* td)
 {
-    __u8* sense=ti->devstat.ii.sense.data;
+    __u8* sense=td->devstat.ii.sense.data;
     int inhibit_cu_recovery=0;
-    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) {
+    int cu_type=td->discipline->cu_type;
+    tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+
+    if (treq==NULL) {
+	    // Nothing to recover! Why call me?
+	    BUG();
+    }
+    if (MOD_BYTE&0x80) inhibit_cu_recovery=1;
+    if (treq->op==TO_BLOCK) {
 	// no recovery for block device, bottom half will retry...
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     }
     if (sense[0]&SENSE_COMMAND_REJECT)
-	switch (tapestate_get(ti)) {
-	case TS_BLOCK_INIT:
-	case TS_DSE_INIT:
-	case TS_EGA_INIT:
-	case TS_WRI_INIT:
-	case TS_WTM_INIT:
+	switch (treq->op) {
+	case TO_DSE:
+	case TO_EGA:
+	case TO_WRI:
+	case TO_WTM:
 	    if (sense[1]&SENSE_WRITE_PROTECT) {
 		// trying to write, but medium is write protected
-		tape34xx_error_recovery_has_failed(ti,EACCES);
+		tape34xx_error_recovery_has_failed(td,EACCES);
 		return;
 	    }
 	default:
-	    tape34xx_error_recovery_HWBUG(ti,1);
+	    tape34xx_error_recovery_HWBUG(td,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(ti)) {
-	case TS_FSF_INIT:
+	switch (treq->op) {
+	case TO_FSF:
 	    // Trying to seek beyond end of recorded area
-	    tape34xx_error_recovery_has_failed(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,EIO);
 	    return;
-	case TS_LBL_INIT:
+	case TO_LBL:
 	    // Block could not be located.
-	    tape34xx_error_recovery_has_failed(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,EIO);
 	    return;
-	case TS_RFO_INIT:
+	case TO_RFO:
 	    // Try to read beyond end of recorded area -> 0 bytes read
-	    tape34xx_error_recovery_has_failed(ti,0);
+	    tape34xx_error_recovery_has_failed(td,0);
 	    return;
+	default:
+            PRINT_ERR("Invalid op in %s:%i\n",__FUNCTION__,__LINE__);
+            tape34xx_error_recovery_has_failed(td,0);
+            return;
 	}
     // Sensing special bits
     if (sense[0]&SENSE_BUS_OUT_CHECK) {
-	tape34xx_error_recovery_do_retry(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     }
     if (sense[0]&SENSE_DATA_CHECK) {
@@ -1827,12 +683,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(ti,2);
+		tape34xx_error_recovery_HWBUG(td,2);
 		return;
 	    } else {
 		// data check is permanent, CU recovery has failed
 		PRINT_WARN("Permanent read error, recovery failed!\n");
-		tape34xx_error_recovery_has_failed(ti,EIO);
+		tape34xx_error_recovery_has_failed(td,EIO);
 		return;
 	    }
 	case 0x25:
@@ -1841,38 +697,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(ti,3);
+		tape34xx_error_recovery_HWBUG(td,3);
 		return;
 	    } else {
 		// data check is permanent, cu-recovery has failed
 		PRINT_WARN("Permanent write error, recovery failed!\n");
-		tape34xx_error_recovery_has_failed(ti,EIO);
+		tape34xx_error_recovery_has_failed(td,EIO);
 		return;
 	    }
 	case 0x26:
 	    // Data Check (read opposite) occurred. We'll recover this.
-	    tape34xx_error_recovery_read_opposite(ti);
+	    tape34xx_error_recovery_read_opposite(td);
 	    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(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,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(ti,ENOSPC);
+	    tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,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(ti,4);
+		    tape34xx_error_recovery_HWBUG(td,4);
 		    return;
 		}
 	}
@@ -1882,11 +738,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(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,EIO);
 	    return;
 	default:
 	    // Overrun bit is set, but erpa does not show overrun error. This is a bug.
-	    tape34xx_error_recovery_HWBUG(ti,5);
+	    tape34xx_error_recovery_HWBUG(td,5);
 	    return;
 	}
     }
@@ -1895,11 +751,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(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,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(ti,6);
+	    tape34xx_error_recovery_HWBUG(td,6);
 	    return;
 	}
     }
@@ -1912,119 +768,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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x23:
 	// Read data check. Should have been be covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(ti,7);
+	tape34xx_error_recovery_HWBUG(td,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(ti);
+	tape34xx_error_recovery_succeded(td);
 	return;
     case 0x25:
 	// Write data check. Should have been covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(ti,8);
+	tape34xx_error_recovery_HWBUG(td,8);
 	return;
     case 0x26:
 	// Data check (read opposite). Should have been covered earlier -> Bug!
-	tape34xx_error_recovery_HWBUG(ti,9);
+	tape34xx_error_recovery_HWBUG(td,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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     case 0x28:
 	// Write id mark check. Should have beed covered earlier -> bug!
-	tape34xx_error_recovery_HWBUG(ti,10);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x2a:
 	// Unsolicited environmental data. An internal counter overflows, we can ignore
 	// this and reissue the cmd.
-	tape34xx_error_recovery_do_retry(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     case 0x2b:
 	// Environmental data present. Indicates either unload completed ok or read buffered 
 	// log command completed ok. 
-	if (tapestate_get(ti)==TS_RUN_INIT) {
+	if (treq->op==TO_RUN) {
 	    // Rewind unload completed ok.
-	    tape34xx_error_recovery_succeded(ti);
+	    tape34xx_error_recovery_succeded(td);
 	    return;
 	}
 	// Since we do not issue read buffered log commands, this should never occur -> bug.
-	tape34xx_error_recovery_HWBUG(ti,11);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x2d:
 	// Data security erase failure.
-	if (tapestate_get(ti)==TS_DSE_INIT) {
+	if (treq->op==TO_DSE) {
 	    // report an I/O error
-	    tape34xx_error_recovery_has_failed(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,EIO);
 	    return;
 	}
 	// Data security erase failure, but no such command issued. This is a bug.
-	tape34xx_error_recovery_HWBUG(ti,12);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(td,EMEDIUMTYPE);
 	return;
     case 0x2f:
 	// This erpa is reserved. This is a bug.
-	tape34xx_error_recovery_HWBUG(ti,13);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EACCES);
+	tape34xx_error_recovery_has_failed(td,EACCES);
 	return;
     case 0x31:
 	// Tape void. Should have beed covered ealier -> bug
-	tape34xx_error_recovery_HWBUG(ti,14);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti)!=TS_RUN_INIT) {
-	    tape34xx_error_recovery_HWBUG(ti,15);
+	if (treq->op!=TO_RUN) {
+	    tape34xx_error_recovery_HWBUG(td,15);
 	    return;
 	}
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x35:
 	// Drive equipment check. One of the following:
@@ -2033,361 +889,366 @@
 	// - 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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x36:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> BUG
-	    tape34xx_error_recovery_HWBUG(ti,16);
+	    tape34xx_error_recovery_HWBUG(td,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(ti,EIO);
+	    tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x38:
 	// Physical end of tape. A read/write operation reached the physical end of tape.
-	if (tapestate_get(ti)==TS_WRI_INIT ||
-	    tapestate_get(ti)==TS_DSE_INIT ||
-	    tapestate_get(ti)==TS_EGA_INIT ||
-	    tapestate_get(ti)==TS_WTM_INIT){
- 	    tape34xx_error_recovery_has_failed(ti,ENOSPC);
-	} else {
-	    tape34xx_error_recovery_has_failed(ti,EIO);
-	}
-	return;
+        if (treq->op==TO_WRI ||
+            treq->op==TO_DSE ||
+            treq->op==TO_EGA ||
+            treq->op==TO_WTM){
+            tape34xx_error_recovery_has_failed(td,ENOSPC);
+        } else {
+            tape34xx_error_recovery_has_failed(td,EIO);
+        }
+        return;
     case 0x39:
 	// Backward at BOT. The drive is at BOT and is requestet to move backward.
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x3b:
 	// Manual rewind or unload. This causes an I/O error.
 	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);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x3c:
     case 0x3d:
     case 0x3e:
     case 0x3f:
 	// These erpas are reserved -> BUG
-	tape34xx_error_recovery_HWBUG(ti,17);
+	tape34xx_error_recovery_HWBUG(td,17);
 	return;
     case 0x40:
 	// Overrun error. This should have been covered earlier -> bug.
-	tape34xx_error_recovery_HWBUG(ti,18);
+	tape34xx_error_recovery_HWBUG(td,18);
 	return;
     case 0x41:
 	// Record sequence error. This should have been covered earlier -> bug.
-	tape34xx_error_recovery_HWBUG(ti,19);
+	tape34xx_error_recovery_HWBUG(td,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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	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(ti,ENOMEDIUM);
+	tape_med_state_set(td,MS_UNLOADED);
+	tape34xx_error_recovery_has_failed(td,ENOMEDIUM);
 	return;
     case 0x44:
 	// Locate Block unsuccessfull. We'll report this.
-	if ((tapestate_get(ti)!=TS_BLOCK_INIT) &&
-	    (tapestate_get(ti)!=TS_LBL_INIT)) {
-	    tape34xx_error_recovery_HWBUG(ti,20); // No locate block was issued...
+	if ((treq->op!=TO_BLOCK) &&
+	    (treq->op!=TO_LBL)) {
+	    tape34xx_error_recovery_HWBUG(td,20); // No locate block was issued...
 	    return;
 	}
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x48:
 	// Log sense data and retry request. We'll do so...
-	tape34xx_error_recovery_do_retry(ti);
+	tape34xx_error_recovery_do_retry(td);
 	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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     case 0x4d:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> bug
-      	    tape34xx_error_recovery_HWBUG(ti,21);
+      	    tape34xx_error_recovery_HWBUG(td,21);
 	    return;
 	case 0x3490:
 	    // Resetting event received. 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(ti);
+	    tape34xx_error_recovery_do_retry(td);
 	    return;
 	}
     case 0x4e:
 	switch (cu_type) {
 	case 0x3480:
 	    // This erpa is reserved for 3480 -> bug.
-	    tape34xx_error_recovery_HWBUG(ti,22);
+	    tape34xx_error_recovery_HWBUG(td,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(ti,ENOBUFS);
+	    tape34xx_error_recovery_has_failed(td,ENOBUFS);
 	    return;
 	}
     case 0x4f:
 	// These erpas are reserved -> bug
-	tape34xx_error_recovery_HWBUG(ti,23);
+	tape34xx_error_recovery_HWBUG(td,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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	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(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     case 0x52:
 	// End of Volume complete. Rewind unload completed ok. We'll report to the user...
-	if (tapestate_get(ti)!=TS_RUN_INIT) {
-	    tape34xx_error_recovery_HWBUG(ti,24);
+	if (treq->op!=TO_RUN) {
+	    tape34xx_error_recovery_HWBUG(td,24);
 	    return;
 	}
-	tape34xx_error_recovery_succeded(ti);
+	tape34xx_error_recovery_succeded(td);
 	return;
     case 0x53:
 	// Global command intercept. We'll have to reissue our command.
-	tape34xx_error_recovery_do_retry(ti);
+	tape34xx_error_recovery_do_retry(td);
 	return;
     case 0x54:
 	// Channel interface recovery (temporary). This can be recovered by reissuing the command.
-	tape34xx_error_recovery_do_retry(ti);
+	tape34xx_error_recovery_do_retry(td);
 	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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,EIO);
 	return;
     case 0x56:
 	// Channel protocol error. This cannot be recovered.
 	PRINT_WARN("A channel protocol error occurred.\n");
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti);
+	    tape34xx_error_recovery_do_retry(td);
 	    return;
 	case 0x3490:
 	    // Global status intercept. We have to reissue the command.
 	    PRINT_WARN("An global status intercept was received, which will be recovered.\n");
-	    tape34xx_error_recovery_do_retry(ti);
+	    tape34xx_error_recovery_do_retry(td);
 	    return;
 	}
     case 0x58:
     case 0x59:
 	// These erpas are reserved -> bug.
-	tape34xx_error_recovery_HWBUG(ti,25);
+	tape34xx_error_recovery_HWBUG(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti);
+	    tape34xx_error_recovery_do_retry(td);
 	    return;
 	}
 	PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n");
-	tape34xx_error_recovery_has_failed(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EIO);
+	tape34xx_error_recovery_has_failed(td,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(ti,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(td,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(ti,EMEDIUMTYPE);
+	tape34xx_error_recovery_has_failed(td,EMEDIUMTYPE);
 	return;
     default:
 	// Reserved erpas -> bug
-	tape34xx_error_recovery_HWBUG(ti,26);
+	tape34xx_error_recovery_HWBUG(td,26);
 	return;
     }
 }
 
-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 (ti) < TS_SIZE) && 
-		      (tapestate_get (ti) >= 0)) ?
-	state_verbose[tapestate_get (ti)] : "UNKNOWN"));
-#endif
-    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:
-	case TS_RFO_INIT:
-	case TS_RBA_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);
-	}
-    } else {
-	PRINT_WARN("Recieved an unsolicited IRQ.\n");
-	tape_dump_sense(&ti->devstat);
-    }
+void tape34xx_error_recovery_has_failed (tape_dev_t* td,int error_id) {
+	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+	tape_sprintf_event (tape_dbf_area,3,"Error Recovery failed for %s\n", tape_op_verbose[treq->op]);
+	treq->rc = -error_id;
+	if(treq->wakeup)
+		treq->wakeup (treq);
 }    
 
-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 (ti) < TS_SIZE) && 
-		      (tapestate_get (ti) >= 0)) ?
-	state_verbose[tapestate_get (ti)] : "UNKNOWN"));
-#endif
-    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(&ti->devstat);
-    }
+void tape34xx_error_recovery_succeded(tape_dev_t* td) {
+	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+	tape_sprintf_event (tape_dbf_area,3,"Error Recovery successfull for %s\n", tape_op_verbose[treq->op]);
+	tape34xx_done_handler(td);
 }
 
-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 (ti) < TS_SIZE) && 
-					  (tapestate_get (ti) >= 0)) ?
-					 state_verbose[tapestate_get (ti)] : "UNKNOWN"));
-#endif
-    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(&ti->devstat);
-    }
+void tape34xx_error_recovery_do_retry(tape_dev_t* td) {
+	tape_ccw_req_t* treq = tape_get_active_ccw_req(td);
+	tape_sprintf_event (tape_dbf_area,3,"xerp retr\n");
+	tape_sprintf_event (tape_dbf_area,3, "%s\n",tape_op_verbose[treq->op]);
+	tape_remove_ccw_req(td,treq);
+	tape_do_io_irq(td, treq,TAPE_NO_WAIT);
 }
     
 void 
-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.
-	ti->cqr=tape34xx_read_opposite(ti,0);
-	if (ti->cqr==NULL)
-	    tape34xx_error_recovery_has_failed(ti,EIO);
-	else
-	    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(ti,EIO);
-	break;
-    case TS_BLOCK_INIT:
-	tape34xx_error_recovery_do_retry(ti);
-	break;
-    default:
-	PRINT_WARN("read_opposite_recovery_called_with_state:%s\n",
-		   (((tapestate_get (ti) < TS_SIZE) && 
-		     (tapestate_get (ti) >= 0)) ?
-		    state_verbose[tapestate_get (ti)] : "UNKNOWN"));
-    }
+tape34xx_error_recovery_read_opposite (tape_dev_t* td) {
+	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+	switch (treq->op) {
+		case TO_RFO:
+			// We did read forward, but the data could not be read 
+			// *correctly*. We will read backward and then skip 
+			// forward again.
+			if(tape34xx_read_opposite(td))
+				tape34xx_error_recovery_do_retry(td);
+			else
+				tape34xx_error_recovery_has_failed(td,EIO);
+			break;
+		case TO_RBA:
+			// We tried to read forward and backward, but hat no 
+			// success -> failed.
+			tape34xx_error_recovery_has_failed(td,EIO);
+			break;
+		default:
+			PRINT_ERR("read_opposite_recovery_called_with_state:%s\n", tape_op_verbose[treq->op]);
+			tape34xx_error_recovery_has_failed(td,EIO);
+		}
 }
 
 void 
-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 (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],
-		stat->ii.sense.data[2], stat->ii.sense.data[3],
-		stat->ii.sense.data[4], stat->ii.sense.data[5],
-		stat->ii.sense.data[6], stat->ii.sense.data[7],
-		stat->ii.sense.data[8], stat->ii.sense.data[9],
-		stat->ii.sense.data[10], stat->ii.sense.data[11],
-		stat->ii.sense.data[12], stat->ii.sense.data[13],
-		stat->ii.sense.data[14], stat->ii.sense.data[15]);
-    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[16], stat->ii.sense.data[17],
-		stat->ii.sense.data[18], stat->ii.sense.data[19],
-		stat->ii.sense.data[20], stat->ii.sense.data[21],
-		stat->ii.sense.data[22], stat->ii.sense.data[23],
-		stat->ii.sense.data[24], stat->ii.sense.data[25],
-		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(ti,EIO);
+tape34xx_error_recovery_HWBUG (tape_dev_t* td,int condno) {
+	tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+	PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
+	PRINT_WARN("Please report this incident.\n");
+	if(treq)
+	PRINT_WARN("Operation of tape:%s\n", tape_op_verbose[treq->op]);
+	tape_dump_sense(td);
+	tape34xx_error_recovery_has_failed(td,EIO);
+}
+
+/*
+ * This routine is called by frontend after an ENOSP on write
+ */
+ 
+void tape34xx_process_eov(tape_dev_t* ti)
+{
+	tape_ccw_req_t *treq;
+	int rc;
+	int tm_written = 0;
+ 
+	/* End of volume: We have to backspace the last written record, then */
+	/* we TRY to write a tapemark and then backspace over the written TM */
+ 
+	treq = tape34xx_ioctl(ti,MTBSR,1,&rc);
+	if(treq){
+		tape_do_io_and_wait(ti,treq,TAPE_WAIT);
+		tape_free_ccw_req(treq);
+	}
+	treq = tape34xx_ioctl(ti,MTWEOF,1,&rc);
+	if(treq){
+		rc = tape_do_io_and_wait(ti,treq,TAPE_WAIT);
+		if((rc == 0) && (treq->rc == 0))
+			tm_written = 1;
+		tape_free_ccw_req(treq);
+	}
+	if(tm_written){
+		treq = tape34xx_ioctl(ti,MTBSR,1,&rc);
+		if(treq){
+			tape_do_io_and_wait(ti,treq,TAPE_WAIT);
+			tape_free_ccw_req(treq);
+		}
+	}
+}
+
+/*
+ * 34xx first level interrupt handler
+ */
+
+void tape34xx_irq(tape_dev_t* td)
+{
+	tape_ccw_req_t* treq = tape_get_active_ccw_req(td);
+	if (treq == NULL) {
+		tape34xx_unsolicited_irq(td);
+	} else if ((td->devstat.dstat & DEV_STAT_UNIT_EXCEP) && 
+		(td->devstat.dstat & DEV_STAT_DEV_END) &&
+		(treq->op == TO_WRI)){
+		/* Write at end of volume */
+		PRINT_INFO("End of volume\n"); /* XXX */
+		tape34xx_error_recovery_has_failed(td,ENOSPC);
+	} else if (td->devstat.dstat & DEV_STAT_UNIT_CHECK) {
+		tape34xx_error_recovery(td);
+	} else if (td->devstat.dstat & (DEV_STAT_DEV_END)) {
+		tape34xx_done_handler(td);
+        } else {
+		tape34xx_default_handler(td);
+	}
 }
+
+EXPORT_SYMBOL(tape34xx_irq);
+EXPORT_SYMBOL(tape34xx_write_block);
+EXPORT_SYMBOL(tape34xx_read_block);
+EXPORT_SYMBOL(tape34xx_ioctl);
+EXPORT_SYMBOL(tape34xx_ioctl_overload);
+EXPORT_SYMBOL(tape34xx_bread);
+EXPORT_SYMBOL(tape34xx_free_bread);
+EXPORT_SYMBOL(tape34xx_process_eov);
+EXPORT_SYMBOL(tape34xx_bread_enable_locate);
+
diff -Nru a/drivers/s390/char/tape34xx.h b/drivers/s390/char/tape34xx.h
--- a/drivers/s390/char/tape34xx.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/tape34xx.h	Sat Jun  8 22:31:51 2002
@@ -69,13 +69,6 @@
 #define         READ_SUBSYS_DATA        0x3E    /* 3490 CMD */
 #define         SET_INTERFACE_ID        0x73    /* 3490 CMD */
 
-#ifndef MIN
-#define MIN(a,b)                ( (a) < (b) ? (a) : (b) )
-#endif
-
-
-#define BLOCKSIZE               4096            /* size of the tape rcds */
-
 #define COMMAND_CHAIN    CCW_FLAG_CC      /* redefine from irq.h */
 #define CHANNEL_END      DEV_STAT_CHN_END /* redefine from irq.h */
 #define DEVICE_END       DEV_STAT_DEV_END /* redefine from irq.h */
@@ -112,72 +105,29 @@
 typedef struct _tape34xx_disc_data_t {
     __u8 modeset_byte;
 } tape34xx_disc_data_t  __attribute__ ((packed, aligned(8)));
+#define MOD_BYTE ((tape34xx_disc_data_t *)td->discdata)->modeset_byte
 
 /* 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 * 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*);
+int tape34xx_ioctl_overload (tape_dev_t* td, unsigned int cmd, unsigned long arg);
+tape_ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_dev_t* td);
+tape_ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_dev_t* td);
+tape_ccw_req_t * tape34xx_ioctl(tape_dev_t* td, int op,int count, int* rc);
+tape_ccw_req_t * tape34xx_bread (struct request *req, tape_dev_t* td,int tapeblock_major);
+void tape34xx_free_bread (tape_ccw_req_t* treq);
+void tape34xx_bread_enable_locate (tape_ccw_req_t * treq);
+tape_ccw_req_t * tape34xx_bwrite (struct request *req, tape_dev_t* td,int tapeblock_major);
 
 /* Event handlers */
-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 *ti);
+void tape34xx_default_handler (tape_dev_t * td);
+void tape34xx_unexpect_uchk_handler (tape_dev_t * td);
+void tape34xx_irq (tape_dev_t* td);
+void tape34xx_process_eov(tape_dev_t* td);
 
 // the error recovery stuff:
-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);
+void tape34xx_error_recovery (tape_dev_t* td);
+void tape34xx_error_recovery_has_failed (tape_dev_t* td,int error_id);
+void tape34xx_error_recovery_succeded(tape_dev_t* td);
+void tape34xx_error_recovery_do_retry(tape_dev_t* td);
+void tape34xx_error_recovery_read_opposite (tape_dev_t* td);
+void  tape34xx_error_recovery_HWBUG (tape_dev_t* td,int condno);
 #endif // _TAPE34XX_H
diff -Nru a/drivers/s390/char/tape3590.c b/drivers/s390/char/tape3590.c
--- a/drivers/s390/char/tape3590.c	Sat Jun  8 22:31:49 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1 +0,0 @@
-// tbd
diff -Nru a/drivers/s390/char/tape3590.h b/drivers/s390/char/tape3590.h
--- a/drivers/s390/char/tape3590.h	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1 +0,0 @@
-// tbd
diff -Nru a/drivers/s390/char/tape_idalbuf.h b/drivers/s390/char/tape_idalbuf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/char/tape_idalbuf.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,213 @@
+/***************************************************************************
+ *
+ *  drivers/s390/char/tape_idalbuf.h
+ *    functions for idal buffer handling
+ *
+ *  S390 and zSeries version
+ *    Copyright (C) 2001 IBM Corporation
+ *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ *
+ ****************************************************************************
+ */
+
+#include <linux/kernel.h>
+#include <asm/hardirq.h> // in_interrupt
+
+/*
+ * Macros
+ */
+
+#ifdef CONFIG_ARCH_S390X
+	// on ESAME each idal entry points to a 4K buffer
+	#define IDALBUF_BLK_SIZE    4096
+#else
+	// on ESA each idal entry points to a 2K buffer
+	#define IDALBUF_BLK_SIZE    2048
+#endif
+
+#define IDALBUF_MAX_ENTRIES 33 // an ida list can have up to 33 entries
+#define IDALBUF_PAGE_ORDER  1  // each chunk has 2exp(1) pages
+
+#define __IDALBUF_CHUNK_SIZE   ((1<<IDALBUF_PAGE_ORDER) * PAGE_SIZE)
+#define __IDALBUF_ENTRIES_PER_CHUNK (__IDALBUF_CHUNK_SIZE/IDALBUF_BLK_SIZE)
+
+// Macro which finds out, if we need idal addressing
+
+#ifdef CONFIG_ARCH_S390X
+#define __IDALBUF_DIRECT_ADDR(idal) \
+	( (idal->size <= __IDALBUF_CHUNK_SIZE) \
+	&& ( ( ((unsigned long)idal->data[0]) >> 31) == 0) )
+#else
+#define __IDALBUF_DIRECT_ADDR(idal) \
+	(idal->size <= __IDALBUF_CHUNK_SIZE)
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/*
+ * The idalbuf data structure
+ */
+
+typedef struct _idalbuf_t{
+	void*   data[IDALBUF_MAX_ENTRIES];
+	int     size;
+} idalbuf_t;
+
+static inline unsigned int
+__round_up_multiple (unsigned int no, unsigned int mult)
+{
+        int rem = no % mult;
+        return (rem ? no - rem + mult : no);
+}
+
+/*
+ * Setup a ccw in a way that the data buf is an idalbuf_mem_t
+ */
+
+static inline void
+idalbuf_set_normalized_cda(ccw1_t *ccw, idalbuf_t* idal)
+{
+	if(__IDALBUF_DIRECT_ADDR(idal)){
+		// we do not need idals - use direct addressing
+		ccw->cda = (unsigned long) idal->data[0];
+	} else {
+		// setup idals
+		ccw->flags |= CCW_FLAG_IDA;
+		ccw->cda = (unsigned long) idal->data;
+	}
+	ccw->count = idal->size;
+}
+
+/*
+ * Alloc size bytes of memory
+ */
+
+static inline idalbuf_t* 
+idalbuf_alloc(size_t size)
+{
+	int i = 0;
+	int count = __round_up_multiple(size,IDALBUF_BLK_SIZE) / IDALBUF_BLK_SIZE;
+	idalbuf_t* rc;
+	char* addr = NULL;
+	int kmalloc_flags;
+	if(in_interrupt())
+		kmalloc_flags = GFP_ATOMIC;
+	else
+		kmalloc_flags = GFP_KERNEL;
+
+	if(size/IDALBUF_BLK_SIZE > IDALBUF_MAX_ENTRIES)
+		BUG();
+	// the ida list must be below 2GB --> GFP_DMA
+	rc = kmalloc(sizeof(idalbuf_t),kmalloc_flags | GFP_DMA);
+	if(!rc)
+		goto error;
+	for(i=0; i< count;i++){
+		if((i % __IDALBUF_ENTRIES_PER_CHUNK) == 0){
+			// data does not need to be below 2GB
+			rc->data[i] = (void*)__get_free_pages(kmalloc_flags ,IDALBUF_PAGE_ORDER);
+			if(!rc->data[i])
+				goto error;
+			addr = (char*)(rc->data[i]);
+		} else {
+			addr+=IDALBUF_BLK_SIZE;
+			rc->data[i] = addr;
+		}
+	}
+	rc->size=size;
+	return rc;
+error:
+	if(rc){
+		int end = i;
+		for(i=end-1;i>=0;i-=__IDALBUF_ENTRIES_PER_CHUNK)
+			free_pages((unsigned long)rc->data[i],IDALBUF_PAGE_ORDER);
+		kfree(rc);
+	}
+	return NULL;
+}
+
+/*
+ * Free an idal buffer
+ */
+
+static inline void
+idalbuf_free(idalbuf_t* idal)
+{
+	int count = __round_up_multiple(idal->size,__IDALBUF_CHUNK_SIZE)/__IDALBUF_CHUNK_SIZE;
+	int i;
+	for(i = 0; i < count; i++){
+		free_pages((unsigned long)idal->data[i*__IDALBUF_ENTRIES_PER_CHUNK],IDALBUF_PAGE_ORDER);
+	}
+	kfree(idal);
+}
+
+/*
+ * Copy count bytes from an idal buffer to contiguous user memory
+ */
+
+static inline int
+idalbuf_copy_to_user(void* to, const idalbuf_t* from, size_t count)
+{
+	int i;
+	int rc = 0;
+	if(count > from->size)
+		BUG();
+	for(i = 0; i < count; i+=__IDALBUF_CHUNK_SIZE){
+		rc = copy_to_user(((char*)to) + i,from->data[i/IDALBUF_BLK_SIZE],MIN(__IDALBUF_CHUNK_SIZE,(count-i)));
+		if(rc)
+			goto out;
+	}
+out:
+	return rc;
+}
+
+/*
+ * Copy count bytes from contiguous user memory to an idal buffer
+ */
+
+static inline int
+idalbuf_copy_from_user(idalbuf_t* to, const void* from, size_t count)
+{
+	int i;
+	int rc = 0;
+	if(count > to->size)
+		BUG();
+	for(i = 0; i < count; i+=__IDALBUF_CHUNK_SIZE){
+		rc = copy_from_user(to->data[i/IDALBUF_BLK_SIZE],((char*)from)+i,MIN(__IDALBUF_CHUNK_SIZE,(count-i)));
+		if(rc)
+			goto out;
+	}
+out:
+	return rc;
+}
+
+/*
+ * Copy count bytes from an idal buffer to a contiguous kernel buffer
+ */
+
+static inline void
+idalbuf_copy_from_idal(void* to, const idalbuf_t* from, size_t count)
+{
+        int i;
+	if(count > from->size)
+		BUG();
+        for(i = 0; i < count; i+=__IDALBUF_CHUNK_SIZE){
+                memcpy((char*)to + i,(from->data[i/IDALBUF_BLK_SIZE]),MIN(__IDALBUF_CHUNK_SIZE,(count-i)) );
+	}
+}
+
+/*
+ * Copy count bytes from a contiguous kernel buffer to an idal buffer
+ */
+ 
+static inline void 
+idalbuf_copy_to_idal(idalbuf_t* to, const void* from, size_t count)
+{
+        int i;
+	if(count > to->size)
+		BUG();
+        for(i = 0; i < count; i+=__IDALBUF_CHUNK_SIZE){
+                memcpy(to->data[i/IDALBUF_BLK_SIZE],(char*)from+i,MIN(__IDALBUF_CHUNK_SIZE,(count-i)) );
+	}
+}
diff -Nru a/drivers/s390/char/tapeblock.c b/drivers/s390/char/tapeblock.c
--- a/drivers/s390/char/tapeblock.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tapeblock.c	Sat Jun  8 22:31:37 2002
@@ -1,4 +1,3 @@
-
 /***************************************************************************
  *
  *  drivers/s390/char/tapeblock.c
@@ -19,7 +18,6 @@
 #include <linux/blk.h>
 #include <linux/version.h>
 #include <linux/interrupt.h>
-#include <asm/ccwcache.h>	/* CCW allocations      */
 #include <asm/debug.h>
 #include <asm/s390dyn.h>
 #include <linux/compatmac.h>
@@ -56,533 +54,451 @@
 static request_queue_t* tapeblock_getqueue (kdev_t kdev);
 
 #ifdef CONFIG_DEVFS_FS
-void
-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);
+devfs_handle_t
+tapeblock_mkdevfstree (tape_dev_t* td) {
+    devfs_handle_t rc=NULL;
+    rc=td->blk_data.devfs_block_dir=devfs_mk_dir (td->devfs_dir, "block", td);
+    if (rc==NULL) goto out_undo;
+    rc=td->blk_data.devfs_disc=devfs_register(td->blk_data.devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
+				    tapeblock_major, td->first_minor,
+				    TAPEBLOCK_DEVFSMODE, &tapeblock_fops, td);
+    if (rc==NULL) goto out_undo;
+    goto out;
+ out_undo:
+    tapeblock_rmdevfstree(td);
+ out:
+    return rc;
 }
 
 void
-tapeblock_rmdevfstree (tape_info_t* ti) {
-    devfs_unregister(ti->devfs_disc);
-    devfs_unregister(ti->devfs_block_dir);
+tapeblock_rmdevfstree (tape_dev_t* td) {
+    if (td->blk_data.devfs_disc)
+            devfs_unregister(td->blk_data.devfs_disc);
+    if (td->blk_data.devfs_block_dir)
+            devfs_unregister(td->blk_data.devfs_block_dir);
 }
 #endif
 
 void 
-tapeblock_setup(tape_info_t* ti) {
-    blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
-    blk_init_queue (&ti->request_queue, tape_request_fn); 
+tapeblock_setup(tape_dev_t* td) {
+    blk_size[tapeblock_major][td->first_minor]=0; // this will be detected
     blk_queue_hardsect_size(&ti->request_queue, 2048);
+    blk_init_queue (&td->blk_data.request_queue, tape_request_fn); 
 #ifdef CONFIG_DEVFS_FS
-    tapeblock_mkdevfstree(ti);
+    tapeblock_mkdevfstree(td);
 #endif
+    set_device_ro (MKDEV(tapeblock_major, td->first_minor), 1);
 }
 
 int
 tapeblock_init(void) {
-    int result;
-    tape_frontend_t* blkfront,*temp;
-    tape_info_t* ti;
-
-    tape_init();
-    /* Register the tape major number to the kernel */
+	int result;
+	tape_frontend_t* blkfront,*temp;
+	tape_dev_t* td;
+	tape_init();
+	/* Register the tape major number to the kernel */
 #ifdef CONFIG_DEVFS_FS
-    result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+	result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
 #else
-    result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
+	result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);
 #endif
-    if (result < 0) {
-        PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major);
-        panic ("cannot get major number for tape block device");
-    }
-    if (tapeblock_major == 0) tapeblock_major = result;   /* accept dynamic major number*/
-    INIT_BLK_DEV(tapeblock_major,tape_request_fn,tapeblock_getqueue,NULL);
-    PRINT_WARN(KERN_ERR " tape gets major %d for block device\n", result);
-    blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
-    memset(blk_size[tapeblock_major],0,256*sizeof(int));
-    max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC);
-    memset(max_sectors[tapeblock_major],0,256*sizeof(int));
-    blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
-    if (blkfront==NULL) panic ("no mem for tape block device structure");
-    blkfront->device_setup=tapeblock_setup;
+	if (result < 0) {
+		PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major);
+		result=-ENODEV;
+		goto out;
+	}
+	if (tapeblock_major == 0) tapeblock_major = result;   /* accept dynamic major number*/
+	INIT_BLK_DEV(tapeblock_major,tape_request_fn,tapeblock_getqueue,NULL);
+	PRINT_WARN(KERN_ERR " tape gets major %d for block device\n", tapeblock_major);
+	blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
+	if (blk_size[tapeblock_major]==NULL) goto out_undo_bdev;
+	memset(blk_size[tapeblock_major],0,256*sizeof(int));
+	hardsect_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
+	if (hardsect_size[tapeblock_major]==NULL) goto out_undo_blk_size;
+	memset(hardsect_size[tapeblock_major],0,256*sizeof(int));
+	max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_KERNEL);
+	if (max_sectors[tapeblock_major]==NULL) goto out_undo_hardsect_size;
+	memset(max_sectors[tapeblock_major],0,256*sizeof(int));
+	blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL);
+	if (blkfront==NULL) goto out_undo_max_sectors;
+	blkfront->device_setup=(tape_setup_device_t)tapeblock_setup;
 #ifdef CONFIG_DEVFS_FS
-    blkfront->mkdevfstree = tapeblock_mkdevfstree;
-    blkfront->rmdevfstree = tapeblock_rmdevfstree;
+	blkfront->mkdevfstree = tapeblock_mkdevfstree;
+	blkfront->rmdevfstree = tapeblock_rmdevfstree;
 #endif
-    blkfront->next=NULL;
-    if (first_frontend==NULL) {
-	first_frontend=blkfront;
-    } else {
-	temp=first_frontend;
-	while (temp->next!=NULL)
-	temp=temp->next;
-	temp->next=blkfront;
-    }
-    ti=first_tape_info;
-    while (ti!=NULL) {
-	tapeblock_setup(ti);
-	ti=ti->next;
-    }
-    return 0;
+	blkfront->next=NULL;
+	if (tape_first_front==NULL) {
+		tape_first_front=blkfront;
+	} else {
+		temp=tape_first_front;
+		while (temp->next!=NULL) 
+			temp=temp->next;
+		temp->next=blkfront;
+	}
+	td=tape_first_dev;
+	while (td!=NULL) {
+		tapeblock_setup(td);
+		td=td->next;
+	}
+	result=0;
+	goto out;
+out_undo_max_sectors:
+	kfree(max_sectors[tapeblock_major]);
+out_undo_hardsect_size:
+	kfree(hardsect_size[tapeblock_major]);
+out_undo_blk_size:
+	kfree(blk_size[tapeblock_major]);
+out_undo_bdev:
+#ifdef CONFIG_DEVFS_FS
+	devfs_unregister_blkdev(tapeblock_major, "tBLK");
+#else
+	unregister_blkdev(tapeblock_major, "tBLK");
+#endif
+	result=-ENOMEM;
+	blk_size[tapeblock_major]=
+	hardsect_size[tapeblock_major]=
+	max_sectors[tapeblock_major]=NULL;
+	tapeblock_major=-1;    
+out:
+	return result;
 }
 
 
 void 
 tapeblock_uninit(void) {
-    unregister_blkdev(tapeblock_major, "tBLK");
+	if (tapeblock_major==-1)
+	        goto out; /* init failed so there is nothing to clean up */
+	if (blk_size[tapeblock_major]!=NULL) {
+		kfree(blk_size[tapeblock_major]);
+		blk_size[tapeblock_major]=NULL;
+	}
+	if (hardsect_size[tapeblock_major]!=NULL) {
+		kfree (hardsect_size[tapeblock_major]);
+		hardsect_size[tapeblock_major]=NULL;
+	}
+	if (max_sectors[tapeblock_major]!=NULL) {
+		kfree (max_sectors[tapeblock_major]);
+		max_sectors[tapeblock_major]=NULL;
+	}
+
+#ifdef CONFIG_DEVFS_FS
+	devfs_unregister_blkdev(tapeblock_major, "tBLK");
+#else
+	unregister_blkdev(tapeblock_major, "tBLK");
+#endif
+
+out:
+	return;
 }
 
 int
 tapeblock_open(struct inode *inode, struct file *filp) {
-    tape_info_t *ti;
-    kdev_t dev;
-    int rc;
-    long lockflags;
+	tape_dev_t *td = NULL;
+	int rc = 0;
+	long lockflags;
+
+
+	tape_sprintf_event (tape_dbf_area,6,"b:open:  %x\n",td->first_minor);
+
+	inode = filp->f_dentry->d_inode;
 
-    inode = filp->f_dentry->d_inode;
-    ti = first_tape_info;
-    while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev)))
-		ti = (tape_info_t *) ti->next;
-	if (ti == NULL)
-		return -ENODEV;
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"b:open:");
-	debug_int_event (tape_debug_area,6,ti->blk_minor);
-#endif
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	if (tapestate_get (ti) != TS_UNUSED) {
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,6,"b:dbusy");
-#endif
-		return -EBUSY;
-	}
-	tapestate_set (ti, TS_IDLE);
-        ti->position=-1;
-        
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-        rc=tapeblock_mediumdetect(ti);
+	td = tape_get_device_by_minor(MINOR (inode->i_rdev));
+	if (td == NULL){
+		rc = -ENODEV;
+		goto error;
+	}
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	if (tape_state_get(td) == TS_NOT_OPER) {
+		tape_sprintf_event (tape_dbf_area,6,"c:nodev\n");
+		rc = -ENODEV;
+		goto out_rel_lock;
+	}
+	if (tape_state_get (td) != TS_UNUSED) {
+		tape_sprintf_event (tape_dbf_area,6,"b:dbusy\n");
+		rc = -EBUSY;
+		goto out_rel_lock;
+	}
+	tape_state_set (td, TS_IN_USE);
+        td->blk_data.position=-1;
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+        rc=tapeblock_mediumdetect(td);
         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;
-	filp->private_data = ti;	/* save the dev.info for later reference */
-        ti->cqr=NULL;
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-    
-	return 0;
+	    s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	    tape_state_set (td, TS_UNUSED);
+	    goto out_rel_lock; // in case of errors, we don't have a size of the medium
+	}
+	if ( td->discipline->owner )
+		__MOD_INC_USE_COUNT(td->discipline->owner);
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+	td->filp = filp;
+	filp->private_data = td;/* save the dev.info for later reference */
+out_rel_lock:
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+error:
+	if(rc != 0){
+		if (td != NULL)
+			tape_put_device(td);
+	}
+	return rc;
 }
 
 int
 tapeblock_release(struct inode *inode, struct file *filp) {
 	long lockflags;
-	tape_info_t *ti,*lastti;
-	ti = first_tape_info;
-	while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev)))
-		ti = (tape_info_t *) ti->next;
-	if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) {
-	    if (ti==first_tape_info) {
-		first_tape_info=ti->next;
-	    } else {
-		lastti=first_tape_info;
-		while (lastti->next!=ti) lastti=lastti->next;
-		lastti->next=ti->next;
-	    }
-	    kfree(ti);    
-	    return 0;
-	}
-	if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,3,"b:notidle!");
-#endif
-		return -ENXIO;	/* error in tape_release */
-	}
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"b:release:");
-	debug_int_event (tape_debug_area,6,ti->blk_minor);
-#endif
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	tapestate_set (ti, TS_UNUSED);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	invalidate_bdev(inode->i_bdev, 0);
-	return 0;
+	tape_dev_t *td = NULL;
+	int rc = 0;
+	if((!inode) || !(inode->i_rdev)) {
+		rc = -EINVAL;
+		goto out;
+	}
+	td = tape_get_device_by_minor(MINOR (inode->i_rdev));
+	if (td==NULL) {
+		rc = -ENODEV;
+		goto out;
+	}
+	s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+
+	tape_sprintf_event (tape_dbf_area,6,"b:release: %x\n",td->first_minor);
+	if(tape_state_get(td) == TS_IN_USE)
+		tape_state_set (td, TS_UNUSED);
+	else if (tape_state_get(td) != TS_NOT_OPER) 
+		BUG();
+	s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags);
+	tape_put_device(td);
+	tape_put_device(td); /* 2x ! */
+	if ( td->discipline->owner )
+		__MOD_DEC_USE_COUNT(td->discipline->owner);
+	invalidate_bdev(inode->i_rdev, 0);
+out:
+	return rc;
 }
 
 static void
-tapeblock_end_request(tape_info_t* ti) {
+tapeblock_end_request(tape_dev_t* td) {
     struct buffer_head *bh;
     int uptodate;
-    if ((tapestate_get(ti)!=TS_FAILED) &&
-	(tapestate_get(ti)!=TS_DONE))
-       BUG(); // A request has to be completed to end it
-    uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?
-#ifdef TAPE_DEBUG
+    tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+    if(treq == NULL){
+	uptodate = 0;
+    }
+    else
+    	uptodate=(treq->rc == 0); // is the buffer up to date?
     if (uptodate) {
-	debug_text_event (tape_debug_area,6,"b:done:");
-	debug_int_event (tape_debug_area,6,(long)ti->cqr);
+	tape_sprintf_event (tape_dbf_area,6,"b:done: %x\n",(unsigned long)treq);
     } else {
-	debug_text_event (tape_debug_area,3,"b:failed:");
-	debug_int_event (tape_debug_area,3,(long)ti->cqr);
+	tape_sprintf_event (tape_dbf_area,3,"b:failed: %x\n",(unsigned long)treq);
     }
-#endif
     // now inform ll_rw_block about a request status
-    while ((bh = ti->current_request->bh) != NULL) {
-	ti->current_request->bh = bh->b_reqnext;
+    while ((bh = td->blk_data.current_request->bh) != NULL) {
+	td->blk_data.current_request->bh = bh->b_reqnext;
 	bh->b_reqnext = NULL;
 	bh->b_end_io (bh, uptodate);
     }
-    if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {
+    if (!end_that_request_first (td->blk_data.current_request, uptodate, "tBLK")) {
 #ifndef DEVICE_NO_RANDOM
-	add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));
+	add_blkdev_randomness (MAJOR (td->blk_data.current_request->rq_dev));
 #endif
-	end_that_request_last (ti->current_request);
+	end_that_request_last (td->blk_data.current_request);
+    }
+    if (treq!=NULL) {
+	    tape_remove_ccw_req(td,treq);
+	    td->discipline->free_bread(treq);
     }
-    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);
+    td->blk_data.current_request=NULL;
     return;
 }
 
 static void
-tapeblock_exec_IO (tape_info_t* ti) {
+tapeblock_exec_IO (tape_dev_t* td) {
     int rc;
     struct request* req;
-    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)ti->cqr);
-#endif
-	    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)ti->cqr);
-#endif 
+    tape_ccw_req_t *treq = tape_get_active_ccw_req(td);
+
+    if (treq) { // process done/failed request
+	while (treq->rc != 0 && td->blk_data.blk_retries>0) {
+	    td->blk_data.blk_retries--;
+	    td->blk_data.position=-1;
+	    td->discipline->bread_enable_locate(treq);
+	    tape_sprintf_event (tape_dbf_area,3,"b:retryreq: %x\n",(unsigned long)treq);
+	    rc = tape_do_io_irq(td,treq,TAPE_SCHED_BLOCK);
+	    if (rc != 0) {
+		tape_sprintf_event (tape_dbf_area,3,"b:doIOfail: %x\n",(unsigned long)treq);
 		continue; // one retry lost 'cause doIO failed
 	    }
 	    return;
 	}
-	tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
+	tapeblock_end_request (td); // check state, inform user, free mem, dev=idl
     }
-    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;
+    if(TAPE_BUSY(td)) BUG(); // tape should be idle now, request should be freed!
+    if (tape_state_get (td) == TS_NOT_OPER) {
 	return;
     }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	if (list_empty (&ti->request_queue.queue_head)) {
+	if (list_empty (&td->blk_data.request_queue.queue_head)) {
 #else
-	if (ti->request_queue==NULL) {
+	if (td->blk_data.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(ti,TS_IDLE);
+	tape_sprintf_event (tape_dbf_area,6,"b:Qempty\n");
 	return;
     }
     // queue is not empty, fetch a request and start IO!
-    req=ti->current_request=tape_next_request(&ti->request_queue);
+    req=td->blk_data.current_request=tape_next_request(&td->blk_data.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(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);
+	tapeblock_end_request (td); // check state, inform user, free mem, dev=idl
+	tapeblock_schedule_exec_io(td);
 	return;
     }
-    ti->cqr=ti->discipline->bread(req,ti,tapeblock_major); //build channel program from request
-    if (!ti->cqr) {
+    treq=td->discipline->bread(req,td,tapeblock_major); //build channel program from request
+    if (!treq) {
 	// ccw generation failed. we try again later.
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,3,"b:cqrNULL");
-#endif
-	schedule_tapeblock_exec_IO(ti);
-	ti->current_request=NULL;
+	tape_sprintf_event (tape_dbf_area,3,"b:cqrNULL\n");
+	tapeblock_schedule_exec_io(td);
+	td->blk_data.current_request=NULL;
 	return;
     }
-    ti->blk_retries = TAPEBLOCK_RETRIES;
-    rc= do_IO (ti->devinfo.irq, ti->cqr->cpaddr, 
-	       (unsigned long) ti->cqr, 0x00, ti->cqr->options);
-    if (rc) {
+    td->blk_data.blk_retries = TAPEBLOCK_RETRIES;
+    rc = tape_do_io_irq(td,treq,TAPE_SCHED_BLOCK);
+    if (rc != 0) {
 	// okay. ssch failed. we try later.
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,3,"b:doIOfail");
-#endif
-	ti->discipline->free_bread(ti->cqr,ti);
-	ti->cqr=NULL;
-	ti->current_request=NULL;
-	schedule_tapeblock_exec_IO(ti);
+	tape_sprintf_event (tape_dbf_area,3,"b:doIOfail\n");
+	tape_remove_ccw_req(td,treq);
+	td->discipline->free_bread(treq);
+	td->blk_data.current_request=NULL;
+	tapeblock_schedule_exec_io(td);
 	return;
     }
     // our request is in IO. we remove it from the queue and exit
-    tape_dequeue_request (&ti->request_queue,req);
+    tape_dequeue_request (&td->blk_data.request_queue,req);
 }
 
 static void 
-do_tape_request (request_queue_t * queue) {
-    tape_info_t* ti;
+do_tape_request (tape_dev_t * td) {
     long 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);
+    if (td==NULL) BUG();
+    s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags);
+    if (tape_state_get(td)!=TS_IN_USE) {
+	s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
 	return;
     }
-    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);
+    tapeblock_exec_IO(td);
+    s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
 }
 
 static void
-run_tapeblock_exec_IO (tape_info_t* ti) {
+run_tapeblock_exec_IO (tape_dev_t* td) {
     long flags_390irq,flags_ior;
     request_queue_t *q = &tape->request_queue;
 
     spin_lock_irqsave (&q->queue_lock, flags_ior);
-    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);
+    s390irq_spin_lock_irqsave(td->devinfo.irq,flags_390irq);
+    atomic_set(&td->blk_data.bh_scheduled,0);
+    tapeblock_exec_IO(td);
+    s390irq_spin_unlock_irqrestore(td->devinfo.irq,flags_390irq);
     spin_unlock_irqrestore (&q->queue_lock, flags_ior);
 }
 
 void
-schedule_tapeblock_exec_IO (tape_info_t *ti)
+tapeblock_schedule_exec_io (tape_dev_t *td)
 {
 	/* Protect against rescheduling, when already running */
-        if (atomic_compare_and_swap(0,1,&ti->bh_scheduled)) {
+        if (atomic_compare_and_swap(0,1,&td->blk_data.bh_scheduled)) {
                 return;
         }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	INIT_LIST_HEAD(&ti->bh_tq.list);
+	INIT_LIST_HEAD(&td->blk_data.bh_tq.list);
 #endif
-	ti->bh_tq.sync = 0;
-	ti->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
-	ti->bh_tq.data = ti;
+	td->blk_data.bh_tq.sync = 0;
+	td->blk_data.bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
+	td->blk_data.bh_tq.data = td;
 
-	queue_task (&ti->bh_tq, &tq_immediate);
+	queue_task (&td->blk_data.bh_tq, &tq_immediate);
 	mark_bh (IMMEDIATE_BH);
 	return;
 }
 
 /* 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* ti=first_tape_info;
-    while (ti!=NULL) {
-	do_tape_request(&ti->request_queue);
-	ti=ti->next;
-    }
+static void tape_request_fn (void) { 
+	tape_dev_t* td=tape_first_dev;
+	long lockflags;
+	read_lock_irqsave(&tape_dev_lock,lockflags);
+	while (td!=NULL) {
+		tape_get_device(td);
+		do_tape_request(td);
+		tape_put_device(td);
+		td=td->next;
+	}
+	read_unlock_irqsave(&tape_dev_lock,lockflags);
 }
 #else
 static void  tape_request_fn (request_queue_t* queue) {
-    do_tape_request(queue);
+	tape_dev_t* td=tape_get_device_by_queue(queue);
+	if (td!=NULL) {
+		do_tape_request(td);
+		tape_put_device(td);
+	}		
 }
 #endif
 
 static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
-    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* ti) {
-        ccw_req_t* cqr;
-    int losize=1,hisize=1,rc;
-    long lockflags;
-#ifdef TAPE_DEBUG
-    debug_text_event (tape_debug_area,3,"b:medDet");
-#endif
-    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=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 (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 (ti->wq,ti->wanna_wakeup);
-	ti->cqr = NULL;
-	tape_free_request (cqr);
-	if (ti->kernbuf) {
-	    kfree (ti->kernbuf);
-	    ti->kernbuf=NULL;
-	}
-	if (signal_pending (current)) {
-		tapestate_set (ti, TS_IDLE);
-		return -ERESTARTSYS;
-	}
-	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 (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 (ti) != TS_DONE) {
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		return -EIO;
-	}
-	tapestate_set (ti, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	losize=hisize;
-    }
-    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 (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 (ti, TS_IDLE);
-	return -ERESTARTSYS;
-    }
-    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 (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 (ti) != TS_DONE) {
-	tapestate_set (ti, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	return -EIO;
-    }
-    tapestate_set (ti, TS_IDLE);
-    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-    while (losize!=hisize) {
-	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 (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 (ti->wq,ti->wanna_wakeup);
-	ti->cqr = NULL;
-	tape_free_request (cqr);
-	if (ti->kernbuf) {
-	    kfree (ti->kernbuf);
-	    ti->kernbuf=NULL;
-	}
-	if (signal_pending (current)) {
-		tapestate_set (ti, TS_IDLE);
-		return -ERESTARTSYS;
-	}
-	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 (ti) == TS_FAILED) {
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		hisize=(hisize+losize)/2;
-		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 (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 (ti, TS_IDLE);
-		    return -ERESTARTSYS;
-		}
-		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 (ti) != TS_DONE) {
-		    tapestate_set (ti, TS_IDLE);
-		    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		    return -EIO;
-		}
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		continue;
-	}
-	if (tapestate_get (ti) != TS_DONE) {
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		return -EIO;
-	}
-	tapestate_set (ti, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	losize=(hisize+losize)/2+1;
-    }
-    blk_size[tapeblock_major][ti->blk_minor]=losize*2;
-    return 0;
+	tape_dev_t* td=tape_get_device_by_minor(MINOR(kdev));
+	if (td!=NULL) return &td->blk_data.request_queue;
+	else return NULL;
+}
+
+int tapeblock_mediumdetect(tape_dev_t* td) {
+	tape_ccw_req_t *treq;
+	unsigned int nr_of_blks;
+	int rc;
+	PRINT_INFO("Detecting media size...\n");
+
+	/* Rewind */
+
+	treq = td->discipline->ioctl (td, MTREW, 1, &rc);
+	if (treq == NULL)
+		return rc;
+	rc = tape_do_io_and_wait (td,treq,TAPE_WAIT_INTERRUPTIBLE);
+	TAPE_MERGE_RC(treq,rc);
+	tape_free_ccw_req (treq);
+	if (rc)
+		return rc;
+
+	/* FSF */
+
+	treq=td->discipline->ioctl (td, MTFSF,1,&rc);
+	if (treq == NULL) 
+		return rc;
+	rc = tape_do_io_and_wait (td,treq,TAPE_WAIT_INTERRUPTIBLE);
+	TAPE_MERGE_RC(treq,rc);
+	tape_free_ccw_req (treq);
+	if (rc)
+		return rc;
+
+	/* TELL */
+
+	treq = td->discipline->ioctl (td, MTTELL, 1, &rc);
+	if (treq == NULL) 
+		return rc;
+	rc = tape_do_io_and_wait(td,treq,TAPE_WAIT_INTERRUPTIBLE);
+	TAPE_MERGE_RC(treq,rc);
+	nr_of_blks = *((int*)(treq->kernbuf)) - 1; /* don't count FM */
+	tape_free_ccw_req (treq);
+	if(rc)
+		return rc;
+
+	/* Rewind */
+
+	treq = td->discipline->ioctl (td, MTREW, 1, &rc);
+        if (treq == NULL)
+		return rc;
+        rc = tape_do_io_and_wait(td,treq,TAPE_WAIT_INTERRUPTIBLE);
+	TAPE_MERGE_RC(treq,rc);
+        tape_free_ccw_req (treq);
+	if(rc)	
+		return rc;
+	return 0;
 }
diff -Nru a/drivers/s390/char/tapeblock.h b/drivers/s390/char/tapeblock.h
--- a/drivers/s390/char/tapeblock.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tapeblock.h	Sat Jun  8 22:31:37 2002
@@ -1,7 +1,7 @@
 
 /***************************************************************************
  *
- *  drivers/s390/char/tapechar.h
+ *  drivers/s390/char/tapeblock.h
  *    character device frontend for tape device driver
  *
  *  S390 and zSeries version
@@ -16,20 +16,20 @@
 #ifndef TAPEBLOCK_H
 #define TAPEBLOCK_H
 #include <linux/config.h>
-#define PARTN_BITS 0
 
 #define TAPEBLOCK_READAHEAD 30
 #define TAPEBLOCK_MAJOR 0
 
-#define TAPEBLOCK_DEFAULTMODE 0060644
+#define TAPEBLOCK_DEVFSMODE 0060644 // blkdev, rwx for user, rw for group&others
 
 int tapeblock_open(struct inode *, struct file *);
 int tapeblock_release(struct inode *, struct file *);
-void tapeblock_setup(tape_info_t* ti);
-void schedule_tapeblock_exec_IO (tape_info_t *ti);
-int tapeblock_mediumdetect(tape_info_t* ti);
+void tapeblock_setup(tape_dev_t* td);
+void tapeblock_schedule_exec_io (tape_dev_t *td);
+int tapeblock_mediumdetect(tape_dev_t* td);
 #ifdef CONFIG_DEVFS_FS
-void tapeblock_mkdevfstree (tape_info_t* ti);
+devfs_handle_t tapeblock_mkdevfstree (tape_dev_t* td);
+void tapeblock_rmdevfstree (tape_dev_t* td);
 #endif
 int tapeblock_init (void);
 void tapeblock_uninit (void);
diff -Nru a/drivers/s390/char/tapechar.c b/drivers/s390/char/tapechar.c
--- a/drivers/s390/char/tapechar.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tapechar.c	Sat Jun  8 22:31:37 2002
@@ -1,4 +1,3 @@
-
 /***************************************************************************
  *
  *  drivers/s390/char/tapechar.c
@@ -7,6 +6,7 @@
  *  S390 and zSeries version
  *    Copyright (C) 2001 IBM Corporation
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
+ *               Michael Holzheu <holzheu@de.ibm.com>
  *               Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *
  *
@@ -18,9 +18,7 @@
 #include <linux/version.h>
 #include <linux/types.h>
 #include <linux/proc_fs.h>
-#include <asm/ccwcache.h>	/* CCW allocations      */
 #include <asm/s390dyn.h>
-#include <asm/debug.h>
 #include <linux/mtio.h>
 #include <asm/uaccess.h>
 #include <linux/compatmac.h>
@@ -33,727 +31,608 @@
 
 #define PRINTK_HEADER "TCHAR:"
 
+/*******************************************************************
+ * GLOBALS
+ *******************************************************************/
+
 /*
  * file operation structure for tape devices
  */
 static struct file_operations tape_fops =
 {
-    //    owner   : THIS_MODULE,
-	llseek:NULL,		/* lseek - default */
-	read:tape_read,		/* read  */
-	write:tape_write,	/* write */
-	readdir:NULL,		/* readdir - bad */
-	poll:NULL,		/* poll */
-	ioctl:tape_ioctl,	/* ioctl */
-	mmap:NULL,		/* mmap */
-	open:tape_open,		/* open */
-	flush:NULL,		/* flush */
-	release:tape_release,	/* release */
-	fsync:NULL,		/* fsync */
-	fasync:NULL,		/* fasync */
-	lock:NULL,
+	read:tapechar_read,
+	write:tapechar_write,
+	ioctl:tapechar_ioctl,
+	open:tapechar_open,
+	release:tapechar_release,
 };
 
-int tape_major = TAPE_MAJOR;
+int tapechar_major = TAPECHAR_MAJOR;
+
+/*******************************************************************
+ * DEVFS Functions
+ *******************************************************************/
 
 #ifdef CONFIG_DEVFS_FS
-void
-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, 
-					    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);
+
+/*
+ * Create Char directory with (non)rewinding entries
+ */
+
+devfs_handle_t
+tapechar_mkdevfstree (tape_dev_t* td) {
+    devfs_handle_t rc=NULL;
+    rc=td->char_data.devfs_char_dir=devfs_mk_dir (td->devfs_dir, "char", td);
+    if (rc==NULL) goto out_undo;
+    rc=td->char_data.devfs_nonrewinding=devfs_register(td->char_data.devfs_char_dir, 
+						    "nonrewinding",
+						    DEVFS_FL_DEFAULT,tapechar_major, 
+						    TAPECHAR_NOREW_MINOR(td->first_minor), 
+						    TAPECHAR_DEVFSMODE, &tape_fops, td);
+    if (rc==NULL) goto out_undo;
+    rc=td->char_data.devfs_rewinding=devfs_register(td->char_data.devfs_char_dir, 
+						 "rewinding",
+						 DEVFS_FL_DEFAULT, tapechar_major, 
+						 TAPECHAR_REW_MINOR(td->first_minor),
+						 TAPECHAR_DEVFSMODE, &tape_fops, td);
+    if (rc==NULL) goto out_undo;
+    goto out;
+ out_undo:
+    tapechar_rmdevfstree (td);
+ out:
+    return rc;
 }
 
+/*
+ * Remove DEVFS entries
+ */
+
 void
-tapechar_rmdevfstree (tape_info_t* ti) {
-    devfs_unregister(ti->devfs_nonrewinding);
-    devfs_unregister(ti->devfs_rewinding);
-    devfs_unregister(ti->devfs_char_dir);
+tapechar_rmdevfstree (tape_dev_t* td) {
+    if (td->char_data.devfs_nonrewinding) 
+	    devfs_unregister(td->char_data.devfs_nonrewinding);
+    if (td->char_data.devfs_rewinding)
+	    devfs_unregister(td->char_data.devfs_rewinding);
+    if (td->char_data.devfs_char_dir)
+	    devfs_unregister(td->char_data.devfs_char_dir);
 }
 #endif
 
+/*******************************************************************
+ * TAPECHAR Setup Functions
+ *******************************************************************/
+
+/*
+ * This function is called for every new tapedevice
+ */
+
 void
-tapechar_setup (tape_info_t * ti)
+tapechar_setup (tape_dev_t * td)
 {
 #ifdef CONFIG_DEVFS_FS
-    tapechar_mkdevfstree(ti);
+    tapechar_mkdevfstree(td);
 #endif
 }
 
+/*
+ * Tapechar init Function
+ */
+
 void
 tapechar_init (void)
 {
 	int result;
 	tape_frontend_t *charfront,*temp;
-	tape_info_t* ti;
+	tape_dev_t* td;
 
 	tape_init();
 
 	/* Register the tape major number to the kernel */
 #ifdef CONFIG_DEVFS_FS
-	result = devfs_register_chrdev (tape_major, "tape", &tape_fops);
+	result = devfs_register_chrdev (tapechar_major, "tape", &tape_fops);
 #else
-	result = register_chrdev (tape_major, "tape", &tape_fops);
+	result = register_chrdev (tapechar_major, "tape", &tape_fops);
 #endif
-
 	if (result < 0) {
-		PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tape_major);
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,3,"c:initfail");
-		debug_text_event (tape_debug_area,3,"regchrfail");
-#endif /* TAPE_DEBUG */
-		panic ("no major number available for tape char device");
+		PRINT_WARN (KERN_ERR "tape: can't get major %d\n", tapechar_major);
+		tape_sprintf_event (tape_dbf_area,3,"c:initfail\n");
+		goto out;
 	}
-	if (tape_major == 0)
-		tape_major = result;	/* accept dynamic major number */
+	if (tapechar_major == 0)
+		tapechar_major = result;	/* accept dynamic major number */
 	PRINT_WARN (KERN_ERR " tape gets major %d for character device\n", result);
 	charfront = kmalloc (sizeof (tape_frontend_t), GFP_KERNEL);
 	if (charfront == NULL) {
-#ifdef TAPE_DEBUG
-                debug_text_event (tape_debug_area,3,"c:initfail");
-		debug_text_event (tape_debug_area,3,"no mem");
-#endif /* TAPE_DEBUG */
-		panic ("no major number available for tape char device");		
+	        PRINT_WARN (KERN_ERR "tapechar: cannot alloc memory for the frontend_t structure\n");
+                tape_sprintf_event (tape_dbf_area,3,"c:initfail no mem\n");
+		goto out;
 	}
-	charfront->device_setup = tapechar_setup;
+	charfront->device_setup = (tape_setup_device_t)tapechar_setup;
 #ifdef CONFIG_DEVFS_FS
 	charfront->mkdevfstree = tapechar_mkdevfstree;
 	charfront->rmdevfstree = tapechar_rmdevfstree;
 #endif
-#ifdef TAPE_DEBUG
-        debug_text_event (tape_debug_area,3,"c:init ok");
-#endif /* TAPE_DEBUG */
+        tape_sprintf_event (tape_dbf_area,3,"c:init ok\n");
 	charfront->next=NULL;
-	if (first_frontend==NULL) {
-	    first_frontend=charfront;
+	if (tape_first_front==NULL) {
+	    tape_first_front=charfront;
 	} else {
-	    temp=first_frontend;
+	    temp=tape_first_front;
 	    while (temp->next!=NULL)
 		temp=temp->next;
 	    temp->next=charfront;
 	}
-	ti=first_tape_info;
-	while (ti!=NULL) {
-	    tapechar_setup(ti);
-	    ti=ti->next;
+	td=tape_first_dev;
+	while (td!=NULL) {
+	    tapechar_setup(td);
+	    td=td->next;
 	}
+ out:
+	return;
 }
 
+/*
+ * cleanup
+ */
+
 void
 tapechar_uninit (void)
 {
-	unregister_chrdev (tape_major, "tape");
+#ifdef CONFIG_DEVFS_FS
+	devfs_unregister_chrdev (tapechar_major, "tape");
+#else
+	unregister_chrdev (tapechar_major, "tape");
+#endif
 }
 
+
+/*******************************************************************
+ * TAPECHAR Util functions
+ *******************************************************************/
+
+/*
+ * Terminate write command (we write two TMs and skip backward over last)
+ * This ensures that the tape is always correctly terminated.
+ * When the user writes afterwards a new file, he will overwrite the
+ * second TM and therefore one TM will remain to seperate the 
+ * two files on the tape...
+ */
+
+static void
+tapechar_terminate_write(tape_dev_t* td)
+{
+	tape_ccw_req_t *treq;
+	int rc;
+
+	treq = td->discipline->ioctl(td, MTWEOF,1,&rc);
+	if (!treq)
+		goto out;
+	tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	tape_free_ccw_req(treq);
+	treq = td->discipline->ioctl(td, MTWEOF,1,&rc);
+	if (!treq)
+		goto out;
+	tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	tape_free_ccw_req(treq);
+	treq = td->discipline->ioctl(td, MTBSR,1,&rc);
+	if (!treq)
+		goto out;
+	tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	tape_free_ccw_req(treq);
+
+out:
+	return;
+}
+	
+
+/*******************************************************************
+ * TAPECHAR Functions:
+ * - read
+ * - write
+ * - open
+ * - close
+ * - ioctl
+ *******************************************************************/
+
 /*
  * Tape device read function
  */
+
 ssize_t
-tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
+tapechar_read (struct file *filp, char *data, size_t count, loff_t * ppos)
 {
-	long lockflags;
-	tape_info_t *ti;
+	tape_dev_t *td;
 	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 */
-	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 */
-		return -ENODEV;
-	}
+	tape_ccw_req_t *treq;
+	int rc = 0;
+	size_t cpysize;
+
+        tape_sprintf_event (tape_dbf_area,6,"c:read\n");
+	td = (tape_dev_t*)filp->private_data;
+	
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,6,"c:ppos wrong");
-#endif /* TAPE_DEBUG */
-		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
+		/* This check uses internal knowledge about how pread and */
+		/* read work... */
+	        tape_sprintf_event (tape_dbf_area,6,"c:ppos wrong\n");
+		rc = -EOVERFLOW;      /* errno=75 Value too large for def. data type */
+		goto out;
 	}
-	if (ti->block_size == 0) {
+	if (td->char_data.block_size == 0) {
 		block_size = count;
 	} else {
-		block_size = ti->block_size;
+	        if (count < td->char_data.block_size) {
+		        rc = -EINVAL; // invalid argument+
+			tape_sprintf_event (tape_dbf_area,3,"tapechar:read smaller than block size was requested\n");
+			goto out;
+		}
+		block_size = td->char_data.block_size;
+	}
+	tape_sprintf_event (tape_dbf_area,6,"c:nbytes: %x\n",block_size);
+	treq = td->discipline->read_block (data, block_size, td);
+	if (!treq) {
+		rc = -ENOBUFS;
+		goto out;
 	}
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:nbytes:");
-	debug_int_event (tape_debug_area,6,block_size);
-#endif
-	cqr = ti->discipline->read_block (data, block_size, ti);
-	if (!cqr) {
-		return -ENOBUFS;
-	}
-	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(ti,TS_IDLE);
-	    kfree (cqr);
-	    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	    return rc;
-	}
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-	wait_event (ti->wq,ti->wanna_wakeup);
-	ti->cqr = NULL;
-	ti->discipline->free_read_block (cqr, ti);
-	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 (ti) != TS_DONE) {
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		return -EIO;
-	}
-	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 - ti->devstat.rescnt);
-#endif	/* TAPE_DEBUG */
-	filp->f_pos += block_size - ti->devstat.rescnt;
-	return block_size - ti->devstat.rescnt;
+
+	rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+	TAPE_MERGE_RC(treq,rc);
+	if(rc != 0)
+		goto out_free;
+	rc = cpysize = block_size - td->devstat.rescnt;
+	if(idalbuf_copy_to_user(treq->userbuf, treq->idal_buf, cpysize)) {
+		tape_sprintf_exception (tape_dbf_area,6,"xfrb segf.\n");
+		rc = -EFAULT;
+	}
+	tape_sprintf_event (tape_dbf_area,6,"c:rbytes:  %x\n", cpysize);
+	filp->f_pos += cpysize;
+out_free:
+	tape_free_ccw_req(treq);
+out:
+	return rc;
 }
 
 /*
  * Tape device write function
  */
+
 ssize_t
-tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
+tapechar_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 {
-	long lockflags;
-	tape_info_t *ti;
+	tape_dev_t *td;
 	size_t block_size;
-	ccw_req_t *cqr;
-	int nblocks, i, rc;
+	tape_ccw_req_t *treq;
+	int nblocks, i = 0,rc = 0;
 	size_t written = 0;
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:write");
-#endif
-	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;
+	tape_sprintf_event (tape_dbf_area,6,"c:write\n");
+
+	td = (tape_dev_t*)filp->private_data;
+	block_size = count;
+        
 	if (ppos != &filp->f_pos) {
 		/* "A request was outside the capabilities of the device." */
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,6,"c:ppos wrong");
-#endif
-		return -EOVERFLOW;	/* errno=75 Value too large for def. data type */
+	        tape_sprintf_event (tape_dbf_area,6,"c:ppos wrong\n");
+		rc = -EOVERFLOW; /* errno=75 Value too large for def. data type */
+		goto out;
 	}
-	if ((ti->block_size != 0) && (count % ti->block_size != 0))
-		return -EIO;
-	if (ti->block_size == 0) {
+	if ((td->char_data.block_size != 0) && (count < td->char_data.block_size)){
+		rc = -EIO;
+		goto out;
+	}
+	if (td->char_data.block_size == 0) {
 		block_size = count;
 		nblocks = 1;
 	} else {
-		block_size = ti->block_size;
-		nblocks = count / (ti->block_size);
+		block_size = td->char_data.block_size;
+		nblocks = count / block_size;
 	}
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,6,"c:nbytes:");
-		debug_int_event (tape_debug_area,6,block_size);
-	        debug_text_event (tape_debug_area,6,"c:nblocks:");
-	        debug_int_event (tape_debug_area,6,nblocks);
-#endif
+	tape_sprintf_event (tape_dbf_area,6,"c:nbytes: %x\n",block_size);
+        tape_sprintf_event (tape_dbf_area,6,"c:nblocks: %x\n",nblocks);
 	for (i = 0; i < nblocks; i++) {
-		cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
-		if (!cqr) {
-			return -ENOBUFS;
-		}
-		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 (ti, TS_IDLE);
-			return -ERESTARTSYS;
-		}
-		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 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 (ti) != TS_DONE) {
-			tapestate_set (ti, TS_IDLE);
-			s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-			return -EIO;
-		}
-		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 - ti->devstat.rescnt);
-#endif
-		filp->f_pos += block_size - ti->devstat.rescnt;
-		written += block_size - ti->devstat.rescnt;
-		if (ti->devstat.rescnt > 0)
-			return written;
-	}
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:wtotal:");
-	debug_int_event (tape_debug_area,6,written);
-#endif
-	return written;
+		treq = td->discipline->write_block (data + i * block_size, block_size, td);
+		if (!treq) {
+			rc = -ENOBUFS;
+			goto out;
+		}
+
+		rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+		TAPE_MERGE_RC(treq,rc);
+		tape_free_ccw_req(treq);
+		if(rc < 0)
+			goto out;
+	        tape_sprintf_event (tape_dbf_area,6,"c:wbytes: %x\n",block_size - td->devstat.rescnt); 
+		filp->f_pos += block_size - td->devstat.rescnt;
+		written += block_size - td->devstat.rescnt;
+		rc = written;
+		if (td->devstat.rescnt > 0)
+			goto out;
+	}
+	tape_sprintf_event (tape_dbf_area,6,"c:wtotal: %x\n",written);
+
+out:
+	if (rc==-ENOSPC){
+		if(td->discipline->process_eov)
+			td->discipline->process_eov(td);
+		if(i > 0){
+			rc = i*block_size;
+			printk("write rc = %i\n",rc); /* XXX */
+		}	
+	}
+	return rc;
 }
 
+/*
+ * MT IOCTLS
+ */
+
 static int
-tape_mtioctop (struct file *filp, short mt_op, int mt_count)
+tapechar_mtioctop (struct file *filp, short mt_op, int mt_count)
 {
-	tape_info_t *ti;
-	ccw_req_t *cqr = NULL;
-	int rc;
-	long lockflags;
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:mtio");
-	debug_text_event (tape_debug_area,6,"c:ioop:");
-	debug_int_event (tape_debug_area,6,mt_op); 
-	debug_text_event (tape_debug_area,6,"c:arg:");
-	debug_int_event (tape_debug_area,6,mt_count);
-#endif
-	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
+	tape_dev_t *td;
+	tape_ccw_req_t *treq = NULL;
+	int rc = 0;
 
-		cqr = ti->discipline->mtrew (ti, mt_count);
-		break;
-	case MTOFFL:		// put drive offline
-
-		cqr = ti->discipline->mtoffl (ti, mt_count);
-		break;
-	case MTUNLOAD:		// unload the tape
-
-		cqr = ti->discipline->mtunload (ti, mt_count);
-		break;
-	case MTWEOF:		// write tapemark
-
-		cqr = ti->discipline->mtweof (ti, mt_count);
-		break;
-	case MTFSF:		// forward space file
-
-		cqr = ti->discipline->mtfsf (ti, mt_count);
-		break;
-	case MTBSF:		// backward space file
-
-		cqr = ti->discipline->mtbsf (ti, mt_count);
-		break;
-	case MTFSFM:		// forward space file, stop at BOT side
-
-		cqr = ti->discipline->mtfsfm (ti, mt_count);
-		break;
-	case MTBSFM:		// backward space file, stop at BOT side
-
-		cqr = ti->discipline->mtbsfm (ti, mt_count);
-		break;
-	case MTFSR:		// forward space file
-
-		cqr = ti->discipline->mtfsr (ti, mt_count);
-		break;
-	case MTBSR:		// backward space file
-
-		cqr = ti->discipline->mtbsr (ti, mt_count);
-		break;
-	case MTNOP:
-		cqr = ti->discipline->mtnop (ti, mt_count);
-		break;
-	case MTEOM:		// postion at the end of portion
-
-	case MTRETEN:		// retension the tape
-
-		cqr = ti->discipline->mteom (ti, mt_count);
-		break;
-	case MTERASE:
-		cqr = ti->discipline->mterase (ti, mt_count);
-		break;
-	case MTSETDENSITY:
-		cqr = ti->discipline->mtsetdensity (ti, mt_count);
-		break;
-	case MTSEEK:
-		cqr = ti->discipline->mtseek (ti, mt_count);
-		break;
-	case MTSETDRVBUFFER:
-		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
-		break;
-	case MTLOCK:
-		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
-		break;
-	case MTUNLOCK:
-		cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
-		break;
-	case MTLOAD:
-		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 = ti->discipline->mtcompression (ti, mt_count);
-		break;
-	case MTSETPART:
-		cqr = ti->discipline->mtsetpart (ti, mt_count);
-		break;
-	case MTMKPART:
-		cqr = ti->discipline->mtmkpart (ti, mt_count);
-		break;
-	case MTTELL:		// return number of block relative to current file
-
-		cqr = ti->discipline->mttell (ti, mt_count);
-		break;
-	case MTSETBLK:
-		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 (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,ti->blk_minor);
-#endif
-		return 0;
-	default:
-#ifdef TAPE_DEBUG
-	    debug_text_event (tape_debug_area,6,"c:inv.mtio");
-#endif
-		return -EINVAL;
-	}
-	if (cqr == NULL) {
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,6,"c:ccwg fail");
-#endif
-		return -ENOSPC;
+	td = (tape_dev_t*)filp->private_data; 
+
+	tape_sprintf_event (tape_dbf_area,6,"c:mtio\n");
+	tape_sprintf_event (tape_dbf_area,6,"c:ioop: %x\n",mt_op);
+	tape_sprintf_event (tape_dbf_area,6,"c:arg:  %x\n",mt_count);
+
+	switch (mt_op) {
+		case MTRETEN:		// retension the tape
+			treq = td->discipline->ioctl (td, MTEOM,1,&rc);
+			break;
+		case MTLOAD:
+			treq = td->discipline->ioctl (td, MTLOAD,1,&rc);
+			if (rc != -EINVAL){
+				// the backend driver has an load function
+				break; 
+			} 
+			// if no medium is in, wait until it gets inserted
+			if (td->medium_state != MS_LOADED) {
+				// create dummy request
+				treq = tape_alloc_ccw_req(1,0,0,TO_LOAD);
+				rc = tape_do_wait_req(td,treq,TAPE_WAIT_INTERRUPTIBLE_NOHALTIO);
+			} else {
+				rc = 0; // already loaded
+			}
+			goto out;
+		case MTSETBLK:
+			td->char_data.block_size = mt_count;
+			tape_sprintf_event (tape_dbf_area,6,"c:setblk:\n");
+			goto out;
+		case MTRESET:
+			td->char_data.block_size = 0;
+			tape_sprintf_event (tape_dbf_area,6,"c:devreset:\n");
+			goto out;
+		default:
+			treq = td->discipline->ioctl (td, mt_op,mt_count,&rc);
 	}
-	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;
+	if (treq == NULL) {
+	        tape_sprintf_event (tape_dbf_area,6,"c:ccwg fail\n");
+		goto out;
 	}
-	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 (ti, TS_IDLE);
-		return -ERESTARTSYS;
-	}
-	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 (ti) != TS_DONE) {
-		tapestate_set (ti, TS_IDLE);
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-		return -EIO;
+
+	if(TAPE_INTERRUPTIBLE_OP(mt_op)){
+		rc = tape_do_io_and_wait(td,treq,TAPE_WAIT_INTERRUPTIBLE);
+	} else {
+		rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
 	}
-	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
+	TAPE_MERGE_RC(treq,rc);
+
+	tape_free_ccw_req(treq);
 
-		return tape_mtioctop (filp, MTREW, 1);
-	case MTFSFM:		//need to skip back over the filemark
+	if ((mt_op == MTEOM) || (mt_op == MTRETEN)){
+		rc = 0; // EOM and RETEN report an error, this is fine...
+	}
 
-		return tape_mtioctop (filp, MTBSFM, 1);
-	case MTBSF:		//need to skip forward over the filemark
+	if(rc != 0)
+		goto out; /* IO Failed */
 
-		return tape_mtioctop (filp, MTFSF, 1);
+	// if medium was unloaded, update the corresponding variable.
+	switch (mt_op) {
+	        case MTOFFL:
+	        case MTUNLOAD:
+			td->medium_state = MS_UNLOADED;
+			break;
+	        case MTRETEN:		//need to rewind the tape after moving to eom
+			return tapechar_mtioctop (filp, MTREW, 1);
+	        case MTFSFM:		//need to skip back over the filemark
+			return tapechar_mtioctop (filp, MTBSFM, 1);
+	        case MTBSF:		//need to skip forward over the filemark
+			return tapechar_mtioctop (filp, MTFSF, 1);
 	}
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:mtio done");
-#endif
-	return 0;
+	tape_sprintf_event (tape_dbf_area,6,"c:mtio done\n");
+out:
+	return rc;
 }
 
 /*
  * Tape device io controls.
  */
+
 int
-tape_ioctl (struct inode *inode, struct file *filp,
+tapechar_ioctl (struct inode *inode, struct file *filp,
 	    unsigned int cmd, unsigned long arg)
 {
-	long lockflags;
-	tape_info_t *ti;
-	ccw_req_t *cqr;
+	tape_dev_t *td;
+	tape_ccw_req_t *treq = NULL;
 	struct mtop op;		/* structure for MTIOCTOP */
 	struct mtpos pos;	/* structure for MTIOCPOS */
 	struct mtget get;
-
 	int rc;
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:ioct");
-#endif
-	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;
-	}
+
+	tape_sprintf_event (tape_dbf_area,6,"c:ioct\n");
+
+        td = (tape_dev_t*)filp->private_data;
+
 	// check for discipline ioctl overloading
-	if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
-	    != -EINVAL) {
-#ifdef TAPE_DEBUG
-	    debug_text_event (tape_debug_area,6,"c:ioverloa");
-#endif
-	    return rc;
+	if ((rc = td->discipline->discipline_ioctl_overload (td, cmd, arg)) != -EINVAL) {
+		tape_sprintf_event (tape_dbf_area,6,"c:ioverloa\n");
+		goto out;
 	}
-
+	rc = 0;
 	switch (cmd) {
 	case MTIOCTOP:		/* tape op command */
 		if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
-			 return -EFAULT;
+			rc = -EFAULT;
+			goto out;
 		}
-		return (tape_mtioctop (filp, op.mt_op, op.mt_count));
-	case MTIOCPOS:		/* query tape position */
-		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;
+		if(op.mt_count < 0){
+			rc = -EINVAL;
+			goto out;
+		}
+		if(op.mt_op == MTBSR  || 
+		   op.mt_op == MTFSR  ||
+		   op.mt_op == MTFSF  ||
+		   op.mt_op == MTBSR  ||
+		   op.mt_op == MTFSFM ||
+		   op.mt_op == MTBSFM) 
+		{
+			int i;
+			/* We assume that the backends can handle count up */	
+			/* to 500. */
+			for(i = 0; i < op.mt_count; i+=500){
+				rc = tapechar_mtioctop (filp, op.mt_op, MIN(500,op.mt_count-i)); 
+				if(rc)
+					goto out;
+			}
+		} else {
+			/* Single operations */
+			rc = tapechar_mtioctop (filp, op.mt_op, op.mt_count);
 		}
-		tape_free_request (cqr);
-		if (signal_pending (current)) {
-			tapestate_set (ti, TS_IDLE);
-			return -ERESTARTSYS;
+		goto out;
+
+	case MTIOCPOS:		/* query tape position */
+		memset (&pos,0,sizeof (struct mtpos));
+		treq = td->discipline->ioctl (td, MTTELL,1,&rc);
+		if(!treq)
+			goto out;
+		rc = tape_do_io_and_wait(td,treq,TAPE_WAIT); 
+		TAPE_MERGE_RC(treq,rc);
+		if(rc == 0){
+			pos.mt_blkno = *((int*)(treq->kernbuf));
+			if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
+				rc = -EFAULT;
 		}
-		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;
+		tape_free_ccw_req(treq);
+		goto out;
+
 	case MTIOCGET:
-		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 = ti->devstat.rescnt;
-		get.mt_dsreg = ti->devstat.ii.sense.data[3];
-		get.mt_gstat = 0;
-		if (ti->devstat.ii.sense.data[1] & 0x08)
-			get.mt_gstat &= GMT_BOT (1);	// BOT
-
-		if (ti->devstat.ii.sense.data[1] & 0x02)
-			get.mt_gstat &= GMT_WR_PROT (1);	// write protected
-
-		if (ti->devstat.ii.sense.data[1] & 0x40)
-			get.mt_gstat &= GMT_ONLINE (1);		//drive online
-
-		ti->cqr = NULL;
-		if (ti->kernbuf != NULL) {
-			kfree (ti->kernbuf);
-			ti->kernbuf = NULL;
-		}
-		tape_free_request (cqr);
-		if (signal_pending (current)) {
-			tapestate_set (ti, TS_IDLE);
-			return -ERESTARTSYS;
+		memset (&get,0,sizeof (struct mtget));
+		treq = td->discipline->ioctl (td, MTTELL,1,&rc);
+		if(!treq)
+                        goto out;
+		rc = tape_do_io_and_wait(td,treq,TAPE_WAIT);
+		TAPE_MERGE_RC(treq,rc);
+		if(rc == 0){
+			get.mt_erreg = treq->rc;
+			get.mt_blkno = *((int*)(treq->kernbuf));
+			get.mt_type = MT_ISUNKNOWN;
+			get.mt_resid = td->devstat.rescnt;
+			get.mt_dsreg = td->tape_state;
+			if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
+				rc = -EFAULT;	
 		}
-		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;
+		tape_free_ccw_req(treq);
+		goto out;
 	default:
-#ifdef TAPE_DEBUG
-	        debug_text_event (tape_debug_area,3,"c:ioct inv");
-#endif	    
-		return -EINVAL;
+	        tape_sprintf_event (tape_dbf_area,3,"c:ioct inv\n");
+		rc = -EINVAL;
+		goto out;
 	}
+out:
+	return rc;
 }
 
 /*
  * Tape device open function.
  */
+
 int
-tape_open (struct inode *inode, struct file *filp)
+tapechar_open (struct inode *inode, struct file *filp)
 {
-	tape_info_t *ti;
-	kdev_t dev;
+	tape_dev_t *td = NULL;
+	int  rc = 0;
 	long lockflags;
 
+	MOD_INC_USE_COUNT;
+
+	tape_sprintf_event (tape_dbf_area,6,"c:open: %x\n",td->first_minor); 
+
 	inode = filp->f_dentry->d_inode;
-	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)
-		return -ENODEV;
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:open:");
-	debug_int_event (tape_debug_area,6,ti->blk_minor);
-#endif
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	if (tapestate_get (ti) != TS_UNUSED) {
-		s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-#ifdef TAPE_DEBUG
-		debug_text_event (tape_debug_area,6,"c:dbusy");
-#endif
-		return -EBUSY;
+
+	td = tape_get_device_by_minor(minor (inode->i_rdev));
+	if (td == NULL){
+		rc = -ENODEV;
+		goto error;
+	}
+	s390irq_spin_lock_irqsave(td->devinfo.irq,lockflags);
+	if (tape_state_get(td) == TS_NOT_OPER) {
+		tape_sprintf_event (tape_dbf_area,6,"c:nodev\n");
+		rc = -ENODEV;
+		goto out;
 	}
-	tapestate_set (ti, TS_IDLE);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 
-	dev = MKDEV (tape_major, MINOR (inode->i_rdev));	/* Get the device */
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	if (ti->rew_minor == MINOR (inode->i_rdev))
-		ti->rew_filp = filp;	/* save for later reference     */
-	else
-		ti->nor_filp = filp;
-	filp->private_data = ti;	/* save the dev.info for later reference */
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+	if (tape_state_get (td) != TS_UNUSED) {
+		tape_sprintf_event (tape_dbf_area,6,"c:dbusy\n");
+		rc = -EBUSY;
+		goto out;
+	}
+	if ( td->discipline->owner )
+		__MOD_INC_USE_COUNT(td->discipline->owner);
+	tape_state_set (td, TS_IN_USE);
+	td->filp = filp; /* save for later reference     */
+	filp->private_data = td;    /* save the dev.info for later reference */
+out:
+	s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
+error:
+	if(rc != 0){
+		MOD_DEC_USE_COUNT;
+		if (td!=NULL)
+			tape_put_device(td);
+	}
+	return rc;
 
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif				/* MODULE */
-	return 0;
 }
 
 /*
  * Tape device release function.
  */
+
 int
-tape_release (struct inode *inode, struct file *filp)
+tapechar_release (struct inode *inode, struct file *filp)
 {
-	long lockflags;
-	tape_info_t *ti,*lastti;
-	ccw_req_t *cqr = NULL;
+	tape_dev_t *td = NULL;
+	tape_ccw_req_t *treq = NULL;
 	int rc = 0;
+	long lockflags;
 
-	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) && (tapestate_get (ti) == TS_NOT_OPER)) {
-	    if (ti==first_tape_info) {
-		first_tape_info=ti->next;
-	    } else {
-		lastti=first_tape_info;
-		while (lastti->next!=ti) lastti=lastti->next;
-		lastti->next=ti->next;
-	    }
-	    kfree(ti);    
-	    goto out;
-	}
-	if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:notidle!");
-#endif
-		rc = -ENXIO;	/* error in tape_release */
-		goto out;
-	}
-#ifdef TAPE_DEBUG
-	debug_text_event (tape_debug_area,6,"c:release:");
-	debug_int_event (tape_debug_area,6,ti->blk_minor);
-#endif
-	if (ti->rew_minor == MINOR (inode->i_rdev)) {
-		cqr = ti->discipline->mtrew (ti, 1);
-		if (cqr != NULL) {
-#ifdef TAPE_DEBUG
-		        debug_text_event (tape_debug_area,6,"c:rewrelea");
-#endif
-			s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-			tapestate_set (ti, TS_REW_RELEASE_INIT);
-			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 (ti->wq,ti->wanna_wakeup);
-			ti->cqr = NULL;
-			tape_free_request (cqr);
+	tape_sprintf_event (tape_dbf_area,6,"c:release: %x\n",td->first_minor);
+
+	td = (tape_dev_t*)filp->private_data;
+
+	if(td->last_op == TO_WRI)
+		tapechar_terminate_write(td);
+
+	if (minor (inode->i_rdev) == TAPECHAR_REW_MINOR(td->first_minor)) {
+		treq = td->discipline->ioctl (td, MTREW,1,&rc);
+		if (treq != NULL) {
+		        tape_sprintf_event (tape_dbf_area,6,"c:rewrelea\n");
+			rc = tape_do_io_and_wait(td, treq, TAPE_WAIT);
+			tape_free_ccw_req (treq);
 		}
 	}
-	s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
-	tapestate_set (ti, TS_UNUSED);
-	s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
-out:
-#ifdef MODULE
+
+	s390irq_spin_lock_irqsave(td->devinfo.irq,lockflags);
+	if(tape_state_get(td) == TS_IN_USE)
+		tape_state_set (td, TS_UNUSED);
+	else if (tape_state_get(td) != TS_NOT_OPER) 
+		BUG();
+	s390irq_spin_unlock_irqrestore(td->devinfo.irq,lockflags);
+	if ( td->discipline->owner )
+		__MOD_DEC_USE_COUNT(td->discipline->owner);
+	tape_put_device(td);
 	MOD_DEC_USE_COUNT;
-#endif				/* MODULE */
 	return rc;
 }
diff -Nru a/drivers/s390/char/tapechar.h b/drivers/s390/char/tapechar.h
--- a/drivers/s390/char/tapechar.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/char/tapechar.h	Sat Jun  8 22:31:51 2002
@@ -16,19 +16,25 @@
 #ifndef TAPECHAR_H
 #define TAPECHAR_H
 #include <linux/config.h>
-#define TAPECHAR_DEFAULTMODE 0020644
-#define  TAPE_MAJOR                    0        /* get dynamic major since no major officialy defined for tape */
+#define TAPECHAR_DEVFSMODE 0020644 // chardev, rwx for user, rw for group&others
+#define TAPECHAR_MAJOR 0  /* get dynamic major since no major officialy defined for tape */
+#define TAPECHAR_NOREW_MINOR(x) x    /* Minor for nonrewinding device */
+#define TAPECHAR_REW_MINOR(x)  (x+1) /* Minor for rewinding device */
+
 /*
- * Prototypes for tape_fops
+ * Prototypes
  */
-ssize_t tape_read(struct file *, char *, size_t, loff_t *);
-ssize_t tape_write(struct file *, const char *, size_t, loff_t *);
-int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
-int tape_open (struct inode *,struct file *);
-int tape_release (struct inode *,struct file *);
+
+ssize_t tapechar_read(struct file *, char *, size_t, loff_t *);
+ssize_t tapechar_write(struct file *, const char *, size_t, loff_t *);
+int tapechar_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
+int tapechar_open (struct inode *,struct file *);
+int tapechar_release (struct inode *,struct file *);
 #ifdef CONFIG_DEVFS_FS
-void tapechar_mkdevfstree (tape_info_t* ti);
+devfs_handle_t tapechar_mkdevfstree (tape_dev_t* td);
+void tapechar_rmdevfstree (tape_dev_t* td);
 #endif
 void tapechar_init (void);
 void tapechar_uninit (void);
+
 #endif /* TAPECHAR_H */
diff -Nru a/drivers/s390/char/tapedefs.h b/drivers/s390/char/tapedefs.h
--- a/drivers/s390/char/tapedefs.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/tapedefs.h	Sat Jun  8 22:31:36 2002
@@ -16,6 +16,7 @@
 #include <linux/blkdev.h>
 #include <linux/blk.h>
 #include <asm/irq.h>
+#include <linux/compatmac.h>
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 #define TAPE_DEBUG               // use s390 debug feature
diff -Nru a/drivers/s390/char/tuball.c b/drivers/s390/char/tuball.c
--- a/drivers/s390/char/tuball.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/char/tuball.c	Sat Jun  8 22:31:36 2002
@@ -24,7 +24,7 @@
 /* Module parameters */
 int tubdebug;
 int tubscrolltime = -1;
-int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
+static int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
 #ifdef MODULE
 MODULE_PARM(tubdebug, "i");
 MODULE_PARM(tubscrolltime, "i");
@@ -38,19 +38,27 @@
  */
 int tubnummins;
 tub_t *(*tubminors)[TUBMAXMINS];
-tub_t *(*(*tubirqs)[256])[256];
+static tub_t *(*(*tubirqs)[256])[256];
 unsigned char tub_ascebc[256];
 unsigned char tub_ebcasc[256];
-int tubinitminors(void);
-void tubfiniminors(void);
-void tubint(int, void *, struct pt_regs *);
+static int tubinitminors(void);
+static void tubfiniminors(void);
+static void tubint(int, void *, struct pt_regs *);
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+static int tubmakemin(int, dev_info_t *);
+#else
+static int tubmakemin(int, s390_dev_info_t *);
+#endif
+
 
 /* Lookup-by-irq functions */
-int tubaddbyirq(tub_t *, int);
-tub_t *tubfindbyirq(int);
-void tubdelbyirq(tub_t *, int);
-void tubfiniirqs(void);
+static int tubaddbyirq(tub_t *, int);
+static tub_t *tubfindbyirq(int);
+static void tubdelbyirq(tub_t *, int);
+static void tubfiniirqs(void);
 
+/* FIXME: put extern declarations in a header */
 extern int fs3270_init(void);
 extern void fs3270_fini(void);
 extern int tty3270_init(void);
@@ -94,7 +102,7 @@
 
 static bcb_t tub3270_con_bcb;		/* Buffer that receives con writes */
 static spinlock_t tub3270_con_bcblock;	/* Lock for the buffer */
-int tub3270_con_irq = -1;		/* set nonneg by _activate() */
+static int tub3270_con_irq = -1;		/* set nonneg by _activate() */
 tub_t *tub3270_con_tubp;		/* set nonzero by _activate() */
 struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */
 
@@ -137,7 +145,7 @@
 static kdev_t
 tub3270_con_device(struct console *conp)
 {
-	return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
+	return tub_mkdev(IBM_TTY3270_MAJOR, conp->index + 1);
 }
 
 static void
@@ -146,8 +154,6 @@
 	/* flush everything:  panic has occurred */
 }
 
-int tub3270_con_write_deadlock_ct;
-int tub3270_con_write_deadlock_bytes;
 static void
 tub3270_con_write(struct console *conp,
 	const char *buf, unsigned int count)
@@ -359,7 +365,7 @@
 /*
  * receive an interrupt
  */
-void
+static void
 tubint(int irq, void *ipp, struct pt_regs *prp)
 {
 	devstat_t *dsp = ipp;
@@ -373,7 +379,7 @@
  * Initialize array of pointers to minor structures tub_t.
  * Returns 0 or -ENOMEM.
  */
-int
+static int
 tubinitminors(void)
 {
 	tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,
@@ -393,7 +399,7 @@
  * The first looks up from minor number at context time; the second
  * looks up from irq at interrupt time.
  */
-int
+static int
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 tubmakemin(int irq, dev_info_t *dp)
 #else
@@ -473,7 +479,7 @@
  * Release array of pointers to minor structures tub_t, but first
  * release any storage pointed to by them.
  */
-void
+static void
 tubfiniminors(void)
 {
 	int i;
@@ -505,7 +511,7 @@
 /*
  * tubaddbyirq() -- Add tub_t for irq lookup in tubint()
  */
-int
+static int
 tubaddbyirq(tub_t *tubp, int irq)
 {
 	int irqhi = (irq >> 8) & 255;
@@ -550,7 +556,7 @@
 /*
  * tubfindbyirq(irq)
  */
-tub_t *
+static tub_t *
 tubfindbyirq(int irq)
 {
 	int irqhi = (irq >> 8) & 255;
@@ -570,7 +576,7 @@
 /*
  * tubdelbyirq(tub_t*, irq)
  */
-void
+static void
 tubdelbyirq(tub_t *tubp, int irq)
 {
 	int irqhi = (irq >> 8) & 255;
@@ -599,7 +605,7 @@
 /*
  * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256]
  */
-void
+static void
 tubfiniirqs(void)
 {
 	int i;
diff -Nru a/drivers/s390/char/tubfs.c b/drivers/s390/char/tubfs.c
--- a/drivers/s390/char/tubfs.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/s390/char/tubfs.c	Sat Jun  8 22:31:35 2002
@@ -34,19 +34,19 @@
 };
 
 #ifdef CONFIG_DEVFS_FS
-devfs_handle_t fs3270_devfs_dir;
-devfs_handle_t fs3270_devfs_tub;
+static devfs_handle_t fs3270_devfs_dir;
+static 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%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", 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%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
 				fs3270_devfs_dir, name);
 }
@@ -56,12 +56,12 @@
 	char name[16];
 	devfs_handle_t handle;
 
-	sprintf(name, "tub%.3x", tubp->devno);
+	sprintf(name, "tub%.4x", 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%.3x", tubp->devno);
+	sprintf(name, "tty%.4x", tubp->devno);
 	handle = devfs_find_handle (fs3270_devfs_dir, name,
 				    IBM_TTY3270_MAJOR, tubp->minor,
 				    DEVFS_SPECIAL_CHR, 0);
@@ -208,9 +208,11 @@
 	while (!signal_pending(current) &&
 	    ((tubp->mode != TBM_FS) ||
 	     (tubp->flags & (TUB_WORKING | TUB_RDPENDING)) != 0)) {
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_INTERRUPTIBLE;
 		TUBUNLOCK(tubp->irq, *flags);
 		schedule();
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_RUNNING;
 		TUBLOCK(tubp->irq, *flags);
 	}
diff -Nru a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h
--- a/drivers/s390/char/tubio.h	Sat Jun  8 22:31:35 2002
+++ b/drivers/s390/char/tubio.h	Sat Jun  8 22:31:35 2002
@@ -13,6 +13,7 @@
 
 #include <linux/module.h>
 #include <linux/version.h>
+#include <linux/tty.h>
 
 #include <linux/major.h>
 #ifndef IBM_TTY3270_MAJOR
@@ -284,15 +285,27 @@
 #define	TUB_UE_BUSY	0x0800
 #define	TUB_INPUT_HACK	0x1000		/* Early init of command line */
 
-#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 tub_major(x) MAJOR(x)
+#define tub_minor(x) MINOR(x)
+#define tub_mkdev(x, y) MKDEV(x, y)
+#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
 #define	S390_CONSOLE_DEV MKDEV(TTYAUX_MAJOR, 1)
+#define tub_major(x) MAJOR(x)
+#define tub_minor(x) MINOR(x)
+#define tub_mkdev(x, y) MKDEV(x, y)
+#else
+#define S390_CONSOLE_DEV mk_kdev(TTYAUX_MAJOR, 1)
+#define tub_major(x) major(x)
+#define tub_minor(x) minor(x)
+#define tub_mkdev(x, y) mk_kdev(x, y)
 #endif
+
+/*
+ * Extra stuff for 3270 console support
+ */
+#ifdef CONFIG_TN3270_CONSOLE
 extern int tub3270_con_devno;
 extern char (*tub3270_con_output)[];
 extern int tub3270_con_outputl;
@@ -351,7 +364,9 @@
 /*
  * Find tub_t * given fullscreen device's irq (subchannel number)
  */
+#if 0
 extern tub_t *tubfindbyirq(int);
+#endif
 #define IRQ2TUB(irq) tubfindbyirq(irq)
 /*
  * Find tub_t * given fullscreen device's inode pointer
@@ -359,7 +374,7 @@
  */
 extern inline tub_t *INODE2TUB(struct inode *ip)
 {
-	unsigned int minor = MINOR(ip->i_rdev);
+	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))
@@ -370,8 +385,8 @@
 		else
 #endif
 #endif
-		if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR)
-			minor = MINOR(current->tty->device);
+		if (tub_major(current->tty->device) == IBM_TTY3270_MAJOR)
+			minor = tub_minor(current->tty->device);
 	}
 	if (minor <= tubnummins && minor > 0)
 		tubp = (*tubminors)[minor];
@@ -383,7 +398,7 @@
  */
 extern inline tub_t *TTY2TUB(struct tty_struct *tty)
 {
-	unsigned int minor = MINOR(tty->device);
+	unsigned int minor = minor(tty->device);
 	tub_t *tubp = NULL;
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
@@ -401,20 +416,25 @@
 extern void tub_inc_use_count(void);
 extern void tub_dec_use_count(void);
 extern int tub3270_movedata(bcb_t *, bcb_t *, int);
+#if 0
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 extern int tubmakemin(int, dev_info_t *);
 #else
 extern int tubmakemin(int, s390_dev_info_t *);
 #endif
+#endif
 extern int tub3270_con_copy(tub_t *);
 extern int tty3270_rcl_init(tub_t *);
 extern int tty3270_rcl_set(tub_t *, char *, int);
 extern void tty3270_rcl_fini(tub_t *);
 extern int tty3270_rcl_get(tub_t *, char *, int, int);
 extern void tty3270_rcl_put(tub_t *, char *, int);
-extern void tty3270_rcl_sync(tub_t *);
 extern void tty3270_rcl_purge(tub_t *);
+#if 0
+/* these appear to be unused outside of tubttyrcl */
+extern void tty3270_rcl_sync(tub_t *);
 extern int tty3270_rcl_resize(tub_t *, int);
+#endif
 extern int tty3270_size(tub_t *, long *);
 extern int tty3270_aid_init(tub_t *);
 extern void tty3270_aid_fini(tub_t *);
diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c
--- a/drivers/s390/char/tubtty.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/s390/char/tubtty.c	Sat Jun  8 22:31:52 2002
@@ -39,7 +39,7 @@
        void tty3270_sched_bh(tub_t *);
 static int tty3270_wait(tub_t *, long *);
        void tty3270_int(tub_t *, devstat_t *);
-       int tty3270_try_logging(tub_t *);
+static int tty3270_try_logging(tub_t *);
 static void tty3270_start_input(tub_t *);
 static void tty3270_do_input(tub_t *);
 static void tty3270_do_enter(tub_t *, char *, int);
@@ -47,25 +47,27 @@
        int tty3270_io(tub_t *);
 static int tty3270_show_tube(int, char *, int);
 
-int tty3270_major = -1;
+static int tty3270_major = -1;
 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];
+static int tty3270_refcount;
+static struct tty_struct *tty3270_table[TUBMAXMINS];
+static struct termios *tty3270_termios[TUBMAXMINS];
+static struct termios *tty3270_termios_locked[TUBMAXMINS];
 #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];
+static int con3270_major = -1;
+static struct tty_driver con3270_driver;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+static int con3270_refcount;
+static struct tty_struct *con3270_table[1];
+static struct termios *con3270_termios[1];
+static struct termios *con3270_termios_locked[1];
+#endif
 #endif /* CONFIG_TN3270_CONSOLE */
 
-int tty3270_proc_index;
-int tty3270_proc_data;
-int tty3270_proc_misc;
-enum tubwhat tty3270_proc_what;
+static int tty3270_proc_index;
+static int tty3270_proc_data;
+static int tty3270_proc_misc;
+static enum tubwhat tty3270_proc_what;
 
 /*
  * tty3270_init() -- Register the tty3270 driver
@@ -471,11 +473,11 @@
 			tubp = (*tubminors)[i];
 #ifdef CONFIG_TN3270_CONSOLE
 			if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
-				len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+				len += sprintf(buf + len, "%.4x CONSOLE %d\n",
 					       tubp->devno, i);
 			else
 #endif
-				len += sprintf(buf + len, "%.3x %d %d\n",
+				len += sprintf(buf + len, "%.4x %d %d\n",
 					       tubp->devno, tty3270_major, i);
 			if (begin + len > off + count)
 				break;
@@ -525,7 +527,6 @@
 	int mycount;
 	tub_t *tubp;
 	struct tty_struct *tty;
-	kdev_t device;
 	int rc;
 
 	mycount = MIN(count, sizeof mybuf - 1);
@@ -538,13 +539,12 @@
 	 */
 	tubp = NULL;
 	tty = current->tty;
-	device = tty? tty->device: 0;
-	if (device) {
-		if (MAJOR(device) == IBM_TTY3270_MAJOR)
-			tubp = (*tubminors)[MINOR(device)];
+	if (tty) {
+		if (tub_major(tty->device) == IBM_TTY3270_MAJOR)
+			tubp = (*tubminors)[tub_minor(tty->device)];
 #ifdef CONFIG_TN3270_CONSOLE
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-		if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
+		if (CONSOLE_IS_3270 && tty->device == S390_CONSOLE_DEV)
 			tubp = tub3270_con_tubp;
 #endif /* LINUX_VERSION_CODE */
 #endif /* CONFIG_TN3270_CONSOLE */
@@ -603,12 +603,20 @@
 static void
 tty3270_bh(void *data)
 {
-	long flags;
 	tub_t *tubp;
+	ioinfo_t *ioinfop;
+	long flags;
 	struct tty_struct *tty;
 
-	tubp = data;
-	TUBLOCK(tubp->irq, flags);
+	ioinfop = ioinfo[(tubp = data)->irq];
+	while (TUBTRYLOCK(tubp->irq, flags) == 0) {
+		if (ioinfop->ui.flags.unready == 1)
+			return;
+	}
+	if (ioinfop->ui.flags.unready == 1 ||
+	    ioinfop->ui.flags.ready == 0)
+		goto do_unlock;
+
 	tubp->flags &= ~TUB_BHPENDING;
 	tty = tubp->tty;
 
@@ -691,9 +699,11 @@
 	add_wait_queue(&tubp->waitq, &wait);
 	while (!signal_pending(current) &&
 	    (tubp->flags & TUB_WORKING) != 0) {
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_INTERRUPTIBLE;
 		TUBUNLOCK(tubp->irq, *flags);
 		schedule();
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_RUNNING;
 		TUBLOCK(tubp->irq, *flags);
 	}
@@ -763,7 +773,7 @@
 	}
 }
 
-int
+static int
 tty3270_try_logging(tub_t *tubp)
 {
 	if (tubp->flags & TUB_WORKING)
diff -Nru a/drivers/s390/char/tubttyaid.c b/drivers/s390/char/tubttyaid.c
--- a/drivers/s390/char/tubttyaid.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tubttyaid.c	Sat Jun  8 22:31:37 2002
@@ -18,7 +18,7 @@
 #define PF11_STR "\033j"
 /* other AID-key default strings */
 
-aid_t aidtab[64] = {
+static aid_t aidtab[64] = {
 /* 00         */	{ 0, 0 },
 /* C1 = PF13  */	{ TA_DOSTRING, 0 },
 /* C2 = PF14  */	{ TA_DOSTRING, 0 },
diff -Nru a/drivers/s390/char/tubttyrcl.c b/drivers/s390/char/tubttyrcl.c
--- a/drivers/s390/char/tubttyrcl.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tubttyrcl.c	Sat Jun  8 22:31:37 2002
@@ -11,13 +11,16 @@
  */
 #include "tubio.h"
 
+static void tty3270_rcl_sync(tub_t *);
+static int tty3270_rcl_resize(tub_t *, int);
+
 int
 tty3270_rcl_init(tub_t *tubp)
 {
 	return tty3270_rcl_resize(tubp, 20);
 }
 
-int
+static int
 tty3270_rcl_resize(tub_t *tubp, int newrclk)
 {
 	char *(*newrclb)[];
@@ -191,7 +194,7 @@
 	tty3270_rcl_sync(tubp);
 }
 
-void
+static void
 tty3270_rcl_sync(tub_t *tubp)
 {
 	tubp->tty_rclb = -1;
diff -Nru a/drivers/s390/char/tubttysiz.c b/drivers/s390/char/tubttysiz.c
--- a/drivers/s390/char/tubttysiz.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/char/tubttysiz.c	Sat Jun  8 22:31:37 2002
@@ -293,9 +293,11 @@
 	while (!signal_pending(current) &&
 	    (stat? (tubp->dstat & stat) == 0:
 	     (tubp->flags & TUB_WORKING) != 0)) {
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_INTERRUPTIBLE;
 		TUBUNLOCK(tubp->irq, *flags);
 		schedule();
+#warning FIXME: [kj] use set_current_state instead of current->state=
 		current->state = TASK_RUNNING;
 		TUBLOCK(tubp->irq, *flags);
 	}
diff -Nru a/drivers/s390/cio/Makefile b/drivers/s390/cio/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/Makefile	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,13 @@
+#
+# Makefile for the S/390 common i/o drivers
+#
+
+obj-y := cio_debug.o # make sure this always comes first
+obj-y += airq.o blacklist.o cio.o ioinfo.o misc.o requestirq.o s390io.o
+
+obj-$(CONFIG_CHSC) += chsc.o
+obj-$(CONFIG_PROC_FS) += proc.o
+
+export-objs += airq.o cio.o ioinfo.o misc.o requestirq.o s390io.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/drivers/s390/cio/airq.c b/drivers/s390/cio/airq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/airq.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,107 @@
+/*
+ *  drivers/s390/cio/airq.c
+ *   S/390 common I/O routines -- special interrupt registration
+ *   currently used only by qdio
+ *
+ *   $Revision: 1.2 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/idals.h>
+#include <asm/debug.h>
+
+#include "airq.h"
+#include "cio_debug.h"
+
+static spinlock_t adapter_lock = SPIN_LOCK_UNLOCKED;
+static adapter_int_handler_t adapter_handler;
+
+/*
+ * register for adapter interrupts
+ *
+ * With HiperSockets the zSeries architecture provides for
+ *  means of adapter interrups, pseudo I/O interrupts that are
+ *  not tied to an I/O subchannel, but to an adapter. However,
+ *  it doesn't disclose the info how to enable/disable them, but
+ *  to recognize them only. Perhaps we should consider them
+ *  being shared interrupts, and thus build a linked list
+ *  of adapter handlers ... to be evaluated ...
+ */
+int
+s390_register_adapter_interrupt (adapter_int_handler_t handler)
+{
+	int ret = 0;
+	char dbf_txt[15];
+
+	CIO_TRACE_EVENT (4, "rgaint");
+
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
+		ret = -EINVAL;
+	else if (adapter_handler)
+		ret = -EBUSY;
+	else
+		adapter_handler = handler;
+
+	spin_unlock (&adapter_lock);
+
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	return (ret);
+}
+
+int
+s390_unregister_adapter_interrupt (adapter_int_handler_t handler)
+{
+	int ret = 0;
+	char dbf_txt[15];
+
+	CIO_TRACE_EVENT (4, "urgaint");
+
+	spin_lock (&adapter_lock);
+
+	if (handler == NULL)
+		ret = -EINVAL;
+	else if (handler != adapter_handler)
+		ret = -EINVAL;
+	else
+		adapter_handler = NULL;
+
+	spin_unlock (&adapter_lock);
+
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	return (ret);
+}
+
+void
+do_adapter_IO (__u32 intparm)
+{
+	CIO_TRACE_EVENT (4, "doaio");
+
+	spin_lock (&adapter_lock);
+
+	if (adapter_handler)
+		(*adapter_handler) (intparm);
+
+	spin_unlock (&adapter_lock);
+
+	return;
+}
+
+EXPORT_SYMBOL (s390_register_adapter_interrupt);
+EXPORT_SYMBOL (s390_unregister_adapter_interrupt);
diff -Nru a/drivers/s390/cio/airq.h b/drivers/s390/cio/airq.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/airq.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,5 @@
+#ifndef S390_AINTERRUPT_H
+#define S390_AINTERRUPT_H
+
+extern void do_adapter_IO (__u32 intparm);
+#endif
diff -Nru a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/blacklist.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,273 @@
+/*
+ *  drivers/s390/cio/blacklist.c
+ *   S/390 common I/O routines -- blacklisting of specific devices
+ *   $Revision: 1.5 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ * 		 15/04/2002 Arnd Bergmann check ranges of user input
+ * 		 18/04/2002 Arnd Bergmann remove bogus optimization and
+ * 		 			  now unnecessary locking
+ * 		 19/04/2002 Arnd Bergmann cleanup parameter parsing
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+
+#include <asm/irq.h>
+#include <asm/s390dyn.h>
+#include <asm/uaccess.h>
+#include <asm/debug.h>
+
+#include "blacklist.h"
+#include "cio_debug.h"
+#include "ioinfo.h"
+#include "proc.h"
+#include "s390io.h"
+
+/* 
+ * "Blacklisting" of certain devices:
+ * Device numbers given in the commandline as cio_ignore=... won't be known
+ * to Linux.
+ *
+ * These can be single devices or ranges of devices
+ */
+
+#define max_devno (0xffffUL)
+static uint32_t bl_dev[(max_devno+1) / 32]; /* 65536 bits to indicate if a
+					       devno is blacklisted or not */
+typedef enum {add, free} range_action;
+
+/* 
+ * Function: blacklist_range
+ * (Un-)blacklist the devices from-to
+ */
+static inline void
+blacklist_range (range_action action, unsigned int from, unsigned int to)
+{
+	if (!to)
+		to = from;
+
+	if ((from > to) || (to > max_devno)) {
+		printk (KERN_WARNING "Invalid blacklist range "
+			"0x%04x to 0x%04x, skipping\n", from, to);
+		return;
+	}
+	for (; from <= to; from++) {
+		(action == add) ? set_bit (from, &bl_dev)
+				: clear_bit (from, &bl_dev);
+	}
+}
+
+/* 
+ * function: blacklist_strtoul
+ * Strip leading '0x' and interpret the values as Hex
+ */
+static inline int
+blacklist_strtoul (const char *str, char **stra)
+{
+        if (*str == '0') {
+                if (*(++str) == 'x')  /* strip leading zero */
+                        str++;        /* strip leading x */
+        }
+        return simple_strtoul (str, stra, 16); /* interpret anything as hex */
+}
+
+static inline int
+blacklist_parse_parameters (char *str, range_action action)
+{
+	unsigned int from, to;
+	while (*str != 0 && *str != '\n') {
+		if (!isxdigit(*str)) {
+			printk(KERN_WARNING "blacklist_setup: error parsing "
+					 "\"%s\"\n", str);
+			return 0;
+		}
+
+		from = blacklist_strtoul (str, &str);
+		to = (*str == '-') ? blacklist_strtoul (str+1, &str) : from;
+
+		printk (KERN_INFO "blacklist_setup: adding range "
+				  "from 0x%04x to 0x%04x\n", from, to);
+		blacklist_range (action, from, to);
+
+		if (*str == ',')
+			str++;
+	}
+	return 1;
+}
+
+/* Parsing the commandline for blacklist parameters, e.g. to blacklist
+ * device IDs 0x1234, 0x1235 and 0x1236, you could use any of:
+ * - cio_ignore=1234-1236
+ * - cio_ignore=0x1234-0x1235,1236
+ * - cio_ignore=0x1234,1235-1236
+ * - cio_ignore=1236 cio_ignore=1234-0x1236
+ * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
+ * - ...
+ */
+static int __init
+blacklist_setup (char *str)
+{
+	CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
+	return blacklist_parse_parameters (str, add);
+}
+
+__setup ("cio_ignore=", blacklist_setup);
+
+/* Checking if devices are blacklisted */
+
+/*
+ * Function: is_blacklisted
+ * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0.
+ * Used by s390_validate_subchannel()
+ */
+int
+is_blacklisted (int devno)
+{
+	return (test_bit (devno, &bl_dev));
+}
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Function: s390_redo_validation
+ * Look for no longer blacklisted devices
+ * FIXME: there must be a better way to do this */
+static inline void
+s390_redo_validation (void)
+{
+	int irq;
+
+	CIO_TRACE_EVENT (0, "redoval");
+
+	for (irq=0; irq <= highest_subchannel; irq++) {
+		if (ioinfo[irq] != INVALID_STORAGE_AREA
+		    || s390_validate_subchannel (irq, 0))
+			continue;
+
+		/* this subchannel has just been unblacklisted, 
+		 * so now try to get it working */
+		s390_device_recognition_irq (irq);
+
+		if (ioinfo[irq]->ui.flags.oper) {
+			devreg_t *pdevreg;
+			pdevreg = s390_search_devreg (ioinfo[irq]);
+			if (pdevreg && pdevreg->oper_func != NULL)
+				pdevreg->oper_func (irq, pdevreg);
+		}
+
+	}
+}
+
+/*
+ * Function: blacklist_parse_proc_parameters
+ * parse the stuff which is piped to /proc/cio_ignore
+ */
+static inline void
+blacklist_parse_proc_parameters (char *buf)
+{
+	if (strncmp (buf, "free ", 5) == 0) {
+		if (strstr (buf + 5, "all"))
+			blacklist_range (free, 0, max_devno);
+		else
+			blacklist_parse_parameters (buf + 5, free);
+	} else if (strncmp (buf, "add ", 4) == 0) {
+		/* FIXME: the old code was checking if the new bl'ed
+		 * devices are already known to the system so
+		 * s390_validate_subchannel would still give a working
+		 * status. is that necessary? */
+		blacklist_parse_parameters (buf + 4, add);
+	} else {
+		printk (KERN_WARNING "cio_ignore: Parse error; \n"
+			KERN_WARNING "try using 'free all|<devno-range>,"
+				     "<devno-range>,...'\n"
+			KERN_WARNING "or 'add <devno-range>,"
+				     "<devno-range>,...'\n");
+		return;
+	}
+
+	s390_redo_validation ();
+}
+
+static int cio_ignore_read (char *page, char **start, off_t off,
+			    int count, int *eof, void *data)
+{
+	int len = 0;
+	const unsigned int entry_size = 14; /* "0xABCD-0xEFGH\n" */
+	long devno = off; /* abuse the page variable
+			   * as counter, see fs/proc/generic.c */
+
+	while ((devno <= max_devno)
+	       && (len + entry_size < count)) {
+		if (test_bit (devno, &bl_dev)) {
+			len += sprintf(page + len, "0x%04lx", devno);
+			devno++;
+			if (test_bit (devno, &bl_dev)) { /* print range */
+				do { devno++; } 
+					while (test_bit (devno, &bl_dev));
+				
+				len += sprintf(page + len, "-0x%04lx", devno-1);
+			}
+			len += sprintf(page + len, "\n");
+		}
+		devno++;
+	}
+
+	if (devno <= max_devno)
+		*eof = 1;
+
+	*start = (char *) (devno - off); /* number of checked entries */
+
+	return len;
+}
+
+static int cio_ignore_write (struct file *file, const char *user_buf,
+			     unsigned long user_len, void *data)
+{
+	char *buf = vmalloc (user_len + 1); /* maybe better use the stack? */
+
+	if (buf == NULL)
+		return -ENOMEM;
+	if (strncpy_from_user (buf, user_buf, user_len) < 0) {
+		vfree (buf);
+		return -EFAULT;
+	}
+	buf[user_len] = '\0';
+
+	CIO_DEBUG(KERN_DEBUG, 2, 
+		  "/proc/cio_ignore: '%s'\n", buf);
+
+	blacklist_parse_proc_parameters (buf);
+
+	vfree (buf);
+	return user_len;
+}
+
+static int
+cio_ignore_proc_init (void)
+{
+	struct proc_dir_entry *entry;
+	entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
+				   &proc_root);
+	if (!entry)
+		return 0;
+
+	entry->read_proc  = cio_ignore_read;
+	entry->write_proc = cio_ignore_write;
+
+	return 1;
+}
+
+__initcall (cio_ignore_proc_init);
+
+#endif /* CONFIG_PROC_FS */
diff -Nru a/drivers/s390/cio/blacklist.h b/drivers/s390/cio/blacklist.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/blacklist.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,6 @@
+#ifndef S390_BLACKLIST_H
+#define S390_BLACKLIST_H
+
+extern int is_blacklisted (int devno);
+
+#endif
diff -Nru a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/chsc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,832 @@
+/*
+ *  drivers/s390/cio/chsc.c
+ *   S/390 common I/O routines -- channel subsystem call
+ *   $Revision: 1.9 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ *					  changes.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+
+#include <asm/idals.h>
+#include <asm/uaccess.h>
+#include <asm/s390io.h>
+#include <asm/debug.h>
+
+#include "cio_debug.h"
+#include "s390io.h"
+#include "proc.h"
+#include "ioinfo.h"
+
+#ifdef CONFIG_DEBUG_CHSC
+#define DBGC printk
+#else
+#define DBGC(args,...) do {} while (0)
+#endif
+
+#define CHSC_DEBUG(printk_level,event_type,event_level,msg...) ({\
+	if (cio_show_msg) DBGC(printk_level msg); \
+	CIO_ ## event_type ## _EVENT (event_level, msg); \
+})
+static __u64 chpids[4]; /* 256 chpids */
+static __u64 chpids_logical[4] = {-1,-1,-1,-1};
+static __u64 chpids_known[4];
+
+static int cio_chsc_desc_avail;
+
+int
+chsc_chpid_logical (int irq, int chp)
+{
+	return test_bit (ioinfo[irq]->schib.pmcw.chpid[chp], &chpids_logical);
+}
+
+/* FIXME: this is _always_ called for every subchannel. shouldn't we
+ * 	  process more than one at a time?*/
+static int
+chsc_get_sch_desc_irq(int irq)
+{
+	int j = 0;
+	int ccode;
+
+	/* FIXME: chsc_area_sei cannot be on the stack since it needs to
+	 * be page-aligned. Implement proper locking or dynamic
+	 * allocation or prove that this function does not have to be
+	 * reentrant! */
+	static chsc_area_t __attribute__ ((aligned(PAGE_SIZE))) chsc_area_ssd;
+
+	typeof (chsc_area_ssd.response_block.response_block_data.ssd_res)
+		*ssd_res = &chsc_area_ssd.response_block.response_block_data.ssd_res;
+
+	chsc_area_ssd = (chsc_area_t) {
+		request_block: {
+			command_code1: 0x0010,
+			command_code2: 0x0004,
+			request_block_data: {
+				ssd_req: {
+					f_sch: irq,
+					l_sch: irq,
+				}
+			}
+		}
+	};
+
+	ccode = chsc(&chsc_area_ssd);
+	if (ccode > 0) {
+		if (cio_show_msg)
+			DBGC( KERN_DEBUG "chsc returned with ccode = %d\n",
+			     ccode);
+		if (ccode == 3)
+			return -ENODEV;
+		return -EBUSY;
+	}
+
+	switch (chsc_area_ssd.response_block.response_code) {
+	case 0x0001: /* everything ok */
+		break;
+	case 0x0002:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "Invalid command!\n");
+	case 0x0003:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "Error in chsc request block!\n");
+		return -EINVAL;
+	case 0x0004:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "Model does not provide ssd\n");
+		return -EOPNOTSUPP;
+	default:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "Unknown CHSC response %d\n", 
+				chsc_area_ssd.response_block.response_code);
+		return -EIO;
+	}
+
+	/* ssd_res->st stores the type of the detected
+	 * subchannel, with the following definitions:
+	 * 
+	 * 0: I/O subchannel:	  All fields have meaning
+	 * 1: CHSC subchannel:	  Only sch_val, st and sch
+	 * 			  have meaning
+	 * 2: Message subchannel: All fields except unit_addr
+	 * 			  have meaning
+	 * 3: ADM subchannel:	  Only sch_val, st and sch
+	 * 			  have meaning
+	 *
+	 * Other types are currently undefined.
+	 *
+	 */
+	if (ssd_res->st > 3) { /* uhm, that looks strange... */
+		CHSC_DEBUG (KERN_DEBUG, CRW, 0, "Strange subchannel type %d"
+			    " for sch %x\n", ssd_res->st, irq);
+		/*
+		 * There may have been a new subchannel type defined in the 
+		 * time since this code was written; since we don't know which
+		 * fields have meaning and what to do with it we just jump out
+		 */
+		return 0; 
+	} else { 
+		const char type[4][8] = {"I/O", "chsc", "message", "ADM"};
+		CHSC_DEBUG (KERN_DEBUG, CRW, 6,"ssd: sch %x is %s subchannel\n",
+				irq, type[ssd_res->st]);
+		if (ioinfo[irq] == INVALID_STORAGE_AREA)
+			/* FIXME: we should do device rec. here... */
+			return 0;
+
+		ioinfo[irq]->ssd_info.valid = 1;
+		ioinfo[irq]->ssd_info.type = ssd_res->st;
+	}
+
+	switch (ssd_res->st) {
+	case 0: /* fall through */
+	case 2:
+		for (j=0;j<8;j++) {
+			if ((0x80 >> j) & ssd_res->path_mask &
+					  ssd_res->fla_valid_mask) {
+				u8 chpid = ssd_res->chpid[j];
+				if (chpid 
+				    && (!test_and_set_bit (chpid, &chpids_known))
+				    && (test_bit (chpid, &chpids_logical)))
+					set_bit  (chpid, &chpids);
+
+				ioinfo[irq]->ssd_info.chpid[j] = chpid;
+				ioinfo[irq]->ssd_info.fla[j]   = ssd_res->fla[j];
+			}
+		}
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int
+chsc_get_sch_descriptions( void )
+{
+	int irq = 0;
+	int err = 0;
+
+	CIO_TRACE_EVENT( 4, "gsdesc");
+
+	/*
+	 * get information about chpids and link addresses 
+	 * by executing the chsc command 'store subchannel description'
+	 */
+
+	for (irq=0; irq<=highest_subchannel; irq++) {
+
+		/*
+		 * retrieve information for each sch
+		 */
+		err = chsc_get_sch_desc_irq(irq);
+		if (err) {
+			static int cio_chsc_err_msg;
+
+			if (!cio_chsc_err_msg) {
+				printk( KERN_ERR
+					"chsc_get_sch_descriptions:"
+					" Error %d while doing chsc; "
+					"processing some machine checks may "
+					"not work\n", err);
+				cio_chsc_err_msg=1;
+			}
+			return err;
+		}
+	}
+	cio_chsc_desc_avail = 1;
+	return 0;
+}
+
+__initcall(chsc_get_sch_descriptions);
+
+
+/* FIXME: don't iterate all subchannels but use the list of known ones*/
+static inline void
+s390_do_chpid_processing( __u8 chpid)
+{
+	int irq;
+	int j;
+	int mask;
+	char dbf_txt[15];
+	int ccode;
+	int was_oper;
+	int chp = 0;
+	int mask2;
+
+	sprintf(dbf_txt, "chpr%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+
+	/* 
+	 * TODO: the chpid may be not the chpid with the link incident,
+	 * but the chpid the report came in through. How to handle???
+	 */
+	clear_bit(chpid, &chpids);
+	if (!test_and_clear_bit(chpid, &chpids_known))
+		return;  /* we didn't know the chpid anyway */
+
+	for (irq=0;irq<=highest_subchannel;irq++) {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) 
+			continue;  /* we don't know the device anyway */
+		if (ioinfo[irq]->st)
+			continue; /* non-io subchannel */
+		for (j=0; j<8;j++) {
+			if (ioinfo[irq]->schib.pmcw.chpid[j] != chpid)
+				continue;
+
+ 			/* 
+ 			 * Note: irq spinlock is grabbed several times
+ 			 * in here
+ 			 */
+			mask2 = 0x80 >> j;
+			s390_send_nop (irq, mask2);
+
+			s390irq_spin_lock(irq);
+
+			/*
+			 * FIXME: is this neccessary?
+			 */				
+			ccode = stsch(irq, &ioinfo[irq]->schib);
+			if (ccode) {
+				CHSC_DEBUG (KERN_WARNING, CRW,2,
+					"do_crw_pending: device on "
+					"sch %x is not operational\n",
+					irq);
+				ioinfo[irq]->ui.flags.oper = 0;
+				break;
+			}
+
+			ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
+				ioinfo[irq]->schib.pmcw.pam &
+				ioinfo[irq]->schib.pmcw.pom;
+
+			if (ioinfo[irq]->opm) {
+				for (chp=0;chp<=7;chp++) {
+					mask2 = 0x80 >> chp;
+					if (ioinfo[irq]->opm & mask2) {
+						if (!test_bit
+						    (ioinfo[irq]->
+						     schib.pmcw.chpid[chp], 
+						     &chpids_logical)) {
+							/* disable using this path */
+							ioinfo[irq]->opm 
+								&= ~mask2;
+						}
+					}
+				}
+			}
+
+			if (!ioinfo[irq]->opm) {
+				/*
+				 * sh*t, our last path has gone...
+				 * Set the device status to not operational
+				 * and eventually notify the device driver
+				 */
+				CHSC_DEBUG (KERN_WARNING, CRW, 2,
+					"do_crw_pending: Last path gone"
+					" for device %x, sch %x\n",
+					ioinfo[irq]->devno, irq);
+
+				was_oper = ioinfo[irq]->ui.flags.oper;
+
+				ioinfo[irq]->ui.flags.oper = 0;
+
+				if (was_oper && ioinfo[irq]->ui.flags.ready) {
+
+					not_oper_handler_func_t nopfunc = 
+						ioinfo[irq]->nopfunc;
+
+					free_irq(irq, ioinfo[irq]->irq_desc.dev_id);
+					if (nopfunc)
+						nopfunc(irq, DEVSTAT_DEVICE_GONE);
+				}
+
+			} else if (ioinfo[irq]->ui.flags.ready) {
+				/* 
+				 * Re-do path verification for the chpid in question
+				 * FIXME: is this neccessary?
+				 */
+				mask = 0x80 >> j;
+
+				if (!s390_DevicePathVerification(irq,mask)) {
+					CHSC_DEBUG (KERN_DEBUG, CRW, 2,
+						"DevicePathVerification "
+						"successful for Subchannel %x, "
+						"chpid %x\n", irq, chpid);
+				}
+			}
+
+			s390irq_spin_unlock(irq);
+			break;
+		}
+	}
+}
+
+/* this used to be in s390_process_res_acc_*, FIXME: find a better name
+ * for this function */
+static int
+s390_check_valid_chpid(u8 chpid)
+{
+	char dbf_txt[15];
+	sprintf(dbf_txt, "accpr%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_txt);
+
+	/*
+	 * I/O resources may have become accessible.
+	 * Scan through all subchannels that may be concerned and
+	 * do a validation on those.
+	 * The more information we have (info), the less scanning
+	 * will we have to do.
+	 */
+
+	if (!cio_chsc_desc_avail) 
+		chsc_get_sch_descriptions();
+
+	if (!cio_chsc_desc_avail) {
+		/*
+		 * Something went wrong...
+		 */
+		CHSC_DEBUG (KERN_WARNING, CRW, 0, "Error: Could not retrieve "
+			    "subchannel descriptions, will not process css"
+			    "machine check...\n");
+		return 0;
+	}
+
+	if (!test_bit(chpid, &chpids_logical))
+		return 0; /* no need to do the rest */
+
+	return 1;
+}
+
+static void
+s390_process_res_acc_chpid (u8 chpid)
+{
+	int irq = 0;
+	int ccode;
+	int chp;
+	int mask;
+	int ret;
+
+	if (!s390_check_valid_chpid(chpid))
+		return;
+	
+	DBGC( KERN_DEBUG "Looking at chpid %x...\n", chpid);
+
+	for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+			/*
+			 * We don't know the device yet, but since a path
+			 * may be available now to the device we'll have
+			 * to do recognition again.
+			 * Since we don't have any idea about which chpid
+			 * that beast may be on we'll have to do a stsch
+			 * on all devices, grr...
+			 */
+			int valret = 0;
+
+			valret = s390_validate_subchannel(irq,0);
+			if (valret == -ENXIO) {
+				/* We're through */
+				return;
+			}
+			if (irq > highest_subchannel)
+				highest_subchannel = irq;
+			if (valret == 0)
+				s390_device_recognition_irq(irq);
+			continue;
+		}
+
+		if (!ioinfo[irq]->st)
+			continue;
+
+		/*
+		 * Send nops down each path to find out
+		 * which path is there
+		 */
+
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+
+			/*
+			 * check if chpid is in information
+			 * updated by ssd
+			 */
+			if ((ioinfo[irq]->ssd_info.valid) &&
+			    (ioinfo[irq]->ssd_info.chpid[chp] == chpid))
+				ret = s390_send_nop (irq, mask);
+		}
+
+		ccode = stsch(irq, &ioinfo[irq]->schib);
+		if (ccode > 0) {
+			ioinfo[irq]->ui.flags.oper = 0;
+			continue;
+		}
+
+		ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
+				   ioinfo[irq]->schib.pmcw.pam &
+				   ioinfo[irq]->schib.pmcw.pom;
+
+		if (ioinfo[irq]->opm) {
+			for (chp=0;chp<=7;chp++) {
+				mask = 0x80 >> chp;
+				if ((ioinfo[irq]->opm & mask) &&
+				    !test_bit (ioinfo[irq]->schib.pmcw.chpid[chp],
+					       &chpids_logical)) {
+
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
+		}
+
+		if ((ioinfo[irq]->ui.flags.ready) && (chpid & ioinfo[irq]->opm))
+			s390_DevicePathVerification(irq, chpid);
+	}
+}
+
+static void
+s390_process_res_acc_linkaddr ( __u8 chpid, __u16 fla, u32 fla_mask)
+{
+	char dbf_txt[15];
+	int irq = 0;
+	int ccode;
+	int chp;
+	int mask, mask2;
+	int ret;
+	int j;
+
+	if (!s390_check_valid_chpid(chpid))
+		return;
+	
+		sprintf(dbf_txt, "fla%x", fla);
+		CIO_TRACE_EVENT( 2, dbf_txt);
+	
+	DBGC (KERN_DEBUG "Looking at chpid %x, link addr %x...\n", chpid, fla);
+
+	for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
+
+		if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+			/* The full program again (see above), grr... */
+			int valret = 0;
+
+			valret = s390_validate_subchannel(irq,0);
+			if (valret == -ENXIO) {
+				/* We're done */
+				return;
+			}
+			if (irq > highest_subchannel)
+				highest_subchannel = irq;
+			if (valret == 0)
+				s390_device_recognition_irq(irq);
+			continue;
+		}
+
+		if (!ioinfo[irq]->st)
+			continue;
+		
+		/*
+		 * Walk through all subchannels and
+		 * look if our chpid and our (masked) link 
+		 * address are in somewhere
+		 * Do a stsch for the found subchannels and
+		 * perform path grouping  
+		 */
+
+		/* Update our ssd_info */
+		if (chsc_get_sch_desc_irq(irq))
+			break;
+
+		for (j=0;j<8;j++) {
+			if ((ioinfo[irq]->ssd_info.chpid[j] == chpid) &&
+			    ((ioinfo[irq]->ssd_info.fla[j]&fla_mask) == fla)) {
+
+				mask2 = 0x80 >> j;
+				ret = s390_send_nop (irq, mask2);
+
+				ccode = stsch(irq,&ioinfo[irq]->schib);
+				if (ccode > 0)
+					break;
+
+				ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
+						   ioinfo[irq]->schib.pmcw.pam &
+						   ioinfo[irq]->schib.pmcw.pom;
+
+				if (ioinfo[irq]->opm) {
+					for (chp=0;chp<=7;chp++) {
+						mask = 0x80 >> chp;
+						if ((ioinfo[irq]->opm & mask)
+						    && (!test_bit (ioinfo[irq]->
+							     schib.pmcw.chpid[chp], 
+							     &chpids_logical))) {
+							/* disable using this path */
+							ioinfo[irq]->opm &= ~mask;
+						}
+					}
+				}
+
+				if (ioinfo[irq]->ui.flags.ready)
+					s390_DevicePathVerification(irq, chpid);
+
+				break;
+			}
+		}
+	}
+}
+
+void
+s390_process_css( void )
+{
+	int ccode;
+
+	/* 
+	 * build the chsc request block for store event information 
+	 * and do the call 
+	 */
+
+	/* FIXME: chsc_area_sei cannot be on the stack since it needs to
+	 * be page-aligned. Implement proper locking or dynamic
+	 * allocation or prove that this function does not have to be
+	 * reentrant! */
+	static chsc_area_t chsc_area_sei __attribute__ ((aligned(PAGE_SIZE))) = {
+		request_block: {
+			command_code1: 0x0010,
+			command_code2: 0x000e
+		}
+	};
+
+	typeof (chsc_area_sei.response_block.response_block_data.sei_res)
+		*sei_res = &chsc_area_sei.response_block.response_block_data.sei_res;
+
+
+	CIO_TRACE_EVENT( 2, "prcss");
+
+	ccode = chsc(&chsc_area_sei);
+
+	if (ccode > 0)
+		return;
+
+
+	switch (chsc_area_sei.response_block.response_code) {
+	/* for debug purposes, check for problems */
+	case 0x0001:
+		break; /* everything ok */
+	case 0x0002:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "s390_process_css:"
+			    "invalid command!\n");
+	case 0x0003:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "s390_process_css:"
+				" error in chsc request block!\n");
+		return;
+	case 0x0005:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "s390_process_css:"
+				" no event information stored\n");
+		return;
+	default:
+		CHSC_DEBUG (KERN_WARNING, CRW, 2, "s390_process_css:"
+				" chsc response %d\n",
+				chsc_area_sei.response_block.response_code);
+		return;
+	}
+
+	CHSC_DEBUG (KERN_DEBUG, CRW, 4, "s390_process_css: "
+		    "event information successfully stored\n");
+
+	if (sei_res->rs != 4) {
+		CHSC_DEBUG (KERN_ERR, CRW, 2, "s390_process_css: "
+			    "reporting source (%04X) isn't a chpid!"
+			    "Aborting processing of machine check...\n",
+			    sei_res->rsid);
+		return;
+	}
+
+	/* which kind of information was stored? */
+	switch (sei_res->cc) {
+	case 1: /* link incident*/
+		CHSC_DEBUG (KERN_DEBUG, CRW, 4, "s390_process_css: "
+			"channel subsystem reports link incident,"
+			" source is chpid %x\n", sei_res->rsid);
+
+		s390_do_chpid_processing(sei_res->rsid);
+		break;
+
+	case 2: /* i/o resource accessibiliy */
+		CHSC_DEBUG (KERN_DEBUG, CRW, 4, "s390_process_css: "
+			"channel subsystem " "reports some I/O "
+			"devices may have become accessable\n");
+		DBGC ( KERN_DEBUG "Data received after sei: \n");
+		DBGC ( KERN_DEBUG "Validity flags: %x\n", sei_res->vf);
+
+		if ((sei_res->vf & 0x80) == 0) {
+			DBGC ( KERN_DEBUG "chpid: %x\n", sei_res->rsid);
+			s390_process_res_acc_chpid (sei_res->rsid);
+		} else if ((sei_res->vf & 0xc0) == 0x80) {
+			DBGC ( KERN_DEBUG "chpid: %x link addr: %x\n",
+				sei_res->rsid, sei_res->fla);
+			s390_process_res_acc_linkaddr (sei_res->rsid, 
+					sei_res->fla, 0xff00);
+		} else if ((sei_res->vf & 0xc0) == 0xc0) {
+			DBGC ( KERN_DEBUG "chpid: %x full link addr: %x\n",
+				sei_res->rsid, sei_res->fla);
+			s390_process_res_acc_linkaddr (sei_res->rsid,
+					sei_res->fla, 0xffff);
+		}
+		DBGC ( KERN_DEBUG "\n");
+
+		break;
+
+	default: /* other stuff */
+		CHSC_DEBUG (KERN_DEBUG, CRW, 4, "s390_process_css: "
+			    "event %d\n", sei_res->cc);
+		break;
+	}
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+static int s390_vary_chpid( __u8 chpid, int on );
+
+/*
+ * Function: cio_parse_chpids_proc_parameters
+ * parse the stuff piped to /proc/chpids
+ */
+static inline void
+cio_parse_chpids_proc_parameters(char* buf)
+{
+	int onoff;
+	int cp;
+
+	if (!strncmp (buf, "on ", 3)) {
+		onoff = 1;
+		buf += 3;
+	} else if (!strncmp (buf, "off ", 4)) {
+		onoff = 0;
+		buf += 4;
+	} else {
+		printk(KERN_ERR "/proc/chpids: Parse error; "
+		       "try using '{on,off} <chpid>'\n");
+		return;
+	}
+
+	if (*buf == '0') {
+		if (*(++buf) == 'x') 	/* strip leading zero */
+			buf++;		/* strip leading x */
+	}
+	cp = simple_strtoul (buf, &buf, 16);	/* interpret anything as hex */
+
+	chsc_get_sch_descriptions();
+	if (!cio_chsc_desc_avail) {
+		printk(KERN_ERR "Could not get chpid status, "
+		       "vary on/off not available\n");
+		return;
+	}
+
+	if (test_bit(cp, &chpids) != onoff) {
+		if (s390_vary_chpid(cp, onoff))
+			printk(KERN_WARNING "/proc/chpids: "
+			       "Invalid chpid specified\n");
+		else
+			printk(KERN_INFO "/proc/chpids: "
+			       "Varied chpid %x logically %sline\n",
+			       cp, onoff ? "on" : "off");
+	} else {
+		printk(KERN_ERR "/proc/chpids: chpid %x is "
+		       "already %sline\n", cp, onoff ? "on" : "off");
+	}
+}
+
+/*
+ * Function: s390_vary_chpid
+ * Varies the specified chpid online or offline
+ */
+static int
+s390_vary_chpid( __u8 chpid, int on) 
+{
+	char dbf_text[15];
+	int irq;
+
+	if ((chpid <=0) || (chpid >= NR_CHPIDS))
+		return -EINVAL;
+
+	sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
+	CIO_TRACE_EVENT( 2, dbf_text);
+
+	if (!test_bit(chpid, &chpids_known)) {
+		printk(KERN_ERR "Can't vary unknown chpid %02X\n", chpid);
+		return -EINVAL;
+	}
+
+	if (on) {
+		set_bit(chpid, &chpids_logical);
+		set_bit(chpid, &chpids);
+	} else {
+		clear_bit(chpid, &chpids_logical);
+		clear_bit(chpid, &chpids);
+	}
+
+	/*
+	 * Redo PathVerification on the devices the chpid connects to
+	 */
+	
+	for (irq=0;irq<=highest_subchannel;irq++) {
+		int chp;
+		/* 
+		 * We don't need to adjust the opm, as this will be done in
+		 * DevicePathVerification...
+		 */
+
+		if ((ioinfo[irq] == INVALID_STORAGE_AREA)
+		    || ioinfo[irq]->st
+		    || (!ioinfo[irq]->ssd_info.valid))
+			continue;
+
+		for (chp = 0; chp < 8; chp++) {
+			if (ioinfo[irq]->ssd_info.chpid[chp] == chpid) {
+
+				DBGC (KERN_DEBUG "Calling "
+				     "DevicePathVerification for irq %d\n",
+				     irq);
+
+				s390_DevicePathVerification(irq, 0);
+				break;
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * /proc/chpids to display available chpids
+ * vary chpids on/off by piping to it
+ */
+
+static int
+cio_chpids_read (char *page, char **start, off_t off,
+		 int count, int *eof, void *data)
+{
+	int chp = off;
+	int len = 0;
+	const unsigned int entry_size = 23;  /* longest entry is
+						"0xYZ logically offline\n" */
+
+	chsc_get_sch_descriptions();
+	if (!cio_chsc_desc_avail) {
+		return sprintf(page, "no info available\n");
+	}
+
+	while (chp < NR_CHPIDS && len + entry_size < count) {
+		if ((test_bit( chp, &chpids)) && test_bit(chp, &chpids_logical))
+			len += sprintf(page+len, "0x%02X online\n", chp);
+		else if (test_bit(chp, &chpids_known))
+			len += sprintf(page+len, "0x%02X logically offline\n",
+					chp);
+		chp++;
+	}
+
+	if (chp < NR_CHPIDS)
+		*eof = 1;
+	
+	*start = (char *) (chp - off);
+	return len;
+}
+
+static int
+cio_chpids_write (struct file *file, const char *user_buf,
+			     unsigned long user_len, void *data)
+{
+	char buffer[16] = {0,};
+
+	if (strncpy_from_user (buffer, user_buf, min(15ul,user_len)) < 0)
+		return -EFAULT;
+
+	CHSC_DEBUG (KERN_DEBUG, MSG, 2, "/proc/chpids: '%s'\n", buffer);
+
+	cio_parse_chpids_proc_parameters(buffer);
+
+	return user_len;
+}
+
+static int
+cio_chpids_proc_init(void)
+{
+	struct proc_dir_entry *entry;
+	entry = create_proc_entry("chpids", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+
+	if (!entry)
+		return 0;
+
+	entry->read_proc  = &cio_chpids_read;
+	entry->write_proc = &cio_chpids_write;
+	
+	return 1;
+}
+
+__initcall(cio_chpids_proc_init);
+#endif /* CONFIG_PROC_FS */
diff -Nru a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/chsc.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,6 @@
+#ifndef S390_CHSC_H
+#define S390_CHSC_H
+
+extern void s390_process_css( void );
+extern int chsc_chpid_logical (int irq, int chp);
+#endif
diff -Nru a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/cio.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,2024 @@
+/*
+ *  drivers/s390/cio/cio.c
+ *   S/390 common I/O routines -- low level i/o calls
+ *   $Revision: 1.15 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ *               05/06/2002 Cornelia Huck  some cleanups
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/delay.h>
+#include <asm/debug.h>
+
+#include "airq.h"
+#include "cio.h"
+#include "cio_debug.h"
+#include "ioinfo.h"
+#include "s390io.h" /* FIXME: try to do without this */
+
+static atomic_t sync_isc = ATOMIC_INIT (-1);
+static int sync_isc_cnt;	/* synchronous irq processing lock */
+
+int cons_dev = -1;	/* identify console device */
+
+/* FIXME: no signed counters here */
+static void
+s390_displayhex (void *ptr, s32 cnt, int level)
+{
+	s32 cnt1, cnt2, maxcnt2;
+	u32 *currptr = (__u32 *) ptr;
+	char buffer[cnt * 12]; /* FIXME: possible stack overflow? */
+
+	for (cnt1 = 0; cnt1 < cnt; cnt1 += 16) {
+		sprintf (buffer, "%08lX ", (unsigned long) currptr);
+		maxcnt2 = cnt - cnt1;
+		if (maxcnt2 > 16)
+			maxcnt2 = 16;
+		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+			sprintf (buffer, "%08X ", *currptr++);
+	}
+	DBG ("%s\n", buffer);
+	if (cio_debug_initialized) 
+		debug_text_event (cio_debug_trace_id, level, buffer);
+}
+
+
+/*
+ * used by s390_start_IO
+ */
+static inline void
+s390_build_orb(int irq, ccw1_t * cpa,
+	       unsigned long flag, __u8 lpm)
+{
+	ioinfo[irq]->orb.intparm = (__u32) (long) &ioinfo[irq]->u_intparm;
+	ioinfo[irq]->orb.fmt = 1;
+	ioinfo[irq]->orb.sync = 1;
+
+	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
+	ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND ? 1:0);
+	ioinfo[irq]->orb.ssic = ((flag & DOIO_ALLOW_SUSPEND)
+				 && (flag & DOIO_SUPPRESS_INTER));
+
+	if (flag & DOIO_VALID_LPM) {
+		ioinfo[irq]->orb.lpm = lpm;
+	} else {
+		ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
+
+	}
+
+#ifdef CONFIG_ARCH_S390X
+	/* 
+	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
+	 */
+	ioinfo[irq]->orb.c64 = 1;
+	ioinfo[irq]->orb.i2k = 0;
+#endif
+
+	ioinfo[irq]->orb.cpa = (__u32) virt_to_phys (cpa);
+
+}
+
+/*
+ * used by s390_start_IO to wait on sync. requests
+ */
+static inline int
+s390_do_sync_wait(int irq, int do_tpi)
+{
+	unsigned long psw_mask;
+	int ccode;
+	uint64_t time_start;
+	uint64_t time_curr;
+	
+	int ready = 0;
+	int io_sub = -1;
+	int do_retry = 1;
+
+	int ret = 0;
+
+	/*
+	 * We shouldn't perform a TPI loop, waiting for an
+	 *  interrupt to occur, but should load a WAIT PSW
+	 *  instead. Otherwise we may keep the channel subsystem
+	 *  busy, not able to present the interrupt. When our
+	 *  sync. interrupt arrived we reset the I/O old PSW to
+	 *  its original value.
+	 */
+	
+	ccode = iac ();
+	
+	switch (ccode) {
+	case 0:	/* primary-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	case 1:	/* secondary-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	case 2:	/* access-register */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+		break;
+	case 3:	/* home-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	default:
+		panic ("start_IO() : unexpected "
+		       "address-space-control %d\n", ccode);
+		break;
+	}
+	
+	/*
+	 * Martin didn't like modifying the new PSW, now we take
+	 *  a fast exit in do_IRQ() instead
+	 */
+	*(__u32 *) __LC_SYNC_IO_WORD = 1;
+
+	asm volatile ("STCK %0":"=m" (time_start));
+	
+	time_start = time_start >> 32;
+	
+	do {
+		if (do_tpi) {
+			tpi_info_t tpi_info = { 0, };
+
+			do {
+				if (tpi (&tpi_info) == 1) {
+					io_sub = tpi_info.irq;
+					break;
+				}
+
+				udelay (100);	/* usecs */
+				asm volatile("STCK %0":"=m" (time_curr));
+				
+				if (((time_curr >> 32) - time_start) >= 3)
+					do_retry = 0;
+				
+			} while (do_retry);
+		} else {
+			__load_psw_mask (psw_mask);
+			
+			io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
+
+		}
+
+		if (do_retry)
+			ready = s390_process_IRQ (io_sub);
+		
+		/*
+		 * surrender when retry count's exceeded ...
+		 */
+	} while (!((io_sub == irq) && (ready == 1)) && do_retry);
+
+	*(__u32 *) __LC_SYNC_IO_WORD = 0;
+
+	if (!do_retry)
+		ret = -ETIMEDOUT;
+	
+	return ret;
+}
+
+/*
+ * Used by halt_IO and clear_IO to wait on sync. requests
+ */
+static void
+s390_do_sync_wait_haltclear(int irq, int halt)
+{
+	int io_sub;
+	__u32 io_parm;
+	unsigned long psw_mask;
+	int ccode;
+	
+	int ready = 0;
+	
+	/*
+	 * For hsch and csch, we don't do a tpi loop as for ssch,
+	 * but load a wait psw if sync processing is requested.
+	 *
+	 * FIXME: Are there case where we can't rely on an interrupt
+	 *        to occurr? Need to check...
+	 */
+
+	ccode = iac ();
+	
+	switch (ccode) {
+	case 0:	/* primary-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_PRIM_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	case 1:	/* secondary-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_SEC_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	case 2:	/* access-register */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_ACC_REG_MODE | _PSW_IO_WAIT;
+		break;
+	case 3:	/* home-space */
+		psw_mask = _IO_PSW_MASK
+			| _PSW_HOME_SPACE_MODE | _PSW_IO_WAIT;
+		break;
+	default: /* FIXME: isn't ccode only 2 bits anyway? */
+		panic (halt?"halt":"clear"
+		       "_IO() : unexpected address-space-control %d\n", 
+		       ccode);
+		break;
+	}
+	
+	/*
+	 * Martin didn't like modifying the new PSW, now we take
+	 *  a fast exit in do_IRQ() instead
+	 */
+	*(__u32 *) __LC_SYNC_IO_WORD = 1;
+	
+	do {
+		__load_psw_mask (psw_mask);
+		
+		io_parm = *(__u32 *) __LC_IO_INT_PARM;
+		io_sub = (__u32) * (__u16 *) __LC_SUBCHANNEL_NR;
+		
+		ready = s390_process_IRQ (io_sub);
+		
+	} while (!((io_sub == irq) && (ready == 1)));
+	
+	*(__u32 *) __LC_SYNC_IO_WORD = 0;
+	
+}
+
+/*
+ * called from start_IO after deferred cc=3 conditions
+ * to print some debug data
+ */
+static inline void
+s390_cc3_print_data(int irq)
+{
+
+	stsch (irq, &(ioinfo[irq]->schib));
+	
+	CIO_DEBUG(KERN_INFO, 4,
+			 "s390_start_IO(%04X) - irb for "
+			 "device %04X, after status pending:\n",
+			 irq, ioinfo[irq]->devstat.devno);
+	
+	s390_displayhex (&(ioinfo[irq]->devstat.ii.irb),
+			 sizeof (irb_t), 4);
+	
+	CIO_DEBUG(KERN_INFO, 4,	
+			 "s390_start_IO(%04X) - schib for "
+			 "device %04X, after status pending:\n",
+			 irq, ioinfo[irq]->devstat.devno);
+	
+	s390_displayhex (&(ioinfo[irq]->schib),
+			 sizeof (schib_t), 4);
+	
+	if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+	CIO_DEBUG(KERN_INFO, 4,	
+			 "s390_start_IO(%04X) "
+			 "- sense data for device %04X,"
+			 " after status pending:\n",
+			 irq,
+			 ioinfo[irq]->devstat.devno);
+		
+		s390_displayhex (ioinfo[irq]->irq_desc.
+				 dev_id->ii.sense.data,
+				 ioinfo[irq]->irq_desc.
+				 dev_id->rescnt, 4);
+	}
+
+}
+
+static inline int
+s390_IO_handle_pending(int irq, int valid_lpm, int halt)
+{
+	int ret;
+	
+	if (halt) {
+		ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
+	} else {
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION
+			| DEVSTAT_STATUS_PENDING;
+	}
+	
+	/*
+	 * initialize the device driver specific devstat irb area
+	 */
+	memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
+		'\0', sizeof (irb_t));
+	
+	/*
+	 * Let the common interrupt handler process the pending status.
+	 *  However, we must avoid calling the user action handler, as
+	 *  it won't be prepared to handle a pending status during
+	 *  do_IO() processing inline. This also implies that process_IRQ
+	 *  must terminate synchronously - especially if device sensing
+	 *  is required.
+	 */
+	ioinfo[irq]->ui.flags.s_pend = 1;
+	ioinfo[irq]->ui.flags.busy = 1;
+	ioinfo[irq]->ui.flags.doio = 1;
+	
+	s390_process_IRQ (irq);
+	
+	ioinfo[irq]->ui.flags.s_pend = 0;
+	ioinfo[irq]->ui.flags.busy = 0;
+	ioinfo[irq]->ui.flags.doio = 0;
+	
+	ioinfo[irq]->ui.flags.repall = 0;
+	ioinfo[irq]->ui.flags.w4final = 0;
+	
+	ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
+	
+	/*
+	 * In multipath mode a condition code 3 implies the last path
+	 *  has gone, except we have previously restricted the I/O to
+	 *  a particular path. A condition code 1 (0 won't occur)
+	 *  results in return code EIO as well as 3 with another path
+	 *  than the one used (i.e. path available mask is non-zero).
+	 */
+	if (ioinfo[irq]->devstat.ii.irb.scsw.cc == 3) {
+		if (!halt) {
+			if (valid_lpm) {
+				ioinfo[irq]->opm &=
+					~(ioinfo[irq]->
+					  devstat.ii.irb.esw.esw1.lpum);
+			} else {
+				ioinfo[irq]->opm = 0;
+				
+			}
+		}
+		
+		if ((halt) || (ioinfo[irq]->opm == 0)) {
+			ret = -ENODEV;
+			ioinfo[irq]->ui.flags.oper = 0;
+		} else {
+			ret = -EIO;
+			
+		}
+		
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+		
+		if (!halt) 
+			s390_cc3_print_data(irq);
+		
+	} else {
+		ret = -EIO;
+		ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
+		ioinfo[irq]->ui.flags.oper = 1;
+		
+	}
+	
+	return ret;
+}
+
+static inline int
+s390_start_IO_handle_notoper(int irq, 
+			     int valid_lpm,
+			     __u8 lpm)
+{
+	int ret;
+
+	if (valid_lpm) {
+		ioinfo[irq]->opm &= ~lpm;
+	} else {
+		ioinfo[irq]->opm = 0;
+		
+	}
+	
+	if (ioinfo[irq]->opm == 0) {
+		ioinfo[irq]->ui.flags.oper = 0;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+		
+	}
+	
+	ret = -ENODEV;
+	
+	memcpy (ioinfo[irq]->irq_desc.dev_id,
+		&(ioinfo[irq]->devstat), sizeof (devstat_t));
+	
+	stsch (irq, &(ioinfo[irq]->schib));
+	
+	CIO_DEBUG(KERN_WARNING, 0, 
+			 "s390_start_IO(%04X) - schib for "
+			 "device %04X, after 'not oper' status:\n",
+			 irq, ioinfo[irq]->devstat.devno);
+	
+	s390_displayhex (&(ioinfo[irq]->schib), 
+			 sizeof (schib_t), 0);
+	
+	return ret;
+}
+
+int
+s390_start_IO (int irq,		/* IRQ */
+	       ccw1_t * cpa,	/* logical channel prog addr */
+	       unsigned long user_intparm,	/* interruption parameter */
+	       __u8 lpm,	/* logical path mask */
+	       unsigned long flag)
+{				/* flags */
+	int ccode;
+	int ret = 0;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	/*
+	 * The flag usage is mutal exclusive ...
+	 */
+	if ((flag & DOIO_EARLY_NOTIFICATION)
+	    && (flag & DOIO_REPORT_ALL)) 
+		return -EINVAL;
+
+	sprintf (dbf_txt, "stIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	s390_build_orb(irq, cpa, flag, lpm);
+
+	/*
+	 * If sync processing was requested we lock the sync ISC, modify the
+	 *  device to present interrupts for this ISC only and switch the
+	 *  CPU to handle this ISC exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
+
+		if (ret) 
+			return (ret);
+
+	}
+
+	if (flag & DOIO_DONT_CALL_INTHDLR) 
+		ioinfo[irq]->ui.flags.repnone = 1;
+
+	/*
+	 * Issue "Start subchannel" and process condition code
+	 */
+	ccode = ssch (irq, &(ioinfo[irq]->orb));
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	switch (ccode) {
+	case 0:
+
+		if (!ioinfo[irq]->ui.flags.w4sense) {
+			/*
+			 * init the device driver specific devstat irb area
+			 *
+			 * Note : don´t clear saved irb info in case of sense !
+			 */
+			memset (&((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->
+				ii.irb, '\0', sizeof (irb_t));
+		}
+
+		memset (&ioinfo[irq]->devstat.ii.irb, '\0', sizeof (irb_t));
+
+		/*
+		 * initialize device status information
+		 */
+		ioinfo[irq]->ui.flags.busy = 1;
+		ioinfo[irq]->ui.flags.doio = 1;
+
+		ioinfo[irq]->u_intparm = user_intparm;
+		ioinfo[irq]->devstat.cstat = 0;
+		ioinfo[irq]->devstat.dstat = 0;
+		ioinfo[irq]->devstat.lpum = 0;
+		ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
+		ioinfo[irq]->devstat.scnt = 0;
+
+		ioinfo[irq]->ui.flags.fast = 0;
+		ioinfo[irq]->ui.flags.repall = 0;
+
+		/*
+		 * Check for either early (FAST) notification requests
+		 *  or if we are to return all interrupt info.
+		 * Default is to call IRQ handler at secondary status only
+		 */
+		if (flag & DOIO_EARLY_NOTIFICATION) {
+			ioinfo[irq]->ui.flags.fast = 1;
+		} else if (flag & DOIO_REPORT_ALL) {
+			ioinfo[irq]->ui.flags.repall = 1;
+
+		}
+
+		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+			ret = s390_do_sync_wait(irq, flag&DOIO_TIMEOUT);
+
+		break;
+
+	case 1:		/* status pending */
+
+		ret = s390_IO_handle_pending(irq, 
+					     flag & DOIO_VALID_LPM,
+					     0);
+		break;
+
+	case 2:		/* busy */
+
+		ret = -EBUSY;
+		break;
+
+	default:		/* device/path not operational */
+
+		ret = s390_start_IO_handle_notoper(irq, 
+						   flag & DOIO_VALID_LPM,
+						   lpm);
+		break;
+
+	}
+
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+		disable_cpu_sync_isc (irq);
+
+	if (flag & DOIO_DONT_CALL_INTHDLR) 
+		ioinfo[irq]->ui.flags.repnone = 0;
+
+	return (ret);
+}
+
+int
+do_IO (int irq,			/* IRQ */
+       ccw1_t * cpa,		/* channel program address */
+       unsigned long user_intparm,	/* interruption parameter */
+       __u8 lpm,		/* logical path mask */
+       unsigned long flag)
+{				/* flags : see above */
+	int ret = 0;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	/* handler registered ? or free_irq() in process already ? */
+	if (!ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready) 
+		return -ENODEV;
+
+	sprintf (dbf_txt, "doIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * Note: We ignore the device operational status - if not operational,
+	 *        the SSCH will lead to an -ENODEV condition ...
+	 */
+	if (!ioinfo[irq]->ui.flags.busy) {	/* last I/O completed ? */
+		ret = s390_start_IO (irq, cpa, user_intparm, lpm, flag);
+		if ((ret == -ETIMEDOUT) && (flag & DOIO_CANCEL_ON_TIMEOUT)) {
+			/*
+			 * We should better cancel the io request here
+			 * or we might not be able to do io on this sch
+			 * again
+			 */
+			cancel_IO (irq);
+		}
+
+	} else if (ioinfo[irq]->ui.flags.fast) {
+		/*
+		 * If primary status was received and ending status is missing,
+		 *  the device driver won't be notified on the ending status
+		 *  if early (fast) interrupt notification was requested.
+		 *  Therefore we have to queue the next incoming request. If
+		 *  halt_IO() is issued while there is a request queued, a HSCH
+		 *  needs to be issued and the queued request must be deleted
+		 *  but its intparm must be returned (see halt_IO() processing)
+		 */
+		if (ioinfo[irq]->ui.flags.w4final
+		    && !ioinfo[irq]->ui.flags.doio_q) {
+			ioinfo[irq]->qflag = flag;
+			ioinfo[irq]->qcpa = cpa;
+			ioinfo[irq]->qintparm = user_intparm;
+			ioinfo[irq]->qlpm = lpm;
+		} else {
+			ret = -EBUSY;
+
+		}
+	} else {
+		ret = -EBUSY;
+
+	}
+
+	return (ret);
+
+}
+
+/*
+ * resume suspended I/O operation
+ */
+int
+resume_IO (int irq)
+{
+	int ret = 0;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "resIO%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * We allow for 'resume' requests only for active I/O operations
+	 */
+	if (ioinfo[irq]->ui.flags.busy) {
+		int ccode;
+
+		ccode = rsch (irq);
+
+		sprintf (dbf_txt, "ccode:%d", ccode);
+		CIO_TRACE_EVENT (4, dbf_txt);
+
+		switch (ccode) {
+		case 0:
+			break;
+
+		case 1:
+			s390_process_IRQ (irq);
+			ret = -EBUSY;
+			break;
+
+		case 2:
+			ret = -EINVAL;
+			break;
+
+		case 3:
+			/*
+			 * useless to wait for request completion
+			 *  as device is no longer operational !
+			 */
+			ioinfo[irq]->ui.flags.oper = 0;
+			ioinfo[irq]->ui.flags.busy = 0;
+			ret = -ENODEV;
+			break;
+
+		}
+
+	} else {
+		ret = -ENOTCONN;
+
+	}
+
+	return (ret);
+}
+
+/*
+ * Note: The "intparm" parameter is not used by the halt_IO() function
+ *       itself, as no ORB is built for the HSCH instruction. However,
+ *       it allows the device interrupt handler to associate the upcoming
+ *       interrupt with the halt_IO() request.
+ */
+int
+halt_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret;
+	int ccode;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	/*
+	 * we only allow for halt_IO if the device has an I/O handler associated
+	 */
+	if (!ioinfo[irq]->ui.flags.ready) 
+		return -ENODEV;
+
+	/*
+	 * we ignore the halt_io() request if ending_status was received but
+	 *  a SENSE operation is waiting for completion.
+	 */
+	if (ioinfo[irq]->ui.flags.w4sense) 
+		return 0;
+
+	sprintf (dbf_txt, "haltIO%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
+
+		if (ret)
+			return (ret);
+	}
+
+	/*
+	 * Issue "Halt subchannel" and process condition code
+	 */
+	ccode = hsch (irq);
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	switch (ccode) {
+	case 0:
+
+		ioinfo[irq]->ui.flags.haltio = 1;
+
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
+
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
+
+		}
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+			s390_do_sync_wait_haltclear(irq, 1);
+
+		ret = 0;
+		break;
+
+	case 1:		/* status pending */
+
+		ret = s390_IO_handle_pending(irq, 0, 1);
+		break;
+
+	case 2:		/* busy */
+
+		ret = -EBUSY;
+		break;
+
+	default:		/* device not operational */
+
+		ret = -ENODEV;
+		break;
+
+	}
+
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+		disable_cpu_sync_isc (irq);
+
+	return (ret);
+}
+
+/*
+ * Note: The "intparm" parameter is not used by the clear_IO() function
+ *       itself, as no ORB is built for the CSCH instruction. However,
+ *       it allows the device interrupt handler to associate the upcoming
+ *       interrupt with the clear_IO() request.
+ */
+int
+clear_IO (int irq, unsigned long user_intparm, unsigned long flag)
+{				/* possible DOIO_WAIT_FOR_INTERRUPT */
+	int ret = 0;
+	int ccode;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return (-ENODEV);
+
+	/*
+	 * we only allow for clear_IO if the device has an I/O handler associated
+	 */
+	if (!ioinfo[irq]->ui.flags.ready)
+		return -ENODEV;
+	/*
+	 * we ignore the clear_io() request if ending_status was received but
+	 *  a SENSE operation is waiting for completion.
+	 */
+	if (ioinfo[irq]->ui.flags.w4sense)
+		return 0;
+
+	sprintf (dbf_txt, "clearIO%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	/*
+	 * If sync processing was requested we lock the sync ISC,
+	 *  modify the device to present interrupts for this ISC only
+	 *  and switch the CPU to handle this ISC exclusively.
+	 */
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) {
+		ret = enable_cpu_sync_isc (irq);
+
+		if (ret)
+			return (ret);
+	}
+
+	/*
+	 * Issue "Clear subchannel" and process condition code
+	 */
+	ccode = csch (irq);
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	switch (ccode) {
+	case 0:
+
+		ioinfo[irq]->ui.flags.haltio = 1;
+
+		if (!ioinfo[irq]->ui.flags.doio) {
+			ioinfo[irq]->ui.flags.busy = 1;
+			ioinfo[irq]->u_intparm = user_intparm;
+			ioinfo[irq]->devstat.cstat = 0;
+			ioinfo[irq]->devstat.dstat = 0;
+			ioinfo[irq]->devstat.lpum = 0;
+			ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
+			ioinfo[irq]->devstat.scnt = 0;
+
+		} else {
+			ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
+
+		}
+
+		/*
+		 * If synchronous I/O processing is requested, we have
+		 *  to wait for the corresponding interrupt to occur by
+		 *  polling the interrupt condition. However, as multiple
+		 *  interrupts may be outstanding, we must not just wait
+		 *  for the first interrupt, but must poll until ours
+		 *  pops up.
+		 */
+		if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+			s390_do_sync_wait_haltclear(irq, 0);
+
+		ret = 0;
+		break;
+
+	case 1:		/* no status pending for csh */
+		BUG ();
+		break;
+
+	case 2:		/* no busy for csh */
+		BUG ();
+		break;
+
+	default:		/* device not operational */
+
+		ret = -ENODEV;
+		break;
+
+	}
+
+	if (flag & DOIO_WAIT_FOR_INTERRUPT) 
+		disable_cpu_sync_isc (irq);
+
+	return (ret);
+}
+
+/*
+ * Function: cancel_IO
+ * Issues a "Cancel Subchannel" on the specified subchannel
+ * Note: We don't need any fancy intparms and flags here
+ *       since xsch is executed synchronously.
+ * Only for common I/O internal use as for now.
+ */
+int
+cancel_IO (int irq)
+{
+	int ccode;
+	char dbf_txt[15];
+	int ret = 0;
+
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "cancelIO%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	ccode = xsch (irq);
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	switch (ccode) {
+
+	case 0:		/* success */
+		ret = 0;
+		break;
+
+	case 1:		/* status pending */
+
+		/* process the pending irq... */
+		s390_process_IRQ (irq);
+		ret = -EBUSY;
+		break;
+
+	case 2:		/* not applicable */
+		ret = -EINVAL;
+		break;
+
+	default:		/* not oper */
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+/*
+ * do_IRQ() handles all normal I/O device IRQ's (the special
+ *          SMP cross-CPU interrupts have their own specific
+ *          handlers).
+ *
+ */
+asmlinkage void
+do_IRQ (struct pt_regs regs)
+{
+	/*
+	 * Get interrupt info from lowcore
+	 */
+	volatile tpi_info_t *tpi_info = (tpi_info_t *) (__LC_SUBCHANNEL_ID);
+	int cpu = smp_processor_id ();
+
+	/*
+	 * take fast exit if CPU is in sync. I/O state
+	 *
+	 * Note: we have to turn off the WAIT bit and re-disable
+	 *       interrupts prior to return as this was the initial
+	 *       entry condition to synchronous I/O.
+	 */
+	if (*(__u32 *) __LC_SYNC_IO_WORD) {
+		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
+		return;
+	}
+	/* endif */
+#ifdef CONFIG_FAST_IRQ
+	do {
+#endif				/* CONFIG_FAST_IRQ */
+
+		/*
+		 * Non I/O-subchannel thin interrupts are processed differently
+		 */
+		if (tpi_info->adapter_IO == 1 &&
+		    tpi_info->int_type == IO_INTERRUPT_TYPE) {
+			irq_enter (cpu, -1);
+			do_adapter_IO (tpi_info->intparm);
+			irq_exit (cpu, -1);
+		} else {
+			unsigned int irq = tpi_info->irq;
+
+			/*
+			 * fix me !!!
+			 *
+			 * instead of boxing the device, we need to schedule device
+			 * recognition, the interrupt stays pending. We need to
+			 * dynamically allocate an ioinfo structure, etc..
+			 */
+			if (ioinfo[irq] == INVALID_STORAGE_AREA) 
+				return;	/* this keeps the device boxed ... */
+
+			if (ioinfo[irq]->st) {
+				/* How can that be? */
+				printk(KERN_WARNING "Received interrupt on "
+				       "non-IO subchannel %x!\n", irq);
+				return;
+			}
+
+			irq_enter (cpu, irq);
+			s390irq_spin_lock (irq);
+			s390_process_IRQ (irq);
+			s390irq_spin_unlock (irq);
+			irq_exit (cpu, irq);
+		}
+
+#ifdef CONFIG_FAST_IRQ
+
+		/*
+		 * Are more interrupts pending?
+		 * If so, the tpi instruction will update the lowcore 
+		 * to hold the info for the next interrupt.
+		 */
+	} while (tpi (NULL) != 0);
+
+#endif				/* CONFIG_FAST_IRQ */
+
+	return;
+}
+
+/*
+ * used by s390_process_irq to start queued channel programs
+ */
+static inline void
+s390_start_queued_io(int irq, devstat_t *udp)
+{
+	int ret;
+	int do_cancel = ioinfo[irq]->qflag & DOIO_CANCEL_ON_TIMEOUT;
+	
+	ret = s390_start_IO (irq,
+			     ioinfo[irq]->qcpa,
+			     ioinfo[irq]->qintparm,
+			     ioinfo[irq]->qlpm,
+			     ioinfo[irq]->qflag);
+	
+	ioinfo[irq]->ui.flags.doio_q = 0;
+	
+	/*
+	 * If s390_start_IO() failed call the device's interrupt
+	 *  handler, the IRQ related devstat area was setup by
+	 *  s390_start_IO() accordingly already (status pending
+	 *  condition).
+	 */
+	if (ret) 
+		ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
+		
+	/* 
+	 * better cancel the io when we time out...
+	 */
+	if ((ret == -ETIMEDOUT) && do_cancel) 
+		cancel_IO (irq);
+
+}
+
+/*
+ * used by s390_process_irq to issue a sense ccw
+ */
+static inline void
+s390_issue_sense(unsigned int irq, devstat_t *dp)
+{
+	int ret_io;
+	ccw1_t *s_ccw = &ioinfo[irq]->senseccw;
+	unsigned long s_flag = 0;
+
+	s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
+	s_ccw->cda = (__u32) virt_to_phys (ioinfo[irq]->sense_data);
+	s_ccw->count = SENSE_MAX_COUNT;
+	s_ccw->flags = CCW_FLAG_SLI;
+	
+	/*
+	 * If free_irq() or a sync do_IO/s390_start_IO() is in
+	 *  process we have to sense synchronously
+	 */
+	if (ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio) 
+		s_flag = DOIO_WAIT_FOR_INTERRUPT;
+	
+	/*
+	 * Reset status info
+	 *
+	 * It does not matter whether this is a sync. or async.
+	 *  SENSE request, but we have to assure we don't call
+	 *  the irq handler now, but keep the irq in busy state.
+	 *  In sync. mode s390_process_IRQ() is called recursively,
+	 *  while in async. mode we re-enter do_IRQ() with the
+	 *  next interrupt.
+	 *
+	 * Note : this may be a delayed sense request !
+	 */
+	ioinfo[irq]->ui.flags.fast = 0;
+	ioinfo[irq]->ui.flags.repall = 0;
+	ioinfo[irq]->ui.flags.w4final = 0;
+	ioinfo[irq]->ui.flags.delsense = 0;
+	
+	dp->cstat = 0;
+	dp->dstat = 0;
+	dp->rescnt = SENSE_MAX_COUNT;
+	
+	ioinfo[irq]->ui.flags.w4sense = 1;
+	
+	ret_io = s390_start_IO (irq, s_ccw, 0xE2C5D5E2,	/* = SENSe */
+				0,	/* n/a */
+				s_flag);
+	
+}
+
+static inline void
+s390_reset_flags_after_ending_status(int irq)
+{
+	ioinfo[irq]->ui.flags.busy = 0;
+	ioinfo[irq]->ui.flags.doio = 0;
+	ioinfo[irq]->ui.flags.haltio = 0;
+	ioinfo[irq]->ui.flags.fast = 0;
+	ioinfo[irq]->ui.flags.repall = 0;
+	ioinfo[irq]->ui.flags.w4final = 0;
+
+	ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
+	ioinfo[irq]->irq_desc.dev_id->flag |= DEVSTAT_FINAL_STATUS;
+	
+}
+
+/*
+ * for cc=0 and cc=1 after tsch
+ */
+static inline int
+s390_process_IRQ_normal(unsigned int irq,
+			int ending_status)
+{
+	unsigned int fctl;	/* function control */
+	unsigned int stctl;	/* status   control */
+	unsigned int actl;	/* activity control */
+	scsw_t *scsw;
+	int allow4handler = 1;
+	devstat_t *dp;
+	devstat_t *udp;
+	
+	dp = &ioinfo[irq]->devstat;
+	udp = ioinfo[irq]->irq_desc.dev_id;
+
+	scsw = &dp->ii.irb.scsw;
+	
+	fctl = scsw->fctl;
+	stctl = scsw->stctl;
+	actl = scsw->actl;
+	
+	ioinfo[irq]->stctl |= stctl;
+	
+	ending_status = (stctl & SCSW_STCTL_SEC_STATUS)
+		|| (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
+		|| (stctl == SCSW_STCTL_STATUS_PEND);
+	
+	/*
+	 * Check for unsolicited interrupts - for debug purposes only
+	 *
+	 * We only consider an interrupt as unsolicited, if the device was not
+	 *  actively in use (busy) and an interrupt other than an ALERT status
+	 *  was received.
+	 *
+	 * Note: We must not issue a message to the console, if the
+	 *       unsolicited interrupt applies to the console device
+	 *       itself !
+	 */
+	if (!(stctl & SCSW_STCTL_ALERT_STATUS)
+	    && (ioinfo[irq]->ui.flags.busy == 0)) {
+		
+		CIO_DEBUG_NOCONS(irq, KERN_INFO, DBG, 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);
+		
+		CIO_DEBUG_NOCONS(irq, KERN_INFO, DBG, 2,
+				 "s390_process_IRQ(%04X) - irb for "
+				 "device %04X, ending_status %d:\n", 
+				 irq, dp->devno, ending_status);
+		
+		s390_displayhex (&(dp->ii.irb),
+				 sizeof (irb_t), 2);
+	}
+	
+	/*
+	 * take fast exit if no handler is available
+	 */
+	if (!ioinfo[irq]->ui.flags.ready)
+		return (ending_status);
+	
+	/*
+	 * Check whether we must issue a SENSE CCW ourselves if there is no
+	 *  concurrent sense facility installed for the subchannel.
+	 *
+	 * Note: We should check for ioinfo[irq]->ui.flags.consns but VM
+	 *       violates the ESA/390 architecture and doesn't present an
+	 *       operand exception for virtual devices without concurrent
+	 *       sense facility available/supported when enabling the
+	 *       concurrent sense facility.
+	 */
+	if (((scsw->dstat & DEV_STAT_UNIT_CHECK) 
+	     && (!dp->flag & DEVSTAT_FLAG_SENSE_AVAIL))
+	    || (ioinfo[irq]->ui.flags.delsense && ending_status)) {
+		
+		allow4handler = 0;
+		
+		if (ending_status) {
+			/*
+			 * We copy the current status information into the device driver
+			 *  status area. Then we can use the local devstat area for device
+			 *  sensing. When finally calling the IRQ handler we must not overlay
+			 *  the original device status but copy the sense data only.
+			 */
+			memcpy (udp, dp, sizeof (devstat_t));
+			
+			s390_issue_sense(irq, dp);
+			
+		} else {
+			/*
+			 * we received an Unit Check but we have no final
+			 *  status yet, therefore we must delay the SENSE
+			 *  processing. However, we must not report this
+			 *  intermediate status to the device interrupt
+			 *  handler.
+			 */
+			ioinfo[irq]->ui.flags.fast = 0;
+			ioinfo[irq]->ui.flags.repall = 0;
+			
+			ioinfo[irq]->ui.flags.delsense = 1;
+			
+		}
+		
+	}
+	
+	/*
+	 * we allow for the device action handler if .
+	 *  - we received ending status
+	 *  - the action handler requested to see all interrupts
+	 *  - we received an intermediate status
+	 *  - fast notification was requested (primary status)
+	 *  - unsolicited interrupts
+	 *
+	 */
+	if (allow4handler) {
+		allow4handler = ending_status
+			|| (ioinfo[irq]->ui.flags.repall)
+			|| (stctl & SCSW_STCTL_INTER_STATUS)
+			|| ((ioinfo[irq]->ui.flags.fast)
+			    && (stctl & SCSW_STCTL_PRIM_STATUS))
+			|| (ioinfo[irq]->ui.flags.oper == 0);
+		
+	}
+	
+	/*
+	 * We used to copy the device status information right before
+	 *  calling the device action handler. However, in status
+	 *  pending situations during do_IO() or halt_IO(), as well as
+	 *  enable_subchannel/disable_subchannel processing we must
+	 *  synchronously return the status information and must not
+	 *  call the device action handler.
+	 *
+	 */
+	if (allow4handler) {
+		/*
+		 * if we were waiting for sense data we copy the sense
+		 *  bytes only as the original status information was
+		 *  saved prior to sense already.
+		 */
+		if (ioinfo[irq]->ui.flags.w4sense) {
+			int sense_count =
+				SENSE_MAX_COUNT - ioinfo[irq]->devstat.rescnt;
+			
+			CIO_DEBUG_NOCONS(irq, KERN_DEBUG, DBG, 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;
+
+			if (sense_count >= 0) {
+				memcpy (udp->ii.sense.data,
+					ioinfo[irq]->sense_data,
+					sense_count);
+			} else {
+				panic ("s390_process_IRQ(%04x) encountered "
+				       "negative sense count\n", irq);
+
+			}
+		} else {
+			memcpy (udp, dp, 
+				sizeof(devstat_t) - 
+				(dp->flag & DEVSTAT_FLAG_SENSE_AVAIL ?  
+				 0 : SENSE_MAX_COUNT));
+			
+		}
+
+	}
+
+	/*
+	 * for status pending situations other than deferred interrupt
+	 *  conditions detected by s390_process_IRQ() itself we must not
+	 *  call the handler. This will synchronously be reported back
+	 *  to the caller instead, e.g. when detected during do_IO().
+	 */
+	if (ioinfo[irq]->ui.flags.s_pend
+	    || ioinfo[irq]->ui.flags.unready
+	    || ioinfo[irq]->ui.flags.repnone) {
+
+		if (ending_status) 
+			s390_reset_flags_after_ending_status(irq);
+
+		allow4handler = 0;
+
+	}
+
+	/*
+	 * Call device action handler if applicable
+	 */
+	if (allow4handler) {
+
+		/*
+		 *  We only reset the busy condition when we are sure that no further
+		 *   interrupt is pending for the current I/O request (ending_status).
+		 */
+		if (ending_status || !ioinfo[irq]->ui.flags.oper) {
+			ioinfo[irq]->ui.flags.oper = 1;	/* dev IS oper */
+
+			s390_reset_flags_after_ending_status(irq);
+			
+			ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
+
+			/*
+			 * reset intparm after final status or we will badly present unsolicited
+			 *  interrupts with a intparm value possibly no longer valid.
+			 */
+			dp->intparm = 0;
+
+			/*
+			 * Was there anything queued ? Start the pending channel program
+			 *  if there is one.
+			 */
+			if (ioinfo[irq]->ui.flags.doio_q) 
+				s390_start_queued_io(irq, udp);
+
+		} else {
+			ioinfo[irq]->ui.flags.w4final = 1;
+			
+			/*
+			 * Eventually reset subchannel PCI status and
+			 *  set the PCI or SUSPENDED flag in the user
+			 *  device status block if appropriate.
+			 */
+			if (dp->cstat & SCHN_STAT_PCI) {
+				udp->flag |= DEVSTAT_PCI;
+				dp->cstat &= ~SCHN_STAT_PCI;
+			}
+
+			if (actl & SCSW_ACTL_SUSPENDED) 
+				udp->flag |= DEVSTAT_SUSPENDED;
+
+			ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
+
+		}
+
+	}
+
+	return ending_status;
+
+}
+
+/*
+ * for cc=3 after tsch
+ */
+static inline int
+s390_process_IRQ_notoper(unsigned int irq,
+			 int ending_status)
+{
+	devstat_t *dp;
+	devstat_t *udp;
+
+	ioinfo[irq]->ui.flags.busy = 0;
+	ioinfo[irq]->ui.flags.doio = 0;
+	ioinfo[irq]->ui.flags.haltio = 0;
+	
+	dp = &ioinfo[irq]->devstat;
+	udp = ioinfo[irq]->irq_desc.dev_id;
+
+	dp->cstat = 0;
+	dp->dstat = 0;
+	
+	if (ioinfo[irq]->ulpm != ioinfo[irq]->opm) 
+		/*
+		 * either it was the only path or it was restricted ...
+		 */
+		ioinfo[irq]->opm &=
+			~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
+	else 
+		ioinfo[irq]->opm = 0;
+	
+	if (ioinfo[irq]->opm == 0) 
+		ioinfo[irq]->ui.flags.oper = 0;
+
+	
+	ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
+	
+	/*
+	 * When we find a device "not oper" we save the status
+	 *  information into the device status area and call the
+	 *  device specific interrupt handler.
+	 *
+	 * Note: currently we don't have any way to reenable
+	 *       the device unless an unsolicited interrupt
+	 *       is presented. We don't check for spurious
+	 *       interrupts on "not oper" conditions.
+	 */
+	
+	if ((ioinfo[irq]->ui.flags.fast)
+	    && (ioinfo[irq]->ui.flags.w4final)) {
+		/*
+		 * If a new request was queued already, we have
+		 *  to simulate the "not oper" status for the
+		 *  queued request by switching the "intparm" value
+		 *  and notify the interrupt handler.
+		 */
+		if (ioinfo[irq]->ui.flags.doio_q) 
+			ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
+			
+	}
+	
+	ioinfo[irq]->ui.flags.fast = 0;
+	ioinfo[irq]->ui.flags.repall = 0;
+	ioinfo[irq]->ui.flags.w4final = 0;
+	
+	/*
+	 * take fast exit if no handler is available
+	 */
+	if (!ioinfo[irq]->ui.flags.ready)
+		return (ending_status);
+	
+	memcpy (udp, &(ioinfo[irq]->devstat), 
+		sizeof(devstat_t) - 
+		(dp->flag & DEVSTAT_FLAG_SENSE_AVAIL ?  0 : SENSE_MAX_COUNT));
+	
+	ioinfo[irq]->devstat.intparm = 0;
+	
+	if (!ioinfo[irq]->ui.flags.s_pend) 
+		ioinfo[irq]->irq_desc.handler (irq, udp, NULL);
+	
+	return 1;
+
+}
+
+
+/* FIXME:  help!!!! */
+/*
+ * s390_process_IRQ() handles status pending situations and interrupts
+ *
+ * Called by : do_IRQ()             - for "real" interrupts
+ *             s390_start_IO, halt_IO()
+ *                                  - status pending cond. after SSCH, or HSCH
+ *             cancel_IO(), clear_IO(), resume_IO()
+ *             s390_set_isc5()
+ *             s390_validate_subchannel(),
+ *             {en,dis}able_subchannel() - status pending conditions (after MSCH)
+ *
+ * Returns: 0 - no ending status received, no further action taken
+ *          1 - interrupt handler was called with ending status
+ */
+int
+s390_process_IRQ (unsigned int irq)
+{
+	int ccode;		/* cond code from tsch() operation */
+	int irb_cc;		/* cond code from irb */
+
+	int issense = 0;
+	int ending_status = 0;
+	devstat_t *dp;
+	devstat_t *udp;
+	scsw_t *scsw;
+
+	char dbf_txt[15];
+
+	if (cio_count_irqs) {
+		int cpu = smp_processor_id ();
+		s390_irq_count[cpu]++;
+	}
+
+	sprintf (dbf_txt, "procIRQ%x", irq);
+	CIO_TRACE_EVENT (3, dbf_txt);
+
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+		static irb_t p_init_irb; /* FIXME: could this be on the stack? */
+		/* we can't properly process the interrupt ... */
+
+		CIO_DEBUG(KERN_CRIT, 0, 
+			  "s390_process_IRQ(%04X) - got interrupt "
+			  "for non-initialized subchannel!\n", irq);
+
+		tsch (irq, &p_init_irb);
+		return (1);
+
+	}
+
+	if (ioinfo[irq]->st) {
+		/* can't be */
+		BUG();
+		return 1;
+	}
+
+	dp = &ioinfo[irq]->devstat;
+	udp = ioinfo[irq]->irq_desc.dev_id;
+
+	/*
+	 * It might be possible that a device was not-oper. at the time
+	 *  of free_irq() processing. This means the handler is no longer
+	 *  available when the device possibly becomes ready again. In
+	 *  this case we perform delayed disable_subchannel() processing.
+	 */
+	if ((!ioinfo[irq]->ui.flags.ready) 
+	    &&  (!ioinfo[irq]->ui.flags.d_disable)) 
+
+		CIO_DEBUG (KERN_CRIT, 0, 
+			   "s390_process_IRQ(%04X) "
+			   "- no interrupt handler registered "
+			   "for device %04X !\n",
+			   irq, ioinfo[irq]->devstat.devno);
+
+	/*
+	 * retrieve the i/o interrupt information (irb),
+	 *  update the device specific status information
+	 *  and possibly call the interrupt handler.
+	 *
+	 * Note 1: At this time we don't process the resulting
+	 *         condition code (ccode) from tsch(), although
+	 *         we probably should.
+	 *
+	 * Note 2: Here we will have to check for channel
+	 *         check conditions and call a channel check
+	 *         handler.
+	 *
+	 * Note 3: If a start function was issued, the interruption
+	 *         parameter relates to it. If a halt function was
+	 *         issued for an idle device, the intparm must not
+	 *         be taken from lowcore, but from the devstat area.
+	 */
+	ccode = tsch (irq, &(dp->ii.irb));
+
+	sprintf (dbf_txt, "ccode:%d", ccode);
+	CIO_TRACE_EVENT (3, dbf_txt);
+
+	if (ccode == 3) 
+		CIO_DEBUG (KERN_WARNING, 0, 
+			   "s390_process_IRQ(%04X) - subchannel "
+			   "is not operational!\n",
+			   irq);
+
+	/*
+	 * We must only accumulate the status if the device is busy already
+	 */
+
+	scsw = &dp->ii.irb.scsw;
+
+	if (ioinfo[irq]->ui.flags.busy) {
+		dp->dstat |= scsw->dstat;
+		dp->cstat |= scsw->cstat;
+		dp->intparm = ioinfo[irq]->u_intparm;
+
+	} else {
+		dp->dstat = scsw->dstat;
+		dp->cstat = scsw->cstat;
+
+		dp->flag = 0;	/* reset status flags */
+		dp->intparm = 0;
+
+	}
+
+	dp->lpum = dp->ii.irb.esw.esw1.lpum;
+
+	/*
+	 * reset device-busy bit if no longer set in irb
+	 */
+	if ((dp->dstat & DEV_STAT_BUSY)
+	    && ((scsw->dstat & DEV_STAT_BUSY) == 0)) 
+		dp->dstat &= ~DEV_STAT_BUSY;
+
+	/*
+	 * Save residual count and CCW information in case primary and
+	 *  secondary status are presented with different interrupts.
+	 */
+	if (scsw->stctl
+	    & (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS)) {
+
+		/*
+		 * If the subchannel status shows status pending
+		 * and we received a check condition, the count
+		 * information is not meaningful.
+		 */
+
+		if (!((scsw->stctl & SCSW_STCTL_STATUS_PEND)
+		      && (scsw->cstat
+			  & (SCHN_STAT_CHN_DATA_CHK
+			     | SCHN_STAT_CHN_CTRL_CHK
+			     | SCHN_STAT_INTF_CTRL_CHK
+			     | SCHN_STAT_PROG_CHECK
+			     | SCHN_STAT_PROT_CHECK
+			     | SCHN_STAT_CHAIN_CHECK)))) {
+
+			dp->rescnt = scsw->count;
+		} else {
+			dp->rescnt = SENSE_MAX_COUNT;
+		}
+
+		dp->cpa = scsw->cpa;
+		
+	}
+	irb_cc = scsw->cc;
+
+	/*
+	 * check for any kind of channel or interface control check but don't
+	 * issue the message for the console device
+	 */
+	if ((scsw->cstat
+	     & (SCHN_STAT_CHN_DATA_CHK
+		| SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) {
+
+		CIO_DEBUG_NOCONS (irq, KERN_WARNING, printk, 0,
+				  "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 (irb_cc != 3) {
+
+			CIO_DEBUG_NOCONS(irq, KERN_WARNING, printk, 0, 
+					 "s390_process_IRQ(%04X) - irb for "
+					 "device %04X after channel check "
+					 "or interface control check:\n",
+					 irq, dp->devno);
+			
+			s390_displayhex (&(dp->ii.irb), 
+					 sizeof (irb_t), 0);
+		}
+		
+	}
+
+	if (scsw->ectl == 0) {
+		issense = 0;
+	} else if ((scsw->stctl == SCSW_STCTL_STATUS_PEND)
+		   && (scsw->eswf == 0)) {
+		issense = 0;
+	} else if ((scsw->stctl ==
+		    (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS))
+		   && ((scsw->actl & SCSW_ACTL_SUSPENDED) == 0)) {
+		issense = 0;
+	} else {
+		issense = dp->ii.irb.esw.esw0.erw.cons;
+
+	}
+
+	if (issense) {
+		dp->scnt = dp->ii.irb.esw.esw0.erw.scnt;
+		dp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+
+		CIO_DEBUG_NOCONS (irq, KERN_DEBUG, DBG, 4,
+				  "s390_process_IRQ( %04X ): "
+				  "concurrent sense bytes avail %d\n",
+				  irq, dp->scnt);
+	}
+
+	switch (irb_cc) {
+	case 1:		/* status pending */
+
+		dp->flag |= DEVSTAT_STATUS_PENDING;
+
+	case 0:		/* normal i/o interruption */
+
+		ending_status = s390_process_IRQ_normal(irq, ending_status);
+
+
+		break;
+
+	case 3:		/* device/path not operational */
+
+		ending_status = s390_process_IRQ_notoper(irq, ending_status); 
+
+		break;
+
+	}
+
+	return (ending_status);
+}
+
+/*
+ * Set the special i/o-interruption subclass 7 for the
+ *  device specified by parameter irq. There can only
+ *  be a single device been operated on this special
+ *  isc. This function is aimed being able to check
+ *  on special device interrupts in disabled state,
+ *  without having to delay I/O processing (by queueing)
+ *  for non-console devices.
+ *
+ * Setting of this isc is done by set_cons_dev(), while
+ *  wait_cons_dev() allows to actively wait on an interrupt
+ *  for this device in disabed state. When the interrupt 
+ *  condition is encountered, wait_cons_dev() calls do_IRQ()
+ *  to have the console device driver processing the
+ *  interrupt.
+ */
+int
+set_cons_dev (int irq)
+{
+	int ccode;
+	int rc = 0;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	if (cons_dev != -1)
+		return -EBUSY;
+
+	sprintf (dbf_txt, "scons%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * modify the indicated console device to operate
+	 *  on special console interrupt subclass 7
+	 */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
+
+	if (ccode) {
+		rc = -ENODEV;
+		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
+	} else {
+		ioinfo[irq]->schib.pmcw.isc = 7;
+
+		ccode = msch (irq, &(ioinfo[irq]->schib));
+
+		if (ccode) {
+			rc = -EIO;
+		} else {
+			cons_dev = irq;
+
+			/*
+			 * enable console I/O-interrupt subclass 7
+			 */
+			ctl_set_bit(6, 24);
+
+		}
+	}
+
+	return (rc);
+}
+
+int
+wait_cons_dev (int irq)
+{
+	int rc = 0;
+	long save_cr6;
+	char dbf_txt[15];
+
+	if (irq != cons_dev)
+		return -EINVAL;
+
+	sprintf (dbf_txt, "wcons%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * before entering the spinlock we may already have
+	 *  processed the interrupt on a different CPU ...
+	 */
+	if (ioinfo[irq]->ui.flags.busy == 1) {
+		long cr6 __attribute__ ((aligned (8)));
+
+		/*
+		 * disable all, but isc 7 (console device)
+		 */
+		__ctl_store (cr6, 6, 6);
+		save_cr6 = cr6;
+		cr6 &= 0x01FFFFFF;
+		__ctl_load (cr6, 6, 6);
+
+		do {
+			tpi_info_t tpi_info = { 0, };
+			if (tpi (&tpi_info) == 1) {
+				s390_process_IRQ (tpi_info.irq);
+			} else {
+				s390irq_spin_unlock (irq);
+				udelay (100);
+				s390irq_spin_lock (irq);
+			}
+			eieio ();
+		} while (ioinfo[irq]->ui.flags.busy == 1);
+
+		/*
+		 * restore previous isc value
+		 */
+		cr6 = save_cr6;
+		__ctl_load (cr6, 6, 6);
+
+	}
+
+	return (rc);
+}
+
+/*
+ * used by {en,dis}able_cpu_sync_isc
+ */
+static inline int
+s390_set_isc5(int irq, int reset)
+{
+	int ccode;
+	int rc = 0;
+	int retry1 = 5;
+	int retry2 = 5;
+	int clear_pend = 0;
+	long cr6 __attribute__ ((aligned (8)));
+
+	do {
+		if (reset)
+			retry2 = 5;
+		else
+			retry2 = 3;
+		do {
+			ccode = msch (irq, &(ioinfo[irq]->schib));
+
+			switch (ccode) {
+			case 0:
+				/*
+				 * disable special interrupt subclass in CPU
+				 */
+				__ctl_store (cr6, 6, 6);
+				if (reset) {
+					/* disable sync isc 5 */
+					cr6 &= 0xFBFFFFFF;
+					/* enable standard isc 3 */
+					cr6 |= 0x10000000;
+					/* enable console isc 7, if neccessary */
+					if (cons_dev != -1)
+						cr6 |= 0x01000000;
+				} else {
+					/* enable sync isc 5 */
+					cr6 |= 0x04000000;
+					/* disable standard isc 3 */
+					cr6 &= 0xEFFFFFFF;
+					/* disable console isc 7, if neccessary */
+					if (cons_dev != -1)
+						cr6 &= 0xFEFFFFFF;
+				}
+				__ctl_load (cr6, 6, 6);
+				
+				retry2 = 0;
+				rc = 0;
+				break;
+				
+			case 1:	/* status pending */
+				ioinfo[irq]->ui.flags.s_pend = 1;
+				s390_process_IRQ (irq);
+				ioinfo[irq]->ui.flags.s_pend = 0;
+
+				retry2--;
+				rc = -EIO;
+				break;
+				
+			case 2:	/* busy */
+				if (reset) {
+					retry2--;
+					udelay (100);	/* give it time */
+				} else {
+					retry2 = 0;
+				}
+				rc = -EBUSY;
+				break;
+				
+			default:	/* not oper */
+				retry2 = 0;
+				rc = -ENODEV;
+				break;
+			}
+			
+		} while (retry2);
+
+
+		if ((rc == 0) || (rc == -ENODEV) || (!reset))
+			retry1 = 0;
+		else
+			retry1--;
+		
+		if (retry1) {
+			/* try stopping it ... */
+			if (!clear_pend) {
+				clear_IO (irq, 0x00004711, 0);
+				clear_pend = 1;
+			
+			}
+		
+		udelay (100);
+
+		}
+
+		
+	} while (retry1 && ccode);
+	
+	return rc;
+}
+
+
+int
+enable_cpu_sync_isc (int irq)
+{
+	int ccode;
+	int rc = 0;
+	char dbf_txt[15];
+
+	sprintf (dbf_txt, "enisc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/* This one spins until it can get the sync_isc lock for irq# irq */
+
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) &&
+	    (!ioinfo[irq]->st)) {
+		if (atomic_read (&sync_isc) != irq)
+			atomic_compare_and_swap_spin (-1, irq, &sync_isc);
+
+		sync_isc_cnt++;
+
+		if (sync_isc_cnt > 255) {	/* fixme : magic number */
+			panic ("Too many recursive calls to enable_sync_isc");
+
+		}
+		/*
+		 * we only run the STSCH/MSCH path for the first enablement
+		 */
+		else if (sync_isc_cnt == 1) {
+			ioinfo[irq]->ui.flags.syncio = 1;
+
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
+
+			if (!ccode) {
+				ioinfo[irq]->schib.pmcw.isc = 5;
+				rc = s390_set_isc5(irq, 0);
+
+			} else {
+				rc = -ENODEV;	/* device is not-operational */
+
+			}
+		}
+
+		if (rc) {	/* can only happen if stsch/msch fails */
+			sync_isc_cnt = 0;
+			atomic_set (&sync_isc, -1);
+		}
+	} else {
+
+		rc = -EINVAL;
+
+	}
+
+	return (rc);
+}
+
+
+int
+disable_cpu_sync_isc (int irq)
+{
+	int rc = 0;
+	int ccode;
+
+	char dbf_txt[15];
+
+	sprintf (dbf_txt, "disisc%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if ((irq <= highest_subchannel) && 
+	    (ioinfo[irq] != INVALID_STORAGE_AREA) && 
+	    (!ioinfo[irq]->st)) {
+		/*
+		 * We disable if we're the top user only, as we may
+		 *  run recursively ... 
+		 * We must not decrease the count immediately; during
+		 *  msch() processing we may face another pending
+		 *  status we have to process recursively (sync).
+		 */
+
+		if (sync_isc_cnt == 1) {
+			ccode = stsch (irq, &(ioinfo[irq]->schib));
+
+			if (!ccode) {
+
+				ioinfo[irq]->schib.pmcw.isc = 3;
+				rc = s390_set_isc5(irq, 1);
+			} else {
+				rc = -ENODEV;
+			}
+				
+			ioinfo[irq]->ui.flags.syncio = 0;
+
+			sync_isc_cnt = 0;
+			atomic_set (&sync_isc, -1);
+
+		} else {
+			sync_isc_cnt--;
+
+		}
+	} else {
+
+		rc = -EINVAL;
+
+	}
+
+	return (rc);
+}
+
+EXPORT_SYMBOL (halt_IO);
+EXPORT_SYMBOL (clear_IO);
+EXPORT_SYMBOL (do_IO);
+EXPORT_SYMBOL (resume_IO);
diff -Nru a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/cio.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,18 @@
+#ifndef S390_CIO_H
+#define S390_CIO_H
+
+extern int
+s390_start_IO (int irq,         /* IRQ */
+               ccw1_t * cpa,    /* logical channel prog addr */
+               unsigned long user_intparm,      /* interruption parameter */
+               __u8 lpm,        /* logical path mask */
+               unsigned long flag);
+
+extern int cancel_IO (int irq);
+
+extern int enable_cpu_sync_isc (int irq);
+extern int disable_cpu_sync_isc (int irq);
+extern int cons_dev;
+extern int s390_process_IRQ (unsigned int irq);
+
+#endif
diff -Nru a/drivers/s390/cio/cio_debug.c b/drivers/s390/cio/cio_debug.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/cio_debug.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,72 @@
+/*
+ *  drivers/s390/cio/cio_debug.c
+ *   S/390 common I/O routines -- message ids for debugging
+ *   $Revision: 1.4 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ */
+
+
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/debug.h>
+
+#include "cio_debug.h"
+
+debug_info_t *cio_debug_msg_id;
+debug_info_t *cio_debug_trace_id;
+debug_info_t *cio_debug_crw_id;
+int cio_debug_initialized;
+
+/*
+ * 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
+ */
+static int __init
+cio_debug_init (void)
+{
+	int ret = 0;
+
+	cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16 * sizeof (long));
+	if (cio_debug_msg_id != NULL) {
+		debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
+		debug_set_level (cio_debug_msg_id, 6);
+	} 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);
+		debug_set_level (cio_debug_trace_id, 6);
+	} 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);
+		debug_set_level (cio_debug_crw_id, 6);
+	} else {
+		ret = -1;
+	}
+	if (ret){
+		printk ("could not initialize debugging\n");
+	} else {
+		printk ("debugging initialized\n");
+		cio_debug_initialized = 1;
+	}
+	return ret;
+}
+
+__initcall (cio_debug_init);
diff -Nru a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/cio_debug.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,70 @@
+#ifndef S390_DEBUG_H
+#define S390_DEBUG_H
+
+#define SANITY_CHECK(irq) do { \
+if (irq > highest_subchannel || irq < 0) \
+		return (-ENODEV); \
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
+		return (-ENODEV); \
+        if (ioinfo[irq]->st) \
+                return -ENODEV; \
+	} while(0)
+
+#define CIO_TRACE_EVENT(imp, txt) do { \
+	if (cio_debug_initialized) \
+		debug_text_event(cio_debug_trace_id, \
+				 imp, \
+				 txt); \
+        }while (0)
+
+#define CIO_MSG_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_msg_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
+
+#define CIO_CRW_EVENT(imp, args...) do { \
+        if (cio_debug_initialized) \
+                debug_sprintf_event(cio_debug_crw_id, \
+                                    imp, \
+                                    ##args); \
+        } while (0)
+
+#undef  CONFIG_DEBUG_IO
+#define CONFIG_DEBUG_CRW
+#define CONFIG_DEBUG_CHSC
+
+#ifdef CONFIG_DEBUG_IO
+#define DBG printk
+#else /* CONFIG_DEBUG_IO */
+#define DBG(args,...)  do {} while (0) 
+#endif /* CONFIG_DEBUG_IO */
+
+#define CIO_DEBUG(printk_level,event_level,msg...) ({\
+	DBG(printk_level msg); \
+	CIO_MSG_EVENT (event_level, msg); \
+})
+
+#define CIO_DEBUG_IFMSG(printk_level,event_level,msg...) ({\
+	if (cio_show_msg) printk(printk_level msg); \
+	CIO_MSG_EVENT (event_level, msg); \
+})
+
+#define CIO_DEBUG_ALWAYS(printk_level,event_level,msg...) ({\
+	printk(printk_level msg); \
+	CIO_MSG_EVENT (event_level, msg); \
+})
+
+#define CIO_DEBUG_NOCONS(irq,printk_level,func,event_level,msg...) ({\
+	if (irq != cons_dev) func(printk_level msg); \
+	CIO_MSG_EVENT (event_level, msg); \
+})
+
+/* for use of debug feature */
+extern debug_info_t *cio_debug_msg_id;
+extern debug_info_t *cio_debug_trace_id;
+extern debug_info_t *cio_debug_crw_id;
+extern int cio_debug_initialized;
+
+#endif
diff -Nru a/drivers/s390/cio/ioinfo.c b/drivers/s390/cio/ioinfo.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/ioinfo.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,292 @@
+/*
+ *  drivers/s390/cio/ioinfo.c
+ *   S/390 common I/O routines -- the ioinfo structure
+ *   $Revision: 1.3 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+
+#include <asm/irq.h>
+#include <asm/debug.h>
+
+#include "ioinfo.h"
+
+unsigned int highest_subchannel;
+
+ioinfo_t *ioinfo_head;
+ioinfo_t *ioinfo_tail;
+ioinfo_t *ioinfo[__MAX_SUBCHANNELS]
+#if 1
+= { [0 ... (__MAX_SUBCHANNELS - 1)] = INVALID_STORAGE_AREA} /*FIXME: define this to 0 */
+#endif
+;
+
+static inline int
+get_next_available_irq (ioinfo_t * pi)
+{
+	int ret_val = -ENODEV;
+
+	while (pi != NULL) {
+		if ((!pi->st) && (pi->ui.flags.oper)) {
+			ret_val = pi->irq;
+			break;
+		} else {
+			pi = pi->next;
+		}
+	}
+
+	return ret_val;
+}
+
+int
+get_irq_first (void)
+{
+	int ret_irq;
+
+	if (ioinfo_head) {
+		if ((ioinfo_head->ui.flags.oper) && 
+		    (!ioinfo_head->st)) {
+			ret_irq = ioinfo_head->irq;
+		} else if (ioinfo_head->next) {
+			ret_irq = get_next_available_irq (ioinfo_head->next);
+
+		} else {
+			ret_irq = -ENODEV;
+
+		}
+	} else {
+		ret_irq = -ENODEV;
+
+	}
+
+	return ret_irq;
+}
+
+int
+get_irq_next (int irq)
+{
+	int ret_irq;
+
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		if (ioinfo[irq]->next) {
+			if ((ioinfo[irq]->next->ui.flags.oper) &&
+			    (!ioinfo[irq]->next->st)) {
+				ret_irq = ioinfo[irq]->next->irq;
+			} else {
+				ret_irq =
+				    get_next_available_irq (ioinfo[irq]->next);
+
+			}
+		} else {
+			ret_irq = -ENODEV;
+
+		}
+	} else {
+		ret_irq = -EINVAL;
+
+	}
+
+	return ret_irq;
+}
+
+int
+get_dev_info_by_irq (int irq, s390_dev_info_t * pdi)
+{
+	if (irq > highest_subchannel || irq < 0) \
+		return (-ENODEV); \
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
+		return (-ENODEV); \
+        if (ioinfo[irq]->st) \
+                return -ENODEV; \
+
+	if (pdi == NULL)
+		return -EINVAL;
+
+	pdi->devno = ioinfo[irq]->schib.pmcw.dev;
+	pdi->irq = irq;
+
+	if (ioinfo[irq]->ui.flags.oper && !ioinfo[irq]->ui.flags.unknown) {
+		pdi->status = 0;
+		memcpy (&(pdi->sid_data),
+			&ioinfo[irq]->senseid, sizeof (senseid_t));
+	} else if (ioinfo[irq]->ui.flags.unknown) {
+		pdi->status = DEVSTAT_UNKNOWN_DEV;
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
+		pdi->sid_data.cu_type = 0xFFFF;
+
+	} else {
+		pdi->status = DEVSTAT_NOT_OPER;
+		memset (&(pdi->sid_data), '\0', sizeof (senseid_t));
+		pdi->sid_data.cu_type = 0xFFFF;
+
+	}
+
+	if (ioinfo[irq]->ui.flags.ready)
+		pdi->status |= DEVSTAT_DEVICE_OWNED;
+
+	return 0;
+}
+
+int
+get_dev_info_by_devno (__u16 devno, s390_dev_info_t * pdi)
+{
+	int i;
+	int rc = -ENODEV;
+
+	if (devno > 0x0000ffff)
+		return -ENODEV;
+	if (pdi == NULL)
+		return -EINVAL;
+
+	for (i = 0; i <= highest_subchannel; i++) {
+
+		if ((ioinfo[i] != INVALID_STORAGE_AREA) &&
+		    (!ioinfo[i]->st) &&
+		    (ioinfo[i]->schib.pmcw.dev == devno)) {
+
+			pdi->irq = i;
+			pdi->devno = devno;
+
+			if (ioinfo[i]->ui.flags.oper
+			    && !ioinfo[i]->ui.flags.unknown) {
+				pdi->status = 0;
+				memcpy (&(pdi->sid_data),
+					&ioinfo[i]->senseid,
+					sizeof (senseid_t));
+			} else if (ioinfo[i]->ui.flags.unknown) {
+				pdi->status = DEVSTAT_UNKNOWN_DEV;
+
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
+
+				pdi->sid_data.cu_type = 0xFFFF;
+			} else {
+				pdi->status = DEVSTAT_NOT_OPER;
+
+				memset (&(pdi->sid_data),
+					'\0', sizeof (senseid_t));
+
+				pdi->sid_data.cu_type = 0xFFFF;
+
+			}
+
+			if (ioinfo[i]->ui.flags.ready)
+				pdi->status |= DEVSTAT_DEVICE_OWNED;
+
+			rc = 0;	/* found */
+			break;
+
+		}
+	}
+
+	return (rc);
+
+}
+
+int
+get_irq_by_devno (__u16 devno)
+{
+	int i;
+	int rc = -1;
+
+	if (devno <= 0x0000ffff) {
+		for (i = 0; i <= highest_subchannel; i++) {
+			if ((ioinfo[i] != INVALID_STORAGE_AREA)
+			    && (!ioinfo[i]->st)
+			    && (ioinfo[i]->schib.pmcw.dev == devno)
+			    && (ioinfo[i]->schib.pmcw.dnv == 1)) {
+				rc = i;
+				break;
+			}
+		}
+	}
+
+	return (rc);
+}
+
+unsigned int
+get_devno_by_irq (int irq)
+{
+	if ((irq > highest_subchannel)
+	    || (irq < 0)
+	    || (ioinfo[irq] == INVALID_STORAGE_AREA)) {
+		return -1;
+
+	}
+
+	if (ioinfo[irq]->st) 
+		return -1;
+
+	/*
+	 * we don't need to check for the device be operational
+	 *  as the initial STSCH will always present the device
+	 *  number defined by the IOCDS regardless of the device
+	 *  existing or not. However, there could be subchannels
+	 *  defined who's device number isn't valid ...
+	 */
+	if (ioinfo[irq]->schib.pmcw.dnv)
+		return (ioinfo[irq]->schib.pmcw.dev);
+	else
+		return -1;
+}
+
+schib_t *
+s390_get_schib (int irq)
+{
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return NULL;
+	if (ioinfo[irq]->st)
+		return NULL;
+	return &ioinfo[irq]->schib;
+}
+
+/* these are used only by the tape driver to store per subchannel 
+ * private data */
+int
+s390_set_private_data(int irq, void *data)
+{
+	if (irq > highest_subchannel || irq < 0)
+		return (-ENODEV);
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return (-ENODEV);
+        if (ioinfo[irq]->st)
+                return -ENODEV;
+	ioinfo[irq]->private_data = data;
+	return 0;
+}
+
+void *
+s390_get_private_data(int irq)
+{
+	if ((irq > highest_subchannel) || (irq < 0))
+		return NULL;
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return NULL;
+	if (ioinfo[irq]->st)
+		return NULL;
+	return ioinfo[irq]->private_data;
+}
+
+
+EXPORT_SYMBOL (ioinfo);
+EXPORT_SYMBOL (get_dev_info_by_irq);
+EXPORT_SYMBOL (get_dev_info_by_devno);
+EXPORT_SYMBOL (get_irq_by_devno);
+EXPORT_SYMBOL (get_devno_by_irq);
+EXPORT_SYMBOL (get_irq_first);
+EXPORT_SYMBOL (get_irq_next);
+EXPORT_SYMBOL (s390_get_schib);
+EXPORT_SYMBOL (s390_set_private_data);
+EXPORT_SYMBOL (s390_get_private_data);
diff -Nru a/drivers/s390/cio/ioinfo.h b/drivers/s390/cio/ioinfo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/ioinfo.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,10 @@
+#ifndef S390_IOINFO_H
+#define S390_IOINFO_H
+
+extern unsigned int highest_subchannel;
+
+extern ioinfo_t *ioinfo_head;
+extern ioinfo_t *ioinfo_tail;
+extern ioinfo_t *ioinfo[__MAX_SUBCHANNELS];
+
+#endif
diff -Nru a/drivers/s390/cio/misc.c b/drivers/s390/cio/misc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/misc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,237 @@
+/*
+ *  drivers/s390/s390io.c
+ *   S/390 common I/O routines
+ *   $Revision: 1.4 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ *               05/03/2002 Cornelia Huck  debug cleanup
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+#include <asm/delay.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include <asm/s390io.h>
+#include <asm/s390dyn.h>
+#include <asm/s390mach.h>
+#include <asm/debug.h>
+
+#include "s390io.h"
+#include "cio_debug.h"
+#include "ioinfo.h"
+#include "proc.h"
+#include "chsc.h"
+
+#ifdef CONFIG_DEBUG_CRW
+#define DBGW printk
+#else
+#define DBGW(args,...) do {} while (0)
+#endif
+
+#define CRW_DEBUG(printk_level,event_level,msg...) ({\
+	DBGW(printk_level msg); \
+	CIO_CRW_EVENT (event_level, msg); \
+})
+
+static void
+s390_process_subchannel_source (int irq)
+{
+	int dev_oper = 0;
+	int dev_no = -1;
+	int lock = 0;
+	int is_owned = 0;
+
+	/*
+	 * If the device isn't known yet
+	 *   we can't lock it ...
+	 */
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		s390irq_spin_lock (irq);
+		lock = 1;
+
+		if (!ioinfo[irq]->st) {
+			dev_oper = ioinfo[irq]->ui.flags.oper;
+			
+			if (ioinfo[irq]->ui.flags.dval)
+				dev_no = ioinfo[irq]->devno;
+			
+			is_owned = ioinfo[irq]->ui.flags.ready;
+		}
+
+	}
+	CRW_DEBUG(KERN_DEBUG, 4, 
+		  "subchannel validation - start\n");
+	s390_validate_subchannel (irq, is_owned);
+
+	if (irq > highest_subchannel)
+		highest_subchannel = irq;
+
+	CRW_DEBUG(KERN_DEBUG, 4, 
+		  "subchannel validation - done\n");
+	/*
+	 * After the validate processing
+	 *   the ioinfo control block
+	 *   should be allocated ...
+	 */
+	if (lock) {
+		s390irq_spin_unlock (irq);
+	}
+
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+
+#ifdef CONFIG_ARCH_S390X
+		CRW_DEBUG(KERN_DEBUG, 4, 
+			  "ioinfo at %08lX\n", 
+			  (unsigned long)ioinfo[irq]);
+#else				/* CONFIG_ARCH_S390X */
+		CRW_DEBUG(KERN_DEBUG, 4, 
+			  "ioinfo at %08X\n", 
+			  (unsigned)ioinfo[irq]);
+#endif				/* CONFIG_ARCH_S390X */
+
+		if (ioinfo[irq]->st)
+			return;
+
+		if (ioinfo[irq]->ui.flags.oper == 0) {
+			not_oper_handler_func_t nopfunc = ioinfo[irq]->nopfunc;
+
+			/*
+			 * If the device has gone
+			 *  call not oper handler               
+			 */
+			if ((dev_oper == 1)
+			    && (nopfunc != NULL)) {
+
+				free_irq (irq, ioinfo[irq]->irq_desc.dev_id);
+				nopfunc (irq, DEVSTAT_DEVICE_GONE);
+
+			}
+		} else {
+			CRW_DEBUG(KERN_DEBUG, 4,
+				  "device recognition - start\n");
+	
+			s390_device_recognition_irq (irq);
+
+			CRW_DEBUG(KERN_DEBUG, 4,
+				  "device recognition - done\n");
+			/*
+			 * the device became operational
+			 */
+			if (dev_oper == 0) {
+				devreg_t *pdevreg;
+
+				pdevreg = s390_search_devreg (ioinfo[irq]);
+
+				if (pdevreg != NULL) {
+					if (pdevreg->oper_func != NULL)
+						pdevreg->
+						    oper_func (irq, pdevreg);
+
+				}
+
+			}
+			/*
+			 * ... it is and was operational, but
+			 *      the devno may have changed
+			 */
+			else if ((ioinfo[irq]->devno != dev_no)
+				 && (ioinfo[irq]->nopfunc != NULL)) {
+
+				ioinfo[irq]->nopfunc (irq, DEVSTAT_REVALIDATE);
+
+			}
+		}
+	}
+}
+
+/*
+ * s390_do_crw_pending
+ *
+ * Called by the machine check handler to process CRW pending
+ *  conditions. It may be a single CRW, or CRWs may be chained.
+ *
+ * Note : we currently process CRWs for subchannel source only
+ */
+void
+s390_do_crw_pending (crwe_t * pcrwe)
+{
+	int irq;
+	int chpid;
+	
+	CRW_DEBUG(KERN_DEBUG, 2, 
+		  "do_crw_pending: starting\n");
+
+	while (pcrwe != NULL) {
+
+		switch (pcrwe->crw.rsc) {
+		case CRW_RSC_SCH:
+			
+			irq = pcrwe->crw.rsid;
+			
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "source is subchannel %04X\n",
+				  irq);
+
+			s390_process_subchannel_source (irq);
+
+			break;
+
+		case CRW_RSC_MONITOR:
+
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "source is monitoring facility\n");
+			break;
+
+		case CRW_RSC_CPATH:
+
+			chpid = pcrwe->crw.rsid;
+
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "source is channel path %02X\n",
+				  chpid);
+			break;
+
+		case CRW_RSC_CONFIG:
+
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "source is configuration-alert facility\n");
+			break;
+
+		case CRW_RSC_CSS:
+
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "source is channel subsystem\n");
+#ifdef CONFIG_CHSC
+			s390_process_css();
+#endif
+			break;
+
+		default:
+
+			CRW_DEBUG(KERN_NOTICE, 2, 
+				  "unknown source\n");
+			break;
+
+		}
+
+		pcrwe = pcrwe->crwe_next;
+
+	}
+
+	CRW_DEBUG(KERN_DEBUG, 2, 
+		  "do_crw_pending: done\n");
+	return;
+}
+
+
diff -Nru a/drivers/s390/cio/misc.h b/drivers/s390/cio/misc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/misc.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,4 @@
+#ifndef S390_MISC_H
+#define S390_MISC_H
+
+#endif
diff -Nru a/drivers/s390/cio/proc.c b/drivers/s390/cio/proc.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/proc.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,269 @@
+/*
+ *  drivers/s390/cio/proc.c
+ *   S/390 common I/O routines -- proc file system entries
+ *   $Revision: 1.4 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ *               05/03/2002 Cornelia Huck  removed /proc/deviceinfo/
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/s390io.h>
+#include <asm/debug.h>
+
+#include "ioinfo.h"
+#include "s390io.h"
+#include "cio_debug.h"
+
+static int chan_proc_init (void);
+
+/* 
+ * Display info on subchannels in /proc/subchannels. 
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
+ */
+
+typedef struct {
+	char *data;
+	int len;
+} tempinfo_t;
+
+static struct proc_dir_entry *chan_subch_entry;
+
+static int
+chan_subch_open (struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	int i = 0;
+	int j = 0;
+	tempinfo_t *info;
+
+	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
+	if (info == NULL) {
+		printk (KERN_WARNING "No memory available for data\n");
+		return -ENOMEM;
+	} else {
+		file->private_data = (void *) info;
+	}
+
+	size += (highest_subchannel + 1) * 128;
+	info->data = (char *) vmalloc (size);
+
+	if (size && info->data == NULL) {
+		printk (KERN_WARNING "No memory available for data\n");
+		vfree (info);
+		return -ENOMEM;
+	}
+
+	len += sprintf (info->data + len,
+			"Device sch.  Dev Type/Model CU  in use  PIM PAM POM CHPIDs\n");
+	len += sprintf (info->data + len,
+			"---------------------------------------------------------------------\n");
+
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (!((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA)
+		      || (ioinfo[i]->st )|| !(ioinfo[i]->ui.flags.oper))) {
+			len +=
+			    sprintf (info->data + len, "%04X   %04X  ",
+				     ioinfo[i]->schib.pmcw.dev, i);
+			if (ioinfo[i]->senseid.dev_type != 0) {
+				len += sprintf (info->data + len,
+						"%04X/%02X   %04X/%02X",
+						ioinfo[i]->senseid.dev_type,
+						ioinfo[i]->senseid.dev_model,
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			} else {
+				len += sprintf (info->data + len,
+						"          %04X/%02X",
+						ioinfo[i]->senseid.cu_type,
+						ioinfo[i]->senseid.cu_model);
+			}
+			if (ioinfo[i]->ui.flags.ready) {
+				len += sprintf (info->data + len, "  yes ");
+			} else {
+				len += sprintf (info->data + len, "      ");
+			}
+			len += sprintf (info->data + len,
+					"    %02X  %02X  %02X  ",
+					ioinfo[i]->schib.pmcw.pim,
+					ioinfo[i]->schib.pmcw.pam,
+					ioinfo[i]->schib.pmcw.pom);
+			for (j = 0; j < 8; j++) {
+				len += sprintf (info->data + len,
+						"%02X",
+						ioinfo[i]->schib.pmcw.chpid[j]);
+				if (j == 3) {
+					len += sprintf (info->data + len, " ");
+				}
+			}
+			len += sprintf (info->data + len, "\n");
+		}
+	}
+	info->len = len;
+
+	return rc;
+}
+
+static int
+chan_subch_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
+chan_subch_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 ((size_t) user_len, 
+			   (size_t) (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
+
+static struct file_operations chan_subch_file_ops = {
+	read:chan_subch_read, open:chan_subch_open, release:chan_subch_close,
+};
+
+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);
+
+/*
+ * Entry /proc/irq_count
+ * display how many irqs have occured per cpu...
+ */
+
+static struct proc_dir_entry *cio_irq_proc_entry;
+
+static int
+cio_irq_proc_open (struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	int size = 1;
+	int len = 0;
+	tempinfo_t *info;
+	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 += NR_CPUS * 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 {
+			for (i = 0; i < NR_CPUS; i++) {
+				if (s390_irq_count[i] != 0)
+					len +=
+					    sprintf (info->data + len, "%lx\n",
+						     s390_irq_count[i]);
+			}
+			info->len = len;
+		}
+	}
+	return rc;
+}
+
+static int
+cio_irq_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_irq_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 ((size_t) user_len, 
+			   (size_t) (p_info->len - *offset));
+		if (copy_to_user (user_buf, &(p_info->data[*offset]), len))
+			return -EFAULT;
+		(*offset) += len;
+		return len;
+	}
+}
+
+static struct file_operations cio_irq_proc_file_ops = {
+	read:cio_irq_proc_read, open:cio_irq_proc_open,
+	release:cio_irq_proc_close,
+};
+
+static int
+cio_irq_proc_init (void)
+{
+	int i;
+
+	if (cio_count_irqs) {
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
+		cio_irq_proc_entry =
+		    create_proc_entry ("irq_count", S_IFREG | S_IRUGO,
+				       &proc_root);
+		cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
+	}
+
+	return 1;
+}
+
+__initcall (cio_irq_proc_init);
diff -Nru a/drivers/s390/cio/proc.h b/drivers/s390/cio/proc.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/proc.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,19 @@
+#ifndef S390_PROC_H
+#define S390_PROC_H
+
+extern int cio_procfs_device_purge (void);
+extern int cio_procfs_device_create (int devno);
+extern int cio_procfs_device_remove (int devno);
+
+//FIXME: shouldn`t this be 'struct{unsigned int len; char data[0]};' ?
+/*
+ * Display info on subchannels in /proc/subchannels.
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.
+ */
+typedef struct {
+        char *data;
+        int len;
+} tempinfo_t;
+
+
+#endif
diff -Nru a/drivers/s390/cio/requestirq.c b/drivers/s390/cio/requestirq.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/requestirq.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,434 @@
+/*
+ *  drivers/s390/cio/requestirq.c
+ *   S/390 common I/O routines -- 
+ *   $Revision: 1.7 $
+ *
+ *    Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
+ *                            IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *		 Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 11/04/2002 Arnd Bergmann Split s390io.c into multiple files,
+ *					  see s390io.c for complete list of
+ * 					  changes.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <asm/irq.h>
+
+#include <asm/delay.h>
+#include <asm/debug.h>
+#include <asm/cpcmd.h>
+
+#include "cio.h"
+#include "cio_debug.h"
+#include "ioinfo.h"
+#include "s390io.h"
+
+static int enable_subchannel (unsigned int irq);
+static int disable_subchannel (unsigned int irq);
+
+/*
+ * Note : internal use of irqflags SA_PROBE for NOT path grouping 
+ *
+ */
+int
+s390_request_irq_special (int irq,
+			  io_handler_func_t io_handler,
+			  not_oper_handler_func_t not_oper_handler,
+			  unsigned long irqflags,
+			  const char *devname, void *dev_id)
+{
+	int retval = 0;
+	unsigned long flags;
+	char dbf_txt[15];
+	int retry;
+
+	if (irq >= __MAX_SUBCHANNELS)
+		return -EINVAL;
+
+	if (!io_handler || !dev_id)
+		return -EINVAL;
+
+	if (ioinfo[irq] == INVALID_STORAGE_AREA)
+		return -ENODEV;
+	
+	if (ioinfo[irq]->st)
+		return -ENODEV;
+
+	sprintf (dbf_txt, "reqsp%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * The following block of code has to be executed atomically
+	 */
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		retry = 5;
+
+		ioinfo[irq]->irq_desc.handler = io_handler;
+		ioinfo[irq]->irq_desc.name = devname;
+		ioinfo[irq]->irq_desc.dev_id = dev_id;
+		ioinfo[irq]->ui.flags.ready = 1;
+
+		do {
+			retval = enable_subchannel (irq);
+			if (retval) {
+				ioinfo[irq]->ui.flags.ready = 0;
+				break;
+			}
+
+			stsch (irq, &ioinfo[irq]->schib);
+			if (ioinfo[irq]->schib.pmcw.ena)
+				retry = 0;
+			else
+				retry--;
+
+		} while (retry);
+	} else {
+		/*
+		 *  interrupt already owned, and shared interrupts
+		 *   aren't supported on S/390.
+		 */
+		retval = -EBUSY;
+
+	}
+
+	s390irq_spin_unlock_irqrestore (irq, flags);
+
+	if (retval == 0) {
+		if (!(irqflags & SA_PROBE)) 
+			s390_DevicePathVerification (irq, 0);
+
+		ioinfo[irq]->nopfunc = not_oper_handler;
+	}
+
+	if (cio_debug_initialized)
+		debug_int_event (cio_debug_trace_id, 4, retval);
+
+	return retval;
+}
+
+int
+s390_request_irq (unsigned int irq,
+		  void (*handler) (int, void *, struct pt_regs *),
+		  unsigned long irqflags, const char *devname, void *dev_id)
+{
+
+	return s390_request_irq_special (irq,
+					 (io_handler_func_t) handler,
+					 NULL, irqflags, devname, dev_id);
+}
+
+void
+s390_free_irq (unsigned int irq, void *dev_id)
+{
+	unsigned long flags;
+	int ret;
+
+	char dbf_txt[15];
+
+	if (irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA)
+		return;
+
+	if (ioinfo[irq]->st)
+		return;
+
+	sprintf (dbf_txt, "free%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	CIO_DEBUG_NOCONS(irq,KERN_DEBUG, printk, 2, 
+			 "Trying to free IRQ %d\n", 
+			 irq);
+
+	/*
+	 * disable the device and reset all IRQ info if
+	 *  the IRQ is actually owned by the handler ...
+	 */
+	if (ioinfo[irq]->ui.flags.ready) {
+		if (dev_id == ioinfo[irq]->irq_desc.dev_id) {
+			/* start deregister */
+			ioinfo[irq]->ui.flags.unready = 1;
+
+			ret = disable_subchannel (irq);
+
+			if (ret == -EBUSY) {
+
+				/*
+				 * kill it !
+				 * We try to terminate the I/O by halt_IO first,
+				 * then clear_IO.
+				 * Because the device may be gone (machine 
+				 * check handling), we can't use sync I/O.
+				 */
+
+				halt_IO (irq, 0xC8C1D3E3, 0);
+				s390irq_spin_unlock_irqrestore (irq, flags);
+				udelay (200000);	/* 200 ms */
+				s390irq_spin_lock_irqsave (irq, flags);
+
+				ret = disable_subchannel (irq);
+
+				if (ret == -EBUSY) {
+
+					clear_IO (irq, 0x40C3D3D9, 0);
+					s390irq_spin_unlock_irqrestore (irq,
+									flags);
+					udelay (1000000);	/* 1000 ms */
+					s390irq_spin_lock_irqsave (irq, flags);
+
+					/* give it a very last try ... */
+					disable_subchannel (irq);
+
+					if (ioinfo[irq]->ui.flags.busy) {
+						CIO_DEBUG_ALWAYS(KERN_CRIT, 0,
+								 "free_irq(%04X) - "
+								 "device %04X busy, "
+								 "retry count exceeded\n",
+								 irq,
+								 ioinfo[irq]->
+								 devstat.devno);
+						
+					}
+				}
+			}
+
+			ioinfo[irq]->ui.flags.ready = 0;
+			ioinfo[irq]->ui.flags.unready = 0;	/* deregister ended */
+
+			ioinfo[irq]->nopfunc = NULL;
+
+			s390irq_spin_unlock_irqrestore (irq, flags);
+		} else {
+			s390irq_spin_unlock_irqrestore (irq, flags);
+
+			CIO_DEBUG_ALWAYS(KERN_ERR, 0,
+					 "free_irq(%04X) : error, "
+					 "dev_id does not match !\n",
+					 irq);
+
+		}
+	} else {
+		s390irq_spin_unlock_irqrestore (irq, flags);
+
+		CIO_DEBUG_ALWAYS(KERN_ERR, 0,
+				 "free_irq(%04X) : error, "
+				 "no action block ... !\n", 
+				 irq);
+
+	}
+}
+
+/*
+ * Enable IRQ by modifying the subchannel
+ */
+static int
+enable_subchannel (unsigned int irq)
+{
+	int ret = 0;
+	int ccode;
+	int retry = 5;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "ensch%x", irq);
+	CIO_TRACE_EVENT (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.
+	 */
+	if (ioinfo[irq]->ui.flags.d_disable) {
+		ioinfo[irq]->ui.flags.d_disable = 0;
+		ret = 0;
+	} else {
+		ccode = stsch (irq, &(ioinfo[irq]->schib));
+
+		if (ccode) {
+			ret = -ENODEV;
+		} else {
+			ioinfo[irq]->schib.pmcw.ena = 1;
+
+			if (irq == cons_dev) {
+				ioinfo[irq]->schib.pmcw.isc = 7;
+			} else {
+				ioinfo[irq]->schib.pmcw.isc = 3;
+
+			}
+
+			do {
+				ccode = msch (irq, &(ioinfo[irq]->schib));
+
+				switch (ccode) {
+				case 0:	/* ok */
+					ret = 0;
+					retry = 0;
+					break;
+
+				case 1:	/* status pending */
+
+					ioinfo[irq]->ui.flags.s_pend = 1;
+					s390_process_IRQ (irq);
+					ioinfo[irq]->ui.flags.s_pend = 0;
+
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch()       
+					 */
+					retry--;
+					break;
+
+				case 2:	/* busy */
+					udelay (100);	/* allow for recovery */
+					ret = -EBUSY;
+					retry--;
+					break;
+
+				case 3:	/* not oper */
+					ioinfo[irq]->ui.flags.oper = 0;
+					retry = 0;
+					ret = -ENODEV;
+					break;
+				}
+
+			} while (retry);
+
+		}
+	}
+
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	return (ret);
+}
+
+/*
+ * Disable IRQ by modifying the subchannel
+ */
+static int
+disable_subchannel (unsigned int irq)
+{
+	int cc;			/* condition code */
+	int ret = 0;		/* function return value */
+	int retry = 5;
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	sprintf (dbf_txt, "dissch%x", irq);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	if (ioinfo[irq]->ui.flags.busy) {
+		/*
+		 * the disable function must not be called while there are
+		 *  requests pending for completion !
+		 */
+		ret = -EBUSY;
+	} else {
+
+		/*
+		 * If device isn't operational we have to perform delayed
+		 *  disabling when the next interrupt occurs - unless the
+		 *  irq is re-requested prior to the interrupt to occur.
+		 */
+		cc = stsch (irq, &(ioinfo[irq]->schib));
+
+		if (cc == 3) {
+			ioinfo[irq]->ui.flags.oper = 0;
+			ioinfo[irq]->ui.flags.d_disable = 1;
+
+			ret = 0;
+		} else {	/* cc == 0 */
+
+			ioinfo[irq]->schib.pmcw.ena = 0;
+
+			do {
+				cc = msch (irq, &(ioinfo[irq]->schib));
+
+				switch (cc) {
+				case 0:	/* ok */
+					retry = 0;
+					ret = 0;
+					break;
+
+				case 1:	/* status pending */
+					ioinfo[irq]->ui.flags.s_pend = 1;
+					s390_process_IRQ (irq);
+					ioinfo[irq]->ui.flags.s_pend = 0;
+
+					ret = -EIO;
+					/* 
+					 * might be overwritten on re-driving 
+					 * the msch() call       
+					 */
+					retry--;
+					break;
+
+				case 2:	/* busy; this should not happen! */
+					CIO_DEBUG_ALWAYS(KERN_CRIT, 0,
+							 "disable_subchannel"
+							 "(%04X) - unexpected "
+							 "busy condition for "
+							 "device %04X received!\n",
+							 irq,
+							 ioinfo[irq]->devstat.
+							 devno);
+					retry = 0;
+					ret = -EBUSY;
+					break;
+
+				case 3:	/* not oper */
+					/*
+					 * should hardly occur ?!
+					 */
+					ioinfo[irq]->ui.flags.oper = 0;
+					ioinfo[irq]->ui.flags.d_disable = 1;
+					retry = 0;
+
+					ret = 0;
+					/* 
+					 * if the device has gone, we don't need 
+					 * to disable it anymore !          
+					 */
+					break;
+
+				}
+
+			} while (retry);
+
+		}
+	}
+
+	sprintf (dbf_txt, "ret:%d", ret);
+	CIO_TRACE_EVENT (2, dbf_txt);
+
+	return (ret);
+}
+
+/* FIXME: there must be a cleaner way to express what happens */
+extern void do_reipl (int);
+void
+reipl (int sch)
+{
+	int i;
+	s390_dev_info_t dev_info;
+
+	for (i = 0; i <= highest_subchannel; i++) {
+		if (get_dev_info_by_irq (i, &dev_info) == 0
+		    && (dev_info.status & DEVSTAT_DEVICE_OWNED)) {
+			free_irq (i, ioinfo[i]->irq_desc.dev_id);
+		}
+	}
+	if (MACHINE_IS_VM)
+		cpcmd ("IPL", NULL, 0);
+	else
+		do_reipl (0x10000 | sch);
+}
+
+EXPORT_SYMBOL (s390_request_irq_special);
diff -Nru a/drivers/s390/cio/s390io.c b/drivers/s390/cio/s390io.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/s390io.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,2437 @@
+/*
+ *  drivers/s390/cio/s390io.c
+ *   S/390 common I/O routines
+ *   $Revision: 1.11 $
+ *
+ *  S390 version
+ *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
+ *                             IBM Corporation
+ *    Author(s): Ingo Adlung (adlung@de.ibm.com)
+ *               Cornelia Huck (cohuck@de.ibm.com) 
+ *               Arnd Bergmann (arndb@de.ibm.com)
+ *    ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ *               01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
+ *                          Fixed lost interrupts and do_adapter_IO
+ *               xx/xx/xxxx nnn          multiple changes not reflected
+ *               03/12/2001 Ingo Adlung  blacklist= - changed to cio_ignore=  
+ *               03/14/2001 Ingo Adlung  disable interrupts before start_IO
+ *                                        in Path Group processing 
+ *                                       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
+ *               xx/xx/xxxx some bugfixes & cleanups
+ *               08/02/2001 Cornelia Huck not already known devices can be blacklisted
+ *                                        by piping to /proc/cio_ignore
+ *               09/xx/2001 couple more fixes
+ *               10/15/2001 Cornelia Huck xsch - internal only for now
+ *               10/29/2001 Cornelia Huck Blacklisting reworked again
+ *               10/29/2001 Cornelia Huck improved utilization of debug feature
+ *               10/29/2001 Cornelia Huck more work on cancel_IO - use the flag
+ *                                        DOIO_CANCEL_ON_TIMEOUT in do_IO to get
+ *                                        io cancelled
+ *               11/15/2001 Cornelia Huck proper behaviour with procfs off
+ *               12/10/2001 Cornelia Huck added private_data + functions to 
+ *                                        ioinfo_t
+ *               11-12/2001 Cornelia Huck various cleanups
+ *               01/09/2002 Cornelia Huck PGID fixes
+ *                                        process css machine checks 
+ *               01/10/2002 Cornelia Huck added /proc/chpids
+ * 		 02/11/2002 Arnd Bergmann split this file into many smaller pieces 
+ * 		 			  in drivers/s39/cio/
+ *               05/03/2002 Cornelia Huck debug cleanup
+ */
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/proc_fs.h>
+#include <asm/delay.h>
+#include <asm/idals.h>
+#include <asm/cpcmd.h>
+
+#include <asm/irq.h>
+#include <asm/s390io.h>
+#include <asm/s390dyn.h>
+#include <asm/s390mach.h>
+#include <asm/debug.h>
+
+#include "s390io.h"
+#include "ioinfo.h"
+#include "cio.h"
+#include "cio_debug.h"
+#include "blacklist.h"
+#include "proc.h"
+#include "chsc.h"
+
+static int init_IRQ_complete; 
+
+static pgid_t global_pgid;
+static schib_t p_init_schib;
+static __u64 irq_IPL_TOD; // FIXME: can be on stack
+
+static void s390_process_subchannels (void);
+static void s390_device_recognition_all (void);
+static int s390_SenseID (int irq, senseid_t * sid, __u8 lpm);
+static int s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid);
+static int s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid);
+
+/* FIXME: intermixed with proc.c */
+int cio_count_irqs = 1;			/* toggle use here... */
+unsigned long s390_irq_count[NR_CPUS];	/* trace how many irqs have occured per cpu... */
+
+int cio_show_msg;
+static int cio_notoper_msg = 1;
+static int cio_sid_with_pgid;     /* if we need a PGID for SenseID, switch this on */
+
+static int __init
+cio_setup (char *parm)
+{
+	if (!strcmp (parm, "yes")) {
+		cio_show_msg = 1;
+	} else if (!strcmp (parm, "no")) {
+		cio_show_msg = 0;
+	} else {
+		printk (KERN_ERR "cio_setup : invalid cio_msg parameter '%s'",
+			parm);
+
+	}
+
+	return 1;
+}
+
+__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 (KERN_ERR
+			"cio_notoper_setup: "
+			"invalid cio_notoper_msg parameter '%s'", parm);
+	}
+
+	return 1;
+}
+
+__setup ("cio_notoper_msg=", cio_notoper_setup);
+
+static int __init
+cio_pgid_setup (char *parm)
+{
+	if (!strcmp (parm, "yes")) {
+		cio_sid_with_pgid = 1;
+	} else if (!strcmp (parm, "no")) {
+		cio_sid_with_pgid = 0;
+	} else {
+		printk (KERN_ERR 
+			"cio_pgid_setup : invalid cio_msg parameter '%s'",
+			parm);
+
+	}
+
+	return 1;
+}
+
+__setup ("cio_sid_with_pgid=", cio_pgid_setup);
+
+/* This function is replacing the init_IRQ function in
+ * arch/s390(x)/kernel/irq.c and is called early during
+ * bootup. Anything called from here must be careful 
+ * about memory allocations */
+void __init
+s390_init_IRQ (void)
+{
+	unsigned long flags;	/* PSW flags */
+	long cr6 __attribute__ ((aligned (8)));
+
+	asm volatile ("STCK %0":"=m" (irq_IPL_TOD));
+
+
+	/*
+	 * As we don't know about the calling environment
+	 *  we assure running disabled. Before leaving the
+	 *  function we resestablish the old environment.
+	 *
+	 * Note : as we don't need a system wide lock, therefore
+	 *        we shouldn't use cli(), but __cli() as this
+	 *        affects the current CPU only.
+	 */
+	__save_flags (flags);
+	__cli ();
+
+	/*
+	 * disable all interrupts
+	 */
+	cr6 = 0;
+	__ctl_load (cr6, 6, 6);
+
+	s390_process_subchannels ();
+
+	if (cio_count_irqs) {
+		int i;
+		for (i = 0; i < NR_CPUS; i++)
+			s390_irq_count[i] = 0;
+	}
+
+	
+	/*
+	 * Let's build our path group ID here.
+	 */
+	
+	global_pgid.cpu_addr = *(__u16 *) __LC_CPUADDR;
+	global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;
+	global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;
+	global_pgid.tod_high = *(__u32 *) & irq_IPL_TOD;
+
+
+	/*
+	 * enable default I/O-interrupt subclass 3
+	 */
+	cr6 = 0x10000000;
+	__ctl_load (cr6, 6, 6);
+
+	s390_device_recognition_all ();
+
+	init_IRQ_complete = 1;
+
+	__restore_flags (flags);
+
+	return;
+}
+
+/*
+ * dummy handler, used during init_IRQ() processing for compatibility only
+ */
+static void
+init_IRQ_handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* this is a dummy handler only ... */
+}
+
+
+/*
+ * Input :
+ *   devno - device number
+ *   ps    - pointer to sense ID data area
+ * Output : none
+ */
+static inline void
+_VM_virtual_device_info (__u16 devno, senseid_t * ps)
+{
+	diag210_t *p_diag_data;
+	int ccode;
+
+	int error = 0;
+
+	CIO_TRACE_EVENT (4, "VMvdinf");
+
+	if (init_IRQ_complete) {
+		p_diag_data = kmalloc (sizeof (diag210_t), GFP_DMA);
+	} else {
+		p_diag_data = alloc_bootmem_low (sizeof (diag210_t));
+
+	}
+
+	p_diag_data->vrdcdvno = devno;
+	p_diag_data->vrdclen = sizeof (diag210_t);
+	ccode = diag210 ((diag210_t *) virt_to_phys (p_diag_data));
+	ps->reserved = 0xff;
+
+	switch (p_diag_data->vrdcvcla) {
+	case 0x80:
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 00:
+
+			ps->cu_type = 0x3215;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		}
+
+		break;
+
+	case 0x40:
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 0xC0:
+
+			ps->cu_type = 0x5080;
+
+			break;
+
+		case 0x80:
+
+			ps->cu_type = 0x2250;
+
+			break;
+
+		case 0x04:
+
+			ps->cu_type = 0x3277;
+
+			break;
+
+		case 0x01:
+
+			ps->cu_type = 0x3278;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		}
+
+		break;
+
+	case 0x20:
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 0x84:
+
+			ps->cu_type = 0x3505;
+
+			break;
+
+		case 0x82:
+
+			ps->cu_type = 0x2540;
+
+			break;
+
+		case 0x81:
+
+			ps->cu_type = 0x2501;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		}
+
+		break;
+
+	case 0x10:
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 0x84:
+
+			ps->cu_type = 0x3525;
+
+			break;
+
+		case 0x82:
+
+			ps->cu_type = 0x2540;
+
+			break;
+
+		case 0x4F:
+		case 0x4E:
+		case 0x48:
+
+			ps->cu_type = 0x3820;
+
+			break;
+
+		case 0x4D:
+		case 0x49:
+		case 0x45:
+
+			ps->cu_type = 0x3800;
+
+			break;
+
+		case 0x4B:
+
+			ps->cu_type = 0x4248;
+
+			break;
+
+		case 0x4A:
+
+			ps->cu_type = 0x4245;
+
+			break;
+
+		case 0x47:
+
+			ps->cu_type = 0x3262;
+
+			break;
+
+		case 0x43:
+
+			ps->cu_type = 0x3203;
+
+			break;
+
+		case 0x42:
+
+			ps->cu_type = 0x3211;
+
+			break;
+
+		case 0x41:
+
+			ps->cu_type = 0x1403;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		}
+
+		break;
+
+	case 0x08:
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 0x82:
+
+			ps->cu_type = 0x3422;
+
+			break;
+
+		case 0x81:
+
+			ps->cu_type = 0x3490;
+
+			break;
+
+		case 0x10:
+
+			ps->cu_type = 0x3420;
+
+			break;
+
+		case 0x02:
+
+			ps->cu_type = 0x3430;
+
+			break;
+
+		case 0x01:
+
+			ps->cu_type = 0x3480;
+
+			break;
+
+		case 0x42:
+
+			ps->cu_type = 0x3424;
+
+			break;
+
+		case 0x44:
+
+			ps->cu_type = 0x9348;
+
+			break;
+
+		default:
+
+			error = 1;
+
+			break;
+
+		}
+
+		break;
+
+	case 02:		/* special device class ... */
+
+		switch (p_diag_data->vrdcvtyp) {
+		case 0x20:	/* OSA */
+
+			ps->cu_type = 0x3088;
+			ps->cu_model = 0x60;
+
+			break;
+
+		default:
+
+			error = 1;
+			break;
+
+		}
+
+		break;
+
+	default:
+
+		error = 1;
+
+		break;
+
+	}
+
+	if (init_IRQ_complete) {
+		kfree (p_diag_data);
+	} else {
+		free_bootmem ((unsigned long) p_diag_data, sizeof (diag210_t));
+
+	}
+
+	if (error) 
+		CIO_DEBUG_ALWAYS(KERN_ERR, 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);
+		
+}
+
+/*
+ * This routine returns the characteristics for the device
+ *  specified. Some old devices might not provide the necessary
+ *  command code information during SenseID processing. In this
+ *  case the function returns -EINVAL. Otherwise the function
+ *  allocates a decice specific data buffer and provides the
+ *  device characteristics together with the buffer size. Its
+ *  the callers responability to release the kernel memory if
+ *  not longer needed. In case of persistent I/O problems -EBUSY
+ *  is returned.
+ *
+ *  The function may be called enabled or disabled. However, the
+ *   caller must have locked the irq it is requesting data for.
+ *
+ * Note : It would have been nice to collect this information
+ *         during init_IRQ() processing but this is not possible
+ *
+ *         a) without statically pre-allocation fixed size buffers
+ *            as virtual memory management isn't available yet.
+ *
+ *         b) without unnecessarily increase system startup by
+ *            evaluating devices eventually not used at all.
+ */
+int
+read_dev_chars (int irq, void **buffer, int length)
+{
+	unsigned int flags;
+	ccw1_t *rdc_ccw;
+	devstat_t devstat;
+	char *rdc_buf;
+	int devflag = 0;
+
+	int ret = 0;
+	int emulated = 0;
+	int retry = 5;
+
+	char dbf_txt[15];
+
+	if (!buffer || !length) {
+		return (-EINVAL);
+
+	}
+
+	SANITY_CHECK (irq);
+
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+
+	}
+
+	sprintf (dbf_txt, "rddevch%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * Before playing around with irq locks we should assure
+	 *   running disabled on (just) our CPU. Sync. I/O requests
+	 *   also require to run disabled.
+	 *
+	 * Note : as no global lock is required, we must not use
+	 *        cli(), but __cli() instead.   
+	 */
+	__save_flags (flags);
+	__cli ();
+
+	rdc_ccw = &ioinfo[irq]->senseccw;
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ret = request_irq (irq,
+				   init_IRQ_handler, SA_PROBE, "RDC", &devstat);
+
+		if (!ret) {
+			emulated = 1;
+
+		}
+
+	}
+
+	if (!ret) {
+		if (!*buffer) {
+			rdc_buf = kmalloc (length, GFP_KERNEL);
+		} else {
+			rdc_buf = *buffer;
+
+		}
+
+		if (!rdc_buf) {
+			ret = -ENOMEM;
+		} else {
+			do {
+				rdc_ccw->cmd_code = CCW_CMD_RDC;
+				rdc_ccw->count = length;
+				rdc_ccw->flags = CCW_FLAG_SLI;
+				ret = set_normalized_cda (rdc_ccw, rdc_buf);
+				if (!ret) {
+
+					memset (ioinfo[irq]->irq_desc.dev_id,
+						'\0', sizeof (devstat_t));
+
+					ret = s390_start_IO (irq, rdc_ccw, 0x00524443,	/* RDC */
+							     0,	/* n/a */
+							     DOIO_WAIT_FOR_INTERRUPT
+							     |
+							     DOIO_DONT_CALL_INTHDLR);
+					retry--;
+					devflag =
+					    ioinfo[irq]->irq_desc.dev_id->flag;
+
+					clear_normalized_cda (rdc_ccw);
+				} else {
+					udelay (100);	/* wait for recovery */
+					retry--;
+				}
+
+			} while ((retry)
+				 && (ret
+				     || (devflag & DEVSTAT_STATUS_PENDING)));
+
+		}
+
+		if (!retry) {
+			ret = (ret == -ENOMEM) ? -ENOMEM : -EBUSY;
+
+		}
+
+		__restore_flags (flags);
+
+		/*
+		 * on success we update the user input parms
+		 */
+		if (!ret) {
+			*buffer = rdc_buf;
+
+		}
+
+		if (emulated) {
+			free_irq (irq, &devstat);
+
+		}
+
+	}
+
+	return (ret);
+}
+
+/*
+ *  Read Configuration data
+ */
+int
+read_conf_data (int irq, void **buffer, int *length, __u8 lpm)
+{
+	unsigned long flags;
+	int ciw_cnt;
+
+	int found = 0;		/* RCD CIW found */
+	int ret = 0;		/* return code */
+
+	char dbf_txt[15];
+
+	SANITY_CHECK (irq);
+
+	if (!buffer || !length) {
+		return (-EINVAL);
+	} else if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+	} else if (ioinfo[irq]->ui.flags.esid == 0) {
+		return (-EOPNOTSUPP);
+
+	}
+
+	sprintf (dbf_txt, "rdconf%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * scan for RCD command in extended SenseID data
+	 */
+
+	for (ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++) {
+		if (ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD) {
+			/*
+			 * paranoia check ...
+			 */
+			if (ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0) {
+				found = 1;
+
+			}
+
+			break;
+
+		}
+	}
+
+	if (found) {
+		devstat_t devstat;	/* inline device status area */
+		devstat_t *pdevstat;
+		int ioflags;
+
+		ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
+		char *rcd_buf = NULL;
+		int emulated = 0;	/* no i/O handler installed */
+		int retry = 5;	/* retry count */
+
+		__save_flags (flags);
+		__cli ();
+
+		if (!ioinfo[irq]->ui.flags.ready) {
+			pdevstat = &devstat;
+			ret = request_irq (irq,
+					   init_IRQ_handler,
+					   SA_PROBE, "RCD", pdevstat);
+
+			if (!ret) {
+				emulated = 1;
+
+			}	/* endif */
+		} else {
+			pdevstat = ioinfo[irq]->irq_desc.dev_id;
+
+		}		/* endif */
+
+		if (!ret) {
+			if (init_IRQ_complete) {
+				rcd_buf =
+				    kmalloc (ioinfo[irq]->senseid.ciw[ciw_cnt].
+					     count, GFP_DMA);
+			} else {
+				rcd_buf =
+				    alloc_bootmem_low (ioinfo[irq]->senseid.
+						       ciw[ciw_cnt].count);
+
+			}
+
+			if (rcd_buf == NULL) {
+				ret = -ENOMEM;
+
+			}
+			if (!ret) {
+				memset (rcd_buf,
+					'\0',
+					ioinfo[irq]->senseid.ciw[ciw_cnt].
+					count);
+
+				do {
+					rcd_ccw->cmd_code =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    cmd;
+					rcd_ccw->cda =
+					    (__u32) virt_to_phys (rcd_buf);
+					rcd_ccw->count =
+					    ioinfo[irq]->senseid.ciw[ciw_cnt].
+					    count;
+					rcd_ccw->flags = CCW_FLAG_SLI;
+
+					memset (pdevstat, '\0',
+						sizeof (devstat_t));
+
+					if (lpm) {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_VALID_LPM |
+						    DOIO_DONT_CALL_INTHDLR;
+					} else {
+						ioflags =
+						    DOIO_WAIT_FOR_INTERRUPT |
+						    DOIO_DONT_CALL_INTHDLR;
+
+					}
+
+					ret = s390_start_IO (irq, rcd_ccw, 0x00524344,	/* == RCD */
+							     lpm, ioflags);
+					switch (ret) {
+					case 0:
+					case -EIO:
+
+						if (!
+						    (pdevstat->
+						     flag &
+						     (DEVSTAT_STATUS_PENDING |
+						      DEVSTAT_NOT_OPER |
+						      DEVSTAT_FLAG_SENSE_AVAIL)))
+						{
+							retry = 0;	/* we got it ... */
+						} else {
+							retry--;	/* try again ... */
+
+						}
+
+						break;
+
+					default:	/* -EBUSY, -ENODEV, ??? */
+						retry = 0;
+
+					}
+
+				} while (retry);
+
+			}
+
+			__restore_flags (flags);
+
+		}
+
+		/*
+		 * on success we update the user input parms
+		 */
+		if (ret == 0) {
+			*length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
+			*buffer = rcd_buf;
+		} else {
+			if (rcd_buf != NULL) {
+				if (init_IRQ_complete) {
+					kfree (rcd_buf);
+				} else {
+					free_bootmem ((unsigned long) rcd_buf,
+						      ioinfo[irq]->senseid.
+						      ciw[ciw_cnt].count);
+
+				}
+
+			}
+
+			*buffer = NULL;
+			*length = 0;
+
+		}
+
+		if (emulated)
+			free_irq (irq, pdevstat);
+	} else {
+		ret = -EOPNOTSUPP;
+
+	}
+
+	return (ret);
+
+}
+
+/*
+ * s390_device_recognition_irq
+ *
+ * Used for individual device recognition. Issues the device
+ *  independant SenseID command to obtain info the device type.
+ *
+ */
+void
+s390_device_recognition_irq (int irq)
+{
+	int ret;
+	char dbf_txt[15];
+
+	sprintf (dbf_txt, "devrec%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * We issue the SenseID command on I/O subchannels we think are
+	 *  operational only.
+	 */
+	if ((ioinfo[irq] != INVALID_STORAGE_AREA)
+	    && (!ioinfo[irq]->st)
+	    && (ioinfo[irq]->schib.pmcw.st == 0)
+	    && (ioinfo[irq]->ui.flags.oper == 1)) {
+		int irq_ret;
+		devstat_t devstat;
+
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "INIT", &devstat);
+
+		if (!irq_ret) {
+			ret = enable_cpu_sync_isc (irq);
+
+			if (!ret) {
+				ioinfo[irq]->ui.flags.unknown = 0;
+
+				memset (&ioinfo[irq]->senseid, '\0',
+					sizeof (senseid_t));
+
+				if (cio_sid_with_pgid) {
+					
+					ret = s390_DevicePathVerification(irq,0);
+					
+					if (ret == -EOPNOTSUPP) 
+						/* 
+						 * Doesn't prevent us from proceeding
+						 */
+						ret = 0;
+				}
+
+				/*
+				 * we'll fallthrough here if we don't want
+				 * to do SPID before SID
+				 */
+				if (!ret) {
+					s390_SenseID (irq, &ioinfo[irq]->senseid, 0xff);
+				}
+				disable_cpu_sync_isc (irq);
+
+			}
+
+			free_irq (irq, &devstat);
+
+		}
+	}
+}
+
+/*
+ * s390_device_recognition_all
+ *
+ * Used for system wide device recognition.
+ *
+ */
+static void __init
+s390_device_recognition_all (void)
+{
+	int irq = 0;		/* let's start with subchannel 0 ... */
+
+	do {
+		s390_device_recognition_irq (irq);
+
+		irq++;
+
+	} while (irq <= highest_subchannel);
+}
+
+/*
+ * s390_process_subchannels
+ *
+ * Determines all subchannels available to the system.
+ * Only called early during startup by s390_init_IRQ
+ */
+static void __init
+s390_process_subchannels (void)
+{
+	int ret;
+	int irq = 0;		/* Evaluate all subchannels starting with 0 ... */
+
+	do {
+		ret = s390_validate_subchannel (irq, 0);
+
+		if (ret != -ENXIO)
+			irq++;
+
+	} while ((ret != -ENXIO) && (irq < __MAX_SUBCHANNELS));
+
+	highest_subchannel = (--irq);
+
+	CIO_DEBUG_ALWAYS(KERN_INFO, 0,
+			 "Highest subchannel number detected "
+			 "(hex) : %04X\n", highest_subchannel);
+}
+
+/*
+ * s390_validate_subchannel()
+ *
+ * Process the subchannel for the requested irq. 
+ * Return codes:
+ * * 0 for valid subchannels
+ * * -ENXIO for non-defined subchannels 
+ *   (indicates highest available subchannel + 1)
+ * * -ENODEV for non-IO subchannels and not operational conditions
+ * * -EIO and -EBUSY for error conditions during msch
+ */
+int
+s390_validate_subchannel (int irq, int enable)
+{
+
+	int retry;		/* retry count for status pending conditions */
+	int ccode;		/* condition code for stsch() only */
+	int ccode2;		/* condition code for other I/O routines */
+	schib_t *p_schib;
+	int ret;
+#ifdef CONFIG_CHSC
+	int      chp = 0;
+	int      mask;
+#endif /* CONFIG_CHSC */
+
+	char dbf_txt[15];
+
+	sprintf (dbf_txt, "valsch%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	/*
+	 * The first subchannel that is not-operational (ccode==3)
+	 *  indicates that there aren't any more devices available.
+	 */
+	if ((init_IRQ_complete)
+	    && (ioinfo[irq] != INVALID_STORAGE_AREA)) {
+		p_schib = &ioinfo[irq]->schib;
+	} else {
+		p_schib = &p_init_schib;
+
+	}
+
+	/*
+	 * If we knew the device before we assume the worst case ...    
+	 */
+	if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+		ioinfo[irq]->ui.flags.oper = 0;
+		ioinfo[irq]->ui.flags.dval = 0;
+
+	}
+
+	ccode = stsch (irq, p_schib);
+
+	if (ccode) {
+		return -ENXIO;
+	}
+	/*
+	 * ... just being curious we check for non I/O subchannels
+	 */
+	if (p_schib->pmcw.st) {
+
+		CIO_DEBUG_IFMSG(KERN_INFO, 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;
+
+	}
+
+	if ((!p_schib->pmcw.dnv) && (!p_schib->pmcw.st)) {
+		return -ENODEV;
+	}
+	if (!p_schib->pmcw.st) {
+		if (ioinfo[irq] == INVALID_STORAGE_AREA
+		    && is_blacklisted (p_schib->pmcw.dev)) {
+			/* 
+			 * This device must not be known to Linux. So we simply say that 
+			 * there is no device and return ENODEV.
+			 */
+			CIO_DEBUG(KERN_DEBUG, 0,
+				  "Blacklisted device detected at devno %04X\n",
+				      p_schib->pmcw.dev);
+			return -ENODEV;
+		}
+	}
+	
+	if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+		if (!init_IRQ_complete) {
+			ioinfo[irq] = (ioinfo_t *)
+			    alloc_bootmem_low (sizeof (ioinfo_t));
+		} else {
+			ioinfo[irq] = (ioinfo_t *)
+			    kmalloc (sizeof (ioinfo_t), GFP_DMA);
+
+		}
+
+		memset (ioinfo[irq], '\0', sizeof (ioinfo_t));
+		memcpy (&ioinfo[irq]->schib, &p_init_schib, sizeof (schib_t));
+
+		/*
+		 * We have to insert the new ioinfo element
+		 *  into the linked list, either at its head,
+		 *  its tail or insert it.
+		 */
+		if (ioinfo_head == NULL) {	/* first element */
+			ioinfo_head = ioinfo[irq];
+			ioinfo_tail = ioinfo[irq];
+		} else if (irq < ioinfo_head->irq) {	/* new head */
+			ioinfo[irq]->next = ioinfo_head;
+			ioinfo_head->prev = ioinfo[irq];
+			ioinfo_head = ioinfo[irq];
+		} else if (irq > ioinfo_tail->irq) {	/* new tail */
+			ioinfo_tail->next = ioinfo[irq];
+			ioinfo[irq]->prev = ioinfo_tail;
+			ioinfo_tail = ioinfo[irq];
+		} else {	/* insert element */
+
+			ioinfo_t *pi = ioinfo_head;
+
+			for (pi = ioinfo_head; pi != NULL; pi = pi->next) {
+
+				if (irq < pi->next->irq) {
+					ioinfo[irq]->next = pi->next;
+					ioinfo[irq]->prev = pi;
+					pi->next->prev = ioinfo[irq];
+					pi->next = ioinfo[irq];
+					break;
+
+				}
+			}
+		}
+	}
+
+	/* initialize some values ... */
+	ioinfo[irq]->irq = irq;
+	ioinfo[irq]->st = ioinfo[irq]->schib.pmcw.st;
+	if (ioinfo[irq]->st)
+		return -ENODEV;
+
+	ioinfo[irq]->ui.flags.pgid_supp = 1;
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!chsc_chpid_logical (irq, chp)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
+		}
+	}
+#endif /* CONFIG_CHSC */
+
+	CIO_DEBUG_IFMSG(KERN_INFO, 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
+	 */
+	if (!ioinfo[irq]->ui.flags.ready) {
+		ioinfo[irq]->nopfunc = NULL;
+		ioinfo[irq]->ui.flags.busy = 0;
+		ioinfo[irq]->ui.flags.dval = 1;
+		ioinfo[irq]->devstat.intparm = 0;
+
+	}
+	ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
+	ioinfo[irq]->devno = ioinfo[irq]->schib.pmcw.dev;
+
+	/*
+	 * We should have at least one CHPID ...
+	 */
+	if (ioinfo[irq]->opm) {
+		/*
+		 * We now have to initially ...
+		 *  ... set "interruption subclass"
+		 *  ... enable "concurrent sense"
+		 *  ... enable "multipath mode" if more than one
+		 *        CHPID is available. This is done regardless
+		 *        whether multiple paths are available for us.
+		 *
+		 * Note : we don't enable the device here, this is temporarily
+		 *        done during device sensing below.
+		 */
+		ioinfo[irq]->schib.pmcw.isc = 3;	/* could be smth. else */
+		ioinfo[irq]->schib.pmcw.csense = 1;	/* concurrent sense */
+		ioinfo[irq]->schib.pmcw.ena = enable;
+		ioinfo[irq]->schib.pmcw.intparm = ioinfo[irq]->schib.pmcw.dev;
+
+		if ((ioinfo[irq]->opm != 0x80)
+		    && (ioinfo[irq]->opm != 0x40)
+		    && (ioinfo[irq]->opm != 0x20)
+		    && (ioinfo[irq]->opm != 0x10)
+		    && (ioinfo[irq]->opm != 0x08)
+		    && (ioinfo[irq]->opm != 0x04)
+		    && (ioinfo[irq]->opm != 0x02)
+		    && (ioinfo[irq]->opm != 0x01)) {
+			ioinfo[irq]->schib.pmcw.mp = 1;	/* multipath mode */
+
+		}
+
+		retry = 5;
+
+		do {
+			ccode2 = msch_err (irq, &ioinfo[irq]->schib);
+
+			switch (ccode2) {
+			case 0:
+				/*
+				 * successful completion
+				 *
+				 * concurrent sense facility available
+				 */
+				ioinfo[irq]->ui.flags.oper = 1;
+				ioinfo[irq]->ui.flags.consns = 1;
+				ret = 0;
+				break;
+
+			case 1:
+				/*
+				 * status pending
+				 *
+				 * How can we have a pending status 
+				 * as the device is disabled for 
+				 * interrupts ?
+				 * Anyway, process it ...
+				 */
+				ioinfo[irq]->ui.flags.s_pend = 1;
+				s390_process_IRQ (irq);
+				ioinfo[irq]->ui.flags.s_pend = 0;
+				retry--;
+				ret = -EIO;
+				break;
+
+			case 2:
+				/*
+				 * busy
+				 *
+				 * we mark it not-oper as we can't 
+				 * properly operate it !
+				 */
+				ioinfo[irq]->ui.flags.oper = 0;
+				udelay (100);	/* allow for recovery */
+				retry--;
+				ret = -EBUSY;
+				break;
+
+			case 3:	/* not operational */
+				ioinfo[irq]->ui.flags.oper = 0;
+				retry = 0;
+				ret = -ENODEV;
+				break;
+
+			default:
+#define PGMCHK_OPERAND_EXC      0x15
+
+				if ((ccode2 & PGMCHK_OPERAND_EXC)
+				    == PGMCHK_OPERAND_EXC) {
+					/*
+					 * re-issue the modify subchannel without trying to
+					 *  enable the concurrent sense facility
+					 */
+					ioinfo[irq]->schib.pmcw.csense = 0;
+
+					ccode2 =
+					    msch_err (irq, &ioinfo[irq]->schib);
+
+					if (ccode2 != 0) {
+						CIO_DEBUG_ALWAYS(KERN_ERR, 0,
+								 "msch() (2) failed"
+								 " with CC=%X\n",
+								 ccode2);
+						ioinfo[irq]->ui.flags.oper = 0;
+						ret = -EIO;
+					} else {
+						ioinfo[irq]->ui.flags.oper = 1;
+						ioinfo[irq]->ui.
+						    flags.consns = 0;
+						ret = 0;
+
+					}
+
+				} else {
+					CIO_DEBUG_ALWAYS(KERN_ERR, 0,
+							 "msch() (1) failed with "
+							 "CC = %X\n", ccode2);
+					ioinfo[irq]->ui.flags.oper = 0;
+					ret = -EIO;
+
+				}
+
+				retry = 0;
+				break;
+
+			}
+
+		} while (ccode2 && retry);
+
+		if ((ccode2 != 0) && (ccode2 != 3)
+		    && (!retry)) {
+			CIO_DEBUG_ALWAYS(KERN_ERR, 0,
+					 " ... msch() retry count for "
+					 "subchannel %04X exceeded, CC = %d\n",
+					 irq, ccode2);
+
+		}
+	} else {
+		/* no path available ... */
+		ioinfo[irq]->ui.flags.oper = 0;
+		ret = -ENODEV;
+
+	}
+
+	return (ret);
+}
+
+/*
+ * s390_SenseID
+ *
+ * Try to obtain the 'control unit'/'device type' information
+ *  associated with the subchannel.
+ *
+ * The function is primarily meant to be called without irq
+ *  action handler in place. However, it also allows for
+ *  use with an action handler in place. If there is already
+ *  an action handler registered assure it can handle the
+ *  s390_SenseID() related device interrupts - interruption
+ *  parameter used is 0x00E2C9C4 ( SID ).
+ */
+static int
+s390_SenseID (int irq, senseid_t * sid, __u8 lpm)
+{
+	ccw1_t *sense_ccw;	/* ccw area for SenseID command */
+	senseid_t isid;		/* internal sid */
+	devstat_t devstat;	/* required by request_irq() */
+	__u8 pathmask;		/* calulate path mask */
+	__u8 domask;		/* path mask to use */
+	int inlreq;		/* inline request_irq() */
+	int irq_ret;		/* return code */
+	devstat_t *pdevstat;	/* ptr to devstat in use */
+	int retry;		/* retry count */
+	int io_retry;		/* retry indicator */
+
+	senseid_t *psid = sid;	/* start with the external buffer */
+	int sbuffer = 0;	/* switch SID data buffer */
+
+	char dbf_txt[15];
+	int i;
+	int failure = 0;	/* nothing went wrong yet */
+
+	SANITY_CHECK (irq);
+
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+
+	}
+
+	sprintf (dbf_txt, "snsID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	inlreq = 0;		/* to make the compiler quiet... */
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+
+		pdevstat = &devstat;
+
+		/*
+		 * Perform SENSE ID command processing. We have to request device
+		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
+		 *  requests and evaluate the devstat area on return therefore
+		 *  we don't need a real I/O handler in place.
+		 */
+		irq_ret =
+		    request_irq (irq, init_IRQ_handler, SA_PROBE, "SID",
+				 &devstat);
+
+		if (irq_ret == 0)
+			inlreq = 1;
+	} else {
+		inlreq = 0;
+		irq_ret = 0;
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+
+	}
+
+	if (irq_ret) {
+		return irq_ret;
+	}
+
+	s390irq_spin_lock (irq);
+
+	if (init_IRQ_complete) {
+		sense_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		sense_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
+
+	}
+
+	/* more than one path installed ? */
+	if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+		sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+		sense_ccw[0].cda = 0;
+		sense_ccw[0].count = 0;
+		sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+
+		sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[1].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[1].count = sizeof (senseid_t);
+		sense_ccw[1].flags = CCW_FLAG_SLI;
+	} else {
+		sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
+		sense_ccw[0].cda = (__u32) virt_to_phys (sid);
+		sense_ccw[0].count = sizeof (senseid_t);
+		sense_ccw[0].flags = CCW_FLAG_SLI;
+
+	}
+
+	for (i = 0; (i < 8); i++) {
+		pathmask = 0x80 >> i;
+
+		domask = ioinfo[irq]->opm & pathmask;
+
+		if (lpm)
+			domask &= lpm;
+
+		if (!domask)
+			continue;
+
+		failure = 0;
+
+		psid->reserved = 0;
+		psid->cu_type = 0xFFFF;	/* initialize fields ... */
+		psid->cu_model = 0;
+		psid->dev_type = 0;
+		psid->dev_model = 0;
+
+		retry = 5;	/* retry count    */
+		io_retry = 1;	/* enable retries */
+
+		/*
+		 * We now issue a SenseID request. In case of BUSY,
+		 *  STATUS PENDING or non-CMD_REJECT error conditions
+		 *  we run simple retries.
+		 */
+		do {
+			memset (pdevstat, '\0', sizeof (devstat_t));
+
+			irq_ret = s390_start_IO (irq, sense_ccw, 0x00E2C9C4,	/* == SID */
+						 domask,
+						 DOIO_WAIT_FOR_INTERRUPT
+						 | DOIO_TIMEOUT
+						 | DOIO_VALID_LPM
+						 | DOIO_DONT_CALL_INTHDLR);
+
+			if ((psid->cu_type != 0xFFFF)
+			    && (psid->reserved == 0xFF)) {
+				if (!sbuffer) {	/* switch buffers */
+					/*
+					 * we report back the
+					 *  first hit only
+					 */
+					psid = &isid;
+
+					if (ioinfo[irq]->schib.pmcw.pim != 0x80) {
+						sense_ccw[1].cda = (__u32)
+						    virt_to_phys (psid);
+					} else {
+						sense_ccw[0].cda = (__u32)
+						    virt_to_phys (psid);
+
+					}
+
+					/*
+					 * if just the very first
+					 *  was requested to be
+					 *  sensed disable further
+					 *  scans.
+					 */
+					if (!lpm)
+						lpm = domask;
+
+					sbuffer = 1;
+
+				}
+
+				if (pdevstat->rescnt < (sizeof (senseid_t) - 8)) {
+					ioinfo[irq]->ui.flags.esid = 1;
+
+				}
+
+				io_retry = 0;
+
+				break;
+			}
+
+			failure = 1;
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
+
+				CIO_DEBUG (KERN_DEBUG, 2,
+					   "SenseID : device %04X on "
+					   "Subchannel %04X "
+					   "reports pending status, "
+					   "retry : %d\n",
+					   ioinfo
+					   [irq]->schib.pmcw.dev, irq, retry);
+			
+			} else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * if the device doesn't support the SenseID
+				 *  command further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.data[0]
+				    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)) {
+
+					CIO_DEBUG(KERN_ERR, 2,
+						  "SenseID : device %04X on "
+						  "Subchannel %04X "
+						  "reports cmd reject or "
+						  "intervention required\n",
+						  ioinfo[irq]->schib.pmcw.dev, 
+						  irq);
+
+					io_retry = 0;
+				} else {
+
+					CIO_DEBUG(KERN_WARNING, 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]);
+					
+				}
+
+			} else if ((pdevstat->flag & DEVSTAT_NOT_OPER)
+				   || (irq_ret == -ENODEV)) {
+
+				CIO_DEBUG(KERN_ERR, 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;
+
+			} else {
+
+				CIO_DEBUG(KERN_INFO, 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);
+
+				if (irq_ret == -ETIMEDOUT) {
+					int xret;
+
+					/*
+					 * Seems we need to cancel the first ssch sometimes...
+					 * On the next try, the ssch will usually be fine.
+					 */
+
+					xret = cancel_IO (irq);
+
+					if (!xret)
+						CIO_MSG_EVENT(4,
+							      "SenseID: sch canceled "
+							      "successfully for irq %x\n",
+							      irq);
+				}
+
+			}
+
+			if (io_retry) {
+				retry--;
+
+				if (retry == 0) {
+					io_retry = 0;
+
+				}
+			}
+
+			if ((failure) && (io_retry)) {
+				/* reset fields... */
+
+				failure = 0;
+
+				psid->reserved = 0;
+				psid->cu_type = 0xFFFF;
+				psid->cu_model = 0;
+				psid->dev_type = 0;
+				psid->dev_model = 0;
+			}
+
+		} while ((io_retry));
+
+	}
+
+	if (init_IRQ_complete) {
+		kfree (sense_ccw);
+	} else {
+		free_bootmem ((unsigned long) sense_ccw, 2 * sizeof (ccw1_t));
+
+	}
+
+	s390irq_spin_unlock (irq);
+
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	/*
+	 * if running under VM check there ... perhaps we should do
+	 *  only if we suffered a command reject, but it doesn't harm
+	 */
+	if ((sid->cu_type == 0xFFFF)
+	    && (MACHINE_IS_VM)) {
+		_VM_virtual_device_info (ioinfo[irq]->schib.pmcw.dev, sid);
+	}
+
+	if (sid->cu_type == 0xFFFF) {
+		/*
+		 * SenseID CU-type of 0xffff indicates that no device
+		 *  information could be retrieved (pre-init value).
+		 *
+		 * If we can't couldn't identify the device type we
+		 *  consider the device "not operational".
+		 */
+		CIO_DEBUG(KERN_WARNING, 2,
+			  "SenseID : unknown device %04X on subchannel %04X\n",
+			  ioinfo[irq]->schib.pmcw.dev, irq);
+
+		ioinfo[irq]->ui.flags.unknown = 1;
+
+	}
+
+	/*
+	 * Issue device info message if unit was operational .
+	 */
+	if (!ioinfo[irq]->ui.flags.unknown) {
+		if (sid->dev_type != 0) {
+
+			CIO_DEBUG_IFMSG(KERN_INFO, 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 {
+
+			CIO_DEBUG_IFMSG(KERN_INFO, 2,
+					"SenseID : device %04X reports:"
+					" Dev Type/Mod = %04X/%02X\n",
+					ioinfo[irq]->schib.pmcw.dev,
+					sid->cu_type,
+					sid->cu_model);
+		}
+
+	}
+
+	if (!ioinfo[irq]->ui.flags.unknown)
+		irq_ret = 0;
+	else
+		irq_ret = -ENODEV;
+
+	return (irq_ret);
+}
+
+/*
+ * Device Path Verification
+ *
+ * Path verification is accomplished by checking which paths (CHPIDs) are
+ *  available. Further, a path group ID is set, if possible in multipath
+ *  mode, otherwise in single path mode.
+ *
+ * Note : This function must not be called during normal device recognition,
+ *         but during device driver initiated request_irq() processing only.
+ */
+int
+s390_DevicePathVerification (int irq, __u8 usermask)
+{
+	int ccode;
+	__u8 pathmask;
+	__u8 domask;
+#ifdef CONFIG_CHSC
+	int chp;
+	int mask;
+	int old_opm = 0;
+#endif /* CONFIG_CHSC */
+
+	int ret = 0;
+	int i;
+	pgid_t pgid;
+	__u8 dev_path;
+	int first = 1;
+
+	char dbf_txt[15];
+
+	sprintf (dbf_txt, "dpver%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if (ioinfo[irq]->st) 
+		return -ENODEV;
+
+#ifdef CONFIG_CHSC
+	old_opm = ioinfo[irq]->opm;
+#endif /* CONFIG_CHSC */
+	ccode = stsch (irq, &(ioinfo[irq]->schib));
+
+	if (ccode) {
+		return -ENODEV;
+	}
+	if (ioinfo[irq]->schib.pmcw.pim == 0x80) {
+		/*
+		 * no error, just not required for single path only devices
+		 */
+		ioinfo[irq]->ui.flags.pgid_supp = 0;
+		ret = 0;
+
+#ifdef CONFIG_CHSC
+		/*
+		 * disable if chpid is logically offline
+		 */
+		if (!chsc_chpid_logical(irq, 0)) {
+			not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+			int was_oper = ioinfo[irq]->ui.flags.oper;
+
+			ioinfo[irq]->opm = 0;
+			ioinfo[irq]->ui.flags.oper = 0;
+			CIO_DEBUG_ALWAYS(KERN_WARNING, 0,
+					 "No logical path for sch %d...\n",
+					 irq);
+			if (old_opm && 
+			    was_oper && 
+			    ioinfo[irq]->ui.flags.ready) {
+
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+			}
+			ret = -ENODEV;
+		} else if (!old_opm) {
+
+			/*
+			 * check for opm...
+			 */
+			ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+				& ioinfo[irq]->schib.pmcw.pam
+				& ioinfo[irq]->schib.pmcw.pom;
+				
+			if (ioinfo[irq]->opm) {
+				devreg_t *pdevreg;
+
+				ioinfo[irq]->ui.flags.oper = 1;
+				pdevreg = s390_search_devreg( ioinfo[irq] );
+
+				if (pdevreg) 
+					if (pdevreg->oper_func)
+						pdevreg->oper_func
+							( irq, pdevreg);
+			}
+			ret = 0;
+		} else {
+			ret = 0;
+		}
+#endif /* CONFIG_CHSC */
+		return ret;
+	}
+
+	ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
+	    & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
+
+#ifdef CONFIG_CHSC
+	if (ioinfo[irq]->opm) {
+		for (chp=0;chp<=7;chp++) {
+			mask = 0x80 >> chp;
+			if (ioinfo[irq]->opm & mask) {
+				if (!chsc_chpid_logical (irq, chp)) {
+					/* disable using this path */
+					ioinfo[irq]->opm &= ~mask;
+				}
+			}
+		}
+	}
+	
+	if ((ioinfo[irq]->opm == 0) && (old_opm)) {
+		not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+		int was_oper = ioinfo[irq]->ui.flags.ready;
+
+		ioinfo[irq]->ui.flags.oper = 0;
+		CIO_DEBUG_ALWAYS(KERN_WARNING, 0, 
+				 "No logical path for sch %d...\n",
+				 irq);
+		if (was_oper && ioinfo[irq]->ui.flags.oper) {
+
+				free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
+				if (nopfunc)
+					nopfunc( irq, DEVSTAT_DEVICE_GONE);
+		}
+		return -ENODEV;
+	}
+
+	if (!old_opm) {
+		/* Hey, we have a new logical path... */
+		devreg_t *pdevreg;
+		
+		ioinfo[irq]->ui.flags.oper = 1;
+		pdevreg = s390_search_devreg( ioinfo[irq] );
+		
+		if (pdevreg) 
+			if (pdevreg->oper_func)
+				pdevreg->oper_func( irq, pdevreg);
+
+	}
+#endif /* CONFIG_CHSC */
+
+	if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
+		return( 0);	/* just exit ... */
+
+	if (usermask) {
+		dev_path = usermask;
+	} else {
+		dev_path = ioinfo[irq]->opm;
+
+	}
+
+	if (ioinfo[irq]->ui.flags.pgid == 0) {
+		memcpy (&ioinfo[irq]->pgid, &global_pgid, sizeof (pgid_t));
+		ioinfo[irq]->ui.flags.pgid = 1;
+	}
+	memcpy (&pgid, &ioinfo[irq]->pgid, sizeof (pgid_t));
+
+	for (i = 0; i < 8 && !ret; i++) {
+		pathmask = 0x80 >> i;
+
+		domask = dev_path & pathmask;
+
+		if (domask) {
+			ret = s390_SetPGID (irq, domask, &pgid);
+
+			/*
+			 * For the *first* path we are prepared
+			 *  for recovery
+			 *
+			 *  - If we fail setting the PGID we assume its
+			 *     using  a different PGID already (VM) we
+			 *     try to sense.
+			 */
+			if (ret == -EOPNOTSUPP && first) {
+				*(int *) &pgid = 0;
+
+				ret = s390_SensePGID (irq, domask, &pgid);
+				first = 0;
+
+				if (ret == 0) {
+					/*
+					 * Check whether we retrieved
+					 *  a reasonable PGID ...
+					 */
+					if (pgid.inf.ps.state1 ==
+					    SNID_STATE1_GROUPED) {
+						memcpy (&ioinfo[irq]->pgid,
+							&pgid, sizeof (pgid_t));
+					} else {	/* ungrouped or garbage ... */
+						ret = -EOPNOTSUPP;
+
+					}
+				} else {
+					ioinfo[irq]->ui.flags.pgid_supp = 0;
+
+					CIO_DEBUG(KERN_WARNING, 2,
+						  "PathVerification(%04X) "
+						  "- Device %04X doesn't "
+						  " support path grouping\n",
+						  irq,
+						  ioinfo[irq]->schib.pmcw.dev);
+					
+				}
+			} else if (ret == -EIO) {
+
+				CIO_DEBUG(KERN_ERR, 2,
+					  "PathVerification(%04X) - I/O error "
+					  "on device %04X\n", irq,
+					  ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
+
+			} else if (ret == -ETIMEDOUT) {
+
+				CIO_DEBUG(KERN_ERR, 2,
+					  "PathVerification(%04X) - I/O timed "
+					  "out on device %04X\n", irq,
+					  ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
+
+			} else if (ret == -EAGAIN) {
+
+				ret = 0;
+
+			} else {
+
+				CIO_DEBUG(KERN_ERR, 2,
+					  "PathVerification(%04X) - "
+					  "Unexpected error on device %04X\n",
+					  irq, ioinfo[irq]->schib.pmcw.dev);
+				
+				ioinfo[irq]->ui.flags.pgid_supp = 0;
+			}
+		}
+	}
+	return ret;
+
+}
+
+/*
+ * s390_SetPGID
+ *
+ * Set Path Group ID
+ *
+ */
+static int
+s390_SetPGID (int irq, __u8 lpm, pgid_t * pgid)
+{
+	ccw1_t *spid_ccw;	/* ccw area for SPID command */
+	devstat_t devstat;	/* required by request_irq() */
+	devstat_t *pdevstat = &devstat;
+	unsigned long flags;
+	char dbf_txt[15];
+
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
+	int mpath = 1;		/* try multi-path first */
+
+	SANITY_CHECK (irq);
+
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+
+	}
+
+	sprintf (dbf_txt, "SPID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		/*
+		 * Perform SetPGID command processing. We have to request device
+		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
+		 *  requests and evaluate the devstat area on return therefore
+		 *  we don't need a real I/O handler in place.
+		 */
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SPID", pdevstat);
+
+		if (irq_ret == 0)
+			inlreq = 1;
+	} else {
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+
+	}
+
+	if (irq_ret) {
+		return irq_ret;
+	}
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	if (init_IRQ_complete) {
+		spid_ccw = kmalloc (2 * sizeof (ccw1_t), GFP_DMA);
+	} else {
+		spid_ccw = alloc_bootmem_low (2 * sizeof (ccw1_t));
+
+	}
+
+	spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
+	spid_ccw[0].cda = 0;
+	spid_ccw[0].count = 0;
+	spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
+
+	spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
+	spid_ccw[1].cda = (__u32) virt_to_phys (pgid);
+	spid_ccw[1].count = sizeof (pgid_t);
+	spid_ccw[1].flags = CCW_FLAG_SLI;
+
+	pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
+
+	/*
+	 * We now issue a SetPGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
+
+		irq_ret = s390_start_IO (irq, spid_ccw, 0xE2D7C9C4,	/* == SPID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR
+					 | DOIO_TIMEOUT);
+
+		if (!irq_ret) {
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
+
+				CIO_DEBUG(KERN_DEBUG, 2,
+					  "SPID - Device %04X "
+					  "on Subchannel %04X "
+					  "reports pending status, "
+					  "retry : %d\n",
+					  ioinfo[irq]->schib.pmcw.dev, 
+					  irq, retry);
+
+				retry--;
+				irq_ret = -EIO;
+			}
+
+			if (pdevstat->flag == (DEVSTAT_START_FUNCTION
+					       | DEVSTAT_FINAL_STATUS)) {
+				retry = 0;	/* successfully set ... */
+				irq_ret = 0;
+			} else if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.
+				    data[0] & SNS0_CMD_REJECT) {
+					if (mpath) {
+						/*
+						 * We now try single path mode.
+						 * Note we must not issue the suspend
+						 * multipath reconnect, or we will get
+						 * a command reject by tapes.
+						 */
+
+						spid_ccw[0].cmd_code =
+						    CCW_CMD_SET_PGID;
+						spid_ccw[0].cda = (__u32)
+						    virt_to_phys (pgid);
+						spid_ccw[0].count =
+						    sizeof (pgid_t);
+						spid_ccw[0].flags =
+						    CCW_FLAG_SLI;
+
+						pgid->inf.fc =
+						    SPID_FUNC_SINGLE_PATH
+						    | SPID_FUNC_ESTABLISH;
+						mpath = 0;
+						retry--;
+						irq_ret = -EIO;
+					} else {
+						irq_ret = -EOPNOTSUPP;
+						retry = 0;
+
+					}
+				} else {
+
+					CIO_DEBUG(KERN_WARNING, 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--;
+					irq_ret = -EIO;
+
+				}
+
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+
+					CIO_DEBUG_ALWAYS(KERN_WARNING, 2,
+							 "SPID - Device %04X "
+							 "on Subchannel %04X, "
+							 "lpm %02X, "
+							 "became 'not "
+							 "operational'\n",
+							 ioinfo[irq]->schib.
+							 pmcw.dev, 
+							 irq, lpm);
+				}
+
+				retry = 0;
+				ioinfo[irq]->opm &= ~lpm;
+				irq_ret = -EAGAIN;
+
+			}
+		} else if (irq_ret == -ETIMEDOUT) {
+			/* 
+			 * SetPGID timed out, so we cancel it before
+			 * we retry
+			 */
+			int xret;
+
+			xret = cancel_IO(irq);
+
+			if (!xret) 
+				CIO_MSG_EVENT(2,
+					      "SetPGID: sch canceled "
+					      "successfully for irq %x\n",
+					      irq);
+			retry--;
+			
+		} else if (irq_ret != -ENODEV) {
+			retry--;
+			irq_ret = -EIO;
+		} else {
+			retry = 0;
+			irq_ret = -ENODEV;
+
+		}
+
+	} while (retry > 0);
+
+	if (init_IRQ_complete) {
+		kfree (spid_ccw);
+	} else {
+		free_bootmem ((unsigned long) spid_ccw, 2 * sizeof (ccw1_t));
+
+	}
+
+	s390irq_spin_unlock_irqrestore (irq, flags);
+
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return (irq_ret);
+}
+
+/*
+ * s390_SensePGID
+ *
+ * Sense Path Group ID
+ *
+ */
+static int
+s390_SensePGID (int irq, __u8 lpm, pgid_t * pgid)
+{
+	ccw1_t *snid_ccw;	/* ccw area for SNID command */
+	devstat_t devstat;	/* required by request_irq() */
+	devstat_t *pdevstat = &devstat;
+	char dbf_txt[15];
+
+	int irq_ret = 0;	/* return code */
+	int retry = 5;		/* retry count */
+	int inlreq = 0;		/* inline request_irq() */
+	unsigned long flags;
+
+	SANITY_CHECK (irq);
+
+	if (ioinfo[irq]->ui.flags.oper == 0) {
+		return (-ENODEV);
+
+	}
+
+	sprintf (dbf_txt, "SNID%x", irq);
+	CIO_TRACE_EVENT (4, dbf_txt);
+
+	if (!ioinfo[irq]->ui.flags.ready) {
+		/*
+		 * Perform SENSE PGID command processing. We have to request device
+		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
+		 *  requests and evaluate the devstat area on return therefore
+		 *  we don't need a real I/O handler in place.
+		 */
+		irq_ret = request_irq (irq,
+				       init_IRQ_handler,
+				       SA_PROBE, "SNID", pdevstat);
+
+		if (irq_ret == 0)
+			inlreq = 1;
+
+	} else {
+		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+
+	}
+
+	if (irq_ret) {
+		return irq_ret;
+	}
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	if (init_IRQ_complete) {
+		snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+	} else {
+		snid_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+
+	}
+
+	snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
+	snid_ccw->cda = (__u32) virt_to_phys (pgid);
+	snid_ccw->count = sizeof (pgid_t);
+	snid_ccw->flags = CCW_FLAG_SLI;
+
+	/*
+	 * We now issue a SensePGID request. In case of BUSY
+	 *  or STATUS PENDING conditions we retry 5 times.
+	 */
+	do {
+		memset (pdevstat, '\0', sizeof (devstat_t));
+
+		irq_ret = s390_start_IO (irq, snid_ccw, 0xE2D5C9C4,	/* == SNID */
+					 lpm,	/* n/a */
+					 DOIO_WAIT_FOR_INTERRUPT
+					 | DOIO_VALID_LPM
+					 | DOIO_DONT_CALL_INTHDLR);
+
+		if (irq_ret == 0) {
+			if (pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+				/*
+				 * If the device doesn't support the
+				 *  Sense Path Group ID command
+				 *  further retries wouldn't help ...
+				 */
+				if (pdevstat->ii.sense.
+				    data[0] & SNS0_CMD_REJECT) {
+					retry = 0;
+					irq_ret = -EOPNOTSUPP;
+				} else {
+
+					CIO_DEBUG(KERN_WARNING, 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--;
+					irq_ret = -EIO;
+
+				}
+			} else if (pdevstat->flag & DEVSTAT_NOT_OPER) {
+				/* don't issue warnings during startup unless requested */
+				if (init_IRQ_complete || cio_notoper_msg) {
+
+					CIO_DEBUG_ALWAYS(KERN_WARNING, 2,
+							 "SNID - Device %04X "
+							 "on Subchannel %04X, "
+							 "lpm %02X, "
+							 "became 'not "
+							 "operational'\n",
+							 ioinfo[irq]->schib.
+							 pmcw.dev, 
+							 irq, lpm);
+				}
+
+				retry = 0;
+				irq_ret = -EIO;
+
+			} else {
+				retry = 0;	/* success ... */
+				irq_ret = 0;
+
+			}
+		} else if (irq_ret != -ENODEV) {	/* -EIO, or -EBUSY */
+
+			if (pdevstat->flag & DEVSTAT_STATUS_PENDING) {
+
+				CIO_DEBUG(KERN_INFO, 2,
+					  "SNID - Device %04X "
+					  "on Subchannel %04X "
+					  "reports pending status, "
+					  "retry : %d\n",
+					  ioinfo[irq]->schib.pmcw.dev, 
+					  irq, retry);
+			}
+
+			CIO_DEBUG_ALWAYS(KERN_INFO, 2,
+					 "SNID - device %04X,"
+					 " start_io() reports rc : %d,"
+					 " retrying ...\n",
+					 ioinfo[irq]->schib.pmcw.dev, 
+					 irq_ret);
+			retry--;
+			irq_ret = -EIO;
+		} else {	/* -ENODEV ... */
+
+			retry = 0;
+			irq_ret = -ENODEV;
+
+		}
+
+	} while (retry > 0);
+
+	if (init_IRQ_complete) {
+		kfree (snid_ccw);
+	} else {
+		free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t));
+
+	}
+
+	s390irq_spin_unlock_irqrestore (irq, flags);
+
+	/*
+	 * If we installed the irq action handler we have to
+	 *  release it too.
+	 */
+	if (inlreq)
+		free_irq (irq, pdevstat);
+
+	return (irq_ret);
+}
+
+/*
+ * Function: s390_send_nop
+ * 
+ * sends a nop CCW to the specified subchannel down the given path(s)
+ * FIXME: why not put nop_ccw on the stack, it's only 64 bits?
+ */
+int
+s390_send_nop(int irq, __u8 lpm)
+{
+ 	char dbf_txt[15];
+ 	ccw1_t *nop_ccw;
+ 	devstat_t devstat;
+ 	devstat_t *pdevstat = &devstat;
+ 	unsigned long flags;
+	
+ 	int irq_ret = 0;
+ 	int inlreq = 0;
+	
+ 	SANITY_CHECK(irq);
+	
+ 	if (!ioinfo[irq]->ui.flags.oper)
+ 		/* no sense in trying */
+ 		return -ENODEV;
+	
+ 	sprintf(dbf_txt, "snop%x", irq);
+ 	CIO_TRACE_EVENT(5, dbf_txt);
+ 
+ 	if (!ioinfo[irq]->ui.flags.ready) {
+ 		/*
+ 		 * If there's no handler, use our dummy handler.
+ 		 */
+ 		irq_ret = request_irq (irq,
+ 				       init_IRQ_handler,
+ 				       SA_PROBE,
+ 				       "SNOP",
+ 				       pdevstat);
+ 		if (!irq_ret)
+ 			inlreq = 1;
+ 	} else {
+ 		pdevstat = ioinfo[irq]->irq_desc.dev_id;
+ 	}
+ 	
+ 	if (irq_ret)
+ 		return irq_ret;
+ 
+ 	s390irq_spin_lock_irqsave (irq, flags);
+ 
+ 	if (init_IRQ_complete)
+ 		nop_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
+ 	else
+ 		nop_ccw = alloc_bootmem_low (sizeof (ccw1_t));
+ 
+ 	nop_ccw->cmd_code = CCW_CMD_NOOP;
+ 	nop_ccw->cda = 0;
+ 	nop_ccw->count = 0;
+ 	nop_ccw->flags = CCW_FLAG_SLI;
+ 
+ 	memset (pdevstat, '\0', sizeof (devstat_t));
+ 	
+ 	irq_ret = s390_start_IO (irq, nop_ccw, 0xE2D5D6D7, lpm,
+ 				 DOIO_WAIT_FOR_INTERRUPT
+ 				 | DOIO_TIMEOUT
+ 				 | DOIO_DONT_CALL_INTHDLR
+ 				 | DOIO_VALID_LPM);
+ 	
+ 	if (irq_ret == -ETIMEDOUT) {
+ 
+ 		/* better cancel... */
+ 		cancel_IO(irq);
+ 	}
+ 
+ 	if (init_IRQ_complete) 
+ 		kfree (nop_ccw);
+ 	else
+ 		free_bootmem ((unsigned long) nop_ccw, sizeof (ccw1_t));
+ 
+ 	s390irq_spin_unlock_irqrestore (irq, flags);
+ 
+ 	if (inlreq)
+ 		free_irq (irq, pdevstat);
+ 
+ 	return irq_ret;
+ 
+}
+
+EXPORT_SYMBOL (read_conf_data);
+EXPORT_SYMBOL (read_dev_chars);
diff -Nru a/drivers/s390/cio/s390io.h b/drivers/s390/cio/s390io.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/cio/s390io.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,20 @@
+#ifndef S390_S390IO_H
+#define S390_S390IO_H
+
+extern __u64 chpids_logical[4];
+
+/* cio_show_msg is needed in chsc.c */
+extern int cio_show_msg;
+
+/* cio_count_irqs is used in proc.c and cio.c */
+extern int cio_count_irqs;
+extern unsigned long s390_irq_count[NR_CPUS];
+extern irb_t p_init_irb;
+
+extern void s390_device_recognition_irq (int irq);
+extern int s390_validate_subchannel (int irq, int enable);
+extern int s390_DevicePathVerification (int irq, __u8 usermask);
+
+extern int s390_send_nop(int irq, __u8 lpm);
+
+#endif
diff -Nru a/drivers/s390/idals.c b/drivers/s390/idals.c
--- a/drivers/s390/idals.c	Sat Jun  8 22:31:51 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,43 +0,0 @@
-/* 
-   * File...........: linux/drivers/s390x/idals.c
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
-   * 12/13/00 changed IDALs to 4kByte-IDALs
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/slab.h>
-
-#include <asm/irq.h>
-#include <asm/idals.h>
-
-#ifdef CONFIG_ARCH_S390X
-
-unsigned long __create_idal (unsigned long address, int count)
-{
-	int nridaws;
-	unsigned long *idal, *tmp;
-
-        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
-		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
-	idal = idal_alloc(nridaws);
-	if (idal != NULL) {
-		tmp = idal;
-		*tmp++ = address;
-		address &= -IDA_BLOCK_SIZE;
-		while (--nridaws > 0) {
-			address += IDA_BLOCK_SIZE;
-			*tmp++ = address;
-		}
-	}
-	return (unsigned long) idal;
-}
-
-EXPORT_SYMBOL (__create_idal);
-
-#endif
diff -Nru a/drivers/s390/misc/chandev.c b/drivers/s390/misc/chandev.c
--- a/drivers/s390/misc/chandev.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/misc/chandev.c	Sat Jun  8 22:31:37 2002
@@ -132,7 +132,7 @@
 };
 
 
-chandev_irqinfo *chandev_irqinfo_head=NULL;
+static chandev_irqinfo *chandev_irqinfo_head=NULL;
 
 typedef struct chandev_parms chandev_parms;
 struct chandev_parms
@@ -146,7 +146,7 @@
 
 static chandev_type chandev_persistent=0; 
 
-chandev_parms *chandev_parms_head=NULL;
+static chandev_parms *chandev_parms_head=NULL;
 
 
 typedef struct chandev_activelist chandev_activelist;
@@ -179,6 +179,7 @@
 static chandev_probelist *chandev_probelist_head=NULL;
 static chandev_activelist *chandev_activelist_head=NULL;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+/* not static, see comment in chandev.h */
 int chandev_use_devno_names=FALSE;
 #endif
 static int chandev_cautious_auto_detect=TRUE;
@@ -324,9 +325,9 @@
 static qheader chandev_not_oper_head={NULL,NULL};
 static spinlock_t           chandev_not_oper_spinlock;
 
-#define chandev_interrupt_check() \
+#define chandev_interrupt_check(name) \
 if(in_interrupt())                \
-     printk(KERN_WARNING __FUNCTION__ " called under interrupt this shouldn't happen\n")
+     printk(KERN_WARNING name " called under interrupt this shouldn't happen\n")
 
 
 #define for_each(variable,head) \
@@ -343,7 +344,7 @@
 static void chandev_lock(void)
 {
 	eieio();
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_lock");
 	if(chandev_lock_owner!=(long)current)
 	{
 		while(!spin_trylock(&chandev_spinlock))
@@ -397,7 +398,7 @@
 
 
 
-void *chandev_alloc(size_t size)
+static void *chandev_alloc(size_t size)
 {
 	void *mem=kmalloc(size,GFP_ATOMIC);
 	if(mem)
@@ -441,7 +442,7 @@
 
 
 
-void chandev_free_listmember(list **listhead,list *member)
+static void chandev_free_listmember(list **listhead,list *member)
 {
 	chandev_lock();
 	if(member)
@@ -455,7 +456,7 @@
 	chandev_unlock();
 }
 
-void chandev_free_queuemember(qheader *qhead,queue *member)
+static void chandev_free_queuemember(qheader *qhead,queue *member)
 {
 	chandev_lock();
 	if(member)
@@ -471,7 +472,7 @@
 
 
 
-void chandev_free_all_list(list **listhead)
+static void chandev_free_all_list(list **listhead)
 {
 	list *head;
 
@@ -481,7 +482,7 @@
 	chandev_unlock();
 }
 
-void chandev_free_all_queue(qheader *qhead)
+static void chandev_free_all_queue(qheader *qhead)
 {
 	chandev_lock();
 	while(qhead->head)
@@ -542,6 +543,7 @@
 					argc+=3;
 					break;
 				default:
+					break;
 				}
 				if(have_tag[tagidx]==FALSE)
 					argc++;
@@ -603,7 +605,7 @@
 }
 
 
-void *chandev_allocstr(const char *str,size_t offset)
+static void *chandev_allocstr(const char *str,size_t offset)
 {
 	char *member;
 
@@ -658,7 +660,7 @@
 
 
 
-int chandev_oper_func(int irq,devreg_t *dreg)
+static int chandev_oper_func(int irq,devreg_t *dreg)
 {
 	chandev_last_machine_check=jiffies;
 	if(atomic_dec_and_test(&chandev_msck_thread_lock))
@@ -692,7 +694,7 @@
 		       irq,status);
 }
 
-chandev_irqinfo *chandev_get_irqinfo_by_irq(int irq)
+static chandev_irqinfo *chandev_get_irqinfo_by_irq(int irq)
 {
 	chandev_irqinfo *curr_irqinfo;
 	for_each(curr_irqinfo,chandev_irqinfo_head)
@@ -701,7 +703,7 @@
 	return(NULL);
 }
 
-chandev *chandev_get_by_irq(int irq)
+static chandev *chandev_get_by_irq(int irq)
 {
 	chandev *curr_chandev;
 
@@ -713,7 +715,7 @@
 	return(NULL);
 }
 
-chandev_activelist *chandev_get_activelist_by_irq(int irq)
+static chandev_activelist *chandev_get_activelist_by_irq(int irq)
 {
 	chandev_activelist *curr_device;
 
@@ -728,7 +730,7 @@
 }
 
 
-void chandev_remove_irqinfo_by_irq(unsigned int irq)
+static void chandev_remove_irqinfo_by_irq(unsigned int irq)
 {
 	chandev_irqinfo *remove_irqinfo;
 	chandev_activelist *curr_device;
@@ -762,7 +764,7 @@
 	
 }
 
-int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
+static int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
 {
 	schib_t *new_schib;
 	
@@ -849,7 +851,7 @@
 }
 
 /* This should be safe even if chandev_free_irq is already called by the device */
-void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
+static void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
 {
 	if(irqinfo)
 		chandev_free_irq(irqinfo->sch.irq,irqinfo->dev_id);
@@ -857,7 +859,7 @@
 
 
 
-void chandev_sprint_type_model(char *buff,s32 type,s16 model)
+static void chandev_sprint_type_model(char *buff,s32 type,s16 model)
 {
 	if(type==-1)
 		strcpy(buff,"    *    ");
@@ -870,13 +872,13 @@
 		sprintf(buff," 0x%02x  ",(int)model);
 }
 
-void chandev_sprint_devinfo(char *buff,s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
+static void chandev_sprint_devinfo(char *buff,s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
 {
 	chandev_sprint_type_model(buff,cu_type,cu_model);
 	chandev_sprint_type_model(&buff[strlen(buff)],dev_type,dev_model);
 }
 
-void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
+static void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
 {
 	chandev_parms      *curr_parms,*next_parms;
 
@@ -892,7 +894,7 @@
 }
 
 
-void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
+static void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
 {
 	chandev_parms      *parms;
 
@@ -988,18 +990,18 @@
 }
 
 
-void chandev_remove(chandev *member)
+static void chandev_remove(chandev *member)
 {
 	chandev_free_queuemember(&chandev_head,(queue *)member);
 }
 
 
-void chandev_remove_all(void)
+static void chandev_remove_all(void)
 {
 	chandev_free_all_queue(&chandev_head);
 }
 
-void chandev_remove_model(chandev_model_info *model)
+static void chandev_remove_model(chandev_model_info *model)
 {
 	chandev *curr_chandev,*next_chandev;
 
@@ -1013,7 +1015,7 @@
 	chandev_unlock();
 }
 
-void chandev_remove_all_models(void)
+static void chandev_remove_all_models(void)
 {
 	chandev_lock();
 	while(chandev_models_head)
@@ -1057,10 +1059,13 @@
 	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);
+
+	/* ficon attached ctc */
+	chandev_add_model(chandev_type_escon,0x3088,0x1E,-1,-1,0,default_msck_bits,FALSE,FALSE);
 }
 
 
-void chandev_del_noauto(u16 devno)
+static void chandev_del_noauto(u16 devno)
 {
 	chandev_noauto_range *curr_noauto,*next_noauto;
 	chandev_lock();
@@ -1070,7 +1075,7 @@
 	chandev_unlock();
 }
 
-void chandev_del_msck(u16 devno)
+static void chandev_del_msck(u16 devno)
 {
 	chandev_msck_range *curr_msck_range,*next_msck_range;
 	chandev_lock();
@@ -1081,7 +1086,8 @@
 }
 
 
-void chandev_add(s390_dev_info_t  *newdevinfo,chandev_model_info *newmodelinfo)
+static void chandev_add(s390_dev_info_t  *newdevinfo,
+			chandev_model_info *newmodelinfo)
 {
 	chandev *new_chandev=NULL;
 
@@ -1100,7 +1106,7 @@
 	}
 }
 
-void chandev_unregister_probe(chandev_probefunc probefunc)
+static void chandev_unregister_probe(chandev_probefunc probefunc)
 {
 	chandev_probelist *curr_probe,*next_probe;
 
@@ -1112,7 +1118,7 @@
 	chandev_unlock();
 }
 
-void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
+static void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
 {
 	chandev_probelist *curr_probe,*next_probe;
 
@@ -1126,7 +1132,7 @@
 
 
 
-void chandev_reset(void)
+static void chandev_reset(void)
 {
 	chandev_lock();
 	chandev_remove_all_models();
@@ -1142,7 +1148,8 @@
 }
 
 
-int chandev_is_chandev(int irq,s390_dev_info_t *devinfo,chandev_force **forceinfo,chandev_model_info **ret_model)
+static 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;
@@ -1192,7 +1199,7 @@
 	return(retval);
 }
 
-void chandev_collect_devices(void)
+static void chandev_collect_devices(void)
 {
 	int curr_irq,loopcnt=0;
 	s390_dev_info_t   curr_devinfo;
@@ -1220,9 +1227,12 @@
 	}
 }
 
-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)
+static 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;
 	
@@ -1270,7 +1280,7 @@
 	return(0);
 }
 
-void chandev_del_force(int read_lo_devno)
+static void chandev_del_force(int read_lo_devno)
 {
 	chandev_force *curr_force,*next_force;
 	
@@ -1285,7 +1295,7 @@
 }
 
 
-void chandev_shutdown(chandev_activelist *curr_device)
+static void chandev_shutdown(chandev_activelist *curr_device)
 {
 	int err=0;
 	chandev_lock();
@@ -1319,12 +1329,12 @@
 	chandev_unlock();
 }
 
-void chandev_shutdown_all(void)
+static void chandev_shutdown_all(void)
 {
 	while(chandev_activelist_head)
 		chandev_shutdown(chandev_activelist_head);
 }
-void chandev_shutdown_by_name(char *devname)
+static void chandev_shutdown_by_name(char *devname)
 {
 	chandev_activelist *curr_device;
 
@@ -1352,7 +1362,7 @@
 	return(NULL);
 }
 
-void chandev_shutdown_by_devno(u16 devno)
+static void chandev_shutdown_by_devno(u16 devno)
 {
 	chandev_activelist *curr_device;
 
@@ -1364,7 +1374,7 @@
 }
 
 
-int chandev_pack_args(char *str)
+static int chandev_pack_args(char *str)
 {
 	char *newstr=str,*next;
 	int strcnt=1;
@@ -1404,7 +1414,7 @@
 	iscomma=4,
 } chandev_strval;
 
-chandev_strval chandev_strcmp(char *teststr,char **str,long *endlong)
+static chandev_strval chandev_strcmp(char *teststr,char **str,long *endlong)
 {
 	char *cur;
 	chandev_strval  retval=isnull;
@@ -1434,7 +1444,7 @@
 {
 	chandev_activelist *newdevice,*curr_device;
 
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_initdevice");
 	if(probeinfo->newdevice!=NULL)
 	{
 		printk("probeinfo->newdevice!=NULL in chandev_initdevice for %s",devname);
@@ -1504,12 +1514,11 @@
 							char numbuff[10];
 							sprintf(numbuff,"%d",idx);
 							if(strcmp(&curr_device->devname[len],numbuff)==0)
-								goto next_idx;
+								continue;
 						}
 					}
 					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);
@@ -1526,13 +1535,15 @@
 }
 
 #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))
+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))
+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)
@@ -1543,7 +1554,7 @@
 #endif
 	
 
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_init_netdev");
 	if (!init_netdevfunc) 
 	{
 		printk("init_netdevfunc=NULL in chandev_init_netdev, it should not be valid.\n");
@@ -1614,7 +1625,7 @@
 		printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
 		return NULL;
 	}
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_initnetdevice");
 	retdevice=chandev_init_netdev(probeinfo,basename,dev,sizeof_priv,init_netdevfunc);
 	if (retdevice) 
 	{
@@ -1635,12 +1646,14 @@
 }
 
 
-int chandev_compare_chpid_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+static 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)
+static 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)||
@@ -1648,7 +1661,8 @@
 		(chan1->dev_model != chan2->dev_model));
 }
 
-int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+static int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,
+					   chandev_subchannel_info *chan2)
 {
 	return((chan1->devno == chan2->devno) &&
 	       (chan1->cu_type == chan2->cu_type) &&
@@ -1660,8 +1674,8 @@
 }
 
 
-int chandev_doprobe(chandev_force *force,chandev *read,
-chandev *write,chandev *data)
+static int chandev_doprobe(chandev_force *force,chandev *read,
+			   chandev *write,chandev *data)
 {
 	chandev_probelist *probe;
 	chandev_model_info *model_info;
@@ -1793,7 +1807,7 @@
 }
 
 
-int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
+static int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
 {
 	int retval=s390_request_irq_special(irqinfo->sch.irq,
 				   irqinfo->handler,
@@ -1809,14 +1823,15 @@
 	return(retval);
 }
 
-void chandev_irqallocerr(chandev_irqinfo *irqinfo,int err)
+static void chandev_irqallocerr(chandev_irqinfo *irqinfo,int 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)
+static void chandev_call_notification_func(chandev_activelist *curr_device,
+					   chandev_irqinfo *curr_irqinfo,
+					   chandev_msck_status prevstatus)
 {
 	if(curr_irqinfo->msck_status!=prevstatus)
 	{
@@ -1850,9 +1865,10 @@
 	}
 }
 
-int chandev_find_eligible_channels(chandev *first_chandev_to_check,
-			       chandev **read,chandev **write,chandev **data,chandev **next,
-				   chandev_type chan_type)
+static 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;
@@ -1917,7 +1933,7 @@
 	return(eligible_found);
 }
 
-chandev *chandev_get_free_chandev_by_devno(int devno)
+static chandev *chandev_get_free_chandev_by_devno(int devno)
 {
 	chandev *curr_chandev;
 	if(devno==-1)
@@ -1934,7 +1950,7 @@
 
 }
 
-void chandev_probe(void)
+static void chandev_probe(void)
 {
 	chandev *read_chandev,*write_chandev,*data_chandev,*curr_chandev,*next_chandev;
 	chandev_force *curr_force;
@@ -1948,7 +1964,7 @@
 	chandev_msck_range *curr_msck_range;
 
 
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_probe");
 	chandev_read_conf_if_necessary();
 	chandev_collect_devices();
 	chandev_lock();
@@ -2264,7 +2280,7 @@
 	last_stridx,
 } chandev_str_enum;
 
-void chandev_add_noauto(u16 lo_devno,u16 hi_devno)
+static void chandev_add_noauto(u16 lo_devno,u16 hi_devno)
 {
 	chandev_noauto_range *new_range;
 
@@ -2277,7 +2293,8 @@
 }
 
 
-void chandev_add_msck_range(u16 lo_devno,u16 hi_devno,int auto_msck_recovery)
+static void chandev_add_msck_range(u16 lo_devno,u16 hi_devno,
+				   int auto_msck_recovery)
 {
 	chandev_msck_range *new_range;
 
@@ -2761,7 +2778,7 @@
 	}
 }
 
-int chandev_do_setup(int in_read_conf,char *buff,int size)
+static int chandev_do_setup(int in_read_conf,char *buff,int size)
 {
 	int curr,comment=FALSE,newline=FALSE,oldnewline=TRUE;
 	char *startline=NULL,*endbuff=&buff[size];
@@ -2864,7 +2881,7 @@
 if(currlen>=length)                          \
        goto exitchan;
 
-void sprintf_msck(char *buff,int auto_msck_recovery)
+static void sprintf_msck(char *buff,int auto_msck_recovery)
 {
 	chandev_msck_status idx;
 	int first_time=TRUE;
@@ -3092,7 +3109,7 @@
 				chandevs_detected=TRUE;
 				if(pass)
 				{
-					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",
+					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_force ? curr_force->chan_type : 
 						       ( curr_model ? curr_model->chan_type : 
@@ -3148,21 +3165,19 @@
 	int         rc;
 	char        *buff;
 	
-	buff=vmalloc(count+1);
-	if(buff)
-	{
-		rc = copy_from_user(buff,buffer,count) ? -EFAULT : 0;
-		if (rc)
-			goto chandev_write_exit;
+	if ((buff=vmalloc(count+1)) == 0)
+		return -ENOMEM;
+	
+	if (copy_from_user(buff,buffer,count) == 0) {
 		chandev_do_setup(FALSE,buff,count);
 		rc=count;
-	chandev_write_exit:
-		vfree(buff);
-		return rc;
+	} else {
+		rc=-EFAULT;
 	}
-	else
-		return -ENOMEM;
-	return(0);
+
+	vfree(buff);
+
+	return rc;
 }
 
 static void __init chandev_create_proc(void)
@@ -3219,7 +3234,7 @@
 	/* Avoid chicked & egg situations where we may be called before we */
 	/* are initialised. */
 
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_register_and_probe");
 	if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_initialised))
 		chandev_init();
 	chandev_lock();
@@ -3252,7 +3267,7 @@
 	chandev_probelist *curr_probe;
 	chandev_activelist *curr_device,*next_device;
 	
-	chandev_interrupt_check();
+	chandev_interrupt_check("chandev_unregister");
 	chandev_lock();
 	for_each(curr_probe,chandev_probelist_head)
 	{
@@ -3281,9 +3296,12 @@
 EXPORT_SYMBOL(chandev_initdevice);
 EXPORT_SYMBOL(chandev_build_device_name);
 EXPORT_SYMBOL(chandev_initnetdevice);
+/* see chandev.h as to why this is exported */
 EXPORT_SYMBOL(chandev_init_netdev);
 EXPORT_SYMBOL(chandev_use_devno_names);
 EXPORT_SYMBOL(chandev_free_irq);
+/* see chandev.h as to why chandev_add_model and chandev_del_model 
+ * are exported */
 EXPORT_SYMBOL(chandev_add_model);
 EXPORT_SYMBOL(chandev_del_model);
 EXPORT_SYMBOL(chandev_persist);
diff -Nru a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
--- a/drivers/s390/net/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/net/Makefile	Sat Jun  8 22:31:37 2002
@@ -6,8 +6,10 @@
 
 ctc-objs := ctcmain.o ctctty.o
 
-obj-y += iucv.o fsm.o
-obj-$(CONFIG_CTC) += ctc.o
+obj-$(CONFIG_IUCV) += iucv.o fsm.o
+obj-$(CONFIG_CTC) += ctc.o fsm.o
 obj-$(CONFIG_IUCV) += netiucv.o
+obj-$(CONFIG_LCS) += lcs.o
 
 include $(TOPDIR)/Rules.make
+
diff -Nru a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
--- a/drivers/s390/net/ctcmain.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/net/ctcmain.c	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.51 2001/09/24 10:38:02 mschwide Exp $
+ * $Id: ctcmain.c,v 1.55 2001/12/03 14:28:45 felfert Exp $
  *
  * CTC / ESCON network driver
  *
@@ -35,7 +35,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.51 $
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.55 $
  *
  */
 
@@ -87,7 +87,9 @@
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
 MODULE_LICENSE("GPL");
+#endif
 #ifndef CTC_CHANDEV
 MODULE_PARM(ctc, "s");
 MODULE_PARM_DESC(ctc,
@@ -343,7 +345,7 @@
 static __inline__ void ctc_clear_busy(net_device *dev)
 {
 	clear_bit(0, &(((ctc_priv *)dev->priv)->tbusy));
-	netif_start_queue(dev);
+	netif_wake_queue(dev);
 }
 
 static __inline__ int ctc_test_and_set_busy(net_device *dev)
@@ -359,7 +361,7 @@
  */
 static void print_banner(void) {
 	static int printed = 0;
-	char vbuf[] = "$Revision: 1.51 $";
+	char vbuf[] = "$Revision: 1.55 $";
 	char *version = vbuf;
 
 	if (printed)
@@ -370,7 +372,16 @@
 			*p = '\0';
 	} else
 		version = " ??? ";
-	printk(KERN_INFO "CTC driver Version%s initialized\n", version);
+	printk(KERN_INFO
+	       "CTC driver Version%swith"
+#ifndef CTC_CHANDEV
+	       "out"
+#endif
+	       " CHANDEV support"
+#ifdef DEBUG
+	       " (DEBUG-VERSION, " __DATE__ __TIME__ ")"
+#endif
+	       " initialized\n", version);
 	printed = 1;
 }
 
@@ -728,12 +739,13 @@
 		pskb->protocol = ntohs(header->type);
 		header->length -= LL_HEADER_LENGTH;
 		if ((header->length == 0) ||
-		    (header->length > skb_tailroom(pskb))) {
+		    (header->length > skb_tailroom(pskb)) ||
+		    (header->length > len)) {
 			printk(KERN_WARNING
 			       "%s Illegal packet size %d "
-			       "received (MTU=%d), "
+			       "received (MTU=%d blocklen=%d), "
 			       "dropping\n", dev->name, header->length,
-			       dev->mtu);
+			       dev->mtu, len);
 #ifdef DEBUG
 			ctc_dump_skb(pskb, -6);
 #endif
@@ -773,6 +785,7 @@
 			ctc_tty_netif_rx(skb);
 		else
 			netif_rx(skb);
+#warning FIXME: [kj] Net drivers should set dev->last_rx immediately after netif_rx
 		privptr->stats.rx_packets++;
 		privptr->stats.rx_bytes += skb->len;
 		if (len > 0) {
@@ -903,7 +916,8 @@
 		if (ch->trans_skb != NULL)
 			dev_kfree_skb(ch->trans_skb);
 		clear_normalized_cda(&ch->ccw[1]);
-		ch->trans_skb = dev_alloc_skb(ch->max_bufsize);
+		ch->trans_skb = __dev_alloc_skb(ch->max_bufsize,
+						GFP_ATOMIC|GFP_DMA);
 		if (ch->trans_skb == NULL) {
 			if (warn)
 				printk(KERN_WARNING
@@ -914,8 +928,7 @@
 			return -ENOMEM;
 		}
 		ch->ccw[1].count = ch->max_bufsize;
-		if (set_normalized_cda(&ch->ccw[1],
-				       virt_to_phys(ch->trans_skb->data))) {
+		if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) {
 			dev_kfree_skb(ch->trans_skb);
 			ch->trans_skb = NULL;
 			if (warn)
@@ -1000,7 +1013,6 @@
 			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))) {
@@ -1013,11 +1025,10 @@
 			i++;
 		}
 		ch->collect_len = 0;
+		spin_unlock(&ch->collect_lock);
+		ch->ccw[1].count = ch->trans_skb->len;
 		fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 		ch->prof.send_stamp = xtime;
-#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) {
@@ -1026,10 +1037,11 @@
 			fsm_deltimer(&ch->timer);
 			ccw_check_return_code(ch, rc);
 		}
-	} else
+	} else {
+		spin_unlock(&ch->collect_lock);
 		fsm_newstate(fi, CH_STATE_TXIDLE);
+	}
 	ctc_clear_busy(dev);
-	spin_unlock(&ch->collect_lock);
 }
 
 /**
@@ -1120,9 +1132,6 @@
 	if (ctc_checkalloc_buffer(ch, 1))
 		return;
 	ch->ccw[1].count = ch->max_bufsize;
-#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);
@@ -1177,9 +1186,6 @@
 	*((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
 	ch->ccw[1].count = 2; /* Transfer only length */
 
-#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);
@@ -1228,9 +1234,6 @@
 			return;
 		ch->ccw[1].count = ch->max_bufsize;
 		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);
@@ -1674,8 +1677,7 @@
 
 			clear_normalized_cda(&ch->ccw[4]);
 			ch->ccw[4].count = skb->len;
-			if (set_normalized_cda(&ch->ccw[4],
-					       virt_to_phys(skb->data))) {
+			if (set_normalized_cda(&ch->ccw[4], skb->data)) {
 				printk(KERN_DEBUG "%s: IDAL alloc failed, "
 				       "restarting channel\n", dev->name);
 				fsm_event(((ctc_priv *)dev->priv)->fsm,
@@ -1686,9 +1688,6 @@
 			fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
 			if (event == CH_EVENT_TIMER)
 				s390irq_spin_lock_irqsave(ch->irq, saveflags);
-#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,
@@ -2449,6 +2448,8 @@
 	} else {
 		__u16 block_len;
 		int ccw_idx;
+		struct sk_buff *nskb;
+		unsigned long hi;
 
 		/**
 		 * Protect skb against beeing free'd by upper
@@ -2463,8 +2464,30 @@
 		       LL_HEADER_LENGTH);
 		block_len = skb->len + 2;
 		*((__u16 *)skb_push(skb, 2)) = block_len;
+
+		/**
+		 * IDAL support in CTC is broken, so we have to
+		 * care about skb's above 2G ourselves.
+		 */
+		hi = ((unsigned long)skb->tail + LL_HEADER_LENGTH) >> 31;
+		if (hi) {
+			nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA);
+			if (!nskb) {
+				atomic_dec(&skb->users);
+				skb_pull(skb, LL_HEADER_LENGTH + 2);
+				return -ENOMEM;
+			} else {
+				memcpy(skb_put(nskb, skb->len),
+				       skb->data, skb->len);
+				atomic_inc(&nskb->users);
+				atomic_dec(&skb->users);
+				dev_kfree_skb_irq(skb);
+				skb = nskb;
+			}
+		}
+
 		ch->ccw[4].count = block_len;
-		if (set_normalized_cda(&ch->ccw[4], virt_to_phys(skb->data))) {
+		if (set_normalized_cda(&ch->ccw[4], skb->data)) {
 			/**
 			 * idal allocation failed, try via copying to
 			 * trans_skb. trans_skb usually has a pre-allocated
@@ -2475,6 +2498,7 @@
 				 * Remove our header. It gets added
 				 * again on retransmit.
 				 */
+				atomic_dec(&skb->users);
 				skb_pull(skb, LL_HEADER_LENGTH + 2);
 				return -EBUSY;
 			}
@@ -2492,18 +2516,11 @@
 			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);
 		s390irq_spin_lock_irqsave(ch->irq, saveflags);
 		ch->prof.send_stamp = xtime;
-#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);
 		if (ccw_idx == 3)
@@ -3684,7 +3701,7 @@
  *
  * @return 0 on success, !0 on error.
  */
-int ctc_init(void) {
+static int ctc_init(void) {
 #ifndef CTC_CHANDEV
 	int   cnt[2];
 	int   itype;
diff -Nru a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
--- a/drivers/s390/net/ctctty.c	Sat Jun  8 22:31:49 2002
+++ b/drivers/s390/net/ctctty.c	Sat Jun  8 22:31:49 2002
@@ -114,7 +114,7 @@
 static char *ctc_ttyname = CTC_TTY_NAME;
 #endif
 
-char *ctc_tty_revision = "$Revision: 1.8 $";
+static char *ctc_tty_revision = "$Revision: 1.8 $";
 
 static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
 static int ctc_tty_shuttingdown = 0;
@@ -358,12 +358,12 @@
 #ifdef MODEM_PARANOIA_CHECK
 	if (!info) {
 		printk(KERN_WARNING "ctc_tty: null info_struct for (%d, %d) in %s\n",
-		       MAJOR(device), MINOR(device), routine);
+		       major(device), minor(device), routine);
 		return 1;
 	}
 	if (info->magic != CTC_ASYNC_MAGIC) {
 		printk(KERN_WARNING "ctc_tty: bad magic for info struct (%d, %d) in %s\n",
-		       MAJOR(device), MINOR(device), routine);
+		       major(device), minor(device), routine);
 		return 1;
 	}
 #endif
@@ -596,6 +596,7 @@
 	ctc_tty_info *info;
 	unsigned long flags;
 
+#warning FIXME [kj] Consider using spinlocks.
 	save_flags(flags);
 	cli();
 	if (!tty) {
@@ -906,6 +907,7 @@
 	if (tty_hung_up_p(filp) ||
 	    (info->flags & CTC_ASYNC_CLOSING)) {
 		if (info->flags & CTC_ASYNC_CLOSING)
+#warning: FIXME [kj] Using sleep_on derivative, is racy. consider using wait_event instead
 			interruptible_sleep_on(&info->close_wait);
 #ifdef MODEM_DO_RESTART
 		if (info->flags & CTC_ASYNC_HUP_NOTIFY)
@@ -1003,7 +1005,7 @@
 	int retval,
 	 line;
 
-	line = MINOR(tty->device) - tty->driver.minor_start;
+	line = minor(tty->device) - tty->driver.minor_start;
 	if (line < 0 || line > CTC_TTY_MAX_DEVICES)
 		return -ENODEV;
 	info = &driver->info[line];
diff -Nru a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c
--- a/drivers/s390/net/fsm.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/s390/net/fsm.c	Sat Jun  8 22:31:43 2002
@@ -195,6 +195,7 @@
 	return 0;
 }
 
+/* FIXME: this function is never used, why */
 void
 fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
 {
diff -Nru a/drivers/s390/net/fsm.h b/drivers/s390/net/fsm.h
--- a/drivers/s390/net/fsm.h	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/net/fsm.h	Sat Jun  8 22:31:36 2002
@@ -1,4 +1,4 @@
-/* $Id: fsm.h,v 1.3 2001/06/18 16:49:19 felfert Exp $
+/* $Id: fsm.h,v 1.4 2001/09/24 10:38:02 mschwide Exp $
  */
 #ifndef _FSM_H_
 #define _FSM_H_
diff -Nru a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
--- a/drivers/s390/net/iucv.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/s390/net/iucv.c	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,5 @@
-/*
- * $Id$
+/* 
+ * $Id: iucv.c,v 1.32 2002/02/12 21:52:20 felfert Exp $
  *
  * IUCV network driver
  *
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV lowlevel driver $Revision$
+ * RELEASE-TAG: IUCV lowlevel driver $Revision: 1.32 $
  *
  */
 
@@ -51,7 +51,7 @@
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
 
-#undef DEBUG
+#define DEBUG
 
 /* FLAGS:
  * All flags are defined in the field IPFLAGS1 of each function
@@ -96,10 +96,10 @@
 	iucv_GeneralInterrupt data;
 } iucv_irqdata;
 
-struct list_head  iucv_irq_queue;
+static struct list_head  iucv_irq_queue;
 static spinlock_t iucv_irq_queue_lock = SPIN_LOCK_UNLOCKED;
 
-struct tq_struct  iucv_tq;
+static struct tq_struct  iucv_tq;
 
 static atomic_t   iucv_bh_scheduled = ATOMIC_INIT (0);
 
@@ -165,6 +165,10 @@
  * declare_flag: is 0 when iucv_declare_buffer has not been called
  */
 static int declare_flag;
+/**
+ * register_flag: is 0 when external interrupt has not been registered
+ */
+static int register_flag;
 
 /****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
 /* Data struct 1: iparml_control
@@ -271,37 +275,56 @@
 
 static iucv_param * iucv_param_pool;
 
+MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
+MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE("GPL");
+#endif
+
 /*
  * Debugging stuff
  *******************************************************************************/
 
+
 #ifdef DEBUG
+static int debuglevel = 0;
+
+MODULE_PARM(debuglevel, "i");
+MODULE_PARM_DESC(debuglevel,
+ "Specifies the debug level (0=off ... 3=all)");
 
 static void
-iucv_dumpit(void *buf, int len)
+iucv_dumpit(char *title, void *buf, int len)
 {
 	int i;
 	__u8 *p = (__u8 *)buf;
 
-	printk(KERN_DEBUG "  ");
+	if (debuglevel < 3)
+		return;
+
+	printk(KERN_DEBUG __FUNCTION__ ": %s\n", title);
+	printk("  ");
 	for (i = 0; i < len; i++) {
 		if (!(i % 16) && i != 0)
 			printk ("\n  ");
 		else if (!(i % 4) && i != 0)
-			printk (" ");
-		printk ("%02X", *p++);
+			printk(" ");
+		printk("%02X", *p++);
 	}
 	if (len % 16)
 		printk ("\n");
 	return;
 }
-#define iucv_debug(fmt, args...) \
-printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args);
+#define iucv_debug(lvl, fmt, args...) \
+do { \
+	if (debuglevel >= lvl) \
+		printk(KERN_DEBUG __FUNCTION__ ": " fmt "\n" , ## args); \
+} while (0)
 
 #else
 
-#define iucv_debug(fmt, args...)
-#define iucv_dumpit(buf, len)
+#define iucv_debug(lvl, fmt, args...)
+#define iucv_dumpit(title, buf, len)
 
 #endif
 
@@ -310,6 +333,25 @@
  *******************************************************************************/
 
 /**
+ * print start banner
+ */
+static void
+iucv_banner(void)
+{
+	char vbuf[] = "$Revision: 1.32 $";
+	char *version = vbuf;
+
+	if ((version = strchr(version, ':'))) {
+		char *p = strchr(version + 1, '$');
+		if (p)
+			*p = '\0';
+	} else
+		version = " ??? ";
+	printk(KERN_INFO
+	       "IUCV lowlevel driver Version%s initialized\n", version);
+}
+
+/**
  * iucv_init - Initialization
  *
  * Allocates and initializes various data structures.
@@ -354,10 +396,26 @@
 	/* Initialize handler table */
 	INIT_LIST_HEAD(&iucv_handler_table);
 
+	iucv_banner();
 	return 0;
 }
 
 /**
+ * iucv_exit - De-Initialization
+ *
+ * Frees everything allocated from iucv_init.
+ */
+static void
+iucv_exit(void)
+{
+	if (iucv_external_int_buffer)
+		kfree(iucv_external_int_buffer);
+	if (iucv_param_pool)
+		kfree(iucv_param_pool);
+	printk(KERN_INFO "IUCV lowlevel driver unloaded\n");
+}
+
+/**
  * grab_param: - Get a parameter buffer from the pre-allocated pool.
  *
  * This function searches for an unused element in the the pre-allocated pool
@@ -410,8 +468,8 @@
 {
 	ulong flags;
 
-	iucv_debug("entering");
-	iucv_dumpit(new, sizeof(handler));
+	iucv_debug(1, "entering");
+	iucv_dumpit("handler:", new, sizeof(handler));
 
 	spin_lock_irqsave (&iucv_lock, flags);
 	if (!list_empty(&iucv_handler_table)) {
@@ -424,7 +482,7 @@
 		list_for_each(lh, &iucv_handler_table) {
 			handler *h = list_entry(lh, handler, list);
 			if (memcmp(&new->id, &h->id, sizeof(h->id)) == 0) {
-				iucv_debug("ret 1");
+				iucv_debug(1, "ret 1");
 				spin_unlock_irqrestore (&iucv_lock, flags);
 				return 1;
 			}
@@ -437,35 +495,11 @@
 	list_add(&new->list, &iucv_handler_table);
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return 0;
 }
 
 /**
- * iucv_remove_handler:
- * @users_handler: handler to be removed
- *
- * Remove handler when application unregisters.
- */
-static void
-iucv_remove_handler(handler *handler)
-{
-	unsigned long flags;
-
-	if ((!iucv_pathid_table) || (!handler))
-		return;
-
-	iucv_debug("entering");
-
-	spin_lock_irqsave (&iucv_lock, flags);
-	list_del(&handler->list);
-	spin_unlock_irqrestore (&iucv_lock, flags);
-
-	iucv_debug("exiting");
-	return;
-}
-
-/**
  * b2f0:
  * @code: identifier of IUCV call to CP.
  * @parm: pointer to 40 byte iparml area passed to CP
@@ -477,8 +511,7 @@
 static __inline__ ulong
 b2f0(__u32 code, void *parm)
 {
-	iucv_debug("iparml before b2f0 call:");
-	iucv_dumpit(parm, sizeof(iucv_param.param));
+	iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
 
 	asm volatile (
 		"LRA   1,0(%1)\n\t"
@@ -489,8 +522,7 @@
 		: "0", "1"
 		);
 
-	iucv_debug("iparml after b2f0 call:");
-	iucv_dumpit(parm, sizeof(iucv_param.param));
+	iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
 
 	return (unsigned long)*((__u8 *)(parm + 3));
 }
@@ -511,9 +543,9 @@
 {
 	ulong flags;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
-	iucv_debug("handler is pointing to %p", handler);
+	iucv_debug(1, "handler is pointing to %p", handler);
 
 	if (pathid > (max_connections - 1))
 		return -EINVAL;
@@ -521,7 +553,7 @@
 	spin_lock_irqsave (&iucv_lock, flags);
 	if (iucv_pathid_table[pathid]) {
 		spin_unlock_irqrestore (&iucv_lock, flags);
-		iucv_debug("pathid entry is %p", iucv_pathid_table[pathid]);
+		iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]);
 		printk(KERN_WARNING
 		       "%s: Pathid being used, error.\n", __FUNCTION__);
 		return -EINVAL;
@@ -529,7 +561,7 @@
 	iucv_pathid_table[pathid] = handler;
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return 0;
 }				/* end of add_pathid function */
 
@@ -546,24 +578,63 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 }
 
-/*
+/**
+ * iucv_declare_buffer_cpu0
+ * Register at VM for subsequent IUCV operations. This is always
+ * executed on CPU 0. Called from iucv_declare_buffer().
+ */
+static void
+iucv_declare_buffer_cpu0 (void *result)
+{
+	iparml_db *parm;
+
+	if (!(result && (smp_processor_id() == 0)))
+		return;
+	parm = (iparml_db *)grab_param();
+	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
+	if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1)
+		*((ulong *)result) = parm->iprcode;
+	release_param(parm);
+}
+
+/**
+ * iucv_retrieve_buffer_cpu0:
+ * Unregister IUCV usage at VM. This is always executed on CPU 0.
+ * Called from iucv_retrieve_buffer().
+ */
+static void
+iucv_retrieve_buffer_cpu0 (void *result)
+{
+	iparml_control *parm;
+
+	if (smp_processor_id() != 0)
+		return;
+	parm = (iparml_control *)grab_param();
+	b2f0(RETRIEVE_BUFFER, parm);
+	release_param(parm);
+}
+
+/**
  * Name: iucv_declare_buffer
  * Purpose: Specifies the guests real address of an external
  *          interrupt.
  * Input: void
  * Output: iprcode - return code from b2f0 call
-*/
-int
+ */
+static int
 iucv_declare_buffer (void)
 {
-	ulong b2f0_result;
-	iparml_db *parm = (iparml_db *)grab_param();
+	ulong b2f0_result = 0x0deadbeef;
 
-	parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer);
-	b2f0_result = b2f0(DECLARE_BUFFER, parm);
-	release_param(parm);
-	iucv_debug("Address of EIB = %p", iucv_external_int_buffer);
-	iucv_debug("exiting");
+	iucv_debug(1, "entering");
+	if (smp_processor_id() == 0)
+		iucv_declare_buffer_cpu0(&b2f0_result);
+	else
+		smp_call_function(iucv_declare_buffer_cpu0, &b2f0_result, 0, 1);
+	iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer);
+	if (b2f0_result == 0x0deadbeef)
+	    b2f0_result = 0xaa;
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -573,23 +644,50 @@
  * Terminates all use of IUCV.
  * Returns: return code from CP
  */
-int
+static int
 iucv_retrieve_buffer (void)
 {
-	ulong b2f0_result = 0;
-	iparml_control *parm = (iparml_control *)grab_param();
+	iucv_debug(1, "entering");
+	if (declare_flag) {
+		if (smp_processor_id() == 0)
+			iucv_retrieve_buffer_cpu0(0);
+		else
+			smp_call_function(iucv_retrieve_buffer_cpu0, 0, 0, 1);
+		declare_flag = 0;
+	}
+	iucv_debug(1, "exiting");
+	return 0;
+}
+
+/**
+ * iucv_remove_handler:
+ * @users_handler: handler to be removed
+ *
+ * Remove handler when application unregisters.
+ */
+static void
+iucv_remove_handler(handler *handler)
+{
+	unsigned long flags;
 
-	iucv_debug("entering");
+	if ((!iucv_pathid_table) || (!handler))
+		return;
 
-	b2f0_result = b2f0(RETRIEVE_BUFFER, parm);
-	release_param(parm);
-	if (b2f0_result == 0) {
-		kfree(iucv_pathid_table);
-		iucv_pathid_table = NULL;
-		declare_flag = 0;
+	iucv_debug(1, "entering");
+
+	spin_lock_irqsave (&iucv_lock, flags);
+	list_del(&handler->list);
+	if (list_empty(&iucv_handler_table)) {
+		iucv_retrieve_buffer();
+		if (register_flag) {
+			unregister_external_interrupt(0x4000, iucv_irq_handler);
+			register_flag = 0;
+		}
 	}
-	iucv_debug("exiting");
-	return b2f0_result;
+	spin_unlock_irqrestore (&iucv_lock, flags);
+
+	iucv_debug(1, "exiting");
+	return;
 }
 
 /**
@@ -623,7 +721,7 @@
 	ulong rc = 0;		/* return code from function calls */
 	handler *new_handler;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	if (ops == NULL) {
 		/* interrupt table is not defined */
@@ -711,17 +809,41 @@
 	if (declare_flag == 0) {
 		rc = iucv_declare_buffer();
 		if (rc) {
+			char *err = "Unknown";
 			iucv_remove_handler(new_handler);
 			kfree(new_handler);
+			switch(rc) {
+				case 0x03:
+					err = "Directory error";
+					break;
+				case 0x0a:
+					err = "Invalid length";
+					break;
+				case 0x13:
+					err = "Buffer already exists";
+					break;
+				case 0x3e:
+					err = "Buffer overlap";
+					break;
+				case 0x5c:
+					err = "Paging or storage error";
+					break;
+				case 0xaa:
+					err = "Function not called";
+					break;
+			}
 			printk(KERN_WARNING "%s: iucv_declare_buffer "
-			       "returned %ld\n", __FUNCTION__, rc);
+			       "returned error 0x%02lx (%s)\n", __FUNCTION__, rc,
+			       err);
 			return NULL;
 		}
+		declare_flag = 1;
+	}
+	if (register_flag == 0) {
 		/* request the 0x4000 external interrupt */
 		rc = register_external_interrupt (0x4000, iucv_irq_handler);
 		if (rc) {
 			iucv_remove_handler(new_handler);
-			iucv_retrieve_buffer();
 			kfree (new_handler);
 			printk(KERN_WARNING "%s: "
 			       "register_external_interrupt returned %ld\n",
@@ -729,9 +851,10 @@
 			return NULL;
 
 		}
-		declare_flag = 1;
+		register_flag = 1;
 	}
-	iucv_debug("exiting");
+	MOD_INC_USE_COUNT;
+	iucv_debug(1, "exiting");
 	return new_handler;
 }				/* end of register function */
 
@@ -741,24 +864,45 @@
  *
  * Unregister application with IUCV.
  * Returns:
- *   Always 0
+ *   0 on success, -EINVAL, if specified handle is invalid.
  */
 
 int
 iucv_unregister_program (iucv_handle_t handle)
 {
-	handler *h = (handler *)handle;
+	handler *h = NULL;
+	struct list_head *lh;
 	int i;
 	ulong flags;
 
-	iucv_debug("entering");
-	iucv_debug("address of handler is %p", h);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "address of handler is %p", h);
+
+	/* Checking if handle is valid  */
+	spin_lock_irqsave (&iucv_lock, flags);
+	list_for_each(lh, &iucv_handler_table) {
+		if ((handler *)handle == list_entry(lh, handler, list)) {
+			h = (handler *)handle;
+			break;
+		}
+	}
+	if (!h) {
+		spin_unlock_irqrestore (&iucv_lock, flags);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
+		return -EINVAL;
+	}
 
 	/**
 	 * First, walk thru iucv_pathid_table and sever any pathid which is
 	 * still pointing to the handler to be removed.
 	 */
-	spin_lock_irqsave (&iucv_lock, flags);
 	for (i = 0; i < max_connections; i++)
 		if (iucv_pathid_table[i] == h) {
 			spin_unlock_irqrestore (&iucv_lock, flags);
@@ -770,7 +914,8 @@
 	iucv_remove_handler(h);
 	kfree(h);
 
-	iucv_debug("exiting");
+	MOD_DEC_USE_COUNT;
+	iucv_debug(1, "exiting");
 	return 0;
 }
 
@@ -811,8 +956,8 @@
 	handler *h = NULL;
 	iparml_control *parm;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	/* Checking if handle is valid  */
 	spin_lock_irqsave (&iucv_lock, flags);
@@ -825,9 +970,14 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
 	if (!h) {
-		printk(KERN_WARNING "%s: NULL handle passed by application "
-		       "or handler not found in iucv_handler_table\n",
-		       __FUNCTION__);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -849,7 +999,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -904,7 +1054,7 @@
 	handler *h = NULL;
 	__u8 no_memory[16] = "NO MEMORY";
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	/* Checking if handle is valid  */
 	spin_lock_irqsave (&iucv_lock, flags);
@@ -917,9 +1067,14 @@
 	spin_unlock_irqrestore (&iucv_lock, flags);
 
 	if (!h) {
-		printk(KERN_WARNING "%s: NULL handle passed by application "
-		       "or handler not found in iucv_handler_table\n",
-		       __FUNCTION__);
+		if (handle)
+			printk(KERN_WARNING
+			       "%s: Handler not found in iucv_handler_table.\n",
+			       __FUNCTION__);
+		else
+			printk(KERN_WARNING
+			       "%s: NULL handle passed by application.\n",
+			       __FUNCTION__);
 		return -EINVAL;
 	}
 
@@ -971,7 +1126,7 @@
 		return(add_pathid_result);
 	}
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -993,8 +1148,8 @@
 	iparml_purge *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_purge *)grab_param();
 
@@ -1012,8 +1167,8 @@
 	
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -1099,8 +1254,8 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_control *)grab_param();
 
@@ -1110,8 +1265,8 @@
 	b2f0_result = b2f0(QUIESCE, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1152,7 +1307,7 @@
 	ulong b2f0_result;
 	int moved = 0;	/* number of bytes moved from parmlist to buffer */
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1170,9 +1325,9 @@
 
 	if (b2f0_result == 0 || b2f0_result == 5) {
 		if (flags1_out) {
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 		}
 
 		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
@@ -1199,7 +1354,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1242,7 +1397,7 @@
 	ulong b2f0_result;
 	int i = 0, moved = 0, need_to_move = 8, dyn_len;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1261,9 +1416,9 @@
 	if (b2f0_result == 0 || b2f0_result == 5) {
 
 		if (flags1_out) {
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 			*flags1_out = (parm->ipflags1 & (~0x07));
-			iucv_debug("*flags1_out = %d", *flags1_out);
+			iucv_debug(2, "*flags1_out = %d", *flags1_out);
 		}
 
 		if (!(parm->ipflags1 & IPRMDATA)) {	/*msg not in parmlist */
@@ -1316,7 +1471,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1337,8 +1492,8 @@
 	iparml_db *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_db *)grab_param();
 
@@ -1350,8 +1505,8 @@
 	b2f0_result = b2f0(REJECT, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1391,7 +1546,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1415,7 +1570,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1457,7 +1612,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1482,7 +1637,7 @@
 	}
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1511,7 +1666,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	parm = (iparml_dpl *)grab_param();
 
@@ -1524,7 +1679,7 @@
 	b2f0_result = b2f0(REPLY, parm);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1543,8 +1698,8 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
-	iucv_debug("pathid = %d", pathid);
+	iucv_debug(1, "entering");
+	iucv_debug(1, "pathid = %d", pathid);
 
 	parm = (iparml_control *)grab_param();
 
@@ -1554,7 +1709,7 @@
 	b2f0_result = b2f0(RESUME, parm);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1582,7 +1737,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1603,7 +1758,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1637,7 +1792,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer)
 		return -EINVAL;
@@ -1657,7 +1812,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1686,7 +1841,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	parm = (iparml_dpl *)grab_param();
 
@@ -1703,7 +1858,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1741,7 +1896,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer || !ansbuf)
 		return -EINVAL;
@@ -1764,7 +1919,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1804,7 +1959,7 @@
 	iparml_db *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!buffer || !ansbuf)
 		return -EINVAL;
@@ -1825,7 +1980,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1861,7 +2016,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!ansbuf)
 		return -EINVAL;
@@ -1883,7 +2038,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 
 	return b2f0_result;
 }
@@ -1924,7 +2079,7 @@
 	iparml_dpl *parm;
 	ulong b2f0_result;
 
-	iucv_debug("entering");
+	iucv_debug(2, "entering");
 
 	if (!ansbuf)
 		return -EINVAL;
@@ -1944,7 +2099,7 @@
 		*msgid = parm->ipmsgid;
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(2, "exiting");
 	return b2f0_result;
 }
 
@@ -1967,7 +2122,7 @@
 	iparml_set_mask *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 
 	parm = (iparml_set_mask *)grab_param();
 
@@ -1976,8 +2131,8 @@
 	b2f0_result = b2f0(SETMASK, parm);
 	release_param(parm);
 
-	iucv_debug("b2f0_result = %ld", b2f0_result);
-	iucv_debug("exiting");
+	iucv_debug(1, "b2f0_result = %ld", b2f0_result);
+	iucv_debug(1, "exiting");
 
 	return b2f0_result;
 }
@@ -1996,7 +2151,7 @@
 	iparml_control *parm;
 	ulong b2f0_result = 0;
 
-	iucv_debug("entering");
+	iucv_debug(1, "entering");
 	parm = (iparml_control *)grab_param();
 
 	memcpy(parm->ipuser, user_data, sizeof(parm->ipuser));
@@ -2008,7 +2163,7 @@
 		iucv_remove_pathid(pathid);
 	release_param(parm);
 
-	iucv_debug("exiting");
+	iucv_debug(1, "exiting");
 	return b2f0_result;
 }
 
@@ -2073,10 +2228,10 @@
 	int rc = 0, j = 0;
 	__u8 no_listener[16] = "NO LISTENER";
 
-	iucv_debug("entering, pathid %d, type %02X",
+	iucv_debug(2, "entering, pathid %d, type %02X",
 		 int_buf->ippathid, int_buf->iptype);
-	iucv_debug("External Interrupt Buffer:");
-	iucv_dumpit(int_buf, sizeof(iucv_GeneralInterrupt));
+	iucv_dumpit("External Interrupt Buffer:",
+		    int_buf, sizeof(iucv_GeneralInterrupt));
 
 	ASCEBC (no_listener, 16);
 
@@ -2088,9 +2243,7 @@
 		} else {
 			h = iucv_pathid_table[int_buf->ippathid];
 			interrupt = h->interrupt_table;
-
-			iucv_debug("Handler:");
-			iucv_dumpit(h, sizeof(handler));
+			iucv_dumpit("Handler:", h, sizeof(handler));
 		}
 	}
 
@@ -2107,14 +2260,15 @@
 					temp_buff2[j] &= (h->id.mask)[j];
 				}
 				
-				iucv_debug("temp_buff1:");
-				iucv_dumpit(temp_buff1, sizeof(temp_buff1));
-				iucv_debug("temp_buff2");
-				iucv_dumpit(temp_buff2, sizeof(temp_buff2));
+				iucv_dumpit("temp_buff1:",
+					    temp_buff1, sizeof(temp_buff1));
+				iucv_dumpit("temp_buff2",
+					    temp_buff2, sizeof(temp_buff2));
 				
 				if (memcmp (temp_buff1, temp_buff2, 24) == 0) {
 					
-					iucv_debug("found a matching handler");
+					iucv_debug(2,
+						   "found a matching handler");
 					break;
 				}
 			}
@@ -2125,8 +2279,9 @@
 				if (rc) {
 					iucv_sever (int_buf->ippathid,
 						    no_listener);
-					iucv_debug("add_pathid failed, rc = %d",
-						   (int)add_pathid_result);
+					iucv_debug(1,
+						   "add_pathid failed, rc = %d",
+						   rc);
 				} else {
 					interrupt = h->interrupt_table;
 					if (interrupt->ConnectionPending) {
@@ -2149,9 +2304,10 @@
 						(iucv_ConnectionComplete *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionComplete not called");
-			}
-			
+					iucv_debug(1,
+						   "ConnectionComplete not called");
+			} else
+				iucv_sever(int_buf->ippathid, no_listener);
 			break;
 			
 		case 0x03:		/* connection severed */
@@ -2174,7 +2330,8 @@
 						(iucv_ConnectionQuiesced *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionQuiesced not called");
+					iucv_debug(1,
+						   "ConnectionQuiesced not called");
 			}
 			break;
 			
@@ -2185,7 +2342,8 @@
 						(iucv_ConnectionResumed *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("ConnectionResumed not called");
+					iucv_debug(1,
+						   "ConnectionResumed not called");
 			}
 			break;
 			
@@ -2197,7 +2355,8 @@
 						(iucv_MessageComplete *)int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("MessageComplete not called");
+					iucv_debug(2,
+						   "MessageComplete not called");
 			}
 			break;
 			
@@ -2209,7 +2368,8 @@
 						(iucv_MessagePending *) int_buf,
 						h->pgm_data);
 				else
-					iucv_debug("MessagePending not called");
+					iucv_debug(2,
+						   "MessagePending not called");
 			}
 			break;
 		default:		/* unknown iucv type */
@@ -2218,7 +2378,7 @@
 			break;
 	}			/* end switch */
 	
-	iucv_debug("exiting pathid %d, type %02X",
+	iucv_debug(2, "exiting pathid %d, type %02X",
 		 int_buf->ippathid, int_buf->iptype);
 
 	return;
@@ -2256,23 +2416,35 @@
 	return;
 }
 
+module_init(iucv_init);
+module_exit(iucv_exit);
+
 /**
  * Export all public stuff
+ * FIXME: I have commented out all the functions that
+ * 	  are not used in netiucv. Is anyone else
+ * 	  using them or should some of them be made
+ * 	  static / removed? pls review. Arnd
  */
 EXPORT_SYMBOL (iucv_accept);
 EXPORT_SYMBOL (iucv_connect);
+#if 0
 EXPORT_SYMBOL (iucv_purge);
 EXPORT_SYMBOL (iucv_query_maxconn);
 EXPORT_SYMBOL (iucv_query_bufsize);
 EXPORT_SYMBOL (iucv_quiesce);
+#endif
 EXPORT_SYMBOL (iucv_receive);
+#if 0
 EXPORT_SYMBOL (iucv_receive_array);
 EXPORT_SYMBOL (iucv_reject);
 EXPORT_SYMBOL (iucv_reply);
 EXPORT_SYMBOL (iucv_reply_array);
 EXPORT_SYMBOL (iucv_reply_prmmsg);
 EXPORT_SYMBOL (iucv_resume);
+#endif
 EXPORT_SYMBOL (iucv_send);
+#if 0
 EXPORT_SYMBOL (iucv_send2way);
 EXPORT_SYMBOL (iucv_send2way_array);
 EXPORT_SYMBOL (iucv_send_array);
@@ -2280,6 +2452,7 @@
 EXPORT_SYMBOL (iucv_send2way_prmmsg_array);
 EXPORT_SYMBOL (iucv_send_prmmsg);
 EXPORT_SYMBOL (iucv_setmask);
+#endif
 EXPORT_SYMBOL (iucv_sever);
 EXPORT_SYMBOL (iucv_register_program);
 EXPORT_SYMBOL (iucv_unregister_program);
diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/net/lcs.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,4146 @@
+/*
+ *  linux/drivers/s390/net/lcs.c
+ *
+ *  Linux for S/390 Lan Channel Station Network Driver
+ *
+ *  Copyright (C)  1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+ *               Frank Pavlic (pavlic@de.ibm.com)
+ *
+ *    $Revision: 1.128 $    $Date: 2002/03/01 16:56:47 $
+ * 
+ * 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.
+ *
+ */
+
+/*
+ 	Thanks to Uli Hild, Martin Schwidefsky,
+	& Ingo who probably will never let it down that 
+	he found the braindamage with my offset calculations on 
+	the IO buffers.
+	( for quality of effort, advise, support & sanity checking )
+	Alex, Boas & the rest of the team for the opportunity to work here.
+
+DRIVER OPERATION OVERVIEW README FIRST
+======================================
+
+The lcs driver currently supports Ethernet & Token Ring, FDDI is still
+experimental.
+
+The lan channel station(lcs) network interface has two channels one read
+channel one  write channel. This is very similar to the S390 CTC interface
+
+The read channel is recognised by having an even cuu number & model 0x3088
+The write channel is recognised by the formula write cuu=read cuu number + 1
+& also a model of 0x3088 only certain cuu models are supported so as not to
+clash with a CTC control unit model.
+
+The driver always has a read outstanding on the read subchannel this is used
+to receive both command replys & network packets ( these are differenciated by
+checking the type field in the lcs header structure ), network packets may
+come in during the startup & shutdown sequence these have to be discarded.
+During normal network I/O the driver will intermittently retry reads to
+permanently keep reads outstanding on the read channel if an -EBUSY or
+similar occurs (otherwise the driver would stop receiving network packets).
+
+The channel progam used work as described below
+===============================================
+The write subchannel has a hack in /net/core/skbuff.c which makes
+sure there is enough head & tailroom to write packets directly out of the
+socket buffer (If their isn't the code will still work). 
+
+If the write subchannel is busy network packets are
+aggregated together into a & queued for transmission, the reason I'm doing
+this is to minimise start subchannels & interrupts which I have been told
+& have proven to be very expensive.
+
+e.g. a ping -f -s 1400 -c 20000 <gateway_addr> >/dev/null used take 40 secs,
+on my machine & a ping -f -s 100 -c 20000 <gateway_addr> >/dev/null took 27
+secs, over token ring with a single buffer this has improved a lot with the
+queueing technique (I also made sure that the delay wasn't caused by waiting
+for the free token).
+
+The new program works as follows
+================================
+The read & channel program consists of of 8 read ccw commands 
+followed by a transfer in channel back to the 1st read ccw. 
+A moving suspend bit is switched on in the read
+ccw of the last buffer processed with pci's switched on in the
+remaining ccw's. This way I recieve buffers with pci's without
+having to issue excess resumes or ssch's & only
+need to issue a resume if the read program gets suspended when
+all the buffers are filled.
+
+The write program consists of 4 to 9 write ccw commands folled
+by a transfer in channel back to the 1st write ccw.
+All unfilled buffers all have the suspend bit on & the
+suspend bit is taken off when buffers are either filled or partially
+filled & the write channel is no longer busy.
+
+The lan channel is started as follows
+1) A halt subchannel is issued to the read & write subchannel
+2) A startup primitive is sent to the lan & the reply is read from the read
+subchannel.
+3) Every possible relative adapter number issued a startlan primative with
+attempts to configure it as token ring ethernet & fddi at some stage in the
+boot sequence or when the module is being inserted.
+The relative adapter number is normally equal to the low byte of the read
+channel cuu/2 & hence the reason for the hint field to speed up lcs_detect.
+5) On success of a startlan we  know whether the osa card is configured as
+token ring, ethernet or fddi, a lanstat primative is issued to get the
+mac address.
+6) The device is now ready for network io.
+
+The shutdown is similar to the startup just a stoplan primative followed
+by a shutdown.
+
+The driver instance globals lcs_drvr_globals are held in the priv element of
+the device structure & these in turn point to a lcs_chan_globals structure
+for the read & write channel. The read & write chan_globals & driver
+globals have their own state machine, so that the interrupt handler can
+make decisions on whether to send packets read to the network layer, or
+whether it is should wake up a process currently issuing lan commands.
+
+*/
+
+#define TRUE 1
+#define FALSE 0
+#define ERETRY 255
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/netdevice.h>
+#if LINUX_VERSION_CODE<KERNEL_VERSION(2,3,0)
+#include <linux/kcomp.h>
+#endif
+
+#if CONFIG_NET_ETHERNET
+#include <linux/etherdevice.h>
+extern int ethif_probe(struct net_device *dev);
+#endif
+#ifdef CONFIG_TR
+#include <linux/trdevice.h>
+extern int trif_probe(struct net_device *dev);
+#endif
+#ifdef CONFIG_FDDI
+#include <linux/fddidevice.h>
+extern int fddiif_probe(struct net_device *dev);
+#endif
+#include <asm/irq.h>
+#include <asm/queue.h>
+#define LCS_CHANDEV CONFIG_CHANDEV
+#if LCS_CHANDEV
+#include <asm/chandev.h>
+#endif
+#ifdef CONFIG_IP_MULTICAST
+#include <linux/inetdevice.h>
+#include <net/arp.h>
+#include <net/ip.h>
+#include <linux/in.h>
+#include <linux/igmp.h>
+#endif
+#include <net/pkt_sched.h>
+#include <net/sock.h>
+#include <net/dst.h>
+
+#define LCS_USE_IDALS  (LINUX_VERSION_CODE>KERNEL_VERSION(2,2,16))
+#if (!CONFIG_ARCH_S390X) || (LCS_USE_IDALS)
+#define lcs_dev_alloc_skb(length) dev_alloc_skb((length))
+#endif
+#if LCS_USE_IDALS
+#  include <asm/idals.h>
+#else
+#define set_normalized_cda(ccw, addr) ((ccw)->cda = (addr),0)
+#define clear_normalized_cda(ccw)
+#endif
+
+#if (LINUX_VERSION_CODE>=KERNEL_VERSION(2,2,18))
+#define LCS_DEBUG 1
+#else
+#define LCS_DEBUG 0
+#endif
+#define LCS_PRINTK_DEBUG   0
+#define LCS_ZERO_COPY_READ 0
+
+#if LCS_DEBUG && !LCS_PRINTK_DEBUG
+#include <asm/debug.h>
+#endif
+
+#if !defined(CONFIG_NET_ETHERNET)&&!defined(CONFIG_TR)&&!defined(CONFIG_FDDI)
+#error Cannot compile lcs.c without some net devices switched on.
+#endif
+
+#define lcs_inline inline
+
+#if LINUX_VERSION_CODE<=KERNEL_VERSION(2,2,16)
+#define lcs_daemonize(name,mask,use_init_fs) s390_daemonize(name,mask)
+#else
+#define lcs_daemonize(noargs...)
+#endif
+
+/* for the proc filesystem */
+static const char *cardname = "S390 Lan Channel Station Interface";
+
+/* lcs ccw command codes */
+
+enum {
+	ccw_write = 0x1,
+	ccw_read = 0x2,
+	ccw_read_backward = 0xc,
+	ccw_control = 0x3,
+	ccw_sense = 0x4,
+	ccw_sense_id = 0xe4,
+	ccw_transfer_in_channel0 = 0x8,
+	ccw_transfer_in_channel1 = 0x8,
+	ccw_set_x_mode = 0xc3,	// according to uli's lan notes
+	ccw_nop = 0x3		// according to uli's notes again
+	    // n.b. ccw_control clashes with this
+	    // so I presume its a special case of
+	    // control
+};
+
+/* startup & shutdown primatives */
+
+typedef enum {
+	lcs_startlan = 1,
+	lcs_stoplan = 2,
+	lcs_lanstat = 4,
+	lcs_startup = 7,
+	lcs_shutdown = 8,
+#ifdef CONFIG_IP_MULTICAST
+	lcs_qipassist = 0xb2,
+	lcs_setipm = 0xb4,
+	lcs_delipm = 0xb5
+#endif
+} lcs_cmd;
+
+typedef enum {
+	command_reject = 0x80,
+	intervention_required = 0x40,
+	bus_out_check = 0x20,
+	equipment_check = 0x10,
+	interface_disconnect = 0x01,
+} lcs_sense_byte_0;
+
+typedef enum {
+	resetting_event = 0x0080,
+	device_online = 0x0020,
+} lcs_sense_byte_1;
+
+/* The type of packet we are transmitting or receiving from the lcs */
+typedef enum {
+	lcs_control_frame_type = 0,	/* for startup shutdown etc */
+	lcs_enet_type = 1,	/* the rest are for normal network io */
+	lcs_token_ring_type = 2,
+	lcs_fddi_type = 7,
+	lcs_autodetect_type = -1,
+} lcs_frame_type;
+
+#define LCS_ILLEGAL_OFFSET 0xffff
+
+static int use_hw_stats = 0;
+static int checksum_received_ip_pkts = 0;
+#if !LCS_CHANDEV
+/* Max number of cuu models we can detect */
+#define LCS_CURR_NUM_MODELS   4
+#define LCS_ADDITIONAL_MODELS 12
+#define LCS_ADDITIONAL_MODELS_X2_STR "24"
+#define LCS_MAX_NUM_MODELS  (LCS_CURR_NUM_MODELS+LCS_ADDITIONAL_MODELS)
+/* max number of parms that can be sent to lcs_setup */
+#define LCS_MAX_NUM_PARMS ((LCS_MAX_NUM_MODELS<<1)+2)
+/* configuration parms for the lcs card */
+typedef struct {
+	int cu_model;
+	int max_rel_adapter_no;
+} lcs_model_info;
+
+/* The models supported currently used in probing */
+#define LCS_CUTYPE 0x3088
+
+/* default configuration parms */
+
+static lcs_model_info lcs_models[LCS_CURR_NUM_MODELS]
+    __attribute__ ((section(".data"))) = {
+	{0x1, 15}, 
+	/* P390/Planter 3172 emulation assume maximum 16 to be safe. */
+	{0x8, 15},		
+	/* 3172/2216 Paralell the 2216 allows 16 ports per card */
+	/* the original 3172 only allows 4 we will assume the max of 16 */
+	{0x60, 1},		
+	/* Only 2 ports allowed on OSA2 cards model 0x60 */
+	{0x1F, 15},		
+	/* 3172/2216 Escon serial the 2216 allows 16 ports per card  */
+	/* the original 3172 only allows 4 we will assume the max of 16 */
+};
+static int additional_model_info[LCS_ADDITIONAL_MODELS << 1] = { 0, };
+/* Set this to one to stop autodetection */
+static int noauto = 0, ignore_sense = 0;
+
+/*
+ * The lcs header 
+ * offset=the offset of the next cmd/network packet 
+ * type=command ethernet token ring fddi frame 
+ * slot=relative adapter no
+ */
+
+#define LCS_MAX_FORCED_DEVNOS 12
+#define LCS_MAX_FORCED_DEVNOS_X2_STR "24"
+typedef struct {
+	int devno;
+	int portno;
+} lcs_dev_portno_pair;
+static int devno_portno_pairs[LCS_MAX_FORCED_DEVNOS << 1] =
+    {[0 ... ((LCS_MAX_FORCED_DEVNOS << 1) - 1)] 2, };
+static lcs_dev_portno_pair *lcs_dev_portno =
+    (lcs_dev_portno_pair *) & devno_portno_pairs[0];
+#endif
+
+#define lcs_header           \
+u16		offset;      \
+u8		type;        \
+u8		slot;
+
+typedef struct {
+lcs_header} lcs_header_type __attribute__ ((packed));
+
+enum {
+	lcs_390_initiated,
+	lcs_lgw_initiated
+};
+
+/*
+ * lcs startup & shutdown commands 
+ */
+#define lcs_base_cmd         \
+u8		cmd_code;    \
+u8		initiator;   \
+u16		sequence_no; \
+u16		return_code; \
+
+typedef struct {
+	lcs_header lcs_base_cmd u8 lan_type;
+	u8 rel_adapter_no;
+	u16 parameter_count;
+	u8 operator_flags[3];
+	u8 reserved[3];
+	u8 command_data[0];
+} lcs_std_cmd __attribute__ ((packed));
+
+typedef struct {
+	lcs_header lcs_base_cmd u16 unused1;
+	u16 buff_size;
+	u8 unused2[6];
+} lcs_startup_cmd __attribute__ ((packed));
+
+#define LCS_ADDR_LEN 6
+
+#ifdef CONFIG_IP_MULTICAST
+typedef struct {
+	u32 ip_addr;
+	u8 mac_address[LCS_ADDR_LEN];
+	u8 reserved[2];
+} lcs_ip_mac_addr_pair __attribute__ ((packed));
+
+typedef enum {
+	ipm_set_required,
+	ipm_delete_required,
+	ipm_on_card
+} lcs_ipm_state;
+typedef struct lcs_ipm_list lcs_ipm_list;
+struct lcs_ipm_list {
+	struct lcs_ipm_list *next;
+	lcs_ip_mac_addr_pair ipm;
+	lcs_ipm_state ipm_state;
+};
+
+#define MAX_IP_MAC_PAIRS      32
+typedef struct {
+	lcs_header lcs_base_cmd u8 lan_type;
+	u8 rel_adapter_no;
+	/* OSA only will only support one IP Multicast entry at a time */
+	u16 num_ipm_pairs;
+	u16 ip_assists_supported;	/* returned by OSA  */
+	u16 ip_assists_enabled;	/* returned by OSA */
+	u16 version;		/* IP version i.e. 4 */
+	lcs_ip_mac_addr_pair ip_mac_pair[MAX_IP_MAC_PAIRS];
+	u32 response_data;
+} lcs_ipm_ctlmsg __attribute__ ((packed));
+typedef struct {
+	lcs_header lcs_base_cmd u8 lan_type;
+	u8 rel_adapter_no;
+	u16 num_ip_pairs;	/* should be 0 */
+	u16 ip_assists_supported;	/* returned by OSA  */
+	u16 ip_assists_enabled;	/* returned by OSA */
+	u16 version;		/* IP version i.e. 4 */
+} lcs_qipassist_ctlmsg __attribute__ ((packed));
+
+typedef enum {
+	/* Not supported by LCS */
+	lcs_arp_processing = 0x0001,
+	lcs_inbound_checksum_support = 0x0002,
+	lcs_outbound_checksum_support = 0x0004,
+	lcs_ip_frag_reassembly = 0x0008,
+	lcs_ip_filtering = 0x0010,
+	/* Supported by lcs 3172 */
+	lcs_ip_v6_support = 0x0020,
+	lcs_multicast_support = 0x0040
+} lcs_assists;
+#define LANCMD_DEFAULT_MCAST_PARMS ,0,NULL
+#else
+#define LANCMD_DEFAULT_MCAST_PARMS
+#endif
+
+typedef struct {
+	lcs_header lcs_base_cmd u8 lan_type;
+	u8 rel_adapter_no;
+	u8 unused1[10];
+	u8 mac_address[LCS_ADDR_LEN];
+	u32 num_packets_deblocked;
+	u32 num_packets_blocked;
+	u32 num_packets_tx_on_lan;
+	u32 num_tx_errors_detected;
+	u32 num_tx_packets_disgarded;
+	u32 num_packets_rx_from_lan;
+	u32 num_rx_errors_detected;
+	u32 num_rx_discarded_nobuffs_avail;
+	u32 num_rx_packets_too_large;
+} lcs_lanstat_reply __attribute__ ((packed));
+
+/* This buffer sizes are used by MVS so they should be reasonable */
+#define LCS_IOBUFFSIZE     0x5000
+#define LCS_NUM_TX_BUFFS    8
+#define LCS_NUM_RX_BUFFS    8
+
+#define LCS_INVALID_LOCK_OWNER            -1
+
+#if LINUX_VERSION_CODE<KERNEL_VERSION(2,2,18)
+typedef struct wait_queue *wait_queue_head_t;
+#endif
+#if LINUX_VERSION_CODE<KERNEL_VERSION(2,4,0)
+typedef dev_info_t s390_dev_info_t;
+#endif
+
+typedef enum {
+	chan_dead,
+	chan_idle,
+	chan_busy,
+	chan_starting_up,
+	chan_started_successfully
+} lcs_chan_busy_state;
+
+#define LCS_MAGIC			0x05A22A05	/* OSA2 to you */
+#define LCS_CHAN_GLOBALS(num_io_buffs)      \
+u32                  irq_allocated_magic;   \
+u16 subchannel;                             \
+u16 devno;                                  \
+struct lcs_drvr_globals *drvr_globals;      \
+atomic_t             sleeping_on_io;        \
+unsigned long        flags;                 \
+int                  rc;                    \
+int                  lock_owner;            \
+int                  lock_cnt;              \
+wait_queue_head_t    wait;                  \
+struct  tq_struct    retry_task;            \
+devstat_t	     devstat;               \
+lcs_chan_busy_state  chan_busy_state;       \
+ccw1_t               ccw[num_io_buffs+1];   \
+
+
+typedef struct {
+	LCS_CHAN_GLOBALS(0)
+} lcs_chan_globals;
+
+typedef struct {
+	LCS_CHAN_GLOBALS(LCS_NUM_RX_BUFFS)
+#if LCS_ZERO_COPY_READ
+	struct sk_buff *skb_buff[LCS_NUM_RX_BUFFS];
+#else
+	u8 *iobuff[LCS_NUM_RX_BUFFS];
+#endif
+	lcs_std_cmd *lancmd_reply_ptr;	/* only used by read channel */
+	u32 rx_idx;
+	u8 pad[0] __attribute__ ((aligned(8)));	/* so the next structure
+						   will be aligned */
+} lcs_read_globals;
+
+typedef struct {
+	LCS_CHAN_GLOBALS(LCS_NUM_TX_BUFFS)
+	u8 *iobuff[LCS_NUM_TX_BUFFS];
+	u32 prepare_idx;	/* current buffer being prepared */
+	u32 tx_idx;		/* last buffer successfully transmitted */
+	unsigned long pkts_still_being_txed;
+	unsigned long bytes_still_being_txed;
+	struct tq_struct resume_task;
+	int resume_queued;
+	int resume_loopcnt;
+	uint64_t last_lcs_txpacket_time;
+	uint64_t last_resume_time;
+	uint64_t adjusted_last_bytes_still_being_txed;
+} lcs_write_globals;
+
+#define LCS_READ_ALLOCSIZE      LCS_IOBUFFSIZE
+
+/*
+ * drvr_globals main state machine 
+ */
+typedef enum {
+	lcs_idle,
+	lcs_halting_subchannels,
+	lcs_doing_io,
+	lcs_idle_requesting_channels_for_lancmds,
+	lcs_requesting_channels_for_lancmds,
+	lcs_got_write_channel_for_lancmds,
+	lcs_doing_lancmds,
+	lcs_interrupted
+} lcs_state;
+
+enum {
+	lcs_invalid_adapter_no = -1
+};
+
+typedef struct lcs_drvr_globals lcs_drvr_globals;
+struct lcs_drvr_globals {
+	struct lcs_drvr_globals *next;
+	struct net_device *dev;
+	atomic_t usage_cnt;	/* used by drvr_globals_valid 
+				 * & lcs_usage_free_drvr_globals */
+	u8 lan_type;
+	u8 cmd_code;
+	unsigned short (*lan_type_trans) (struct sk_buff * skb,
+					  struct net_device * dev);
+	wait_queue_head_t lanstat_wait;	/* processes asleep awaiting 
+					 * lanstat results */
+	int doing_lanstat;
+	int up;
+	lcs_state state;
+	lcs_read_globals *read;
+	lcs_write_globals *write;
+	u16 sequence_no;
+	s16 rel_adapter_no;
+	int slow_hw;
+	/* To insure only one kernel thread runs at a time */
+	atomic_t kernel_thread_lock;
+	int (*kernel_thread_routine) (lcs_drvr_globals * drvr_globals);
+	struct tq_struct kernel_thread_task;
+	u16 lgw_sequence_no;	/* this isn't required just being thorough */
+	atomic_t retry_cnt;
+	struct net_device_stats stats __attribute__ ((aligned(4)));
+#ifdef CONFIG_IP_MULTICAST
+	spinlock_t ipm_lock;
+	lcs_ipm_list *ipm_list;
+#endif
+	/* So I can use atomic atomic_t for stats if required  */
+	u8 pad[0] __attribute__ ((aligned(8)));
+	/* CCW's need 8 byte alignment ( Thanks Martin ) */
+} __attribute__ ((aligned(8)));
+
+/* 
+ * A token ring header can be 40 bytes if you include the llc & rcf so we 
+ * leave a small bit extra.
+ */
+
+#define LCS_TX_HIWATERMARK          LCS_IOBUFFSIZE-60
+
+#define LCS_ALLOCSIZE (sizeof(lcs_drvr_globals)+sizeof(lcs_read_globals)+sizeof(lcs_write_globals))
+
+/* Function prototypes */
+static int lcs_rxpacket(lcs_drvr_globals * drvr_globals, u8 * start_buff,
+		 lcs_std_cmd ** lancmd_reply
+#if LCS_ZERO_COPY_READ
+		 , u32 curr_idx
+#endif
+		 );
+static int lcs_txpacket(struct sk_buff *skb, struct net_device *dev);
+static int lcs_detect(lcs_drvr_globals * drvr_globals, s16 forced_port_no,
+		      u8 hint_port_no, u8 max_port_no,
+		      lcs_frame_type frame_type, u8 * mac_address);
+static int lcs_check_reset(lcs_chan_globals * chan_globals);
+static void lcs_restartreadio(lcs_drvr_globals * drvr_globals);
+static void lcs_restartwriteio(lcs_drvr_globals * drvr_globals);
+static void lcs_queued_restartreadio(lcs_drvr_globals * drvr_globals);
+static void lcs_queued_restartwriteio(lcs_drvr_globals * drvr_globals);
+static void lcs_resume_writetask(lcs_write_globals * write);
+#ifdef MODULE
+void cleanup_module(void);
+#endif
+
+#ifdef CONFIG_IP_MULTICAST
+static int lcs_fix_multicast_list(lcs_drvr_globals * drvr_globals);
+#endif
+
+#define lcs_debug_initmessage      char *message=NULL;
+#define lcs_debug_setmessage(string) message=string
+
+#if LCS_DEBUG
+#if LCS_PRINTK_DEBUG
+#define lcs_debug_event(level,args...)      printk(##args)
+#define lcs_debug_exception(level,args...)  printk(##args)
+#define lcs_bad_news(args...)         printk(KERN_CRIT ##args);
+#define lcs_good_news(args...)         printk(##args);
+#else
+static debug_info_t *lcs_id = NULL;
+#define lcs_debug_event(args...)      debug_sprintf_event(lcs_id,##args)
+#define lcs_debug_exception(args...)  debug_sprintf_exception(lcs_id,##args)
+
+/* &formatstr[3] is to get over the KERN_CRIT prefix */
+#define lcs_bad_news(format,args...)                   \
+{                                                      \
+        char *formatstr= KERN_CRIT format;             \
+	lcs_debug_exception(0,&formatstr[3] ,## args); \
+	printk(formatstr ,## args);                    \
+}
+
+#define lcs_good_news(format,args...)                  \
+{                                                      \
+        char *formatstr=format;                        \
+	lcs_debug_event(0,formatstr ,## args);         \
+	printk(formatstr ,## args);                    \
+}
+#endif
+
+#define lcs_debugchannel(message,chan_globals) \
+lcs_debugchannel_func((message),(lcs_chan_globals *)(chan_globals))
+
+static void
+lcs_debugchannel_func(char *message, lcs_chan_globals * chan_globals)
+{
+	lcs_drvr_globals *drvr_globals;
+
+	if (message) {
+		lcs_debug_event(0, "lcs: %s\n", message);
+	}
+	lcs_debug_event(0, "lcs  irq=%04x devno=%04x %s\n",
+			(int) chan_globals->subchannel,
+			(int) chan_globals->devno, (message ? message : ""));
+	lcs_debug_event(0, "chan globals=%p\n", chan_globals);
+	if (chan_globals) {
+		drvr_globals = chan_globals->drvr_globals;
+		if (drvr_globals) {
+			if (drvr_globals->read !=
+			    (lcs_read_globals *) chan_globals
+			    && drvr_globals->write !=
+			    (lcs_write_globals *) chan_globals)
+				lcs_debug_event(0,
+						"drvr globals inconsistent\n");
+			lcs_debug_event(0, "drvr_globals=%p:state=%d\n",
+					drvr_globals, drvr_globals->state);
+			lcs_debug_event(0,
+					"chan globals sleeping_on_io=%d"
+					" busy_state=%d lock_owner=%d "
+					"lock_cnt=%d\n",
+					atomic_read(&chan_globals->
+						    sleeping_on_io),
+					chan_globals->chan_busy_state,
+					chan_globals->lock_owner,
+					chan_globals->lock_cnt);
+		}
+	}
+	lcs_debug_exception(0, "leaving lcs_debugchannel\n");
+}
+
+static void
+lcs_debug_display_read_buff(char *message, lcs_std_cmd * lancmd_reply_ptr)
+{
+	int *read_buff = (int *) lancmd_reply_ptr;
+
+	lcs_debug_event(1, "%s %08x %08x %08x\n", message,
+			read_buff[0], read_buff[1], read_buff[2]);
+}
+
+#else
+#define lcs_debug_event(noargs...)
+#define lcs_debug_exception(noargs...)
+#define lcs_bad_news(args...)  printk(KERN_CRIT ##args)
+#define lcs_good_news(args...)  printk(##args)
+#define lcs_debugchannel(message,chan_globals)   \
+printk("lcs  irq=%04x devno=%04x %s\n",(int)chan_globals->subchannel, \
+(int)chan_globals->devno,(message ? message:""))
+#define lcs_debug_display_read_buff(noargs...)
+#endif
+
+#if (!LCS_USE_IDALS) && (CONFIG_ARCH_S390X)
+static inline struct sk_buff *
+lcs_dev_alloc_skb(unsigned int length)
+{
+	struct sk_buff *skb;
+
+	skb = alloc_skb(length + 16, GFP_ATOMIC | GFP_DMA);
+	if (skb)
+		skb_reserve(skb, 16);
+	return skb;
+}
+#endif
+
+static void lcs_inline
+lcs_resetstate(lcs_drvr_globals * drvr_globals)
+{
+	drvr_globals->state = lcs_idle;
+}
+
+/* 
+ * Primatives used to put the process to sleep or wake it up during startup 
+ * or shutdown.
+ */
+static lcs_inline void
+lcs_initqueue_func(lcs_chan_globals * chan_globals)
+{
+	atomic_set(&chan_globals->sleeping_on_io, TRUE);
+	chan_globals->rc = 0;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	init_waitqueue_head(&chan_globals->wait);
+#else
+	chan_globals->wait = NULL;
+#endif
+}
+
+#define lcs_initqueue(chan_globals) \
+	lcs_initqueue_func((lcs_chan_globals *)chan_globals)
+
+static void
+lcs_wakeup_func(lcs_chan_globals * chan_globals, int rc)
+{
+	lcs_debug_event(2, "lcs_wakeup called sch=%04x rc=%d\n,",
+			(int) chan_globals->subchannel, rc);
+	atomic_set(&chan_globals->sleeping_on_io, FALSE);
+	if (chan_globals->rc == 0)
+		chan_globals->rc = rc;
+	wake_up(&chan_globals->wait);
+}
+
+#define TOD_SHIFT_TO_USECS 12
+static inline uint64_t
+lcs_get_tod(void)
+{
+	uint64_t cc;
+
+ 	asm volatile ("STCK %0":"=m" (cc));
+	return (cc);
+}
+
+#define lcs_wakeup(chan_globals,rc) \
+	lcs_wakeup_func((lcs_chan_globals *)chan_globals,(rc))
+static int
+lcs_sleepon_func(lcs_chan_globals * chan_globals, int extratime)
+{
+	/*
+	   We have a miniscule chance of sleeping here for 1 second
+	   we have to unfortunately live with it as down_interruptible
+	   dosen't wake up for timers just signals.
+	 */
+	int rc = 0;
+
+	lcs_debug_event(2, "lcs_sleepon called sch=%04x\n,",
+			(int) chan_globals->subchannel);
+#warning FIXME: [kj] Using sleep_on derivative, is racy. consider using wait_event instead
+	sleep_on_timeout(&chan_globals->wait, HZ);
+	if (atomic_read(&chan_globals->sleeping_on_io) && chan_globals->rc == 0
+	    && extratime) {
+		lcs_bad_news
+		    ("lcs_sleepon network card taking time responding "
+		     "irq=%04x devno=%04x,\n"
+		     "please be patient, ctrl-c will exit if shell prompt "
+		     "is available.\n",
+		     (int) chan_globals->subchannel, (int) chan_globals->devno);
+#warning FIXME: [kj] Using sleep_on derivative, is racy. consider using wait_event instead
+		interruptible_sleep_on_timeout(&chan_globals->wait,
+					       extratime * HZ);
+	}
+	if (atomic_read(&chan_globals->sleeping_on_io) && chan_globals->rc == 0) {
+		chan_globals->drvr_globals->state = lcs_interrupted;
+		rc = (test_thread_flag(TIF_SIGPENDING) ? -EINTR : -ETIMEDOUT);
+
+	}
+	if (chan_globals->rc)
+		rc = chan_globals->rc;
+	lcs_debug_event(2, "lcs_sleepon sch=%04x devno=%04x rc=%d\n",
+			(int) chan_globals->subchannel,
+			(int) chan_globals->devno, rc);
+	return (rc);
+
+}
+
+#define lcs_sleepon(chan_globals,extratime) \
+	lcs_sleepon_func((lcs_chan_globals *)chan_globals,extratime)
+
+static void
+lcs_chan_lock_func(lcs_chan_globals * chan_globals)
+{
+	eieio();
+	if (chan_globals->lock_owner != smp_processor_id()) {
+		s390irq_spin_lock_irqsave(chan_globals->subchannel,
+					  chan_globals->flags);
+		chan_globals->lock_cnt = 1;
+		chan_globals->lock_owner = smp_processor_id();
+
+	} else
+		chan_globals->lock_cnt++;
+	if (chan_globals->lock_cnt < 0 || chan_globals->lock_cnt > 100) {
+		lcs_bad_news("bad lock_cnt %d in lcs_chan_lock chan_globals=%p"
+			     " devno=%04x returnaddrs=%p,%p cpu=%d\n",
+			     chan_globals->lock_cnt, chan_globals,
+			     (int) chan_globals->devno,
+			     __builtin_return_address(0),
+			     __builtin_return_address(1), smp_processor_id());
+		chan_globals->lock_cnt = 1;
+	}
+}
+
+static void
+lcs_chan_unlock_func(lcs_chan_globals * chan_globals)
+{
+	if (chan_globals->lock_cnt <= 0) {
+		lcs_bad_news
+		    ("bad lock_cnt %d in lcs_chan_unlock chan_globals=%p"
+		     " devno=%04x returnaddrs=%p,%p cpu=%d\n",
+		     chan_globals->lock_cnt, chan_globals,
+		     (int) chan_globals->devno, __builtin_return_address(0),
+		     __builtin_return_address(1), smp_processor_id());
+		chan_globals->lock_cnt = 1;
+	}
+
+	if (--chan_globals->lock_cnt == 0) {
+		chan_globals->lock_owner = LCS_INVALID_LOCK_OWNER;
+		s390irq_spin_unlock_irqrestore(chan_globals->subchannel,
+					       chan_globals->flags);
+	}
+
+}
+
+#define lcs_chan_lock(chan_globals) \
+	lcs_chan_lock_func((lcs_chan_globals *)chan_globals)
+#define lcs_chan_unlock(chan_globals) \
+	lcs_chan_unlock_func((lcs_chan_globals *)chan_globals)
+
+static int inline
+lcs_getbuffs_filled(lcs_write_globals * write)
+{
+	return ((write->prepare_idx - write->tx_idx) +
+		(write->prepare_idx >
+		 write->tx_idx ? -1 : (LCS_NUM_TX_BUFFS - 1))
+		+ (write->ccw[write->prepare_idx].count ? 1 : 0));
+}
+
+/*
+ * A little utility routine to make a ccw chain.
+ */
+static void
+initccws(ccw1_t * ccws, u8 * iobuff[], int num_ccws, u8 cmd_code, u16 count,
+	 u8 flags)
+{
+	int cnt;
+	ccw1_t *origccws = ccws;
+	memset(ccws, 0, sizeof (ccw1_t) * num_ccws + 1);
+	for (cnt = 0; cnt < num_ccws; cnt++, ccws++) {
+		ccws->cmd_code = cmd_code;
+		ccws->count = count;
+		ccws->flags = flags;
+		/* ccw addresses are 32 bit */
+		(u32) ccws->cda = (u32) virt_to_phys(iobuff[cnt]);
+	}
+	ccws->cmd_code = ccw_transfer_in_channel1;
+	(u32) ccws->cda = (u32) virt_to_phys(origccws);
+}
+
+/*
+ * linked list used to hold all the lcs_drvr_globals so they can be
+ * freed up when the driver is finished 
+ */
+static spinlock_t lcs_card_list_lock = SPIN_LOCK_UNLOCKED;
+static lcs_drvr_globals *lcs_card_list = NULL;
+
+/*
+  This function is required for kernel threads & timers
+  going off after the driver is closed & long gone & causing mischef.
+  ( thanks Ingo for making me aware that this was happening :-) )
+ */
+static int
+lcs_drvr_globals_valid(lcs_drvr_globals * drvr_globals)
+{
+	int in_list = FALSE;
+
+	if (drvr_globals) {
+		spin_lock(&lcs_card_list_lock);
+		in_list =
+		    is_in_list((list *) lcs_card_list, (list *) drvr_globals);
+		if (in_list)
+			atomic_inc(&drvr_globals->usage_cnt);
+		spin_unlock(&lcs_card_list_lock);
+	}
+	return (in_list);
+}
+
+static void *
+lcs_dma_alloc(size_t allocsize)
+{
+	void *newalloc = kmalloc(allocsize, GFP_KERNEL | GFP_DMA);
+	if (newalloc)
+		memset(newalloc, 0, allocsize);
+	return (newalloc);
+}
+
+static void
+lcs_usage_free_drvr_globals(lcs_drvr_globals * drvr_globals)
+{
+#if LCS_ZERO_COPY_READ
+	struct sk_buff **skb_buff;
+#endif
+	u8 **iobuff;
+	int cnt, refcnt;
+
+	lcs_debug_event(2, "lcs_usage_free_drvr_globals_called %p\n",
+			drvr_globals);
+	if (drvr_globals) {
+		lcs_read_globals *read = drvr_globals->read;
+		refcnt = atomic_dec_return(&drvr_globals->usage_cnt);
+		if (refcnt < 0)
+			lcs_bad_news("bad ref cnt drvr_globals %p ref %d\n",
+				     drvr_globals, refcnt);
+		if (refcnt <= 0) {
+			spin_lock(&lcs_card_list_lock);
+			if (!remove_from_list
+			    ((list **) & lcs_card_list, (list *) drvr_globals))
+				lcs_bad_news("drvr globals not in list %p\n",
+					     drvr_globals);
+			spin_unlock(&lcs_card_list_lock);
+			lcs_debug_event(2, "freeing drvr globals\n");
+			iobuff = drvr_globals->write->iobuff;
+			for (cnt = 0; cnt < LCS_NUM_TX_BUFFS; cnt++) {
+				if (iobuff[cnt])
+					kfree(iobuff[cnt]);
+			}
+#if LCS_ZERO_COPY_READ
+			skb_buff = read->skb_buff;
+			for (cnt = 0; cnt < LCS_NUM_RX_BUFFS; cnt++) {
+				clear_normalized_cda(&read->ccw[cnt]);
+				if (skb_buff[cnt])
+					dev_kfree_skb(skb_buff[cnt]);
+			}
+#else
+			iobuff = read->iobuff;
+			for (cnt = 0; cnt < LCS_NUM_RX_BUFFS; cnt++) {
+				clear_normalized_cda(&read->ccw[cnt]);
+				if (iobuff[cnt])
+					kfree(iobuff[cnt]);
+			}
+#endif
+			if (drvr_globals->dev)
+				drvr_globals->dev->priv = NULL;
+#ifdef  CONFIG_IP_MULTICAST
+			while (drvr_globals->ipm_list) {
+				spin_lock(&drvr_globals->ipm_lock);
+				remove_from_list((list **) & drvr_globals->
+						 ipm_list,
+						 (list *) drvr_globals->
+						 ipm_list);
+				spin_unlock(&drvr_globals->ipm_lock);
+				kfree(drvr_globals->ipm_list);
+			}
+#endif
+			memset(drvr_globals, 0, LCS_ALLOCSIZE);
+			kfree(drvr_globals);
+		}
+	}
+}
+
+static void
+lcs_kernel_thread(lcs_drvr_globals * drvr_globals)
+{
+#if LINUX_VERSION_CODE<=KERNEL_VERSION(2,2,16)
+	/* tq_scheduler sometimes leaves interrupts disabled from do
+	 * bottom half */
+	__sti();
+#endif
+	if (kernel_thread((int (*)(void *)) drvr_globals->kernel_thread_routine,
+			  (void *) drvr_globals, SIGCHLD) < 0) {
+		atomic_set(&drvr_globals->kernel_thread_lock, 1);
+		lcs_debug_exception(1,
+				    "lcs_kernel_thread failed to launch a new "
+				    "thread drvr_globals=%p routine=%p",
+				    drvr_globals,
+				    drvr_globals->kernel_thread_routine);
+	}
+}
+
+static int
+lcs_initreadccws(lcs_read_globals * read)
+{
+
+	int cnt;
+	ccw1_t *origccws, *ccws;
+#if LCS_ZERO_COPY_READ
+	struct sk_buff *curr_skb;
+#else
+	u8 *curr_iobuff;
+#endif
+
+	origccws = ccws = read->ccw;
+	memset(ccws, 0, sizeof (ccw1_t) * LCS_NUM_RX_BUFFS + 1);
+	for (cnt = 0; cnt < LCS_NUM_RX_BUFFS; cnt++, ccws++) {
+		ccws->cmd_code = ccw_read;
+#if LCS_ZERO_COPY_READ
+		curr_skb = read->skb_buff[cnt];
+		if (set_normalized_cda(ccws, curr_skb->data))
+			return -ENOMEM
+#else
+		curr_iobuff = read->iobuff[cnt];
+		if (set_normalized_cda(ccws, curr_iobuff))
+			return -ENOMEM;
+#endif
+	}
+	ccws->cmd_code = ccw_transfer_in_channel1;
+	(u32) ccws->cda = (u32) virt_to_phys(origccws);
+	return 0;
+
+}
+
+/* 
+ * Allocates driver instance globals 
+ */
+static lcs_drvr_globals *
+lcs_alloc_drvr_globals(void)
+{
+	lcs_drvr_globals *drvr_globals;
+	lcs_write_globals *write;
+	lcs_read_globals *read;
+	int cnt;
+	struct tq_struct *lcs_tq;
+
+	lcs_debug_event(2, "lcs_alloc_drvr_globals called\n");
+	drvr_globals = lcs_dma_alloc(LCS_ALLOCSIZE);
+	if (!drvr_globals)
+		return (NULL);
+	atomic_set(&drvr_globals->usage_cnt, 1);
+	drvr_globals->rel_adapter_no = lcs_invalid_adapter_no;
+	read = drvr_globals->read = (lcs_read_globals *) (drvr_globals + 1);
+	write = drvr_globals->write =
+	    (lcs_write_globals *) ((addr_t) read + sizeof (lcs_read_globals));
+	write->lock_owner = drvr_globals->read->lock_owner =
+	    LCS_INVALID_LOCK_OWNER;
+	for (cnt = 0; cnt < LCS_NUM_TX_BUFFS; cnt++) {
+		if ((write->iobuff[cnt] =
+		     lcs_dma_alloc(LCS_IOBUFFSIZE)) == NULL)
+			goto Fail;
+
+	}
+	for (cnt = 0; cnt < LCS_NUM_RX_BUFFS; cnt++) {
+#if LCS_ZERO_COPY_READ
+		if ((read->skb_buff[cnt] =
+		     lcs_dev_alloc_skb(LCS_READ_ALLOCSIZE)) == NULL)
+#else
+		if ((read->iobuff[cnt] =
+		     kmalloc(LCS_READ_ALLOCSIZE, GFP_ATOMIC | GFP_DMA)) == NULL)
+#endif
+			goto Fail;
+	}
+	if (lcs_initreadccws(read))
+		goto Fail;
+	read->drvr_globals = drvr_globals;
+	write->drvr_globals = drvr_globals;
+	lcs_resetstate(drvr_globals);
+	lcs_tq = &drvr_globals->kernel_thread_task;
+	lcs_tq->routine = (void (*)(void *)) lcs_kernel_thread;
+	lcs_tq->data = (void *) drvr_globals;
+#if LINUX_VERSION_CODE>KERNEL_VERSION(2,3,0)
+	lcs_tq->sync = read->retry_task.sync = write->retry_task.sync = 0;
+#endif
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	INIT_LIST_HEAD(&lcs_tq->list);
+	INIT_LIST_HEAD(&read->retry_task.list);
+	INIT_LIST_HEAD(&write->retry_task.list);
+#endif
+	read->retry_task.routine = (void (*)(void *)) lcs_queued_restartreadio;
+	write->retry_task.routine =
+	    (void (*)(void *)) lcs_queued_restartwriteio;
+	write->retry_task.data = read->retry_task.data = (void *) drvr_globals;
+	write->resume_task.routine = (void (*)(void *)) lcs_resume_writetask;
+	write->resume_task.data = (void *) write;
+	read->chan_busy_state = write->chan_busy_state = chan_dead;
+	atomic_set(&drvr_globals->kernel_thread_lock, 1);
+	spin_lock(&lcs_card_list_lock);
+	add_to_list((list **) & lcs_card_list, (list *) drvr_globals);
+	spin_unlock(&lcs_card_list_lock);
+	drvr_globals->up = FALSE;
+	return (drvr_globals);
+Fail:
+	lcs_usage_free_drvr_globals(drvr_globals);
+	return (NULL);
+}
+
+static void
+lcs_retry(lcs_chan_globals * chan_globals)
+{
+	lcs_debug_event(1, "lcs_retry subchannel %04x scheduling retry\n",
+			chan_globals->subchannel);
+	MOD_INC_USE_COUNT;
+#if LINUX_VERSION_CODE>KERNEL_VERSION(2,2,16)
+	schedule_task(&chan_globals->retry_task);
+#else
+	queue_task(&chan_globals->retry_task, &tq_scheduler);
+#endif
+}
+
+static int
+lcs_doio_func(lcs_chan_globals * chan_globals, unsigned long flags)
+{
+	int rc;
+	lcs_debug_event(2, "lcs_doio subchannel=%x\n",
+			(int) chan_globals->subchannel);
+	lcs_chan_lock(chan_globals);
+
+	rc = do_IO(chan_globals->subchannel, &chan_globals->ccw[0],
+		   (addr_t) chan_globals, 0, flags);
+
+	if (rc) {
+#if LCS_DEBUG
+		lcs_debug_event(1,"lcs_doio do_IO returned %d for " \
+				"subchannel %X\n",rc,chan_globals->subchannel);
+#endif
+		if (rc == -ENODEV)
+			chan_globals->chan_busy_state = chan_dead;
+		else
+			lcs_retry(chan_globals);
+	} else
+		chan_globals->chan_busy_state = chan_started_successfully;
+	lcs_chan_unlock(chan_globals);
+	return (rc);
+}
+
+#define lcs_doio(chan_globals,flags)  \
+	lcs_doio_func((lcs_chan_globals *)(chan_globals),(flags))
+
+/* 
+ * halt subchannel wrapper used during driver startup 
+ */
+static int
+lcs_hsch_func(lcs_chan_globals * chan_globals)
+{
+	int rc = 0;
+	lcs_debug_event(2, "lcs_hsch subchannel=%x\n",
+			(int) chan_globals->subchannel);
+	lcs_chan_lock(chan_globals);
+	lcs_initqueue(chan_globals);
+	chan_globals->drvr_globals->state = lcs_halting_subchannels;
+	rc = halt_IO(chan_globals->subchannel, (addr_t) chan_globals, 0);
+	lcs_chan_unlock(chan_globals);
+	if (rc == 0)
+		rc = lcs_sleepon_func(chan_globals, 0);
+	else
+		lcs_debug_event(2, "lcs_hsch subchannel=%x rc=%d\n",
+				(int) chan_globals->subchannel, rc);
+	return (rc);
+}
+
+#define lcs_hsch(chan_globals) \
+	lcs_hsch_func((lcs_chan_globals *)(chan_globals))
+
+static void
+wait_on_write(lcs_drvr_globals * drvr_globals)
+{
+	lcs_write_globals *write = drvr_globals->write;
+
+	if (drvr_globals->state == lcs_doing_io) {
+		if (drvr_globals->dev)
+			netif_stop_queue(drvr_globals->dev);
+		lcs_chan_lock(write);
+		if (drvr_globals->state == lcs_doing_io &&
+		    (write->chan_busy_state == chan_busy
+		     || write->resume_queued)) {
+			lcs_initqueue(write);
+			drvr_globals->state =
+			    lcs_requesting_channels_for_lancmds;
+			lcs_chan_unlock(write);
+			lcs_sleepon(write, 0);
+		} else
+			lcs_chan_unlock(write);
+	}
+	drvr_globals->state = lcs_doing_lancmds;
+}
+
+static int
+lcs_getcmdsize(u8 cmd_code)
+{
+	int cmdsize;
+	switch (cmd_code) {
+	case lcs_startlan:
+	case lcs_stoplan:
+	case lcs_lanstat:
+	case lcs_shutdown:
+		cmdsize = sizeof (lcs_std_cmd);
+		break;
+	case lcs_startup:
+		cmdsize = sizeof (lcs_startup_cmd);
+		break;
+#ifdef CONFIG_IP_MULTICAST
+	case lcs_setipm:
+	case lcs_delipm:
+		cmdsize = sizeof (lcs_ipm_ctlmsg);
+		break;
+	case lcs_qipassist:
+		cmdsize = sizeof (lcs_qipassist_ctlmsg);
+		break;
+#endif
+	default:
+		lcs_debug_event(1, "illegal lan cmd %d in lcs_getcmdsize\n",
+				cmd_code);
+		cmdsize = -EINVAL;
+	}
+	if (cmdsize != -EINVAL)
+		cmdsize -= sizeof (lcs_header_type);
+	return (cmdsize);
+}
+
+static lcs_header_type *
+lcs_getfreetxbuff(lcs_write_globals * write, u8 type, u8 slot, int len)
+{
+	ccw1_t *curr_ccw;
+	int new_buff = FALSE;
+	lcs_header_type *retbuff;
+	u32 virt_cda;
+
+	curr_ccw = &write->ccw[write->prepare_idx];
+	if (curr_ccw->count == 0)
+		new_buff = TRUE;
+	else if ((curr_ccw->count + len + sizeof (lcs_header_type) +
+		  sizeof (u16)) > LCS_IOBUFFSIZE) {
+
+		if (write->prepare_idx == write->tx_idx)
+			return (NULL);
+		write->prepare_idx =
+		    ((write->prepare_idx + 1) & (LCS_NUM_TX_BUFFS - 1));
+		curr_ccw->flags &= ~CCW_FLAG_SUSPEND;
+		new_buff = TRUE;
+		curr_ccw = &write->ccw[write->prepare_idx];
+	}
+	if (new_buff) {
+		if ((curr_ccw->flags & CCW_FLAG_SUSPEND) == 0) {
+			lcs_bad_news
+			    ("Bug/Race condition detected in "
+			     "lcs_getfreetxbuff "
+			     "CCW_FLAG_SUSPEND not set for\n"
+			     "for ccw at %p", curr_ccw);
+			return (NULL);
+		}
+		if (curr_ccw->count != 0) {
+			lcs_bad_news
+			    ("Bug/Race condition detected in "
+			     "lcs_getfreetxbuff "
+			     "count!=0 in new buffer\n"
+			     "for ccw at %p", curr_ccw);
+			return (NULL);
+		}
+	}
+	len += sizeof (lcs_header_type);
+	virt_cda = (u32) virt_to_phys((void *) ((addr_t) curr_ccw->cda));
+	if (new_buff) {
+		retbuff = (lcs_header_type *) ((addr_t) virt_cda);
+		curr_ccw->count = len + sizeof (u16);
+	} else {
+		retbuff =
+		    (lcs_header_type *) (virt_cda + curr_ccw->count -
+					 sizeof (u16));
+		curr_ccw->count += len;
+		len = curr_ccw->count - sizeof (u16);
+	}
+	retbuff->offset = len;
+	*((u16 *) ((addr_t) (virt_cda + len))) = 0;
+	retbuff->type = type;
+	retbuff->slot = slot;
+	lcs_debug_event(2,
+			"lcs_getfreetxbuff write=%p prepare_idx=%u "
+			"tx_idx=%u len=%d\n",
+			write, write->prepare_idx, write->tx_idx, len);
+	return (retbuff);
+}
+
+static lcs_std_cmd *
+lcs_prepare_lancmd(lcs_write_globals * write, u8 cmd_code, u8 rel_adapter_no,
+		   u8 initiator, u8 lan_type)
+{
+	lcs_std_cmd *writecmd;
+	int cmdsize = lcs_getcmdsize(cmd_code);
+	if (cmdsize < 0)
+		return (NULL);
+	/* Force a fresh ccw buff */
+	writecmd =
+	    (lcs_std_cmd *) lcs_getfreetxbuff(write, lcs_control_frame_type, 0,
+					      cmdsize);
+	if (writecmd == NULL)
+		return (NULL);
+	memset((void *) (((addr_t) writecmd) + sizeof (lcs_header_type)), 0,
+	       cmdsize);
+	writecmd->cmd_code = cmd_code;
+	writecmd->initiator = initiator;
+	switch (cmd_code) {
+	case lcs_startlan:
+	case lcs_stoplan:
+	case lcs_lanstat:
+#ifdef CONFIG_IP_MULTICAST
+	case lcs_setipm:
+	case lcs_delipm:
+	case lcs_qipassist:
+#endif
+		writecmd->lan_type = lan_type;
+		writecmd->rel_adapter_no = rel_adapter_no;
+		break;
+	case lcs_startup:
+		((lcs_startup_cmd *) writecmd)->buff_size = LCS_IOBUFFSIZE;
+		break;
+	case lcs_shutdown:
+		break;
+	default:
+		break;
+	}
+	return (writecmd);
+}
+
+#if LCS_DEBUG_RESUME
+int lcs_read_resume_cnt, lcs_write_resume_cnt;
+#endif
+
+static void
+lcs_interrupt_resume_read(lcs_read_globals * read)
+{
+	int rc;
+	ccw1_t *curr_ccw;
+
+	lcs_debug_event(2, "lcs_interrupt_resume_read entered\n");
+	if ((read->ccw[(read->rx_idx - 1) & (LCS_NUM_RX_BUFFS - 1)].
+	     flags & CCW_FLAG_SUSPEND) == 0)
+		lcs_bad_news
+		    ("lcs_interrupt_resume_read detected possible lack of "
+		     "suspend bug\n");
+	curr_ccw = &read->ccw[read->rx_idx];
+	curr_ccw->flags = CCW_FLAG_CC | CCW_FLAG_SLI | CCW_FLAG_PCI
+#if LCS_USE_IDALS
+	    | (curr_ccw->flags & CCW_FLAG_IDA)
+#endif
+	    ;
+	if ((rc = resume_IO(read->subchannel)) == 0) {
+#if LCS_DEBUG_RESUME
+		lcs_read_resume_cnt++;
+#endif
+		read->chan_busy_state = chan_busy;
+	} else
+		lcs_bad_news
+		    ("lcs_interrupt_resume_read returned %d for "
+		     "subchannel %X\n",
+		     rc, read->subchannel);
+}
+
+static void
+lcs_resume_read(lcs_read_globals * read)
+{
+	lcs_debug_event(2, "lcs_resume_read entered\n");
+	lcs_chan_lock(read);
+	if (read->chan_busy_state == chan_idle)
+		lcs_interrupt_resume_read(read);
+	read->lancmd_reply_ptr = NULL;
+	lcs_chan_unlock(read);
+}
+
+static int
+lcs_resume_write(lcs_write_globals * write)
+{
+	int rc = 0;
+
+	lcs_debug_event(2, "lcs_resume_write entered write=%p\n", write);
+	lcs_chan_lock(write);
+	if (write->chan_busy_state == chan_idle && lcs_getbuffs_filled(write)) {
+		write->ccw[write->prepare_idx].flags &= ~CCW_FLAG_SUSPEND;
+		write->prepare_idx =
+		    ((write->prepare_idx + 1) & (LCS_NUM_TX_BUFFS - 1));
+		if ((rc = resume_IO(write->subchannel)) == 0) {
+			lcs_debug_event(2,"lcs_resume_write resume_IO "
+					"successful prepare_idx=%u "
+					"tx_idx=%u\n",
+					write->prepare_idx, write->tx_idx);
+#if LCS_DEBUG_RESUME
+			lcs_write_resume_cnt++;
+#endif
+			write->chan_busy_state = chan_busy;
+			/* the << TOD_SHIFT_TO_USECS is to adjust 
+			   the inequality to microseconds 
+			   for the tod in lcs_tx_is_busy
+			   The extra is adjustment is
+			   so that the tx_is_busy will weigh 
+			   in favour of large transmission buffers.
+			 */
+
+			write->adjusted_last_bytes_still_being_txed =
+			    (uint64_t) ((write->bytes_still_being_txed +
+					 500) << TOD_SHIFT_TO_USECS);
+			write->last_resume_time = lcs_get_tod();
+		} else
+			lcs_bad_news
+			    ("lcs_resume_write returned %d for "
+			     "subchannel %X\n",rc,write->subchannel);
+
+	}
+	lcs_chan_unlock(write);
+	return rc;
+}
+
+/*
+  Unfortunately we don't know if the lcs interface is busy
+  simply by knowing we have started a transmission & not
+  recieved a interrupt yet because the osa microcode simply
+  copies the packet into its own internal buffers.
+  I estimate whether the interface maybe busy by assuming
+  an extremely optimistic 30MB/sec transmission rate ( might
+  happen on a gigabit ethernet card ), i.e. if this routine
+  returns true the interface is almost definitely busy.
+ */
+static int
+lcs_tx_is_busy(lcs_write_globals * write, uint64_t tod)
+{
+	uint64_t delta_tx = tod - write->last_resume_time;
+	int rc;
+
+	/* 30MB/sec = 30 bytes per usec */
+	if (write->adjusted_last_bytes_still_being_txed < (30 * delta_tx))
+		rc = FALSE;
+	else
+		rc = TRUE;
+#if 0
+	lcs_debug_event(2,
+			"%s being txed %08X tod %08X last resume=%08X "
+			"delta_tx %08X\n",
+			(rc ? "lcs busy" : "lcs not busy"),
+			(unsigned) ((write->
+				     adjusted_last_bytes_still_being_txed >>
+				     TOD_SHIFT_TO_USECS)),
+			(unsigned) (tod >> TOD_SHIFT_TO_USECS),
+			(unsigned) (write->
+				    last_resume_time >> TOD_SHIFT_TO_USECS),
+			(unsigned) ((delta_tx) >> TOD_SHIFT_TO_USECS));
+#endif
+	return (rc);
+}
+
+static void
+lcs_queue_write(lcs_write_globals * write)
+{
+	/* wait on write in shutdown func should avoid this 
+	 * needing mod usage counts */
+	lcs_debug_event(2, "lcs_queue_write write=%p\n", write);
+	write->resume_queued = TRUE;
+	queue_task(&write->resume_task, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
+}
+
+static void
+lcs_queue_write_if_necessary(lcs_write_globals * write)
+{
+	lcs_debug_event(2, "lcs_queue_write_if_necessary write=%p\n", write);
+	if (!write->resume_queued) {
+		write->resume_loopcnt = 0;
+		lcs_queue_write(write);
+	}
+}
+
+static int
+lcs_should_queue_write(lcs_write_globals * write, uint64_t tod)
+{
+
+	if (lcs_getbuffs_filled(write) < (LCS_NUM_TX_BUFFS - 1)
+	    && (lcs_tx_is_busy(write, tod) ||
+		((tod - write->last_lcs_txpacket_time) <
+		 (25 << TOD_SHIFT_TO_USECS))))
+		return (TRUE);
+	return (FALSE);
+
+}
+
+static void
+lcs_resume_writetask(lcs_write_globals * write)
+{
+	uint64_t tod;
+
+	lcs_debug_event(2, "lcs_resume_writetask write=%p\n", write);
+	lcs_chan_lock(write);
+	tod = lcs_get_tod();
+	if (write->resume_loopcnt < 20 && lcs_should_queue_write(write, tod)) {
+		write->resume_loopcnt++;
+		lcs_queue_write(write);
+		lcs_chan_unlock(write);
+		return;
+	} else {
+#if 0
+		if (write->resume_loopcnt > 10)
+			lcs_debug_event(1,"lcs_resume_writetask bad "
+					"loopcnt %d\n",write->resume_loopcnt);
+#endif
+		lcs_resume_write(write);
+	}
+	write->resume_queued = FALSE;
+	lcs_chan_unlock(write);
+}
+
+static int
+lcs_calcsleeptime(lcs_drvr_globals * drvr_globals, u8 cmd_code)
+{
+	if ((cmd_code == lcs_startlan || cmd_code == lcs_stoplan))
+		return (drvr_globals->slow_hw ? 60 : 5);
+	else
+		return (drvr_globals->slow_hw ? 5 : 5);
+
+}
+
+static int
+lcs_resumeandwait(lcs_write_globals * write, u8 cmd_code)
+{
+	int rc;
+
+	lcs_initqueue(write);
+	if ((rc = lcs_resume_write(write)))
+		return (rc);
+	return (lcs_sleepon
+		(write, lcs_calcsleeptime(write->drvr_globals, cmd_code)));
+}
+
+static int
+lcs_lgw_common(lcs_drvr_globals * drvr_globals, u8 cmd_code)
+{
+
+	lcs_write_globals *write = drvr_globals->write;
+	lcs_std_cmd *writecmd;
+	wait_on_write(drvr_globals);
+	writecmd = lcs_prepare_lancmd(write, cmd_code,
+				      drvr_globals->rel_adapter_no,
+				      lcs_lgw_initiated,
+				      drvr_globals->lan_type);
+	writecmd->sequence_no = drvr_globals->lgw_sequence_no;
+	return (lcs_resumeandwait(write, cmd_code));
+}
+
+static void
+lcs_start_doing_io(lcs_drvr_globals * drvr_globals)
+{
+	netif_wake_queue(drvr_globals->dev);
+	drvr_globals->state = lcs_doing_io;
+}
+
+static int
+lcs_lgw_stoplan(lcs_drvr_globals * drvr_globals)
+{
+	struct net_device *dev;
+
+	lcs_daemonize("lcs_lgw_stoplan", 0, TRUE);
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->state != lcs_doing_io)
+		goto Done1;
+	dev = drvr_globals->dev;
+	lcs_bad_news("lcs problems detected %s temporarily unavailable.\n",
+		     dev->name);
+	lcs_lgw_common(drvr_globals, lcs_stoplan);
+	netif_stop_queue(dev);
+	drvr_globals->state = lcs_doing_io;
+Done1:
+	atomic_set(&drvr_globals->kernel_thread_lock, 1);
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static int
+lcs_lgw_startlan(lcs_drvr_globals * drvr_globals)
+{
+	struct net_device *dev;
+
+	lcs_daemonize("lcs_lgw_startlan", 0, TRUE);
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->state != lcs_doing_io)
+		goto Done1;
+	dev = drvr_globals->dev;
+	lcs_good_news("lcs device %s restarted.\n", dev->name);
+	lcs_lgw_common(drvr_globals, lcs_startlan);
+	lcs_start_doing_io(drvr_globals);
+Done1:
+	atomic_set(&drvr_globals->kernel_thread_lock, 1);
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static int
+lcs_lgw_resetlan(lcs_drvr_globals * drvr_globals)
+{
+	struct net_device *dev;
+	int retrycnt;
+
+	lcs_daemonize("lcs_lgw_resetlan", 0, TRUE);
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->state != lcs_doing_io)
+		goto Done1;
+	dev = drvr_globals->dev;
+	lcs_debug_event(0, "lcs reset %s.\n", dev->name);
+	for (retrycnt = 0; retrycnt < 10; retrycnt++) {
+		if (lcs_detect(drvr_globals,drvr_globals->rel_adapter_no,0,0,
+			       drvr_globals->lan_type,dev->dev_addr) == 0) {
+			lcs_start_doing_io(drvr_globals);
+			lcs_good_news("lcs reset %s successfully.\n",
+				      dev->name);
+			goto Done1;
+		}
+		lcs_debug_event(0, "lcs_resetlan retrycnt %d\n", retrycnt);
+		schedule_timeout(3 * HZ);
+		atomic_set(&drvr_globals->retry_cnt, 0);
+	}
+	lcs_resetstate(drvr_globals);
+	lcs_bad_news("lcs problems occured restarting after reset %s.\n",
+		     dev->name);
+Done1:
+	atomic_set(&drvr_globals->kernel_thread_lock, 1);
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static void
+lcs_queue_thread(int (*routine) (lcs_drvr_globals *),
+		 lcs_drvr_globals * drvr_globals)
+{
+	if (atomic_dec_and_test(&drvr_globals->kernel_thread_lock)) {
+		netif_stop_queue(drvr_globals->dev);
+		MOD_INC_USE_COUNT;
+		drvr_globals->kernel_thread_routine = routine;
+#if LINUX_VERSION_CODE<=KERNEL_VERSION(2,2,16)
+		queue_task(&drvr_globals->kernel_thread_task, &tq_scheduler);
+#else
+		schedule_task(&drvr_globals->kernel_thread_task);
+#endif
+	} else
+		lcs_debug_event(1,"lcs_queue_thread busy drvr_globals=%p "
+				"routine=%p",drvr_globals,routine);
+}
+
+static int
+lcs_check_reset(lcs_chan_globals * chan_globals)
+{
+	lcs_drvr_globals *drvr_globals = chan_globals->drvr_globals;
+	devstat_t *devstat = &chan_globals->devstat;
+
+	if (devstat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+		if (drvr_globals->state == lcs_doing_io &&
+		    (devstat->scnt >= 1) &&
+		    ((lcs_sense_byte_1) (devstat->ii.sense.data[1]))
+		    == resetting_event) {
+			lcs_debug_exception(0,"lcs reseting event occuring "
+					    "devno=%04x\n",
+					    (int) chan_globals->devno);
+			atomic_set(&drvr_globals->retry_cnt, 0);
+			switch (drvr_globals->state) {
+			case lcs_idle_requesting_channels_for_lancmds:
+			case lcs_requesting_channels_for_lancmds:
+			case lcs_got_write_channel_for_lancmds:
+			case lcs_doing_lancmds:
+				lcs_wakeup(drvr_globals->read, -ERETRY);
+				lcs_wakeup(drvr_globals->write, -ERETRY);
+				break;
+			case lcs_doing_io:
+				lcs_queue_thread(lcs_lgw_resetlan,
+						 drvr_globals);
+				break;
+			default:
+				break;
+			}
+			return (TRUE);
+		} else {
+			if ((devstat->scnt >= 1) && ((lcs_sense_byte_0)
+						     (devstat->ii.sense.
+						      data[0]) ==
+						     (intervention_required |
+						      interface_disconnect)))
+				lcs_debug_exception(0,
+						    "lcs intervention_required "
+						    "& interface_disconnect "
+						    "detected devno=0x%04x\n",
+						    (int) chan_globals->devno);
+			else {
+				lcs_debug_event(0,
+						"lcs unknown sense data "
+						"devno=0x%04x\n"
+						"sense_cnt=%d sense_data=\n"
+						"%08x %08x %08x %08x\n"
+						"%08x %08x %08x %08x\n",
+						(int) chan_globals->devno,
+						(int) devstat->scnt,
+						((int *)&devstat->
+						 ii.sense.data)[0],
+						((int *)&devstat->
+						 ii.sense.data)[1],
+						((int *)&devstat->
+						 ii.sense.data)[2],
+						((int *)&devstat->
+						 ii.sense.data)[3],
+						((int *)&devstat->
+						 ii.sense.data)[4],
+						((int *)&devstat->
+						 ii.sense.data)[5],
+						((int *)&devstat->
+						 ii.sense.data)[6],
+						((int *)&devstat->
+						 ii.sense.data)[7]);
+				if (devstat->scnt > 2
+				    || (devstat->ii.sense.data[0] == 0
+					&& devstat->ii.sense.data[1] == 0)) {
+					lcs_debug_event(0,
+							"lcs sense data "
+							"looks like rubbish "
+							"ignoring it\n");
+					devstat->flag &=
+						~DEVSTAT_FLAG_SENSE_AVAIL;
+				}
+			}
+		}
+	}
+	return (FALSE);
+}
+
+#if LCS_ZERO_COPY_READ
+static inline void
+lcs_rxskb(lcs_drvr_globals * drvr_globals, struct sk_buff *skb, u16 pkt_len,
+	  u16 offset, struct net_device_stats *stats)
+{
+	stats->rx_bytes += pkt_len;
+	if (use_hw_stats == FALSE)
+		stats->rx_packets++;
+	lcs_debug_event(2, "netif_rx called\n");
+	lcs_debug_event(2, "received %u bytes rx_bytes=%lu\n",
+			(unsigned) pkt_len, stats->rx_bytes);
+	skb_reserve(skb, sizeof (lcs_header_type) + offset);
+	skb_put(skb, pkt_len);
+	/* Horrible horrible kludge to fix bug in some socket code */
+	/* usage of skb->truesize hopefully this bug will be fixed in */
+	/* upper layers soon */
+	skb->truesize = skb->len;
+	skb->protocol = drvr_globals->lan_type_trans(skb, skb->dev);
+	netif_rx(skb);
+	skb->dev->last_rx = jiffies;
+}
+#endif
+
+static int
+lcs_rxpacket(lcs_drvr_globals * drvr_globals, u8 * start_lcs_buff,
+	     lcs_std_cmd ** lancmd_reply
+#if LCS_ZERO_COPY_READ
+	     , u32 curr_idx
+#endif
+    )
+{
+	lcs_read_globals *read = NULL;
+
+	struct sk_buff *curr_skb
+#if LCS_ZERO_COPY_READ
+	, *prev_skb
+#endif
+	;
+	struct net_device *dev = NULL;
+	struct net_device_stats *stats = NULL;
+	lcs_header_type *lcs_header_ptr = (lcs_header_type *) start_lcs_buff;
+	u16 curr_offset, curr_pkt_len
+#if  LCS_ZERO_COPY_READ
+	, prev_pkt_len, curr_skb_offset, prev_skb_offset
+#endif
+	;
+
+	lcs_debug_event(2, "Entering lcs_rxpacket\n");
+	if (drvr_globals == NULL) {
+		lcs_bad_news("drvr_globals=NULL\n");
+		return -EPERM;
+	}
+
+	dev = drvr_globals->dev;
+	read = drvr_globals->read;
+#if LCS_ZERO_COPY_READ
+	if (atomic_read(skb_datarefp(read->skb_buff[curr_idx])) != 1) {
+		lcs_bad_news("lcs_rxpacket skb->refcnt=%d start_lcs_buff=%p\n",
+			     atomic_read(skb_datarefp
+					 (read->skb_buff[curr_idx])),
+			     start_lcs_buff);
+		return -EIO;
+	}
+#endif
+	stats = &drvr_globals->stats;
+	lcs_debug_event(2, "We appear to have received a packet buff=%p\n",
+			lcs_header_ptr);
+#if LCS_ZERO_COPY_READ
+	curr_skb = NULL;
+	curr_pkt_len = curr_skb_offset =
+#endif
+	    curr_offset = 0;
+	while (lcs_header_ptr->offset) {
+		lcs_debug_event(3, "lcs_header_ptr=%p curroffset=%d\n",
+				lcs_header_ptr, curr_offset);
+#if LCS_ZERO_COPY_READ
+		prev_pkt_len = curr_pkt_len;
+		prev_skb = curr_skb;
+		prev_skb_offset = curr_skb_offset;
+#endif
+#if 0
+		static int idx = 0;
+		idx++;
+		if ((idx & 0x1ff) == 0) {
+			lcs_header_ptr->type = lcs_control_frame_type;
+			((lcs_std_cmd *) lcs_header_ptr)->initiator =
+			    lcs_lgw_initiated;
+			(((lcs_std_cmd *) lcs_header_ptr)->cmd_code) =
+			    lcs_startup;
+		}
+#endif
+		if (lcs_header_ptr->offset > LCS_IOBUFFSIZE ||
+		    lcs_header_ptr->offset < curr_offset) {
+			if (use_hw_stats == FALSE) {
+				stats->rx_length_errors++;
+				stats->rx_errors++;
+			}
+			lcs_bad_news
+			    ("lcs whacko rx_buffer read_globals=%p "
+			     "curr_offset=%d new_offset=%d\n",
+			     read, (int) curr_offset,
+			     (int) lcs_header_ptr->offset);
+			return -EIO;
+		}
+
+		if (lcs_header_ptr->type == lcs_control_frame_type) {
+			if (((lcs_std_cmd *) lcs_header_ptr)->initiator ==
+			    lcs_lgw_initiated
+			    && drvr_globals->state == lcs_doing_io) {
+				drvr_globals->lgw_sequence_no =
+				    ((lcs_std_cmd *) lcs_header_ptr)->sequence_no;
+				lcs_debug_display_read_buff
+				    ("lgw_initiated_command read buff",
+				     ((lcs_std_cmd *) lcs_header_ptr));
+				switch ((int)
+					(((lcs_std_cmd *)lcs_header_ptr)->
+					 cmd_code)) {
+				case lcs_startup:
+					atomic_set(&drvr_globals->retry_cnt,
+						   -1);
+					lcs_queue_thread(lcs_lgw_resetlan,
+							 drvr_globals);
+					break;
+				case lcs_startlan:
+					lcs_queue_thread(lcs_lgw_startlan,
+							 drvr_globals);
+					break;
+				case lcs_stoplan:
+					lcs_queue_thread(lcs_lgw_stoplan,
+							 drvr_globals);
+					break;
+				default:
+					lcs_debug_exception(1,"lcs "
+					    "unrecognised lgw command "
+					    "received 0x%02x on "
+					    "devno=%04x\n",
+					    (int)((lcs_std_cmd *)
+						  lcs_header_ptr)->cmd_code,
+					    (int)read->devno);
+				}
+			} else {
+				if (drvr_globals->state == lcs_doing_lancmds) {
+					if (((((lcs_std_cmd *) 
+					       lcs_header_ptr)->sequence_no ==
+					      drvr_globals->sequence_no))
+					    &&
+					    (((lcs_std_cmd *) 
+					      lcs_header_ptr)->cmd_code ==
+					     drvr_globals->cmd_code)) {
+						*lancmd_reply =
+						    read->lancmd_reply_ptr =
+						    (lcs_std_cmd *)lcs_header_ptr;
+						lcs_debug_event(2,
+							"got a valid "
+							"lancommand %p "
+							"cmd_code=%02x "
+							"sequence_no=%d\n",
+							read->lancmd_reply_ptr,
+							(int) 
+							((lcs_std_cmd *)
+							 lcs_header_ptr)->
+							cmd_code, 
+							(int) 
+							((lcs_std_cmd *)
+							 lcs_header_ptr)->
+							sequence_no);
+						lcs_wakeup((lcs_chan_globals *)
+							   read, 0);
+						break;
+					}
+				}
+			}
+		} else if (dev && drvr_globals->state == lcs_doing_io) {	
+			/* the packet is for tcpip */
+			
+			/* dev_alloc_skb allocs with GFP_ATOMIC currently */
+			/* so this should be okay under interrupt */
+			/* hopefully .... */
+#if LCS_ZERO_COPY_READ
+			if (curr_skb == NULL) {
+				/* We need to detach the buffer */
+				struct sk_buff *new_skb;
+				ccw1_t temp_ccw = read->ccw[curr_idx];
+				if (set_normalized_cda (&temp_ccw,
+							new_skb->data)) {
+					stats->rx_dropped++;
+					lcs_bad_news
+					    ("%s: Memory squeeze, "
+					     "dropping packet.\n",
+					     dev->name);
+					return -ENOMEM;
+				}
+				if ((new_skb=
+				     lcs_dev_alloc_skb(LCS_READ_ALLOCSIZE))==
+				    NULL) {
+					clear_normalized_cda(&temp_ccw);
+					stats->rx_dropped++;
+					lcs_bad_news
+					    ("%s: Memory squeeze, "
+					     "dropping packet.\n",
+					     dev->name);
+					return -ENOMEM;
+				}
+				curr_skb = read->skb_buff[curr_idx];
+				curr_skb->dev = dev;
+				curr_skb->ip_summed=(checksum_received_ip_pkts
+						     ? CHECKSUM_NONE :
+						     CHECKSUM_UNNECESSARY);
+				clear_normalized_cda(&read->ccw[curr_idx]);
+				read->skb_buff[curr_idx] = new_skb;
+				read->ccw[curr_idx] = temp_ccw;
+			} else {
+				curr_skb = skb_clone(prev_skb, GFP_ATOMIC);
+				if (curr_skb == NULL) {
+					curr_skb = prev_skb;
+					stats->rx_dropped++;
+					lcs_bad_news("%s: Memory squeeze, "
+						     "dropping packet.\n",
+						     dev->name);
+					return -ENOMEM;
+				}
+				curr_skb_offset = curr_offset;
+			}
+			if (prev_skb)
+				lcs_rxskb(drvr_globals, prev_skb, prev_pkt_len,
+					  prev_skb_offset, stats);
+			curr_pkt_len =
+			    lcs_header_ptr->offset - curr_skb_offset -
+			    sizeof (lcs_header_type);
+#else
+			curr_pkt_len =
+			    lcs_header_ptr->offset - curr_offset -
+			    sizeof (lcs_header_type);
+			curr_skb = lcs_dev_alloc_skb(curr_pkt_len);
+			if (curr_skb) {
+				curr_skb->dev = dev;
+				memcpy(skb_put(curr_skb, curr_pkt_len),
+				       lcs_header_ptr + 1, curr_pkt_len);
+				curr_skb->protocol =
+				    drvr_globals->lan_type_trans(curr_skb, dev);
+				curr_skb->ip_summed =
+				    (checksum_received_ip_pkts ? CHECKSUM_NONE :
+				     CHECKSUM_UNNECESSARY);
+				stats->rx_bytes += curr_pkt_len;
+				if (use_hw_stats == FALSE)
+					stats->rx_packets++;
+				lcs_debug_event(2,"netif_rx called\n");
+				lcs_debug_event(2,"received %u bytes " \
+						"rx_bytes=%lu\n",
+						(unsigned) curr_pkt_len,
+						stats->rx_bytes);
+				netif_rx(curr_skb);
+				curr_skb->dev->last_rx = jiffies;
+			} else {
+				lcs_bad_news
+				    ("%s: Memory squeeze, dropping packet.\n",
+				     dev->name);
+				stats->rx_dropped++;
+				return -ENOMEM;
+			}
+#endif
+		}
+		curr_offset = lcs_header_ptr->offset;
+		((addr_t) lcs_header_ptr) = start_lcs_buff + curr_offset;
+	}
+#if LCS_ZERO_COPY_READ
+	if (curr_skb)
+		lcs_rxskb(drvr_globals, curr_skb, curr_pkt_len, curr_skb_offset,
+			  stats);
+#endif
+	return 0;
+}
+
+/*
+ * This is the main interrupt handler it does a lot of sanity checking &
+ * wakes up a process if doing startup or shutdown or calls 
+ * queues lcs_rxpacket if a network packet is received or
+ * resets transmit busy a network packet has been transmitted &
+ * marks the bottom half so that networking knows it can transmit more packets 
+ * N.B. if we decide to call ssch directly or indirectly from the irq_handler 
+ * we had better increment chan_globals->lock_cnt & decrement it when done to avoid
+ * deadlocks ( this count can be over 2 inside the interrupt handler ),
+ * but not in normal tasks.
+ */
+
+static void
+lcs_handle_irq(int irq, devstat_t * devstat, struct pt_regs *regs)
+{
+	union {
+		lcs_read_globals *read;
+		lcs_write_globals *write;
+		lcs_chan_globals *globals;
+	} chan;
+	struct net_device *dev = NULL;
+	lcs_drvr_globals *drvr_globals = NULL;
+	lcs_debug_initmessage struct net_device_stats *stats;
+	ccw1_t *curr_ccw;
+	lcs_header_type *lcs_hdr;
+	u32 curr_ccwidx, curr_ccwidx2, curr_idx;
+	int chan_globals_valid = FALSE;
+
+	chan.globals = NULL;
+	if (!devstat)
+		goto lcs_int_spurious;
+	chan.globals = (lcs_chan_globals *) devstat->intparm;
+	if (!chan.globals || (irq != chan.globals->subchannel))
+		goto lcs_int_spurious;
+	chan_globals_valid = TRUE;
+	drvr_globals = chan.globals->drvr_globals;
+	lcs_debug_event(2,
+			"lcs_handle_irq irq=%x chan_globals=%p drvr_globals=%p"
+			" drvr_state=%d devstat=%p irb=%p cpu=%d "
+			"chan_busy_state=%d\n",
+			irq, chan.globals, drvr_globals, drvr_globals->state,
+			&chan.globals->devstat, &chan.globals->devstat.ii.irb,
+			smp_processor_id(), chan.globals->chan_busy_state);
+	if (chan.globals->lock_cnt)
+		lcs_bad_news("lcs_handle_irq lock owner %d lock_cnt=%d\n",
+			     chan.globals->lock_owner, chan.globals->lock_cnt);
+	if (drvr_globals->state == lcs_interrupted) {
+		lcs_wakeup(chan.globals, -EINTR);
+	} else {
+		if (lcs_check_reset(chan.globals))
+			return;
+		if (chan.globals->irq_allocated_magic != LCS_MAGIC)
+			goto lcs_int_spurious;
+	}
+	dev = drvr_globals->dev;
+	if (dev == NULL && drvr_globals->state == lcs_doing_io) {
+		lcs_debug_setmessage("dev=NULL in handle irq");
+		goto lcs_int_debug_info;
+	}
+	stats = &drvr_globals->stats;
+	if (drvr_globals->state == lcs_halting_subchannels) {
+		lcs_wakeup(chan.globals, 0);
+		return;
+	}
+	chan.globals->lock_owner = smp_processor_id();
+	chan.globals->lock_cnt = 1;
+	if (drvr_globals->read == chan.read) {
+		if (devstat->dstat != 0 ||
+		    (devstat->cstat & ~SCHN_STAT_PCI) != 0) {
+
+			lcs_debug_event(0,
+					"lcs_handle_irq dstat=%02x cstat=%02x "
+					"drvr_globals_state=%d\n",
+					devstat->dstat, devstat->cstat,
+					drvr_globals->state);
+			switch (drvr_globals->state) {
+			case lcs_idle_requesting_channels_for_lancmds:
+			case lcs_requesting_channels_for_lancmds:
+			case lcs_got_write_channel_for_lancmds:
+			case lcs_doing_lancmds:
+				lcs_restartreadio(drvr_globals);
+				break;
+			case lcs_doing_io:
+				lcs_retry(chan.globals);
+				break;
+			default:
+				break;
+			}
+			goto lcs_normal_ret;
+		}
+		switch (chan.read->chan_busy_state) {
+		case chan_busy: {
+			int rxerr = 0;
+			lcs_std_cmd *lancmd_reply_ptr;
+			
+			switch (drvr_globals->state) {
+			case lcs_doing_io:
+			case lcs_doing_lancmds:
+				curr_idx =
+		    			((ccw1_t *)
+	    				 phys_to_virt(devstat->cpa) -
+    					 &chan.read->ccw[0]);
+				/* We don't need to divide by
+				 * sizeof(ccw1_t) here as we are
+				 * doing pointer arithmetic */
+				curr_ccwidx = ((curr_idx - 2) 
+					       & (LCS_NUM_RX_BUFFS - 1));
+				curr_ccwidx2 = ((curr_idx - 1) 
+						& (LCS_NUM_RX_BUFFS - 1));
+				for (curr_idx = chan.read->rx_idx;
+				     curr_idx != curr_ccwidx2;
+				     curr_idx = ((curr_idx + 1) 
+						 & (LCS_NUM_RX_BUFFS - 1))) {
+#if LCS_ZERO_COPY_READ
+					lcs_hdr = (lcs_header_type *) 
+						(chan.read->
+						 skb_buff[curr_idx]->data);
+#else
+					lcs_hdr = (lcs_header_type *)
+						(chan.read->
+						 iobuff[curr_idx]);
+#endif
+					
+					if (lcs_hdr->offset !=
+					    LCS_ILLEGAL_OFFSET) {
+						/* Detect duplicate interrupts 
+						   unfilled buffers etc. */
+						lancmd_reply_ptr = NULL;
+						if (rxerr != -ENOMEM)
+							rxerr = lcs_rxpacket
+							(drvr_globals,
+							 (u8 *)lcs_hdr,
+							 &lancmd_reply_ptr
+#if LCS_ZERO_COPY_READ
+							 , curr_idx
+#endif
+							);
+						if (lancmd_reply_ptr == NULL) {
+#if LCS_ZERO_COPY_READ
+							lcs_hdr =
+							(lcs_header_type *) 
+							(chan.read->
+							 skb_buff[curr_idx]->
+							 data);
+#endif
+							lcs_hdr->offset =
+							LCS_ILLEGAL_OFFSET;
+						}
+					} else {
+						lcs_bad_news
+							("lcs_handle_irq race "
+							 "condition Illegal"
+							 " offset buffer "
+							 "for ccw=%p\n",
+							 &chan.read->
+							 ccw[curr_idx]);
+						goto lcs_int_debug_info;
+					}
+				}
+				if (chan.read->rx_idx != curr_ccwidx2) {
+					curr_ccw =
+						&chan.read->ccw[curr_ccwidx];
+					curr_ccw->flags =
+						CCW_FLAG_CC | CCW_FLAG_SLI |
+						CCW_FLAG_SUSPEND
+#if LCS_USE_IDALS
+						| (curr_ccw->flags &
+						   CCW_FLAG_IDA)
+#endif
+						;
+					curr_idx = (chan.read->rx_idx - 1) & 
+						(LCS_NUM_RX_BUFFS - 1);
+					curr_ccw = &chan.read->ccw[curr_idx];
+					curr_ccw->flags = CCW_FLAG_CC |
+						CCW_FLAG_SLI |
+						CCW_FLAG_PCI
+#if LCS_USE_IDALS
+						| (curr_ccw->flags &
+						   CCW_FLAG_IDA)
+#endif
+						;
+					chan.read->rx_idx = curr_ccwidx2;
+				}
+				break;
+			default:
+				break;
+			}
+				}
+				break;
+		case chan_started_successfully:
+			chan.read->chan_busy_state = chan_busy;
+			break;
+		default:
+			break;
+		}
+
+		/*
+		   We need to suspend if till the lancmd reply is consumed.
+		 */
+		if ((chan.read->chan_busy_state == chan_busy ||
+		     chan.read->chan_busy_state == chan_idle) &&
+#if 0
+		    devstat->flag & DEVSTAT_SUSPENDED
+#else
+		    devstat->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED
+#endif
+		    ) {
+			chan.read->chan_busy_state = chan_idle;
+			if (chan.read->lancmd_reply_ptr == NULL) {
+				lcs_debug_event(2,"resume called from "
+						"interrupt handler.\n");
+				lcs_interrupt_resume_read(chan.read);
+			}
+		}
+	} else {
+
+		if (devstat->dstat != 0 ||
+		    devstat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
+		    devstat->cstat != 0) {
+			lcs_debug_event(0,
+					"lcs_handle_irq write channel "
+					"dstat=%02x flag=%x cstat=%02x "
+					"drvr_globals_state=%d\n",
+					(int) devstat->dstat,
+					(int) devstat->flag,
+					(int) devstat->cstat,
+					drvr_globals->state);
+			switch (drvr_globals->state) {
+			case lcs_idle_requesting_channels_for_lancmds:
+			case lcs_requesting_channels_for_lancmds:
+			case lcs_got_write_channel_for_lancmds:
+			case lcs_doing_lancmds:
+				lcs_restartwriteio(drvr_globals);
+				break;
+			case lcs_doing_io:
+				lcs_queue_thread(lcs_lgw_resetlan,
+						 drvr_globals);
+				break;
+			default:
+				break;
+			}
+			goto lcs_normal_ret;
+		}
+		switch (chan.write->chan_busy_state) {
+		case chan_started_successfully:
+			chan.write->chan_busy_state = chan_idle;
+			break;
+		case chan_busy:
+			chan.write->chan_busy_state = chan_idle;
+#if 0
+			if (devstat->flag & DEVSTAT_SUSPENDED)
+#else
+			if (devstat->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED)
+#endif
+			{
+				switch (drvr_globals->state) {
+				case lcs_doing_io:
+				case lcs_requesting_channels_for_lancmds:
+				case lcs_doing_lancmds:
+					curr_idx =
+					    ((ccw1_t *)
+					     phys_to_virt(devstat->cpa) -
+					     &chan.write->ccw[0]);
+					curr_ccwidx =
+					    ((curr_idx - 2) & 
+					     (LCS_NUM_TX_BUFFS - 1));
+					curr_ccwidx2 =
+					    ((curr_idx - 1) 
+					     & (LCS_NUM_TX_BUFFS - 1));
+					if (curr_ccwidx == chan.write->tx_idx) {
+						lcs_bad_news
+						    ("lcs_handle_irq race "
+						     "tx_idx=%d=curr_ccwidx "
+						     "prepare_idx=%u "
+						     "write_globals=%p\n",
+						     chan.write->tx_idx,
+						     chan.write->prepare_idx,
+						     chan.write);
+						goto lcs_int_debug_info;
+					}
+
+					for (curr_idx =
+					     ((chan.write->tx_idx + 1) 
+					      & (LCS_NUM_TX_BUFFS - 1));
+					     curr_idx != curr_ccwidx2;
+					     curr_idx =
+					     ((curr_idx + 1) 
+					      & (LCS_NUM_TX_BUFFS - 1))) {
+						curr_ccw =
+						    &chan.write->ccw[curr_idx];
+						curr_ccw->flags |=
+						    CCW_FLAG_SUSPEND;
+						curr_ccw->count = 0;
+					}
+					chan.write->tx_idx = curr_ccwidx;
+					curr_ccw =
+					    &chan.write->ccw[chan.write->
+							     prepare_idx];
+					if (curr_ccw !=
+					    &chan.write->ccw[curr_ccwidx]) {
+					    if (curr_ccw->count != 0) {
+						/* Tx the buffer currently
+						 * being prepared */
+					 	if (drvr_globals->state ==
+						    lcs_doing_io &&
+						    lcs_should_queue_write
+						    (chan.write, lcs_get_tod()))
+						lcs_queue_write_if_necessary
+								(chan.write);
+						else
+							lcs_resume_write
+								(chan.write);
+					    }
+					} else {
+						lcs_bad_news
+						    ("lcs_handle_irq race "
+						     "tx_idx=%u=prepare_idx "
+						     "write_globals=%p\n",
+						     (int) chan.write->
+						     prepare_idx, chan.write);
+						goto lcs_normal_ret;
+					}
+					break;
+				default:
+					break;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+		if (chan.write->chan_busy_state == chan_idle) {
+			switch (drvr_globals->state) {
+			case lcs_idle_requesting_channels_for_lancmds:
+			case lcs_requesting_channels_for_lancmds:
+				drvr_globals->state =
+				    lcs_got_write_channel_for_lancmds;
+			case lcs_doing_lancmds:
+				lcs_wakeup(chan.globals, 0);
+				break;
+			case lcs_doing_io:
+				stats->tx_bytes +=
+				    chan.write->bytes_still_being_txed;
+				chan.write->bytes_still_being_txed = 0;
+				if (!use_hw_stats)
+					stats->tx_packets +=
+					    chan.write->pkts_still_being_txed;
+				chan.write->pkts_still_being_txed = 0;
+				netif_wake_queue(dev);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	goto lcs_normal_ret;
+lcs_int_spurious:
+	lcs_debug_setmessage("received spurious interrupt");
+lcs_int_debug_info:
+	lcs_debugchannel(message, chan.globals);
+lcs_normal_ret:
+	lcs_debug_event(2, "lcs irq exited irq=%x\n", irq);
+	if (chan_globals_valid) {
+		chan.globals->lock_owner = LCS_INVALID_LOCK_OWNER;
+		chan.globals->lock_cnt = 0;
+	}
+}
+
+/* 
+ * Wrappers to allocate irqs if these fail the io channel is probably
+ * being used by another device.
+ */
+static int
+lcs_allocirq_func(lcs_chan_globals * chan_globals)
+{
+	int rc;
+
+	lcs_debug_event(2, "lcs_allocirq called chan_globals=%p\n",
+			chan_globals);
+	if (chan_globals->irq_allocated_magic) {
+		lcs_bad_news("lcs_allocirq irq already allocated");
+		return -EBUSY;
+	} else {
+		chan_globals->devstat.intparm = (addr_t) chan_globals;
+		rc =
+#if LCS_CHANDEV
+		    chandev_request_irq
+#else
+		    request_irq
+#endif
+		    (chan_globals->subchannel,
+		     (void (*)(int, void *, struct pt_regs *)) lcs_handle_irq,
+		     0, cardname, &chan_globals->devstat);
+		if (!rc)
+			chan_globals->irq_allocated_magic = LCS_MAGIC;
+
+#if LCS_DEBUG
+		else
+			lcs_debug_event(2,"request irq failed error code %d "
+					"subchannel %2X\n",
+					rc,chan_globals->subchannel);
+#endif
+		return rc;
+	}
+}
+
+#define lcs_allocirq(chan_globals) \
+	lcs_allocirq_func((lcs_chan_globals *)(chan_globals))
+
+static void
+lcs_freeirq(lcs_chan_globals * chan_globals)
+{
+	if (chan_globals->irq_allocated_magic) {
+#if LCS_CHANDEV
+		chandev_free_irq(chan_globals->subchannel,
+				 &chan_globals->devstat);
+#else
+		free_irq(chan_globals->subchannel, &chan_globals->devstat);
+#endif
+		chan_globals->irq_allocated_magic = 0;
+	}
+}
+
+static lcs_inline void
+lcs_freeallirqs(lcs_drvr_globals * drvr_globals)
+{
+	lcs_debug_event(2, "lcs_freeallirqs called %p\n", drvr_globals);
+	lcs_freeirq((lcs_chan_globals *) drvr_globals->read);
+	lcs_freeirq((lcs_chan_globals *) drvr_globals->write);
+}
+
+/*
+ * Generic routine for sending all startup & shutdown command primatives  
+ * to lcs.
+ * A unit check with a sense code of 0x42 may be presented here if this
+ * happens we restart the startup procedure, currently the osa card has been
+ * seen to present the unit check very late in the startup sequence 
+ * & resend outstanding buffers already read, the source of this problem is
+ * unknown, this problem is handled basically by checking sequence
+ * numbers & disgarding packets already received.
+ */
+static int
+lcs_lancmd(lcs_cmd cmd_code, u8 rel_adapter_no, lcs_drvr_globals * drvr_globals
+#ifdef CONFIG_IP_MULTICAST
+	   , u16 num_ipm_pairs, lcs_ip_mac_addr_pair * ip_mac_pairs
+#endif
+)
+{
+	lcs_std_cmd *readcmd, *writecmd;
+	lcs_read_globals *read;
+	lcs_write_globals *write;
+	int rc = 0;
+	int retry_cnt = 0;
+
+	read = drvr_globals->read;
+	write = drvr_globals->write;
+	lcs_debug_exception(2, "lcs_lancmd cmd code=%02x drvr_globals=%p\n",
+			    (int) cmd_code, drvr_globals);
+	wait_on_write(drvr_globals);
+Retry:
+	read->lancmd_reply_ptr = NULL;
+	do {
+		if ((writecmd =
+		     lcs_prepare_lancmd(write, cmd_code, rel_adapter_no,
+					lcs_390_initiated,
+					drvr_globals->lan_type)) == 0) {
+			lcs_debug_event(2, "lancmd2 lcs_prepare_cmd failed\n");
+			return (-EIO);
+		}
+		lcs_debug_event(2, "lcs_lancmd writecmd=%p\n", writecmd);
+		read->lancmd_reply_ptr = NULL;
+		lcs_initqueue(read);
+#ifdef CONFIG_IP_MULTICAST
+		if (cmd_code == lcs_setipm || cmd_code == lcs_delipm) {
+			((lcs_ipm_ctlmsg *) writecmd)->version = 4;
+			((lcs_ipm_ctlmsg *) writecmd)->num_ipm_pairs =
+			    num_ipm_pairs;
+			memcpy(&((lcs_ipm_ctlmsg *) writecmd)->ip_mac_pair[0],
+			       ip_mac_pairs,
+			       sizeof (lcs_ip_mac_addr_pair) * num_ipm_pairs);
+		}
+		if (cmd_code == lcs_qipassist) {
+			((lcs_qipassist_ctlmsg *) writecmd)->num_ip_pairs = 0;
+			((lcs_qipassist_ctlmsg *) writecmd)->version = 4;
+		}
+#endif
+		writecmd->sequence_no = ++drvr_globals->sequence_no;
+		lcs_debug_event(2, "sequence_no=%d\n",
+				(int) drvr_globals->sequence_no);
+		drvr_globals->cmd_code = cmd_code;
+		rc = lcs_resumeandwait(write, cmd_code);
+	} while (rc == -EAGAIN && retry_cnt++ < 3);
+	if (rc)
+		goto Done;
+	rc = lcs_sleepon(read, lcs_calcsleeptime(drvr_globals, cmd_code));
+	if (rc == -ERETRY)
+		goto Done;
+	if ((readcmd = read->lancmd_reply_ptr) == NULL || rc == -EAGAIN) {
+		if (retry_cnt++ < 3) {
+			lcs_debug_event(2,
+					"retrying cmd_code=0x02 read_cmd=%p "
+					"rc=%d\n",
+					(int) cmd_code, readcmd, rc);
+			goto Retry;
+		} else {
+			lcs_debug_event(2,"lcs_lancmd retry count "
+					"exceeded giving up\n");
+			goto Done;
+		}
+	}
+	if (readcmd->cmd_code != cmd_code
+	    || (writecmd->sequence_no - readcmd->sequence_no) > 3) {
+		lcs_debug_event(1,
+				"readcmd=%p read_cmd_code=%02x write_cmd_code=%02x "
+				"read_seq=%04x write_seq=%04x\n",
+				readcmd, (int) readcmd->cmd_code,
+				(int) cmd_code, (int) readcmd->sequence_no,
+				(int) writecmd->sequence_no);
+		goto Fail;
+	} else {
+		switch (cmd_code) {
+		case lcs_lanstat:
+			if (readcmd->rel_adapter_no != rel_adapter_no) {
+				lcs_debug_event(1, "rel adapters differ\n");
+				goto Fail;
+			}
+			/* I got back a funny rel adapter no from stoplan 
+			 * so I'll assume it's broke */
+		case lcs_startlan:
+			if (readcmd->lan_type != writecmd->lan_type) {
+				lcs_debug_event(1,"lan types differ\n");
+				goto Fail;
+			}
+			if (readcmd->return_code != 0) {
+				lcs_debug_event(2,"readcmd_return_code=%02x\n",
+						(int) readcmd->return_code);
+				rc = -ENXIO;
+				goto Done;
+			}
+		case lcs_stoplan:
+			/* the stoplan primative should return the
+			 * adapter type */
+			/* it dosen't appar to though */
+		case lcs_startup:
+		case lcs_shutdown:
+#ifdef CONFIG_IP_MULTICAST
+		case lcs_setipm:
+		case lcs_delipm:
+		case lcs_qipassist:
+#endif
+			if (readcmd->return_code != 0)
+				goto Fail;
+
+		}
+	}
+Done:
+	lcs_debug_event(2, "lcs_lancmd cmd_code=%02x rc=%d reply_ptr=%p\n",
+			(int) cmd_code, rc, read->lancmd_reply_ptr);
+#if LCS_DEBUG
+	if (rc && read->lancmd_reply_ptr)
+		lcs_debug_display_read_buff("reply", read->lancmd_reply_ptr);
+#endif
+	drvr_globals->state = lcs_idle;
+	if (rc || (cmd_code != lcs_lanstat
+#ifdef CONFIG_IP_MULTICAST
+		   && cmd_code != lcs_qipassist
+#endif
+	    ))
+		lcs_resume_read(read);
+	return rc;
+Fail:
+	rc = -EIO;
+	goto Done;
+}
+
+#ifdef CONFIG_IP_MULTICAST
+static int
+lcs_print_ipassists(lcs_qipassist_ctlmsg * reply, char *name,
+		    char *ipassist_str, lcs_assists mask)
+{
+	lcs_good_news("%s: %s supported %s enabled %s\n",
+		      name, ipassist_str,
+		      reply->ip_assists_supported & mask ? "yes" : "no",
+		      reply->ip_assists_enabled & mask ? "yes" : "no");
+	return ((reply->ip_assists_supported & reply->
+		 ip_assists_enabled & mask) ? TRUE : FALSE);
+}
+
+static int
+lcs_check_multicast_supported(lcs_drvr_globals * drvr_globals)
+{
+	lcs_qipassist_ctlmsg *lcs_reply;
+	char *name = drvr_globals->dev->name;
+	int rc = FALSE;
+	if (lcs_lancmd(lcs_qipassist, drvr_globals->rel_adapter_no,
+		       drvr_globals LANCMD_DEFAULT_MCAST_PARMS) == 0) {
+		lcs_reply = (lcs_qipassist_ctlmsg *)
+		    drvr_globals->read->lancmd_reply_ptr;
+		if (lcs_reply) {
+			lcs_print_ipassists(lcs_reply, name, "ip v6",
+					    lcs_ip_v6_support);
+			rc = lcs_print_ipassists(lcs_reply, name, "multicast",
+						 lcs_multicast_support);
+		}
+	} else
+		lcs_good_news("qipassist failed, ipassists assumed "
+			      "unsupported for %s\n",name);
+	lcs_resume_read(drvr_globals->read);
+	return (rc);
+}
+#endif
+
+/* 
+ * Update network statistics from hardware.
+ */
+static int
+lcs_gethwinfo(struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals = ((lcs_drvr_globals *) dev->priv);
+	lcs_lanstat_reply *lcs_reply;
+	struct net_device_stats *stats;
+	int rc;
+	lcs_read_globals *read = drvr_globals->read;
+
+	if ((rc = lcs_lancmd(lcs_lanstat,
+			     drvr_globals->rel_adapter_no,
+			     drvr_globals LANCMD_DEFAULT_MCAST_PARMS)) == 0) {
+
+		lcs_reply = (lcs_lanstat_reply *)
+		    read->lancmd_reply_ptr;
+		if (lcs_reply) {
+			stats = &drvr_globals->stats;
+			stats->rx_packets = lcs_reply->num_packets_rx_from_lan;
+			stats->rx_errors = lcs_reply->num_rx_errors_detected;
+			stats->rx_length_errors =
+			    lcs_reply->num_rx_packets_too_large;
+			stats->rx_missed_errors =
+			    lcs_reply->num_rx_discarded_nobuffs_avail;
+			stats->tx_packets = lcs_reply->num_packets_tx_on_lan;
+			stats->tx_errors = lcs_reply->num_tx_errors_detected;
+			stats->tx_aborted_errors =
+			    lcs_reply->num_tx_packets_disgarded;
+		}
+	}
+#if LCS_DEBUG
+	else
+		lcs_debug_event(2, "gethwinfo failed\n");
+#endif
+	lcs_resume_read(read);
+	return rc;
+}
+
+/*
+ * Displays the mac address etc. on startup.
+ */
+static void
+lcs_displayinfo(struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals = ((lcs_drvr_globals *) dev->priv);
+	u8 *mac_address = dev->dev_addr;
+	lcs_read_globals *read = drvr_globals->read;
+	lcs_write_globals *write = drvr_globals->write;
+
+	lcs_good_news
+	    ("\nlcs: %s configured as follows read subchannel=%x "
+	     "write subchannel=%x\n"
+	     "read_devno=%04x write_devno=%04x\n"
+	     "hw_address=%02X:%02X:%02X:%02X:%02X:%02X rel_adapter_no=%d\n",
+	     dev->name, read->subchannel, write->subchannel, (int) read->devno,
+	     (int) write->devno, (int) mac_address[0], (int) mac_address[1],
+	     (int) mac_address[2], (int) mac_address[3], (int) mac_address[4],
+	     (int) mac_address[5], drvr_globals->rel_adapter_no);
+}
+
+/* shutdown osa card */
+
+static int
+lcs_halt_channels(lcs_drvr_globals * drvr_globals, int delay)
+{
+	int rc, rc2;
+	if (delay & 1) {
+/* [arnd] maybe better rethink/rewrite this whole function */
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(2);
+	}
+	rc = lcs_hsch(drvr_globals->read);
+	if (delay & 2) {
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(2);
+	}
+	drvr_globals->read->chan_busy_state = chan_dead;
+	rc2 = lcs_hsch(drvr_globals->write);
+	if (delay & 4) {
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(2);
+	}
+	drvr_globals->write->chan_busy_state = chan_dead;
+	return (rc ? rc : rc2);
+}
+
+static int
+lcs_stopcard(lcs_drvr_globals * drvr_globals)
+{
+	int rc1, rc2, rc3;
+
+	rc1 = rc2 = rc3 = 0;
+	drvr_globals->up = FALSE;
+	lcs_debug_event(2, "lcs_stopcard called\n");
+	if (drvr_globals->state == lcs_interrupted)
+		drvr_globals->state = lcs_idle;
+	/* Make sure that we don't attempt to resume a channel */
+	/* that was halted or dead to avoid the -ENOTCONNECTED */
+	/* errors reported from Ingo on resume_IO */
+	if (drvr_globals->read->chan_busy_state != chan_dead &&
+	    drvr_globals->write->chan_busy_state != chan_dead) {
+		rc1 = lcs_lancmd(lcs_stoplan, drvr_globals->rel_adapter_no,
+				 drvr_globals LANCMD_DEFAULT_MCAST_PARMS);
+		/* We probably haven't got a good relative adapter no */
+		if (drvr_globals->rel_adapter_no != lcs_invalid_adapter_no)
+			rc2 = lcs_lancmd(lcs_shutdown, 0, drvr_globals
+					 LANCMD_DEFAULT_MCAST_PARMS);
+	}
+	lcs_resetstate(drvr_globals);
+	rc3 = lcs_halt_channels(drvr_globals, 7);
+	lcs_resetstate(drvr_globals);
+	return (rc1 ? rc1 : (rc2 ? rc2 : rc3));
+}
+
+static void
+lcs_initwriteccws(lcs_write_globals * write)
+{
+	initccws(write->ccw, write->iobuff, LCS_NUM_TX_BUFFS, ccw_write, 0,
+		 CCW_FLAG_CC | CCW_FLAG_SLI | CCW_FLAG_SUSPEND);
+	write->prepare_idx = 0;
+	write->tx_idx = LCS_NUM_TX_BUFFS - 1;
+	write->resume_queued = FALSE;
+	write->bytes_still_being_txed = write->pkts_still_being_txed = 0;
+	write->adjusted_last_bytes_still_being_txed = 0;
+	write->last_resume_time = lcs_get_tod();
+	write->chan_busy_state = chan_starting_up;
+}
+
+static void
+lcs_startreadio(lcs_read_globals * read)
+{
+	int cnt;
+	ccw1_t *ccws;
+	lcs_debug_event(0, "lcs_startreadio read_globals=%p\n", read);
+	ccws = read->ccw;
+	for (cnt = 0; cnt < LCS_NUM_RX_BUFFS; cnt++, ccws++) {
+		ccws->count = LCS_IOBUFFSIZE;
+		ccws->flags = CCW_FLAG_CC | CCW_FLAG_SLI |
+		    (cnt ==
+		     (LCS_NUM_RX_BUFFS - 1) ? CCW_FLAG_SUSPEND : CCW_FLAG_PCI)
+#if LCS_USE_IDALS
+		    | (ccws->flags & CCW_FLAG_IDA)
+#endif
+		    ;
+#if LCS_ZERO_COPY_READ
+		((lcs_header_type *) read->skb_buff[cnt]->data)->offset =
+		    LCS_ILLEGAL_OFFSET;
+#else
+		((lcs_header_type *) read->iobuff[cnt])->offset =
+		    LCS_ILLEGAL_OFFSET;
+#endif
+	}
+	read->lancmd_reply_ptr = NULL;
+	read->rx_idx = 0;
+	read->chan_busy_state = chan_starting_up;
+	lcs_doio(read, DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND
+		 /*|DOIO_REPORT_ALL */ );
+
+}
+
+static void
+lcs_startwriteio(lcs_write_globals * write)
+{
+	lcs_debug_event(0, "lcs_startwriteio write_globals=%p\n", write);
+	lcs_initwriteccws(write);
+	lcs_doio(write,DOIO_DENY_PREFETCH | DOIO_ALLOW_SUSPEND 
+		 /* | DOIO_REPORT_ALL */
+		 );
+}
+
+static void
+lcs_restartreadio(lcs_drvr_globals * drvr_globals)
+{
+	lcs_debug_event(2, "lcs_restartreadio\n");
+	lcs_wakeup(drvr_globals->read, -EAGAIN);
+	lcs_startreadio(drvr_globals->read);
+}
+
+static void
+lcs_queued_restartreadio(lcs_drvr_globals * drvr_globals)
+{
+
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->state == lcs_idle
+	    || drvr_globals->state == lcs_halting_subchannels)
+		goto Done1;
+	lcs_restartreadio(drvr_globals);
+Done1:
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+}
+
+static void
+lcs_restartwriteio(lcs_drvr_globals * drvr_globals)
+{
+	lcs_write_globals *write;
+
+	write = drvr_globals->write;
+	write->bytes_still_being_txed = 0;
+	drvr_globals->stats.tx_dropped += write->pkts_still_being_txed;
+	if (!use_hw_stats)
+		drvr_globals->stats.tx_errors += write->pkts_still_being_txed;
+	write->pkts_still_being_txed = 0;
+	switch (drvr_globals->state) {
+	case lcs_doing_io:
+		netif_wake_queue(drvr_globals->dev);
+		break;
+	case lcs_idle_requesting_channels_for_lancmds:
+	case lcs_requesting_channels_for_lancmds:
+	case lcs_got_write_channel_for_lancmds:
+		lcs_wakeup(write, 0);
+		break;
+	case lcs_doing_lancmds:
+		lcs_wakeup(write, -EAGAIN);
+		break;
+	default:
+		break;
+	}
+	lcs_startwriteio(write);
+}
+
+static void
+lcs_queued_restartwriteio(lcs_drvr_globals * drvr_globals)
+{
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->state == lcs_idle ||
+	    drvr_globals->state == lcs_halting_subchannels)
+		goto Done1;
+	lcs_restartwriteio(drvr_globals);
+Done1:
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+}
+
+static void
+lcs_startallio(lcs_drvr_globals * drvr_globals)
+{
+	if (drvr_globals->dev)
+		netif_stop_queue(drvr_globals->dev);
+	drvr_globals->state = lcs_idle_requesting_channels_for_lancmds;
+	lcs_startreadio(drvr_globals->read);
+	lcs_initqueue(drvr_globals->write);
+	lcs_startwriteio(drvr_globals->write);
+	lcs_sleepon(drvr_globals->write, 0);
+	drvr_globals->state = lcs_doing_lancmds;
+}
+
+/*
+ * The osa detection/startup routine called from lcs_probe on
+ * bootup & lcs_open this is called after the irq's are allocated &
+ * successful sensing of the read & write subchannels.
+ */
+
+static int
+lcs_detect(lcs_drvr_globals * drvr_globals, s16 forced_port_no, u8 hint_port_no,
+	   u8 max_port_no, lcs_frame_type frame_type, u8 * mac_address)
+{
+	int rc = 0, successful_startup = FALSE;
+	int rel_adapter_no, rel_adapter_idx;
+	lcs_read_globals *read;
+	lcs_write_globals *write;
+	lcs_lanstat_reply *lcs_reply;
+
+	read = drvr_globals->read;
+	write = drvr_globals->write;
+#ifdef CONFIG_IP_MULTICAST
+	spin_lock_init(&drvr_globals->ipm_lock);
+#endif
+	lcs_debug_event(1, "Entering detect read subchannel=%X\n",
+			(unsigned) drvr_globals->read->subchannel);
+	if (drvr_globals->dev)
+		netif_stop_queue(drvr_globals->dev);
+	do {
+		lcs_debug_event(1, "lcs_detect retry_cnt=%d\n",
+				drvr_globals->retry_cnt);
+		if (atomic_read(&drvr_globals->retry_cnt) >= 0) {
+			if (atomic_read(&drvr_globals->retry_cnt) > 0)
+				lcs_resetstate(drvr_globals);
+			if (atomic_read(&drvr_globals->retry_cnt) > 1
+			    && rc != -ERETRY) {
+				/* Time to change tactics */
+				rc = lcs_stopcard(drvr_globals);
+			} else
+				rc = lcs_halt_channels(drvr_globals,
+				       (atomic_read(&drvr_globals->retry_cnt)
+					==0) ? 0 : 7);
+			if (rc)
+				continue;
+			lcs_startallio(drvr_globals);
+			if ((rc =
+			     lcs_lancmd(lcs_startup, 0,
+					drvr_globals
+					LANCMD_DEFAULT_MCAST_PARMS)))
+				continue;
+			else
+				successful_startup = TRUE;
+		} else if ((rc = lcs_lgw_common(drvr_globals, lcs_startup)))
+			continue;
+		else
+			successful_startup = TRUE;
+		for (rel_adapter_idx = 0; 
+		     rel_adapter_idx <= max_port_no &&
+		     (rc == -ENXIO || rel_adapter_idx == 0);
+		     rel_adapter_idx++) {
+			if (forced_port_no != -1) {
+				if (rel_adapter_idx > 0)
+					break;
+				rel_adapter_no = forced_port_no;
+			} else {
+				rel_adapter_no =
+				    (rel_adapter_idx ==
+				     0 ? hint_port_no : (rel_adapter_idx ==
+							 hint_port_no ? 0 :
+							 rel_adapter_idx));
+			}
+			lcs_debug_event(2,
+					"Trying startlan rel adapter no %u\n",
+					(unsigned) rel_adapter_no);
+			rc = -1;
+			if (frame_type == lcs_autodetect_type) {
+#ifdef CONFIG_NET_ETHERNET
+				drvr_globals->lan_type = lcs_enet_type;
+				rc = lcs_lancmd(lcs_startlan, rel_adapter_no,
+						drvr_globals
+						LANCMD_DEFAULT_MCAST_PARMS);
+				if (rc == 0)
+					goto lcs_good_detect;
+#endif
+#ifdef CONFIG_TR
+				drvr_globals->lan_type = lcs_token_ring_type;
+				rc = lcs_lancmd(lcs_startlan, rel_adapter_no,
+						drvr_globals
+						LANCMD_DEFAULT_MCAST_PARMS);
+				if (rc == 0)
+					goto lcs_good_detect;
+#endif
+#ifdef CONFIG_FDDI
+				drvr_globals->lan_type = lcs_fddi_type;
+				rc = lcs_lancmd(lcs_startlan, rel_adapter_no,
+						drvr_globals
+						LANCMD_DEFAULT_MCAST_PARMS);
+#endif
+			} else {
+				drvr_globals->lan_type = frame_type;
+				rc = lcs_lancmd(lcs_startlan, rel_adapter_no,
+						drvr_globals
+						LANCMD_DEFAULT_MCAST_PARMS);
+			}
+lcs_good_detect:
+			if (rc == 0) {
+				lcs_debug_event(2,"Found relative adapter "
+						"number %d\n",
+						rel_adapter_no);
+				drvr_globals->rel_adapter_no = rel_adapter_no;
+lcs_do_lanstat:
+				rc = lcs_lancmd(lcs_lanstat,
+						drvr_globals->rel_adapter_no,
+						drvr_globals
+						LANCMD_DEFAULT_MCAST_PARMS);
+				if (!rc) {
+					lcs_reply = (lcs_lanstat_reply *)
+					    drvr_globals->read->
+					    lancmd_reply_ptr;
+					if (lcs_reply == NULL)
+						goto lcs_do_lanstat;
+					memcpy(mac_address,
+					       lcs_reply->mac_address,
+					       LCS_ADDR_LEN);
+					lcs_resume_read(drvr_globals->read);
+					drvr_globals->up = TRUE;
+					return (0);
+				}
+			}
+		}
+
+	} while ((rc == -EAGAIN || rc == -ETIMEDOUT || rc == -ERETRY)
+		 && atomic_inc_return(&drvr_globals->retry_cnt) < 5);
+	if (successful_startup && rc)
+		lcs_bad_news
+		    ("A partially successful startup read_devno=%04x "
+		     "write_devno=%4x was detected rc=%d\n"
+		     "please check your configuration parameters,cables "
+		     "& connection to the network.\n",
+		     drvr_globals->read->devno,drvr_globals->write->devno,rc);
+	return (rc == EINTR ? -EINTR : -ENODEV);
+}
+
+/* Called by user doing ifconfig <network_device e.g. tr0> up */
+static int
+lcs_open(struct net_device *dev)
+{
+	int rc = 0;
+	lcs_drvr_globals *drvr_globals;
+	lcs_read_globals *read;
+	lcs_write_globals *write;
+
+#if LCS_DEBUG_RESUME
+	lcs_read_resume_cnt = lcs_write_resume_cnt = 0;
+#endif
+	drvr_globals = ((lcs_drvr_globals *) dev->priv);
+	read = drvr_globals->read;
+	write = drvr_globals->write;
+	drvr_globals->state = lcs_idle;
+	if (use_hw_stats == FALSE)
+		memset(&drvr_globals->stats, 0,
+		       sizeof (struct net_device_stats));
+	atomic_set(&drvr_globals->retry_cnt, 0);
+	if ((rc = lcs_detect(drvr_globals, drvr_globals->rel_adapter_no, 0, 0,
+			     drvr_globals->lan_type, dev->dev_addr))) {
+		lcs_debug_event(2, "Opening %s failed errcode=%d.\n",
+				dev->name,rc);
+		lcs_resetstate(drvr_globals);
+	} else {
+		MOD_INC_USE_COUNT;
+		lcs_start_doing_io(drvr_globals);
+		lcs_debug_event(2, "Successfully opened %s\n", dev->name);
+#if LCS_DEBUG && !LCS_PRINTK_DEBUG
+		/* When debugging we are usually only intrested till
+		 * the device is open. */
+		if (lcs_id && lcs_id->level != DEBUG_MAX_LEVEL)
+			debug_set_level(lcs_id, 0);
+#endif
+	}
+	return rc;
+}
+
+/* Called by user doing ifconfig <network_device e.g. tr0> down */
+static int
+lcs_close(struct net_device *dev)
+{
+	lcs_debug_event(2, "lcs_close called\n");
+	netif_stop_queue(dev);
+	lcs_stopcard((lcs_drvr_globals *) dev->priv);
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static int
+lcs_txpacket(struct sk_buff *skb, struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals;
+	lcs_write_globals *write;
+	u16 pkt_len;
+	lcs_header_type *tx_lcs_header_ptr;
+	uint64_t tod, delta_tx;
+	struct net_device_stats *stats;
+
+	lcs_debug_event(2, "lcs_txpacket\n");
+	if (dev == NULL || dev->priv == NULL) {
+		lcs_debug_event(1, "lcs txpacket detected sick code\n");
+		return -EINVAL;
+	}
+	drvr_globals = ((lcs_drvr_globals *) dev->priv);
+	write = drvr_globals->write;
+	tod = lcs_get_tod();
+	delta_tx = tod - write->last_lcs_txpacket_time;
+	write->last_lcs_txpacket_time = tod;
+	stats = &drvr_globals->stats;
+	if (write->chan_busy_state != chan_busy &&
+	    write->chan_busy_state != chan_idle) {
+		dst_link_failure(skb);
+		dev_kfree_skb(skb);
+		stats->tx_dropped++;
+		if (!use_hw_stats) {
+			stats->tx_errors++;
+			stats->tx_carrier_errors++;
+		}
+		return (0);
+	}
+	if (netif_queue_stopped(dev)) {
+		lcs_debug_event(1, "lcs_txpacket netif_is_busy dev=%p\n", dev);
+
+		stats->tx_dropped++;
+		return -EBUSY;
+	}
+	if (!skb) {
+		lcs_debug_event(1, "lcs_txpacket skb=NULL dev=%p\n", dev);
+		stats->tx_dropped++;
+		if (!use_hw_stats)
+			stats->tx_errors++;
+		return -EIO;
+	}
+	lcs_debug_event(2, "skb_len %d\n", skb->len);
+	pkt_len = skb->len;
+#if 0
+	/* This apparently can be omitted & saves us a lot of hassle */
+	pkt_len = (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+#endif
+	dev->trans_start = jiffies;
+	lcs_chan_lock(write);
+	if ((tx_lcs_header_ptr = lcs_getfreetxbuff(write,
+						   drvr_globals->lan_type,
+						   drvr_globals->rel_adapter_no,
+						   pkt_len)) == NULL) {
+		netif_stop_queue(dev);
+		stats->tx_dropped++;
+		lcs_debug_event(1,"lcs_txpacket no tx buffers "
+				"available dev=%p\n",dev);
+		lcs_resume_write(write);
+		lcs_chan_unlock(write);
+		return -EBUSY;
+	}
+	write->bytes_still_being_txed += pkt_len;
+	write->pkts_still_being_txed++;
+	memcpy(++tx_lcs_header_ptr, skb->data, pkt_len);
+	dev_kfree_skb(skb);
+
+	if (lcs_should_queue_write(write, tod)) {
+		lcs_queue_write_if_necessary(write);
+	} else {
+		lcs_resume_write(write);
+	}
+	lcs_chan_unlock(write);
+	return (0);
+}
+
+/*
+ * Used by ifconfig & the proc filesystem to receive network statistics
+ */
+static struct net_device_stats *
+lcs_getstats(struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals = (lcs_drvr_globals *) dev->priv;
+	lcs_debug_event(2, "lcs_enet_stats\n");
+
+	if (dev == NULL || dev->priv == NULL)
+		return NULL;	/* shouldn't happen */
+	if (use_hw_stats) {
+		if (drvr_globals->doing_lanstat)
+#warning FIXME: [kj] Using sleep_on derivative, is racy. consider using wait_event instead
+			interruptible_sleep_on(&drvr_globals->lanstat_wait);
+		else {
+			if (drvr_globals->state == lcs_doing_io) {
+				drvr_globals->doing_lanstat = TRUE;
+				lcs_gethwinfo(dev);
+				drvr_globals->doing_lanstat = FALSE;
+				netif_wake_queue(dev);
+				/* Gracefully start the lan again */
+				drvr_globals->state = lcs_doing_io;
+				/* Wake up processes awaiting
+				 * lanstat results */
+				wake_up_interruptible(&drvr_globals->
+						      lanstat_wait);
+			}
+		}
+	}
+	return &((lcs_drvr_globals *) dev->priv)->stats;
+
+}
+
+#if !LCS_CHANDEV
+/*
+ * Used to setup kernel parameters for the osa card
+ * read the printk's in the function for a description of how it
+ * should be called.
+ */
+static __inline__ lcs_model_info *
+lcs_get_model_info_by_idx(int idx)
+{
+	return (idx < LCS_CURR_NUM_MODELS ? &lcs_models[idx] :
+		(lcs_model_info *) & additional_model_info
+		[(idx - LCS_CURR_NUM_MODELS) << 1]);
+}
+static void
+lcs_display_conf(void)
+{
+	int cu_idx;
+	lcs_model_info *model_info;
+
+	lcs_good_news("\nlcs configured to use %s statistics,\n"
+		      "ip checksumming of received packets is %s.\n"
+		      "autodetection is %s ignore sense is %s.\n",
+		      (use_hw_stats ? "hw" : "sw"),
+		      (checksum_received_ip_pkts ? "on" : "off"),
+		      (noauto ? "off" : "on"), (ignore_sense ? "on" : "off"));
+	lcs_good_news("configured to detect\n");
+	for (cu_idx = 0; cu_idx < LCS_MAX_NUM_MODELS; cu_idx++) {
+		model_info = lcs_get_model_info_by_idx(cu_idx);
+		if ((model_info->max_rel_adapter_no == 0))
+			break;
+		lcs_good_news("cu_model 0x%02X,%d rel_adapter(s)\n",
+			      model_info->cu_model,
+			      model_info->max_rel_adapter_no);
+	}
+}
+
+MODULE_AUTHOR
+("(C) 1999 IBM Corp. by DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com>");
+MODULE_DESCRIPTION("Linux for S/390 Lan Channel Station Network Driver");
+MODULE_LICENSE("GPL");
+
+#ifdef MODULE
+MODULE_PARM(use_hw_stats, "i");
+MODULE_PARM_DESC(use_hw_stats,
+		 "Get network stats from LANSTAT lcs primitive as opposed to "
+		 "doing it in software\n"
+		 "this isn't used by MVS not recommended "
+		 "& dosen't appear to work usually\n");
+MODULE_PARM(checksum_received_ip_pkts, "i");
+MODULE_PARM_DESC(checksum_received_ip_pkts,
+		 "Do ip checksumming on inbound packets");
+
+MODULE_PARM(additional_model_info, "0-" LCS_ADDITIONAL_MODELS_X2_STR "i");
+MODULE_PARM_DESC(additional_model_info,
+		 "This is made up of sets of model/max rel adapter no pairs\n"
+		 "e.g. insmod additional_model_info=0x70,3 will look for "
+		 "2 ports on a model 0x70.\n");
+MODULE_PARM(devno_portno_pairs, "0-" LCS_MAX_FORCED_DEVNOS_X2_STR "i");
+MODULE_PARM_DESC(devno_portno_pairs, "devno,rel_adapter_no pairs\n"
+		 "rel adapter no of -1 indicates don't use this adapter.");
+MODULE_PARM(noauto, "i");
+MODULE_PARM_DESC(noauto,
+		 "set this equal to 1 if you want autodetection off, "
+		 "this means you have\n"
+		 "explicitly configure LCS devices with the "
+		 "devno_portno_pairs module parameter\n.");
+MODULE_PARM(ignore_sense, "i");
+MODULE_PARM_DESC(ignore_sense,
+		 "set this to 1 if you wish to ignore sense information "
+		 "from the device layer for\n"
+		 "non auto detected devices.\n");
+#else
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+static int __init
+lcs_setup_models(char *str)
+#else
+void __init
+lcs_setup_models(char *str, int *ints)
+#endif
+{
+	int max_parms = LCS_MAX_NUM_PARMS - (LCS_CURR_NUM_MODELS << 1);
+	int num_new_models;
+#if  LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	int ints[(LCS_ADDITIONAL_MODELS << 1) + 1];
+	get_options(str, (LCS_ADDITIONAL_MODELS << 1), ints);
+#endif
+	num_new_models = (ints[0] - 2);
+	if (num_new_models < 0)
+		num_new_models = 0;
+	else if (num_new_models & 1)
+		num_new_models = -1;
+	else
+		num_new_models >>= 1;
+	if ((ints[0] >= 1 && ints[0] <= max_parms) && num_new_models >= 0) {
+		use_hw_stats = ints[1];
+		if (ints[0] >= 2)
+			checksum_received_ip_pkts = ints[2];
+		if (num_new_models) {
+			memcpy(&additional_model_info[0], &ints[3],
+			       num_new_models * sizeof (lcs_model_info));
+		}
+		lcs_display_conf();
+	} else {
+		lcs_bad_news("lcs_setup: incorrect number of arguments\n");
+		printk("Usage: lcs=hw-stats,ip-checksumming,additional "
+		       "cu model/max rel adapter no. pairs. \n");
+		printk("  The driver now auto detects how the card is "
+		         "configured.\n");
+		printk("  e.g lcs=1,1,0x60,2\n");
+		printk("  Will collect network stats from LANSTAT lcs "
+		         "primitive as opposed\n");
+		printk("  to doing it in software for ifconfig (this isn't "
+		         "used by MVS & doesn't\n");
+		printk("  to be widely supported, ip checksum received "
+		         "packets\n");
+		printk("  and detect 0x3088 model 0x60 devices\n");
+		printk("  will look for 2 ports per card associated with "
+		         "this model.\n");
+		printk("  The default is to use sw stats, with ip "
+		         "checksumming off,\n");
+		printk("  this improves performance, network hw uses "
+		         "a crc32\n");
+		printk("  ( crc64 for fddi ) which should be adequete to "
+		         "gaurantee\n");
+		printk("  integrity for normal use\n");
+		printk("  however, financial institutions etc. may like "
+		         "the additional\n");
+		printk("  security of ip checksumming.\n");
+	}
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	return (1);
+#endif
+}
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+static int __init
+lcs_setup_devnos(char *str)
+#else
+void __init
+lcs_setup_devnos(char *str, int *ints)
+#endif
+{
+	int fixed_devnos;
+#if  LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	int ints[(LCS_MAX_FORCED_DEVNOS << 1) + 1];
+	get_options(str, (LCS_MAX_FORCED_DEVNOS << 1), ints);
+#endif
+	fixed_devnos = ints[0];
+	if ((fixed_devnos & 1) == 0 && fixed_devnos > 0) {
+		memcpy(devno_portno_pairs, &ints[1],
+		       sizeof (int) * fixed_devnos);
+	} else {
+		lcs_bad_news("lcs_setup: incorrect number of arguments\n");
+		printk("usage lcs_devno=devno,rel_adapter_no pairs\n");
+		printk
+		    ("rel adapter no of -1 indicates don't use this adapter.\n");
+	}
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	return (1);
+#endif
+}
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+static int __init
+lcs_noauto(char *str)
+#else
+void __init
+lcs_noauto(char *str, int *ints)
+#endif
+{
+	noauto = 1;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	return (1);
+#endif
+}
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+static int __init
+lcs_ignore_sense(char *str)
+#else
+void __init
+lcs_ignore_sense(char *str, int *ints)
+#endif
+{
+	ignore_sense = 1;
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+	return (1);
+#endif
+}
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+__setup("lcs_devno=", lcs_setup_devnos);
+__setup("lcs=", lcs_setup_models);
+__setup("lcs_noauto", lcs_noauto);
+__setup("lcs_ignore_sense", lcs_ignore_sense);
+#endif
+#endif
+
+static lcs_inline int
+lcs_model_supported(s390_dev_info_t * dev_info_ptr, int *forced_rel_adapter_no)
+{
+	int cu_idx, dev_port_idx;
+	lcs_model_info *model_info;
+	lcs_dev_portno_pair *dev_portno;
+
+	*forced_rel_adapter_no = -1;
+	for (dev_port_idx = 0; dev_port_idx < LCS_MAX_FORCED_DEVNOS;
+	     dev_port_idx++) {
+		dev_portno = &lcs_dev_portno[dev_port_idx];
+		if (dev_portno->portno == -2)
+			break;
+		/*
+		   Check are we dealing with the device passed in as
+		   a parameter.
+		 */
+		if ((dev_portno->devno & 0xfffe) ==
+		    (dev_info_ptr->devno & 0xfffe)) {
+			/* portno=-1 we want to ignore this device */
+			if (dev_portno->portno == -1)
+				return (-1);
+			else {
+				*forced_rel_adapter_no = dev_portno->portno;
+				break;
+			}
+		}
+	}
+	if (noauto && *forced_rel_adapter_no == -1)
+		return (-1);
+	if (ignore_sense)
+		return (*forced_rel_adapter_no);
+	if (dev_info_ptr->sid_data.cu_type != LCS_CUTYPE)
+		return (-1);
+	for (cu_idx = 0; cu_idx < LCS_MAX_NUM_MODELS; cu_idx++) {
+		model_info = lcs_get_model_info_by_idx(cu_idx);
+		if (model_info->max_rel_adapter_no == 0)
+			break;
+		if (model_info->cu_model == dev_info_ptr->sid_data.cu_model) {
+			if (*forced_rel_adapter_no == -1)
+				return (model_info->max_rel_adapter_no);
+			else
+				return (*forced_rel_adapter_no);
+		}
+	}
+	return (-1);
+}
+
+#endif				/* LCS_CHANDEV */
+
+#if !LCS_CHANDEV
+void
+lcs_unregister(struct net_device *dev, u8 lan_type)
+{
+	if (dev) {
+		switch (lan_type) {
+#ifdef CONFIG_FDDI
+		case lcs_fddi_type:
+			unregister_netdev(dev);
+			break;
+#endif
+#ifdef CONFIG_NET_ETHERNET
+		case lcs_enet_type:
+			unregister_netdev(dev);
+			break;
+#endif
+#ifdef CONFIG_TR
+		case lcs_token_ring_type:
+			unregister_trdev(dev);
+			break;
+#endif
+		default:
+			lcs_bad_news
+			    ("lcs_unregister attempt to unregister %p "
+			     "unknown device type\n",
+			     dev);
+			return;
+		}
+
+	}
+}
+#endif
+#ifdef CONFIG_IP_MULTICAST
+static int
+lcs_fix_multicast_list(lcs_drvr_globals * drvr_globals)
+{
+	lcs_ipm_list *curr_lmem;
+	lcs_state oldstate;
+
+	lcs_daemonize("lcs_fix_multi", 0, TRUE);
+	if (!lcs_drvr_globals_valid(drvr_globals))
+		goto Done2;
+	if (drvr_globals->up == FALSE)
+		goto Done1;
+	oldstate = drvr_globals->state;
+	spin_lock(&drvr_globals->ipm_lock);
+	for (curr_lmem = drvr_globals->ipm_list; curr_lmem;
+	     curr_lmem = curr_lmem->next) {
+		switch (curr_lmem->ipm_state) {
+		case ipm_set_required:
+			spin_unlock(&drvr_globals->ipm_lock);
+			if (lcs_lancmd
+			    (lcs_setipm, drvr_globals->rel_adapter_no,
+			     drvr_globals, 1, &curr_lmem->ipm)) {
+				lcs_good_news("lcs_fix_multicast_list "
+					      "failed to add multicast "
+					      "entry %x multicast address "
+					      "table possibly full.\n",
+					      (u32) curr_lmem->ipm.ip_addr);
+			} else
+				curr_lmem->ipm_state = ipm_on_card;
+			spin_lock(&drvr_globals->ipm_lock);
+			break;
+		case ipm_delete_required:
+			spin_unlock(&drvr_globals->ipm_lock);
+			lcs_lancmd(lcs_delipm, drvr_globals->rel_adapter_no,
+				   drvr_globals, 1, &curr_lmem->ipm);
+			spin_lock(&drvr_globals->ipm_lock);
+			if (remove_from_list((list **)&drvr_globals->ipm_list,
+					     (list *)curr_lmem))
+				kfree(curr_lmem);
+			else
+				lcs_bad_news("lcs_fix_multicast_list "
+					     "detected nonexistant entry"
+					     " ipm_list=%p member %p\n",
+					     drvr_globals->ipm_list,curr_lmem);
+			break;
+		case ipm_on_card:
+			break;
+		}
+	}
+	spin_unlock(&drvr_globals->ipm_lock);
+	drvr_globals->state = oldstate;
+	if (oldstate == lcs_doing_io && drvr_globals->dev)
+		netif_wake_queue(drvr_globals->dev);
+Done1:
+	atomic_set(&drvr_globals->kernel_thread_lock, 1);
+	lcs_usage_free_drvr_globals(drvr_globals);
+Done2:
+	MOD_DEC_USE_COUNT;
+	return (0);
+}
+
+static void
+lcs_get_mac_for_ipm(__u32 ipm, char *mac, struct net_device *dev)
+{
+#ifdef CONFIG_TR
+	if (dev->type == ARPHRD_IEEE802_TR)
+		ip_tr_mc_map(ipm, mac);
+	else
+#endif
+#if defined(CONFIG_NET_ETHERNET) || defined (CONFIG_FDDI)
+		ip_eth_mc_map(ipm, mac);
+#endif
+}
+
+/*
+  Owing to a quirk in the osa microcode it is incompatible with its API's 
+  & we can only add or delete a single ipm entry at a time.
+  We are also called with the spin_lock_bh held meaning we in_interrupt is true
+  to add & delete multicast entries to get around this we indirectly start
+  a kernel thread which executes the io commands necessary at a later
+  time.
+  We also need ip addresses for the setipm & delipm primatives
+  to do this we use lcs_get_mac_for_ipm.
+  N.B. We even need to kmalloc GFP_ATOMIC here
+
+ */
+static void
+lcs_set_multicast_list(struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals;
+	struct ip_mc_list *im4;
+	struct in_device *in4_dev;
+	int addr_in_list;
+
+#if 0				/* LCS doesn't do IPV6 yet. */
+	struct ifmcaddr6 *im6;
+	struct inet6_dev *in6_dev;
+#endif
+	char buf[MAX_ADDR_LEN];
+	lcs_ipm_list *curr_lmem, *new_lmem;
+	lcs_state oldstate;
+
+	if ((dev == NULL) || (dev->priv == NULL)) {
+		lcs_bad_news("invalid dev=%p in lcs_set_multicast_list\n", dev);
+		return;
+	}
+	drvr_globals = (lcs_drvr_globals *) dev->priv;
+	oldstate = drvr_globals->state;
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
+	if ((in4_dev = in_dev_get(dev)) == NULL)
+		return;
+	read_lock(&in4_dev->lock);
+#else
+	if ((in4_dev = dev->ip_ptr) == NULL)
+		return;
+#endif
+	/* Pass 1 find the entries to be deleted */
+	/* This is done first to avoid overflowing the cards */
+	/* onboard multicast list. */
+	spin_lock(&drvr_globals->ipm_lock);
+	for (curr_lmem = drvr_globals->ipm_list; curr_lmem;
+	     curr_lmem = curr_lmem->next) {
+		addr_in_list = FALSE;
+		for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
+			lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
+			if ((memcmp(buf, &curr_lmem->ipm.mac_address,
+				    LCS_ADDR_LEN) == 0) &&
+			    (curr_lmem->ipm.ip_addr == im4->multiaddr)) {
+				addr_in_list = TRUE;
+				break;
+			}
+
+		}
+		if (!addr_in_list)
+			curr_lmem->ipm_state = ipm_delete_required;
+	}
+	/* Pass 2 find the new entries to be added */
+	for (im4 = in4_dev->mc_list; im4; im4 = im4->next) {
+		lcs_get_mac_for_ipm(im4->multiaddr, buf, dev);
+		addr_in_list = FALSE;
+		for (curr_lmem = drvr_globals->ipm_list; curr_lmem;
+		     curr_lmem = curr_lmem->next) {
+			if ((memcmp
+			     (buf, &curr_lmem->ipm.mac_address,
+			      LCS_ADDR_LEN) == 0)
+			    && (curr_lmem->ipm.ip_addr == im4->multiaddr)) {
+				addr_in_list = TRUE;
+				break;
+			}
+		}
+		if (!addr_in_list) {
+			new_lmem =
+			    (lcs_ipm_list *) kmalloc(sizeof (lcs_ipm_list),
+						     GFP_ATOMIC);
+			if (!new_lmem) {
+				lcs_good_news
+				    ("lcs_set_multicast_list failed to add "
+				     "multicast entry %x not enough memory.\n",
+				     (u32) im4->multiaddr);
+				goto done;
+			}
+			memset(new_lmem, 0, sizeof (lcs_ipm_list));
+			memcpy(&new_lmem->ipm.mac_address, buf, LCS_ADDR_LEN);
+			new_lmem->ipm.ip_addr = im4->multiaddr;
+			new_lmem->ipm_state = ipm_set_required;
+			add_to_list((list **) & drvr_globals->ipm_list,
+				    (list *) new_lmem);
+		}
+	}
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
+	read_unlock(&in4_dev->lock);
+	in_dev_put(in4_dev);
+#endif
+#if 0				/* LCS doesn't do IPV6 yet */
+	if ((in6_dev = in6_dev_get(dev)) == NULL)
+		return;
+	read_lock_bh(&in6_dev->lock);
+	for (im6 = in6_dev->mc_list; im6; im6 = im6->next) {
+	}
+	read_unlock(&in4_dev->lock);
+	in6_dev_put(idev);
+#endif
+done:
+	spin_unlock(&drvr_globals->ipm_lock);
+	lcs_queue_thread(lcs_fix_multicast_list, drvr_globals);
+}
+#endif
+
+static void
+lcs_set_slow_hw(lcs_drvr_globals * drvr_globals, u16 cu_type, u8 cu_model)
+{
+	drvr_globals->slow_hw =
+	    ((cu_type == 0x3088
+	      && (cu_model == 0x8 || cu_model == 0x1f)) ? TRUE : FALSE);
+}
+
+#if LCS_DEBUG && !LCS_PRINTK_DEBUG
+
+static void
+lcs_debug_register(void)
+{
+	if (lcs_id == NULL) {
+		lcs_id = debug_register("lcs", 1, 16, 16 * sizeof (long));
+		debug_register_view(lcs_id, &debug_sprintf_view);
+		debug_set_level(lcs_id, 0);
+	}
+}
+#endif
+
+/*
+ * The main device detection routine called  on bootup or module installation
+ * to do. An unfortunately unwieldly function which dosen't lend itself
+ * easily to being broken into smaller functional blocks & my reason for
+ * hating tabs of 8. 
+ */
+
+#if LCS_CHANDEV
+static int
+lcs_probe(chandev_probeinfo * probeinfo)
+{
+	lcs_drvr_globals *drvr_globals = NULL;
+	int rc = -ENODEV;
+	lcs_write_globals *write;
+	lcs_read_globals *read;
+	u8 mac_address[LCS_ADDR_LEN];
+	struct net_device *dev = NULL;
+	char *basename = NULL;
+	struct net_device *(*init_netdevfunc) (struct net_device * dev,
+					       int sizeof_priv) = NULL;
+	void (*unreg_netdevfunc) (struct net_device * dev) = NULL;
+
+	drvr_globals = lcs_alloc_drvr_globals();
+	if (!drvr_globals) {
+		lcs_bad_news("lcs_probe kmalloc failed\n");
+		return -ENOMEM;
+	}
+	read = drvr_globals->read;
+	write = drvr_globals->write;
+	read->subchannel = probeinfo->read.irq;
+	write->subchannel = probeinfo->write.irq;
+	read->devno = probeinfo->read.devno;
+	write->devno = probeinfo->write.devno;
+	lcs_set_slow_hw(drvr_globals, probeinfo->read.cu_type,
+			probeinfo->read.cu_model);
+	if (lcs_allocirq(read) || lcs_allocirq(write)) {
+		rc = -ENODEV;
+		goto Fail;
+	}
+	checksum_received_ip_pkts = probeinfo->checksum_received_ip_pkts;
+	use_hw_stats = probeinfo->use_hw_stats;
+	atomic_set(&drvr_globals->retry_cnt, 0);
+	rc = lcs_detect(drvr_globals,
+			(probeinfo->device_forced ? probeinfo->
+			 port_protocol_no : -1), probeinfo->hint_port_no,
+			probeinfo->max_port_no, lcs_autodetect_type,
+			mac_address);
+
+	if (rc) {
+		lcs_stopcard(drvr_globals);
+		goto Fail;
+	} else {
+		/*Fill in the fields of the device structure 
+		 * with interface specific values.
+		 */
+		switch (drvr_globals->lan_type) {
+#ifdef CONFIG_NET_ETHERNET
+		case lcs_enet_type:
+			init_netdevfunc = init_etherdev;
+			unreg_netdevfunc = unregister_netdev;
+			basename = "eth";
+			drvr_globals->lan_type_trans = eth_type_trans;
+			break;
+#endif
+#ifdef CONFIG_TR
+		case lcs_token_ring_type:
+			init_netdevfunc = init_trdev;
+			unreg_netdevfunc = unregister_netdev;
+			basename = "tr";
+			drvr_globals->lan_type_trans = tr_type_trans;
+			break;
+#endif
+#ifdef CONFIG_FDDI
+		case lcs_fddi_type:
+			init_netdevfunc = init_fddidev;
+			unreg_netdevfunc = unregister_netdev;
+			basename = "fddi";
+			drvr_globals->lan_type_trans = fddi_type_trans;
+			break;
+#endif
+		}
+		probeinfo->memory_usage_in_k =
+		    -(((LCS_READ_ALLOCSIZE * LCS_NUM_RX_BUFFS) +
+		       (LCS_NUM_TX_BUFFS * LCS_IOBUFFSIZE)) / 1024);
+		if ((dev =
+		     chandev_initnetdevice(probeinfo,
+					   drvr_globals->rel_adapter_no, NULL,
+					   0, basename, init_netdevfunc,
+					   unreg_netdevfunc)) == 0)
+			goto Fail;
+		memcpy(dev->dev_addr, mac_address, LCS_ADDR_LEN);
+		dev->open = lcs_open;
+		dev->stop = lcs_close;
+		dev->hard_start_xmit = lcs_txpacket;
+		dev->get_stats = lcs_getstats;
+
+		drvr_globals->dev = dev;
+
+		dev->priv = drvr_globals;
+#ifdef CONFIG_IP_MULTICAST
+		dev->set_multicast_list =
+		    (lcs_check_multicast_supported(drvr_globals)
+		     ? lcs_set_multicast_list : NULL);
+#endif
+		lcs_stopcard(drvr_globals);
+		netif_stop_queue(dev);
+		lcs_displayinfo(dev);
+		lcs_debug_exception(0, "device structure=%p drvr globals=%p\n"
+				    "read=%p write=%p\n"
+				    "read_ccws=%p  write_cwws=%p\n", dev,
+				    drvr_globals, drvr_globals->read,
+				    drvr_globals->write,
+				    &drvr_globals->read->ccw[0],
+				    &drvr_globals->write->ccw[0]);
+		return 0;
+	}
+Fail:
+	if (drvr_globals) {
+		lcs_freeallirqs(drvr_globals);
+		lcs_usage_free_drvr_globals(drvr_globals);
+	}
+	lcs_debug_event(2, "osa_probe error %d\n", rc);
+	return rc;
+}
+#else
+int __init
+lcs_probe(void)
+{
+	int read_irq, write_irq;
+	s390_dev_info_t read_devinfo, write_devinfo;
+	lcs_drvr_globals *drvr_globals = NULL;
+	int hint, detect_error;
+	int rc = -ENODEV;
+	int max_rel_adapter_no;
+	int err;
+	int forced_rel_adapter_no;
+	int lcs_loopcnt = 0;
+	u8 mac_address[LCS_ADDR_LEN];
+	struct net_device *dev = NULL;
+	lcs_frame_type lan_type = lcs_autodetect_type;
+	lcs_write_globals *write;
+	lcs_read_globals *read;
+
+	lcs_debug_event(1, "Starting lcs_probe dev=%p\n", dev);
+
+	for (read_irq = get_irq_first(); read_irq >= 0;
+	     read_irq = get_irq_next(read_irq)) {
+		/* check read channel
+		 * we had to do the cu_model check also because ctc devices
+		 * have the same cutype & after asking some people
+		 * the model numbers are given out pseudo randomly so
+		 * we can't just take a range of them also the 
+		 * dev_type & models are 0
+		 */
+		lcs_loopcnt++;
+		if (lcs_loopcnt > 0x10000) {
+			lcs_bad_news("lcs probe detected infinite loop "
+				     "bug in get_irq_next\n");
+			goto Fail;
+		}
+		if ((err = get_dev_info_by_irq(read_irq, &read_devinfo))) {
+			lcs_bad_news("lcs_probe get_dev_info_by_irq "
+				     "reported err=%X on irq %d\n"
+				     "should not happen\n", err, read_irq);
+			continue;
+		}
+		if (read_devinfo.status & DEVSTAT_DEVICE_OWNED)
+			continue;
+		if (read_devinfo.devno & 1)
+			continue;
+		if ((max_rel_adapter_no =
+		     lcs_model_supported(&read_devinfo,
+					 &forced_rel_adapter_no)) < 0)
+			continue;
+		if (get_dev_info_by_devno
+		    (read_devinfo.devno + 1, &write_devinfo))
+			continue;
+		if (write_devinfo.status & DEVSTAT_DEVICE_OWNED)
+			continue;
+		write_irq = write_devinfo.irq;
+		if ((ignore_sense==FALSE && forced_rel_adapter_no != -1) &&
+		    ((write_devinfo.sid_data.cu_type !=
+		      read_devinfo.sid_data.cu_type)
+		     || (write_devinfo.sid_data.cu_model !=
+			 read_devinfo.sid_data.cu_model)))
+			continue;
+		if (drvr_globals == NULL) {
+			drvr_globals = lcs_alloc_drvr_globals();
+			if (!drvr_globals) {
+				lcs_bad_news("lcs_probe kmalloc failed\n");
+				return -ENOMEM;
+			}
+		}
+		read = drvr_globals->read;
+		write = drvr_globals->write;
+		read->subchannel = read_irq;
+		write->subchannel = write_irq;
+		read->devno = read_devinfo.devno;
+		write->devno = write_devinfo.devno;
+		lcs_set_slow_hw(drvr_globals, read_devinfo.sid_data.cu_type,
+				read_devinfo.sid_data.cu_model);
+		if (lcs_allocirq(read) || lcs_allocirq(write)) {
+			lcs_freeallirqs(drvr_globals);
+			/* We may find another card further up the chain */
+		} else {
+			if (forced_rel_adapter_no == -1) {
+				hint = (read_devinfo.devno & 0xFF) >> 1;
+				/* The card is possibly emulated e.g P/390 */
+				/* or possibly configured to use a shared */
+				/* port configured by osa-sf. */
+				if (hint > max_rel_adapter_no) {
+					hint = 0;
+				}
+			} else {
+				hint = -1;
+			}
+			detect_error =
+			    lcs_detect(drvr_globals, forced_rel_adapter_no,
+				       hint, max_rel_adapter_no, lan_type,
+				       mac_address, 0);
+			if (detect_error) {
+				lcs_stopcard(drvr_globals);
+				lcs_freeallirqs(drvr_globals);
+			} else {
+				/*
+				 * Fill in the fields of the device structure 
+				 * with interface specific values.
+				 */
+				switch (drvr_globals->lan_type) {
+#ifdef CONFIG_NET_ETHERNET
+				case lcs_enet_type:
+					dev = init_etherdev(dev, 0);
+					drvr_globals->lan_type_trans =
+					    eth_type_trans;
+					break;
+#endif
+#ifdef CONFIG_TR
+				case lcs_token_ring_type:
+					dev = init_trdev(dev, 0);
+					drvr_globals->lan_type_trans =
+					    tr_type_trans;
+					break;
+#endif
+#ifdef CONFIG_FDDI
+				case lcs_fddi_type:
+					/* I'm not sure whether this
+					 * function is 
+					 * in the generic kernel anymore */
+					dev = init_fddidev(dev, 0);
+					drvr_globals->lan_type_trans =
+					    fddi_type_trans;
+					break;
+#endif
+				}
+				if (dev)
+					memcpy(dev->dev_addr, mac_address,
+					       LCS_ADDR_LEN);
+				else {
+					rc = -ENOMEM;
+					goto Fail;
+				}
+				dev->open = lcs_open;
+				dev->stop = lcs_close;
+				dev->hard_start_xmit = lcs_txpacket;
+				dev->get_stats = lcs_getstats;
+				drvr_globals->dev = dev;
+				dev->priv = drvr_globals;
+#ifdef CONFIG_IP_MULTICAST
+				dev->set_multicast_list =
+				    (lcs_check_multicast_supported(drvr_globals)
+				     ? lcs_set_multicast_list : NULL);
+#endif
+				lcs_stopcard(drvr_globals);
+				netif_stop_queue(dev);
+				lcs_displayinfo(dev);
+				lcs_debug_event(0,"device structure=%p "
+						"drvr globals=%p\n"
+						"read=%p write=%p\n"
+						"read_ccws=%p  write_cwws=%p\n",
+						dev, drvr_globals,
+						drvr_globals->read,
+						drvr_globals->write,
+						&drvr_globals->read->ccw[0],
+						&drvr_globals->write->ccw[0]);
+
+				return 0;
+			}
+		}
+	}
+Fail:
+	if (drvr_globals) {
+
+		lcs_freeallirqs(drvr_globals);
+		lcs_usage_free_drvr_globals(drvr_globals);
+
+	}
+	lcs_debug_event(2, "osa_probe error %d\n", rc);
+	return rc;
+}
+#endif
+
+#if LCS_CHANDEV || MODULE
+static int
+lcs_shutdown_card(struct net_device *dev)
+{
+	lcs_drvr_globals *drvr_globals = ((lcs_drvr_globals *) dev->priv);
+
+#if !LCS_CHANDEV
+	lcs_unregister(dev, drvr_globals->lan_type);	
+	/* unregister_netdev calls close */
+#endif
+	lcs_freeallirqs(drvr_globals);
+	lcs_usage_free_drvr_globals(drvr_globals);
+	kfree(dev);
+	return (0);
+}
+#endif
+
+#if LCS_CHANDEV
+static void
+lcs_msck_notification_func(struct net_device *dev, int msck_irq,
+			   chandev_msck_status prevstatus,
+			   chandev_msck_status newstatus)
+{
+	lcs_drvr_globals *drvr_globals = (lcs_drvr_globals *) dev->priv;
+
+	lcs_debug_event(0,"lcs_msck_notifcation_func drvr_globals=%p "
+			"msck_irq=%d prevstatus=%d newstatus=%d",
+			drvr_globals, msck_irq, prevstatus, newstatus);
+	if (!drvr_globals) {
+		lcs_debug_exception(0,"lcs_msck_notification_func "
+				    "drvr_globals=NULL");
+		return;
+	}
+	if (drvr_globals->state == lcs_doing_io) {
+		if (newstatus == chandev_status_good
+		    || newstatus == chandev_status_all_chans_good) {
+			switch (prevstatus) {
+			case chandev_status_no_path:
+			case chandev_status_gone:
+			case chandev_status_not_oper:
+				if (msck_irq == drvr_globals->read->subchannel)
+					lcs_restartreadio(drvr_globals);
+				else
+					lcs_restartwriteio(drvr_globals);
+				break;
+			default:
+				break;
+			}
+		} else if (msck_irq == drvr_globals->write->subchannel
+			   && newstatus != chandev_status_revalidate)
+			drvr_globals->write->chan_busy_state = chan_dead;
+
+	} else			/* Allow lcs_detect loop a few more times */
+		atomic_set(&drvr_globals->retry_cnt, 0);
+}
+#endif
+
+#if MODULE
+static void
+lcs_cleanup(void)
+{
+#if LCS_CHANDEV
+	chandev_unregister(lcs_probe, TRUE);
+#else
+	while (lcs_card_list)
+		lcs_shutdown_card(lcs_card_list->dev);
+#endif
+}
+#endif
+
+#if MODULE
+int
+init_module(void)
+#else
+#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
+static
+#endif
+    int __init
+lcs_init(void)
+#endif
+{
+	int cardsfound = 0;
+#if MODULE && LINUX_VERSION_CODE>KERNEL_VERSION(2,4,5)
+	int persist = chandev_persist(chandev_type_lcs);
+#endif
+	static char initstr[] = "Starting lcs "
+#ifdef MODULE
+	    "module "
+#else
+	    "compiled into kernel "
+#endif
+	    " $Revision: 1.128 $ $Date: 2002/03/01 16:56:47 $ \n"
+#if LCS_CHANDEV
+	    "with"
+#else
+	    "without"
+#endif
+	    " chandev support,"
+#ifdef CONFIG_IP_MULTICAST
+	    "with"
+#else
+	    "without"
+#endif
+	    " multicast support, "
+#ifdef CONFIG_NET_ETHERNET
+	    "with"
+#else
+	    "without"
+#endif
+	    " ethernet support, "
+#ifdef CONFIG_TR
+	    "with"
+#else
+	    "without"
+#endif
+	    " token ring support"
+#if 0
+	    ", "
+#ifdef CONFIG_FDDI
+	    "with"
+#else
+	    "without"
+#endif
+	    " fddi support"
+#endif
+	    ".\n";
+
+	lcs_good_news(initstr);
+#if LCS_DEBUG && !LCS_PRINTK_DEBUG
+	lcs_debug_register();
+#endif
+
+#if LCS_CHANDEV
+	cardsfound = chandev_register_and_probe(lcs_probe,
+		       (chandev_shutdownfunc) lcs_shutdown_card,
+		       (chandev_msck_notification_func)
+		       lcs_msck_notification_func,
+		       chandev_type_lcs);
+#else
+	while ((lcs_probe() == 0)) {
+		cardsfound++;
+	}
+#endif
+	if (cardsfound <= 0) {
+		lcs_bad_news("No lcs capable cards found\n");
+#if MODULE
+#if LINUX_VERSION_CODE>KERNEL_VERSION(2,4,5)
+		if (!persist)
+#endif
+			cleanup_module();
+#endif
+	}
+#if !LCS_CHANDEV
+	else {
+		lcs_display_conf();
+	}
+#endif
+	return (cardsfound ? 0 : (
+#if MODULE && LINUX_VERSION_CODE>KERNEL_VERSION(2,4,5)
+					 persist ? 0 :
+#endif
+					 -ENODEV));
+}
+
+/*
+ * Code for module loading & unloading
+ */
+
+#ifdef MODULE
+void
+cleanup_module(void)
+{
+	lcs_good_news("Terminating lcs module.\n");
+	lcs_cleanup();
+#if LCS_DEBUG && !LCS_PRINTK_DEBUG
+	if (lcs_id) {
+		debug_unregister_view(lcs_id, &debug_sprintf_view);
+		debug_unregister(lcs_id);
+		lcs_id = NULL;
+	}
+#endif
+}
+#else
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,2,18)
+__initcall(lcs_init);
+#endif
+#endif
diff -Nru a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
--- a/drivers/s390/net/netiucv.c	Sat Jun  8 22:31:49 2002
+++ b/drivers/s390/net/netiucv.c	Sat Jun  8 22:31:49 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: netiucv.c,v 1.12 2001/09/24 10:38:02 mschwide Exp $
+ * $Id: netiucv.c,v 1.17 2002/02/12 21:52:20 felfert Exp $
  *
  * IUCV network driver
  *
@@ -28,7 +28,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * RELEASE-TAG: IUCV network driver $Revision: 1.12 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.17 $
  *
  */
 
@@ -70,7 +70,7 @@
 MODULE_PARM (iucv, "1s");
 MODULE_PARM_DESC (iucv,
 		  "Specify the initial remote userids for iucv0 .. iucvn:\n"
-		  "iucv=userid0:userid1:...:useridN\n");
+		  "iucv=userid0:userid1:...:useridN");
 #endif
 
 static char *iucv = "";
@@ -118,7 +118,7 @@
 /**
  * Linked list of all connection structs.
  */
-iucv_connection *connections;
+static iucv_connection *connections;
 
 /**
  * Representation of event-data for the
@@ -166,7 +166,7 @@
 static __inline__ void netiucv_clear_busy(net_device *dev)
 {
 	clear_bit(0, &(((netiucv_priv *)dev->priv)->tbusy));
-	netif_start_queue(dev);
+	netif_wake_queue(dev);
 }
 
 static __inline__ int netiucv_test_and_set_busy(net_device *dev)
@@ -177,8 +177,8 @@
 
 #define SET_DEVICE_START(device, value)
 
-__u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
-__u8 iucvMagic[16] = {
+static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static __u8 iucvMagic[16] = {
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
 };
@@ -188,7 +188,7 @@
  * match exactly as specified in order to give connection_pending()
  * control.
  */
-__u8 mask[] = {
+static __u8 mask[] = {
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
@@ -520,7 +520,7 @@
 		header->next -= NETIUCV_HDRLEN;
 		if (skb_tailroom(pskb) < header->next) {
 			printk(KERN_WARNING
-			       "%s: Ilegal next field in iucv header: %d > %d\n",
+			       "%s: Illegal next field in iucv header: %d > %d\n",
 			       dev->name, header->next, skb_tailroom(pskb));
 			return;
 		}
@@ -540,6 +540,7 @@
 		skb->protocol = pskb->protocol;
 		pskb->ip_summed = CHECKSUM_UNNECESSARY;
 		netif_rx(skb);
+#warning FIXME: [kj] Net drivers should set dev->last_rx immediately after netif_rx
 		privptr->stats.rx_packets++;
 		privptr->stats.rx_bytes += skb->len;
 		skb_pull(pskb, header->next);
@@ -590,7 +591,8 @@
 	iucv_connection *conn = ev->conn;
 	iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data;
 	netiucv_priv *privptr = NULL;
-	struct sk_buff *skb = (struct sk_buff *)eib->ipmsgtag;
+			         /* Shut up, gcc! skb is always below 2G. */
+	struct sk_buff *skb = (struct sk_buff *)(unsigned long)eib->ipmsgtag;
 	__u32 txbytes = 0;
 	__u32 txpackets = 0;
 	__u32 stat_maxcq = 0;
@@ -610,10 +612,9 @@
 				(skb->len - NETIUCV_HDRLEN - NETIUCV_HDRLEN);
 		}
 		dev_kfree_skb_any(skb);
-	} else {
-		conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head;
-		conn->tx_buff->len = 0;
 	}
+	conn->tx_buff->data = conn->tx_buff->tail = conn->tx_buff->head;
+	conn->tx_buff->len = 0;
 	spin_lock_irqsave(&conn->collect_lock, saveflags);
 	while ((skb = skb_dequeue(&conn->collect_queue))) {
 		header.next = conn->tx_buff->len + skb->len + NETIUCV_HDRLEN;
@@ -740,7 +741,8 @@
 		case CONN_STATE_TX:
 			printk(KERN_INFO "%s: Remote dropped connection\n",
 			       netdev->name);
-			iucv_unregister_program(conn->handle);
+			if (conn->handle)
+				iucv_unregister_program(conn->handle);
 			conn->handle = 0;
 			fsm_newstate(fi, CONN_STATE_STOPPED);
 			fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
@@ -853,7 +855,8 @@
 #endif
 	fsm_newstate(fi, CONN_STATE_STOPPED);
 	netiucv_purge_skb_queue(&conn->collect_queue);
-	iucv_unregister_program(conn->handle);
+	if (conn->handle)
+		iucv_unregister_program(conn->handle);
 	conn->handle = 0;
 	fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev);
 }
@@ -1099,7 +1102,10 @@
 		fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC,
 			     CONN_EVENT_TIMER, conn);
 		conn->prof.send_stamp = xtime;
-		rc = iucv_send(conn->pathid, NULL, 0, 0, (__u32)nskb, 0,
+		
+		rc = iucv_send(conn->pathid, NULL, 0, 0,
+			       /* Shut up, gcc! nskb is always below 2G. */
+			       (__u32)(((unsigned long)nskb)&0xffffffff), 0,
 			       nskb->data, nskb->len);
 		conn->prof.doios_single++;
 		conn->prof.txlen += skb->len;
@@ -1139,6 +1145,7 @@
 static int
 netiucv_open(net_device *dev) {
 	MOD_INC_USE_COUNT;
+	SET_DEVICE_START(dev, 1);
 	fsm_event(((netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START, dev);
 	return 0;
 }
@@ -1530,9 +1537,7 @@
 	if (file->f_pos == 0) {
 		p += sprintf(p, "Device FSM state: %s\n",
 			     fsm_getstate_str(privptr->fsm));
-		p += sprintf(p, "RX channel FSM state: %s\n",
-			     fsm_getstate_str(privptr->conn->fsm));
-		p += sprintf(p, "TX channel FSM state: %s\n",
+		p += sprintf(p, "Connection FSM state: %s\n",
 			     fsm_getstate_str(privptr->conn->fsm));
 		p += sprintf(p, "Max. TX buffer used: %ld\n",
 			     privptr->conn->prof.maxmulti);
@@ -1786,7 +1791,6 @@
 	dev->addr_len            = 0;
 	dev->type                = ARPHRD_SLIP;
 	dev->tx_queue_len        = NETIUCV_QUEUELEN_DEFAULT;
-	SET_DEVICE_START(dev, 1);
 	dev_init_buffers(dev);
 	dev->flags	         = IFF_POINTOPOINT | IFF_NOARP;
 	return dev;
@@ -1818,7 +1822,7 @@
 static void
 netiucv_banner(void)
 {
-	char vbuf[] = "$Revision: 1.12 $";
+	char vbuf[] = "$Revision: 1.17 $";
 	char *version = vbuf;
 
 	if ((version = strchr(version, ':'))) {
@@ -1831,7 +1835,6 @@
 }
 
 #ifndef MODULE
-#  define init_return(a) return a
 static int __init
 iucv_setup(char *param)
 {
@@ -1842,12 +1845,14 @@
 	* is called.
 	*/
 	iucv = param;
-	init_return(1);
+	return 1;
 }
 
 __setup ("iucv=", iucv_setup);
+
 #else
-static void
+
+static void __exit
 netiucv_exit(void)
 {
 	while (connections) {
@@ -1860,9 +1865,11 @@
 	printk(KERN_INFO "NETIUCV driver unloaded\n");
 	return;
 }
+
+module_exit(netiucv_exit);
 #endif
 
-static int
+static int __init
 netiucv_init(void)
 {
 	char *p = iucv;
@@ -1924,8 +1931,5 @@
 	return 0;
 }
 
-#ifdef MODULE
 module_init(netiucv_init);
-module_exit(netiucv_exit);
 MODULE_LICENSE("GPL");
-#endif
diff -Nru a/drivers/s390/qdio.c b/drivers/s390/qdio.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/qdio.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,3542 @@
+/*
+ *
+ * linux/drivers/s390/qdio.c
+ *
+ * Linux for S/390 QDIO base support, Hipersocket base support
+ * version 2
+ *
+ * Copyright 2000,2002 IBM Corporation
+ * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
+ *
+ * Restriction: only 63 iqdio subchannels would have its own indicator,
+ * after that, subsequent subchannels share one indicator
+ *
+ *
+ *
+ *
+ * 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.
+ */
+
+/* we want the eyecatcher to be at the top of the code */
+void volatile qdio_eyecatcher(void)
+{
+	return;
+}
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+
+#include <asm/debug.h>
+
+#include <asm/qdio.h>
+
+#define VERSION_QDIO_C "$Revision: 1.122 $"
+
+/****************** MODULE PARAMETER VARIABLES ********************/
+MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
+MODULE_DESCRIPTION("QDIO base support version 2, " \
+		   "Copyright 2000 IBM Corporation");
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
+MODULE_LICENSE("GPL");
+#endif
+
+/******************** HERE WE GO ***********************************/
+
+static const char *version="QDIO base support version 2 ("
+	VERSION_QDIO_C "/" VERSION_QDIO_H ")";
+
+#ifdef QDIO_PERFORMANCE_STATS
+static int proc_perf_file_registration;
+static unsigned long i_p_c=0,i_p_nc=0,o_p_c=0,o_p_nc=0,ii_p_c=0,ii_p_nc=0;
+
+static struct {
+	unsigned int tl_runs;
+
+	unsigned int siga_outs;
+	unsigned int siga_ins;
+	unsigned int siga_syncs;
+	unsigned int pcis;
+	unsigned int thinints;
+	unsigned int fast_reqs;
+
+	__u64 start_time_outbound;
+	unsigned int outbound_cnt;
+	unsigned int outbound_time;
+	__u64 start_time_inbound;
+	unsigned int inbound_cnt;
+	unsigned int inbound_time;
+} perf_stats;
+
+#endif /* QDIO_PERFORMANCE_STATS */
+
+static int indicator_used[INDICATORS_PER_CACHELINE];
+static __u32 * volatile indicators;
+static __u32 volatile spare_indicator;
+
+static debug_info_t *qdio_dbf_setup=NULL;
+static debug_info_t *qdio_dbf_sbal=NULL;
+static debug_info_t *qdio_dbf_trace=NULL;
+static debug_info_t *qdio_dbf_sense=NULL;
+#ifdef QDIO_DBF_LIKE_HELL
+static debug_info_t *qdio_dbf_slsb_out=NULL;
+static debug_info_t *qdio_dbf_slsb_in=NULL;
+#endif /* QDIO_DBF_LIKE_HELL */
+
+static qdio_irq_t *first_irq[QDIO_IRQ_BUCKETS];
+static rwlock_t irq_list_lock[QDIO_IRQ_BUCKETS]={
+	[0 ... (QDIO_IRQ_BUCKETS-1)] = RW_LOCK_UNLOCKED
+};
+
+static struct semaphore init_sema;
+
+static qdio_chsc_area_t *chsc_area;
+/* iQDIO stuff: */
+static volatile qdio_q_t *iq_list=NULL; /* volatile as it could change
+					   during a while loop */
+static spinlock_t iq_list_lock=SPIN_LOCK_UNLOCKED;
+static int register_thinint_result;
+static void iqdio_tl(unsigned long);
+static DECLARE_TASKLET(iqdio_tasklet,iqdio_tl,0);
+
+#define HEXDUMP16(importance,header,ptr) \
+QDIO_PRINT_##importance(header "%02x %02x %02x %02x  " \
+			"%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+			"%02x %02x %02x %02x\n",*(((char*)ptr)), \
+			*(((char*)ptr)+1),*(((char*)ptr)+2), \
+			*(((char*)ptr)+3),*(((char*)ptr)+4), \
+			*(((char*)ptr)+5),*(((char*)ptr)+6), \
+			*(((char*)ptr)+7),*(((char*)ptr)+8), \
+			*(((char*)ptr)+9),*(((char*)ptr)+10), \
+			*(((char*)ptr)+11),*(((char*)ptr)+12), \
+			*(((char*)ptr)+13),*(((char*)ptr)+14), \
+			*(((char*)ptr)+15)); \
+QDIO_PRINT_##importance(header "%02x %02x %02x %02x  %02x %02x %02x %02x  " \
+			"%02x %02x %02x %02x  %02x %02x %02x %02x\n", \
+			*(((char*)ptr)+16),*(((char*)ptr)+17), \
+			*(((char*)ptr)+18),*(((char*)ptr)+19), \
+			*(((char*)ptr)+20),*(((char*)ptr)+21), \
+			*(((char*)ptr)+22),*(((char*)ptr)+23), \
+			*(((char*)ptr)+24),*(((char*)ptr)+25), \
+			*(((char*)ptr)+26),*(((char*)ptr)+27), \
+			*(((char*)ptr)+28),*(((char*)ptr)+29), \
+			*(((char*)ptr)+30),*(((char*)ptr)+31));
+
+#define atomic_swap(a,b) xchg((int*)a.counter,b)
+
+/* not a macro, as one of the arguments is atomic_read */
+static inline int qdio_min(int a,int b)
+{
+	if (a<b)
+		return a;
+	else
+		return b;
+}
+
+#define SYNC_MEMORY if (q->siga_sync) qdio_siga_sync(q)
+#define NOW qdio_get_micros()
+#define SAVE_TIMESTAMP(q) q->timing.last_transfer_time=NOW
+#define GET_SAVED_TIMESTAMP(q) (q->timing.last_transfer_time)
+#define SAVE_FRONTIER(q,val) q->last_move_ftc=val
+#define GET_SAVED_FRONTIER(q) (q->last_move_ftc)
+
+#define MY_MODULE_STRING(x) #x
+
+#ifdef QDIO_DBF_LIKE_HELL
+
+#define my_spin_lock(x) do { \
+	void *ptr=x; \
+	QDIO_DBF_TEXT6(0,trace,"sp_lck"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	spin_lock(x); \
+} while (0)
+#define my_spin_unlock(x) do { \
+	void *ptr=x; \
+	QDIO_DBF_TEXT6(0,trace,"sp_unlck"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	spin_unlock(x); \
+} while (0)
+#define my_spin_lock_irqsave(x,y) do { \
+	void *ptr=x; \
+	QDIO_DBF_TEXT6(0,trace,"sp_lck_i"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	spin_lock_irqsave(x,y); \
+} while (0)
+#define my_spin_unlock_irqrestore(x,y) do { \
+	void *ptr=x; \
+        QDIO_DBF_TEXT6(0,trace,"sp_nlk_i"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	spin_unlock_irqrestore(x,y); \
+} while (0)
+#define my_s390irq_spin_lock_irqsave(x,y) do { \
+	void *ptr=x; \
+	QDIO_DBF_TEXT6(0,trace,"sp_lck3i"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	s390irq_spin_lock_irqsave(x,y); \
+} while (0)
+#define my_s390irq_spin_unlock_irqrestore(x,y) do { \
+	void *ptr=x; \
+        QDIO_DBF_TEXT6(0,trace,"sp_nlk3i"); \
+	QDIO_DBF_HEX6(0,trace,&ptr,sizeof(void*)); \
+	s390irq_spin_unlock_irqrestore(x,y); \
+} while (0)
+
+#else /* QDIO_DBF_LIKE_HELL */
+
+#define my_spin_lock(x) spin_lock(x)
+#define my_spin_unlock(x) spin_unlock(x)
+#define my_spin_lock_irqsave(x,y) spin_lock_irqsave(x,y)
+#define my_spin_unlock_irqrestore(x,y) spin_unlock_irqrestore(x,y)
+#define my_s390irq_spin_lock_irqsave(x,y) s390irq_spin_lock_irqsave(x,y)
+#define my_s390irq_spin_unlock_irqrestore(x,y) s390irq_spin_unlock_irqrestore(x,y)
+
+#endif /* QDIO_DBF_LIKE_HELL */
+ 
+#ifdef QDIO_32_BIT
+#define QDIO_GET_ADDR(x) ((__u32)(long)x)
+#else /* QDIO_32_BIT */
+#define QDIO_GET_ADDR(x) ((__u32)(unsigned long)x)
+#endif /* QDIO_32_BIT */
+
+
+/***************** SCRUBBER HELPER ROUTINES **********************/
+
+static inline volatile __u64 qdio_get_micros(void)
+{
+        __u64 time;
+
+        asm volatile ("STCK %0" : "=m" (time));
+        return time>>12; /* time>>12 is microseconds*/
+}
+static inline unsigned long qdio_get_millis(void)
+{
+	return (unsigned long)(qdio_get_micros()>>12);
+}
+
+static __inline__ int atomic_return_add (int i, atomic_t *v)
+{
+	int old, new;
+	__CS_LOOP(old, new, v, i, "ar");
+	return old;
+}
+
+static void qdio_wait_nonbusy(unsigned int timeout)
+{
+        unsigned int start;
+        unsigned long flags;
+        char dbf_text[15];
+
+	sprintf(dbf_text,"wtnb%4x",timeout);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+
+	start=qdio_get_millis();
+	save_flags(flags); cli();
+	for (;;) {
+		set_task_state(current,TASK_INTERRUPTIBLE);
+		if (qdio_get_millis()-start>timeout) {
+			goto out;
+		}
+		restore_flags(flags);
+		schedule_timeout(((start+timeout-qdio_get_millis())>>10)*HZ);
+		save_flags(flags); cli();
+	}
+out:
+	set_task_state(current,TASK_RUNNING);
+	restore_flags(flags);
+}
+
+static int qdio_wait_for_no_use_count(atomic_t *use_count)
+{
+	unsigned long start;
+
+	QDIO_DBF_TEXT3(0,trace,"wtnousec");
+	start=qdio_get_millis();
+	for (;;) {
+		if (qdio_get_millis()-start>QDIO_NO_USE_COUNT_TIMEOUT) {
+			QDIO_DBF_TEXT1(1,trace,"WTNOUSTO");
+			return -ETIME;
+		}
+		if (!atomic_read(use_count)) {
+			QDIO_DBF_TEXT3(0,trace,"wtnoused");
+			return 0;
+		}
+		qdio_wait_nonbusy(QDIO_NO_USE_COUNT_TIME);
+	}
+}
+
+/* unfortunately, we can't just xchg the values; in do_QDIO we want to reserve
+ * the q in any case, so that we'll not be interrupted when we are in
+ * qdio_mark_iq... shouldn't have a really bad impact, as reserving almost
+ * ever works (last famous words) */
+static inline int qdio_reserve_q(qdio_q_t *q)
+{
+	return atomic_return_add(1,&q->use_count);
+}
+
+static inline void qdio_release_q(qdio_q_t *q)
+{
+	atomic_dec(&q->use_count);
+}
+#ifdef QDIO_DBF_LIKE_HELL 
+#define set_slsb(x,y) \
+  if(q->queue_type==QDIO_TRACE_QTYPE) { \
+        if(q->is_input_q) { \
+            QDIO_DBF_HEX2(0,slsb_in,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \
+        } else { \
+            QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \
+        } \
+  } \
+  qdio_set_slsb(x,y); \
+  if(q->queue_type==QDIO_TRACE_QTYPE) { \
+        if(q->is_input_q) { \
+            QDIO_DBF_HEX2(0,slsb_in,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \
+        } else { \
+            QDIO_DBF_HEX2(0,slsb_out,&q->slsb,QDIO_MAX_BUFFERS_PER_Q); \
+        } \
+  }
+#else /* QDIO_DBF_LIKE_HELL */
+#define set_slsb(x,y) qdio_set_slsb(x,y)
+#endif /* QDIO_DBF_LIKE_HELL */
+static volatile inline void qdio_set_slsb(volatile char *slsb,
+					  unsigned char value)
+{
+	xchg((char*)slsb,value);
+}
+
+static inline int qdio_siga_sync(qdio_q_t *q)
+{
+	unsigned int gpr2,gpr3;
+	int cc;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"sigasync");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.siga_syncs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+	if (q->is_input_q) {
+		gpr2=0;
+		gpr3=q->mask;
+	} else {
+		gpr2=q->mask;
+		gpr3=0;
+	}
+
+#ifdef QDIO_32_BIT
+	asm volatile (
+		"lhi	0,2	\n\t"
+		"lr	1,%1	\n\t"
+		"lr	2,%2	\n\t"
+		"lr	3,%3	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (gpr2), "d" (gpr3)
+		: "cc", "0", "1", "2", "3"
+		);
+#else /* QDIO_32_BIT */
+	asm volatile (
+		"lghi	0,2	\n\t"
+		"llgfr	1,%1	\n\t"
+		"llgfr	2,%2	\n\t"
+		"llgfr	3,%3	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (gpr2), "d" (gpr3)
+		: "cc", "0", "1", "2", "3"
+		);
+#endif /* QDIO_32_BIT */
+
+	if (cc) {
+#ifndef QDIO_DBF_LIKE_HELL
+		/* when QDIO_DBF_LIKE_HELL, we put that already out */
+		QDIO_DBF_TEXT3(0,trace,"sigasync");
+		QDIO_DBF_HEX3(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		QDIO_DBF_HEX3(0,trace,&cc,sizeof(int*));
+	}
+
+	return cc;
+}
+
+/* returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
+   an access exception */
+static inline int qdio_siga_output(qdio_q_t *q)
+{
+	int cc;
+	__u32 busy_bit;
+	__u64 start_time=0;
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.siga_outs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"sigaout");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	for (;;) {
+
+#ifdef QDIO_32_BIT
+		asm volatile (
+		      "lhi	0,0	\n\t"
+		      "lr	1,%2	\n\t"
+		      "lr	2,%3	\n\t"
+		      "siga	0	\n\t"
+		      "0:"
+		      "ipm	%0	\n\t"
+		      "srl	%0,28	\n\t"
+		      "srl	0,31	\n\t"
+		      "lr	%1,0	\n\t"
+		      "1:	\n\t"
+		      ".section .fixup,\"ax\"\n\t"
+		      "2:	\n\t"
+		      "lhi	%0,%4	\n\t"
+		      "bras	1,3f	\n\t"
+		      ".long 1b	\n\t"
+		      "3:	\n\t"
+		      "l	1,0(1)	\n\t"
+		      "br	1	\n\t"
+		      ".previous	\n\t"
+		      ".section __ex_table,\"a\"\n\t"
+		      ".align 4	\n\t"
+		      ".long	0b,2b	\n\t"
+		      ".previous	\n\t"
+			: "=d" (cc), "=d" (busy_bit)
+			: "d" (0x10000|q->irq), "d" (q->mask),
+			"i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
+			: "cc", "0", "1", "2", "memory"
+		);
+#else /* QDIO_32_BIT */
+		asm volatile (
+		      "lghi	0,0	\n\t"
+		      "llgfr	1,%2	\n\t"
+		      "llgfr	2,%3	\n\t"
+	      	      "siga	0	\n\t"
+		      "0:"
+		      "ipm	%0	\n\t"
+		      "srl	%0,28	\n\t"
+		      "srl	0,31	\n\t"
+		      "llgfr	%1,0	\n\t"
+		      "1:	\n\t"
+		      ".section .fixup,\"ax\"\n\t"
+		      "lghi	%0,%4	\n\t"
+		      "jg	1b	\n\t"
+		      ".previous\n\t"
+      		      ".section __ex_table,\"a\"\n\t"
+      		      ".align 8	\n\t"
+      		      ".quad	0b,1b	\n\t"
+      		      ".previous	\n\t"
+		      : "=d" (cc), "=d" (busy_bit)
+		      : "d" (0x10000|q->irq), "d" (q->mask),
+	      	      "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
+	      	      : "cc", "0", "1", "2", "memory"
+	     );
+#endif /* QDIO_32_BIT */
+
+//QDIO_PRINT_ERR("cc=%x, busy=%x\n",cc,busy_bit);
+	     if ( (cc==2) && (busy_bit) &&
+		  (q->is_iqdio_q) ) {
+		     if (!start_time) start_time=NOW;
+		     if ((NOW-start_time)>QDIO_BUSY_BIT_PATIENCE)
+			     break;
+	     } else
+		     break;
+	}
+
+	if ((cc==2) && (busy_bit)) cc|=QDIO_SIGA_ERROR_B_BIT_SET;
+
+	if (cc) {
+#ifndef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT3(0,trace,"sigaout");
+		QDIO_DBF_HEX3(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		QDIO_DBF_HEX3(0,trace,&cc,sizeof(int*));
+	}
+
+	return cc;
+}
+
+static inline int qdio_siga_input(qdio_q_t *q)
+{
+	int cc;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"sigain");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.siga_ins++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+#ifdef QDIO_32_BIT
+	asm volatile (
+		"lhi	0,1	\n\t"
+		"lr	1,%1	\n\t"
+		"lr	2,%2	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (q->mask)
+		: "cc", "0", "1", "2", "memory"
+		);
+#else /* QDIO_32_BIT */
+	asm volatile (
+		"lghi	0,1	\n\t"
+		"llgfr	1,%1	\n\t"
+		"llgfr	2,%2	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (q->mask)
+		: "cc", "0", "1", "2", "memory"
+		);
+#endif /* QDIO_32_BIT */
+
+	if (cc) {
+#ifndef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT3(0,trace,"sigain");
+		QDIO_DBF_HEX3(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		QDIO_DBF_HEX3(0,trace,&cc,sizeof(int*));
+	}
+
+	return cc;
+}
+
+/* locked by the locks in qdio_activate and qdio_cleanup */
+static __u32 * volatile qdio_get_indicator(void)
+{
+	int i=1;
+	int found=0;
+
+	while (i<INDICATORS_PER_CACHELINE) {
+		if (!indicator_used[i]) {
+			indicator_used[i]=1;
+			found=1;
+			break;
+		}
+		i++;
+	}
+
+	if (found)
+		return indicators+i;
+	else
+		return (__u32 * volatile) &spare_indicator;
+}
+
+/* locked by the locks in qdio_activate and qdio_cleanup */
+static void qdio_put_indicator(__u32 *addr)
+{
+	int i;
+
+	if ( (addr) && (addr!=&spare_indicator) ) {
+		i=addr-indicators;
+		indicator_used[i]=0;
+	}
+}
+
+static inline volatile void iqdio_clear_summary_bit(__u32 *location)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT5(0,trace,"clrsummb");
+	QDIO_DBF_HEX5(0,trace,&location,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+	xchg(location,0);
+}
+
+static inline volatile void iqdio_set_summary_bit(__u32 *location)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT5(0,trace,"setsummb");
+	QDIO_DBF_HEX5(0,trace,&location,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+	xchg(location,-1);
+}
+
+static inline void iqdio_sched_tl(void)
+{
+	tasklet_hi_schedule(&iqdio_tasklet);
+}
+
+static inline void qdio_mark_iq(qdio_q_t *q)
+{
+	unsigned long flags;
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"mark iq");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	my_spin_lock_irqsave(&iq_list_lock,flags);
+	if (atomic_read(&q->is_in_shutdown)) goto out_unlock;
+
+	if (q->is_input_q) {
+		if ((q->list_prev) || (q->list_next)) goto out_unlock;
+
+		if (!iq_list) {
+			iq_list=q;
+			q->list_prev=q;
+			q->list_next=q;
+		} else {
+			q->list_next=iq_list;
+			q->list_prev=iq_list->list_prev;
+			iq_list->list_prev->list_next=q;
+			iq_list->list_prev=q;
+		}
+		my_spin_unlock_irqrestore(&iq_list_lock,flags);
+
+		iqdio_set_summary_bit((__u32*)q->dev_st_chg_ind);
+		iqdio_sched_tl();
+	}
+	return;
+out_unlock:
+	my_spin_unlock_irqrestore(&iq_list_lock,flags);
+	return;
+}
+
+static inline void qdio_mark_q(qdio_q_t *q)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"mark q");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (atomic_read(&q->is_in_shutdown)) return;
+
+	tasklet_schedule(&q->tasklet);
+}
+
+static inline int qdio_stop_polling(qdio_q_t *q)
+{
+#ifdef QDIO_USE_PROCESSING_STATE
+	int gsf;
+
+	if (!atomic_swap(&q->polling,0)) return 1;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"stoppoll");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	/* show the card that we are not polling anymore */
+	if (q->is_input_q) {
+		gsf=GET_SAVED_FRONTIER(q);
+		set_slsb(&q->slsb.acc.val[(gsf+QDIO_MAX_BUFFERS_PER_Q-1)&
+			 (QDIO_MAX_BUFFERS_PER_Q-1)],SLSB_P_INPUT_NOT_INIT);
+		/* we don't issue this SYNC_MEMORY, as we trust Rick T and
+		 * moreover will not use the PROCESSING state, so q->polling
+		 * was 0
+		SYNC_MEMORY;*/
+		if (q->slsb.acc.val[gsf]==SLSB_P_INPUT_PRIMED) {
+			/* set our summary bit again, as otherwise there is a
+			 * small window we can miss between resetting it and
+			 * checking for PRIMED state */
+			if (q->is_iqdio_q)
+				iqdio_set_summary_bit
+					((__u32*)q->dev_st_chg_ind);
+			return 0;
+		}
+	}
+#endif /* QDIO_USE_PROCESSING_STATE */
+	return 1;
+}
+
+/* see the comment in do_QDIO and before qdio_reserve_q about the
+ * sophisticated locking outside of unmark_q, so that we don't need to
+ * disable the interrupts :-) */
+static inline void qdio_unmark_q(qdio_q_t *q)
+{
+	unsigned long flags;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"unmark q");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if ((!q->list_prev)||(!q->list_next)) return;
+
+	if ((q->is_iqdio_q)&&(q->is_input_q)) {
+		/* iQDIO */
+		my_spin_lock_irqsave(&iq_list_lock,flags);
+		if (q->list_next==q) {
+			/* q was the only interesting q */
+			iq_list=NULL;
+			q->list_next=NULL;
+			q->list_prev=NULL;
+		} else {
+			q->list_next->list_prev=q->list_prev;
+			q->list_prev->list_next=q->list_next;
+			iq_list=q->list_next;
+			q->list_next=NULL;
+			q->list_prev=NULL;
+		}
+		my_spin_unlock_irqrestore(&iq_list_lock,flags);
+	}
+}
+
+static inline volatile unsigned long iqdio_clear_global_summary(void)
+{
+	unsigned long time;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT5(0,trace,"clrglobl");
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_32_BIT
+	asm volatile (
+		"lhi	1,3	\n\t"
+		".insn	rre,0xb2650000,2,0	\n\t"
+		"lr	%0,3	\n\t"
+		: "=d" (time) : : "cc", "1", "2", "3"
+		);
+#else /* QDIO_32_BIT */
+	asm volatile (
+		"lghi	1,3	\n\t"
+		".insn	rre,0xb2650000,2,0	\n\t"
+		"lgr	%0,3	\n\t"
+		: "=d" (time) : : "cc", "1", "2", "3"
+		);
+#endif /* QDIO_32_BIT */
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_HEX5(0,trace,&time,sizeof(unsigned long));
+#endif /* QDIO_DBF_LIKE_HELL */
+	return time;
+}
+
+/************************* INBOUND ROUTINES *******************************/
+
+
+inline static int qdio_get_inbound_buffer_frontier(qdio_q_t *q)
+{
+	int f,f_mod_no;
+	volatile char *slsb;
+	char slsbyte;
+	int first_not_to_check;
+	char dbf_text[15];
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"getibfro");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	slsb=&q->slsb.acc.val[0];
+	f_mod_no=f=q->first_to_check;
+	/* we don't check 128 buffers, as otherwise qdio_has_inbound_q_moved
+	 * would return 0 */
+	first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),
+				      (QDIO_MAX_BUFFERS_PER_Q-1));
+
+	/* we don't use this one, as a PCI or we after a thin interrupt
+	 * will sync the queues
+	SYNC_MEMORY;*/
+
+check_next:
+	f_mod_no=f&(QDIO_MAX_BUFFERS_PER_Q-1);
+	if (f==first_not_to_check) goto out;
+	slsbyte=slsb[f_mod_no];
+
+	/* CU_EMPTY means frontier is reached */
+	if (slsbyte==SLSB_CU_INPUT_EMPTY) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT5(0,trace,"inptempt");
+#endif /* QDIO_DBF_LIKE_HELL */
+		goto out;
+	}
+
+	/* P_PRIMED means set slsb to P_PROCESSING and move on */
+	if (slsbyte==SLSB_P_INPUT_PRIMED) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT5(0,trace,"inptprim");
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_USE_PROCESSING_STATE
+		/* as soon as running under VM, polling the input queues will
+		 * kill VM in terms of CP overhead */
+		if (q->siga_sync) {
+			set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
+		} else {
+			set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_PROCESSING);
+			atomic_set(&q->polling,1);
+		}
+#else /* QDIO_USE_PROCESSING_STATE */
+		set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
+#endif /* QDIO_USE_PROCESSING_STATE */
+		/* not needed, as the inbound queue will be synced on the next
+		 * siga-r
+		SYNC_MEMORY;*/
+		f++;
+		atomic_dec(&q->number_of_buffers_used);
+		goto check_next;
+	}
+
+	if ( (slsbyte==SLSB_P_INPUT_NOT_INIT) ||
+	     (slsbyte==SLSB_P_INPUT_PROCESSING) ) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT5(0,trace,"inpnipro");
+#endif /* QDIO_DBF_LIKE_HELL */
+		goto out;
+	}
+
+	/* P_ERROR means frontier is reached, break and report error */
+	if (slsbyte==SLSB_P_INPUT_ERROR) {
+		sprintf(dbf_text,"inperr%2x",f_mod_no);
+		QDIO_DBF_TEXT3(1,trace,dbf_text);
+		QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);
+
+		/* kind of process the buffer */
+		set_slsb(&slsb[f_mod_no],SLSB_P_INPUT_NOT_INIT);
+
+		if (q->qdio_error)
+			q->error_status_flags|=
+				QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR;
+		q->qdio_error=SLSB_P_INPUT_ERROR;
+		q->error_status_flags|=QDIO_STATUS_LOOK_FOR_ERROR;
+
+		/* we increment the frontier, as this buffer
+		 * was processed obviously */
+		f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+		atomic_dec(&q->number_of_buffers_used);
+
+		goto out;
+	}
+
+	/* everything else means frontier not changed (HALTED or so) */
+out:
+	q->first_to_check=f_mod_no;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	return q->first_to_check;
+}
+
+inline static int qdio_has_inbound_q_moved(qdio_q_t *q)
+{
+	int i;
+
+#ifdef QDIO_PERFORMANCE_STATS
+	static int old_pcis=0;
+	static int old_thinints=0;
+
+	if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
+		perf_stats.start_time_inbound=NOW;
+	else
+		old_pcis=perf_stats.pcis;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+	i=qdio_get_inbound_buffer_frontier(q);
+	if ( (i!=GET_SAVED_FRONTIER(q)) ||
+	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {
+		SAVE_FRONTIER(q,i);
+		if ((!q->siga_sync)&&(!q->hydra_gives_outbound_pcis)) {
+			SAVE_TIMESTAMP(q);
+		}
+
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inhasmvd");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 1;
+	} else {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inhsntmv");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 0;
+	}
+}
+
+/* means, no more buffers to be filled */
+inline static int iqdio_is_inbound_q_done(qdio_q_t *q)
+{
+	int no_used;
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	no_used=atomic_read(&q->number_of_buffers_used);
+
+	/* propagate the change from 82 to 80 through VM */
+	SYNC_MEMORY;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	if (no_used) {
+		sprintf(dbf_text,"iqisnt%02x",no_used);
+		QDIO_DBF_TEXT4(0,trace,dbf_text);
+	} else {
+		QDIO_DBF_TEXT4(0,trace,"iniqisdo");
+	}
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (!no_used) {
+		return 1;
+	}
+
+	if (q->siga_sync) {
+		if (q->slsb.acc.val[q->first_to_check]==SLSB_P_INPUT_PRIMED) {
+			/* ok, the next input buffer is primed. that means,
+			 * that device state change indicator and adapter
+			 * local summary are set, so we will find it next
+			 * time.
+			 * we will return 0 below, as there is nothing to
+			 * do, except of scheduling ourselves for the next
+			 * time. */
+			iqdio_set_summary_bit((__u32*)q->dev_st_chg_ind);
+			iqdio_sched_tl();
+		} else {
+			/* nothing more to do, if next buffer is not PRIMED.
+			 * note that we did a SYNC_MEMORY before, that there
+			 * has been a sychnronization.
+			 * we will return 0 below, as there is nothing to do
+			 * (stop_polling not necessary, as we have not been
+			 * using the PROCESSING state */
+		}
+	} else {
+		/* we'll check for more primed buffers
+		 * in qeth_stop_polling */
+	}
+
+	return 0;
+}
+
+inline static int qdio_is_inbound_q_done(qdio_q_t *q)
+{
+	int no_used;
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	no_used=atomic_read(&q->number_of_buffers_used);
+
+	/* we need that one for synchronization with Hydra, as Hydra
+	 * does a kind of PCI avoidance */
+	SYNC_MEMORY;
+
+	if (!no_used) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inqisdnA");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+		QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 1;
+	}
+
+	if (q->slsb.acc.val[q->first_to_check]==SLSB_P_INPUT_PRIMED) {
+		/* we got something to do */
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inqisntA");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 0;
+	}
+
+	/* on VM, we don't poll, so the q is always done here */
+	if (q->siga_sync) return 1;
+	if (q->hydra_gives_outbound_pcis) return 1;
+
+	/* at this point we know, that inbound first_to_check
+	   has (probably) not moved (see qdio_inbound_processing) */
+	if (NOW>GET_SAVED_TIMESTAMP(q)+q->timing.threshold) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inqisdon");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+		sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
+		QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 1;
+	} else {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"inqisntd");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+		sprintf(dbf_text,"pf%02xcn%02x",q->first_to_check,no_used);
+		QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 0;
+	}
+}
+
+static inline void qdio_translate_buffer_back(qdio_q_t *q,int bufno)
+{
+	if (!q->is_0copy_sbals_q)
+		memcpy(q->qdio_buffers[bufno],
+		       (void*)q->sbal[bufno],SBAL_SIZE);
+}
+
+inline static void qdio_kick_inbound_handler(qdio_q_t *q)
+{
+	int count=0;
+	int start,end,real_end,i;
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+
+	QDIO_DBF_TEXT4(0,trace,"kickinh");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	start=q->first_element_to_kick;
+	real_end=q->first_to_check;
+	end=(real_end+QDIO_MAX_BUFFERS_PER_Q-1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+
+	i=start;
+	while (1) {
+		count++;
+		qdio_translate_buffer_back(q,i);
+		if (i==end) break;
+		i=(i+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+	}
+
+#ifdef QDIO_DBF_LIKE_HELL
+	sprintf(dbf_text,"s=%2xc=%2x",start,count);
+	QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (q->state==QDIO_IRQ_STATE_ACTIVE)
+		q->handler(q->irq,
+			   QDIO_STATUS_INBOUND_INT|q->error_status_flags,
+			   q->qdio_error,q->siga_error,q->q_no,start,count,
+			   q->int_parm);
+
+	/* for the next time: */
+	q->first_element_to_kick=real_end;
+	q->qdio_error=0;
+	q->siga_error=0;
+	q->error_status_flags=0;
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
+	perf_stats.inbound_cnt++;
+#endif /* QDIO_PERFORMANCE_STATS */
+}
+
+static inline void iqdio_inbound_processing(qdio_q_t *q)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"iqinproc");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	/* we first want to reserve the q, so that we know, that we don't
+	 * interrupt ourselves and call qdio_unmark_q, as is_in_shutdown might
+	 * be set */
+	if (qdio_reserve_q(q)) {
+		qdio_release_q(q);
+#ifdef QDIO_PERFORMANCE_STATS
+		ii_p_c++;
+#endif /* QDIO_PERFORMANCE_STATS */
+		/* as we might just be about to stop polling, we make
+		 * sure that we check again at least once more */
+		iqdio_sched_tl();
+		return;
+	}
+#ifdef QDIO_PERFORMANCE_STATS
+	ii_p_nc++;
+#endif /* QDIO_PERFORMANCE_STATS */
+	if (atomic_read(&q->is_in_shutdown)) {
+		qdio_unmark_q(q);
+		goto out;
+	}
+
+	if (*(q->dev_st_chg_ind)) {
+		iqdio_clear_summary_bit((__u32*)q->dev_st_chg_ind);
+
+		if (!q->siga_sync_done_on_thinints) {
+			SYNC_MEMORY;
+		}
+
+		if (qdio_has_inbound_q_moved(q)) {
+			qdio_kick_inbound_handler(q);
+			if (iqdio_is_inbound_q_done(q)) {
+				if (!qdio_stop_polling(q)) {
+					/* we set the flags to get into
+					 * the stuff next time, see also
+					 * comment in qdio_stop_polling */
+					iqdio_set_summary_bit
+						((__u32*)q->dev_st_chg_ind);
+					iqdio_sched_tl();
+				}
+			}
+		}
+	}
+out:
+	qdio_release_q(q);
+}
+
+static void qdio_inbound_processing(qdio_q_t *q)
+{
+	int q_laps=0;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"qinproc");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (qdio_reserve_q(q)) {
+		qdio_release_q(q);
+#ifdef QDIO_PERFORMANCE_STATS
+		i_p_c++;
+#endif /* QDIO_PERFORMANCE_STATS */
+		/* as we're sissies, we'll check next time */
+		if (!atomic_read(&q->is_in_shutdown)) {
+			qdio_mark_q(q);
+#ifdef QDIO_DBF_LIKE_HELL
+			QDIO_DBF_TEXT4(0,trace,"busy,agn");
+#endif /* QDIO_DBF_LIKE_HELL */
+		}
+		return;
+	}
+#ifdef QDIO_PERFORMANCE_STATS
+	i_p_nc++;
+	perf_stats.tl_runs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+again:
+	if (qdio_has_inbound_q_moved(q)) {
+		qdio_kick_inbound_handler(q);
+		if (!qdio_stop_polling(q)) {
+			q_laps++;
+			if (q_laps<QDIO_Q_LAPS) goto again;
+		}
+		qdio_mark_q(q);
+	} else {
+		if (!qdio_is_inbound_q_done(q)) /* means poll time is 
+						   not yet over */
+			qdio_mark_q(q);
+	}
+
+	qdio_release_q(q);
+}
+
+/************************* OUTBOUND ROUTINES *******************************/
+
+inline static int qdio_get_outbound_buffer_frontier(qdio_q_t *q)
+{
+	int f,f_mod_no;
+	volatile char *slsb;
+	int first_not_to_check;
+	char dbf_text[15];
+	char slsbyte;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"getobfro");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	slsb=&q->slsb.acc.val[0];
+	f_mod_no=f=q->first_to_check;
+	/* f point to already processed elements, so f+no_used is correct...
+	 * ... but: we don't check 128 buffers, as otherwise
+	 * qdio_has_outbound_q_moved would return 0 */
+	first_not_to_check=f+qdio_min(atomic_read(&q->number_of_buffers_used),
+				      (QDIO_MAX_BUFFERS_PER_Q-1));
+
+	if ((!q->is_iqdio_q)&&(!q->hydra_gives_outbound_pcis)) {
+		SYNC_MEMORY;
+	}
+
+check_next:
+	if (f==first_not_to_check) goto out;
+	slsbyte=slsb[f_mod_no];
+
+	/* the hydra has not fetched the output yet */
+	if (slsbyte==SLSB_CU_OUTPUT_PRIMED) {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT5(0,trace,"outpprim");
+#endif /* QDIO_DBF_LIKE_HELL */
+		goto out;
+	}
+
+	/* the hydra got it */
+	if (slsbyte==SLSB_P_OUTPUT_EMPTY) {
+		atomic_dec(&q->number_of_buffers_used);
+		f++;
+		f_mod_no=f&(QDIO_MAX_BUFFERS_PER_Q-1);
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT5(0,trace,"outpempt");
+#endif /* QDIO_DBF_LIKE_HELL */
+		goto check_next;
+	}
+
+	if (slsbyte==SLSB_P_OUTPUT_ERROR) {
+		QDIO_DBF_TEXT3(0,trace,"outperr");
+		sprintf(dbf_text,"%x-%x-%x",f_mod_no,
+			q->sbal[f_mod_no]->element[14].sbalf.value,
+			q->sbal[f_mod_no]->element[15].sbalf.value);
+		QDIO_DBF_TEXT3(1,trace,dbf_text);
+		QDIO_DBF_HEX2(1,sbal,q->sbal[f_mod_no],256);
+
+		/* kind of process the buffer */
+		set_slsb(&q->slsb.acc.val[f_mod_no],
+			 SLSB_P_OUTPUT_NOT_INIT);
+
+		qdio_translate_buffer_back(q,f_mod_no);
+
+		/* we increment the frontier, as this buffer
+		 * was processed obviously */
+		atomic_dec(&q->number_of_buffers_used);
+		f_mod_no=(f_mod_no+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+
+		if (q->qdio_error)
+			q->error_status_flags|=
+				QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR;
+		q->qdio_error=SLSB_P_OUTPUT_ERROR;
+		q->error_status_flags|=QDIO_STATUS_LOOK_FOR_ERROR;
+
+		goto out;
+	}
+
+	/* no new buffers */
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT5(0,trace,"outpni");
+#endif /* QDIO_DBF_LIKE_HELL */
+	goto out;
+
+out:
+	return (q->first_to_check=f_mod_no);
+}
+
+/* all buffers are processed */
+inline static int qdio_is_outbound_q_done(qdio_q_t *q)
+{
+	int no_used;
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	no_used=atomic_read(&q->number_of_buffers_used);
+
+#ifdef QDIO_DBF_LIKE_HELL
+	if (no_used) {
+		sprintf(dbf_text,"oqisnt%02x",no_used);
+		QDIO_DBF_TEXT4(0,trace,dbf_text);
+	} else {
+		QDIO_DBF_TEXT4(0,trace,"oqisdone");
+	}
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+	return (no_used==0);
+}
+
+inline static int qdio_has_outbound_q_moved(qdio_q_t *q)
+{
+	int i;
+
+	i=qdio_get_outbound_buffer_frontier(q);
+
+	if ( (i!=GET_SAVED_FRONTIER(q)) ||
+	     (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) {
+		SAVE_FRONTIER(q,i);
+		SAVE_TIMESTAMP(q);
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"oqhasmvd");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 1;
+	} else {
+#ifdef QDIO_DBF_LIKE_HELL
+		QDIO_DBF_TEXT4(0,trace,"oqhsntmv");
+		QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+		return 0;
+	}
+}
+
+inline static void qdio_kick_outbound_q(qdio_q_t *q)
+{
+	int result;
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"kickoutq");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (!q->siga_out) return;
+
+	result=qdio_siga_output(q);
+
+	if (result) {
+		if (q->siga_error)
+			q->error_status_flags|=
+				QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR;
+		q->error_status_flags|=
+			QDIO_STATUS_LOOK_FOR_ERROR;
+		q->siga_error=result;
+	}
+}
+
+inline static void qdio_kick_outbound_handler(qdio_q_t *q)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	int start=q->first_element_to_kick;
+	/* last_move_ftc was just updated */
+	int real_end=GET_SAVED_FRONTIER(q);
+	int end=(real_end+QDIO_MAX_BUFFERS_PER_Q-1)&
+		(QDIO_MAX_BUFFERS_PER_Q-1);
+	int count=(end+QDIO_MAX_BUFFERS_PER_Q+1-start)&
+		(QDIO_MAX_BUFFERS_PER_Q-1);
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"kickouth");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_DBF_LIKE_HELL
+	sprintf(dbf_text,"s=%2xc=%2x",start,count);
+	QDIO_DBF_TEXT4(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (q->state==QDIO_IRQ_STATE_ACTIVE)
+		q->handler(q->irq,QDIO_STATUS_OUTBOUND_INT|
+			   q->error_status_flags,
+			   q->qdio_error,q->siga_error,q->q_no,start,count,
+			   q->int_parm);
+
+	/* for the next time: */
+	q->first_element_to_kick=real_end;
+	q->qdio_error=0;
+	q->siga_error=0;
+	q->error_status_flags=0;
+}
+
+static void qdio_outbound_processing(qdio_q_t *q)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"qoutproc");
+	QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (qdio_reserve_q(q)) {
+		qdio_release_q(q);
+#ifdef QDIO_PERFORMANCE_STATS
+		o_p_c++;
+#endif /* QDIO_PERFORMANCE_STATS */
+		/* as we're sissies, we'll check next time */
+		if (!atomic_read(&q->is_in_shutdown)) {
+			qdio_mark_q(q);
+#ifdef QDIO_DBF_LIKE_HELL
+			QDIO_DBF_TEXT4(0,trace,"busy,agn");
+#endif /* QDIO_DBF_LIKE_HELL */
+		}
+		return;
+	}
+#ifdef QDIO_PERFORMANCE_STATS
+	o_p_nc++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.tl_runs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+	if (qdio_has_outbound_q_moved(q)) {
+		qdio_kick_outbound_handler(q);
+	}
+
+	if (q->is_iqdio_q) {
+		/* for asynchronous queues, we better check, if the fill
+		 * level is too high */
+		if (atomic_read(&q->number_of_buffers_used)>
+		    IQDIO_FILL_LEVEL_TO_POLL) {
+			qdio_mark_q(q);
+		}
+	} else if (!q->hydra_gives_outbound_pcis) {
+		if (!qdio_is_outbound_q_done(q)) {
+			qdio_mark_q(q);
+		}
+	}
+
+	qdio_release_q(q);
+}
+
+/************************* MAIN ROUTINES *******************************/
+
+static inline void iqdio_inbound_checks(void)
+{
+	qdio_q_t *q;
+#ifdef QDIO_USE_PROCESSING_STATE
+	int q_laps=0;
+#endif /* QDIO_USE_PROCESSING_STATE */
+
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[15];
+
+	QDIO_DBF_TEXT4(0,trace,"iqdinbck");
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT5(0,trace,"iqlocsum");
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_USE_PROCESSING_STATE
+again:
+#endif /* QDIO_USE_PROCESSING_STATE */
+
+	q=(qdio_q_t*)iq_list;
+	do {
+		if (!q) break;
+		iqdio_inbound_processing(q);
+		q=(qdio_q_t*)q->list_next;
+	} while (q!=(qdio_q_t*)iq_list);
+
+#ifdef QDIO_USE_PROCESSING_STATE
+	q=(qdio_q_t*)iq_list;
+	do {
+		if (!q) {
+			iqdio_sched_tl();
+			break;
+		}
+		/* under VM, we have not used the PROCESSING state, so no
+		 * need to stop polling */
+		if (q->siga_sync) {
+			q=(qdio_q_t*)q->list_next;
+			continue;
+		}
+
+		if (qdio_reserve_q(q)) {
+			qdio_release_q(q);
+#ifdef QDIO_PERFORMANCE_STATS
+			ii_p_c++;
+#endif /* QDIO_PERFORMANCE_STATS */
+			/* as we might just be about to stop polling, we make
+			 * sure that we check again at least once more */
+
+			/* sanity -- we'd get here without setting the
+			 * dev st chg ind */
+			iqdio_set_summary_bit((__u32*)q->dev_st_chg_ind);
+			iqdio_sched_tl();
+			break;
+		}
+		if (!qdio_stop_polling(q)) {
+			q_laps++;
+			if (q_laps<QDIO_Q_LAPS) {
+				qdio_release_q(q);
+				goto again;
+			} else {
+				/* we set the flags to get into the stuff
+				 * next time, see also comment in
+				 * qdio_stop_polling */
+				iqdio_set_summary_bit((__u32*)
+						      q->dev_st_chg_ind);
+				iqdio_sched_tl();
+			}
+		}
+		qdio_release_q(q);
+		q=(qdio_q_t*)q->list_next;
+	} while (q!=(qdio_q_t*)iq_list);
+#endif /* QDIO_USE_PROCESSING_STATE */
+}
+
+static void iqdio_check_for_polling(void)
+{
+}
+
+static void iqdio_tl(unsigned long data)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
+#endif /* QDIO_DBF_LIKE_HELL */
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.tl_runs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+	iqdio_inbound_checks();
+	iqdio_check_for_polling();
+}
+
+/********************* GENERAL HELPER_ROUTINES ***********************/
+
+static qdio_irq_t *qdio_get_irq_ptr(int irq)
+{
+	qdio_irq_t *irq_ptr;
+	int bucket=irq&(QDIO_IRQ_BUCKETS-1);
+
+	read_lock(&irq_list_lock[bucket]);
+	irq_ptr=first_irq[bucket];
+	while (irq_ptr) {
+		if (irq_ptr->irq==irq) break;
+		irq_ptr=irq_ptr->next;
+	}
+	read_unlock(&irq_list_lock[bucket]);
+	return irq_ptr;
+}
+
+static qdio_irq_t *qdio_get_irq_ptr_wolock(int irq)
+{
+	qdio_irq_t *irq_ptr=first_irq[irq&(QDIO_IRQ_BUCKETS-1)];
+
+	while (irq_ptr) {
+		if (irq_ptr->irq==irq) break;
+		irq_ptr=irq_ptr->next;
+	}
+	return irq_ptr;
+}
+
+/* irq_ptr->irq should be set already! */
+static void qdio_insert_irq_ptr(qdio_irq_t *irq_ptr)
+{
+	qdio_irq_t *i_p;
+	int irq,bucket;
+
+	if (!irq_ptr) return;
+
+	irq=irq_ptr->irq;
+	bucket=irq&(QDIO_IRQ_BUCKETS-1);
+
+	write_lock(&irq_list_lock[bucket]);
+
+	if (irq_ptr==qdio_get_irq_ptr_wolock(irq)) goto out;
+
+	if (!first_irq[bucket]) {
+		first_irq[bucket]=irq_ptr;
+	} else {
+		i_p=first_irq[bucket];
+		while (i_p->next)
+			i_p=i_p->next;
+		i_p->next=irq_ptr;
+	}
+	irq_ptr->next=NULL;
+out:
+	write_unlock(&irq_list_lock[bucket]);
+}
+
+static void qdio_remove_irq_ptr(qdio_irq_t *irq_ptr)
+{
+	qdio_irq_t *i_p;
+	int irq,bucket;
+
+	if (!irq_ptr) return;
+
+	irq=irq_ptr->irq;
+	bucket=irq&(QDIO_IRQ_BUCKETS-1);
+
+	write_lock(&irq_list_lock[bucket]);
+
+	if (!qdio_get_irq_ptr_wolock(irq)) goto out;
+
+	if (first_irq[irq&(QDIO_IRQ_BUCKETS-1)]==irq_ptr) {
+		first_irq[irq&(QDIO_IRQ_BUCKETS-1)]=irq_ptr->next;
+	} else {
+		for (i_p=first_irq[irq&(QDIO_IRQ_BUCKETS-1)];
+		     i_p->next!=irq_ptr;i_p=i_p->next);
+		i_p->next=irq_ptr->next;
+	}
+	irq_ptr->next=NULL;
+out:
+	write_unlock(&irq_list_lock[bucket]);
+}
+
+static void qdio_release_irq_memory(qdio_irq_t *irq_ptr)
+{
+	int i,j;
+	int available;
+
+	for (i=0;i<QDIO_MAX_QUEUES_PER_IRQ;i++) {
+		if (!irq_ptr->input_qs[i]) goto next;
+		available=0;
+		if (!irq_ptr->input_qs[i]->is_0copy_sbals_q)
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+				if (!available) {
+					if (irq_ptr->input_qs[i]->sbal[j])
+						kfree((void*)irq_ptr->
+						      input_qs[i]->sbal[j]);
+					available=PAGE_SIZE;
+				}
+				available-=sizeof(sbal_t);
+			}
+		if (irq_ptr->input_qs[i]->slib)
+			kfree(irq_ptr->input_qs[i]->slib);
+			kfree(irq_ptr->input_qs[i]);
+
+next:
+		if (!irq_ptr->output_qs[i]) goto next2;
+		available=0;
+		if (!irq_ptr->output_qs[i]->is_0copy_sbals_q)
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+				if (!available) {
+					if (irq_ptr->output_qs[i]->sbal[j])
+						kfree((void*)irq_ptr->
+						      output_qs[i]->sbal[j]);
+					available=PAGE_SIZE;
+				}
+				available-=sizeof(sbal_t);
+			}
+		if (irq_ptr->output_qs[i]->slib)
+			kfree(irq_ptr->output_qs[i]->slib);
+		kfree(irq_ptr->output_qs[i]);
+next2:
+	}
+	if (irq_ptr->qdr) kfree(irq_ptr->qdr);
+	kfree(irq_ptr);
+	QDIO_DBF_TEXT3(0,setup,"MOD_DEC_");
+	MOD_DEC_USE_COUNT;
+}
+
+static inline void qdio_wakeup(atomic_t *var,qdio_irq_t *irq_ptr)
+{
+	wait_queue_head_t *wait_q;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[20];
+	sprintf(dbf_text,"qwkp%4x",irq_ptr->irq);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	atomic_set(var,1);
+	if ((wait_q=&irq_ptr->wait_q))
+		wake_up(wait_q);
+}
+
+static int qdio_sleepon(atomic_t *var,int timeout,qdio_irq_t *irq_ptr)
+{
+        __u64 stop;
+	int retval;
+        DECLARE_WAITQUEUE (current_wait_q,current);
+
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[20];
+	sprintf(dbf_text,"qslp%4x",irq_ptr->irq);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	add_wait_queue(&irq_ptr->wait_q,&current_wait_q);
+        stop=(qdio_get_micros()>>10)+timeout;
+        for (;;) {
+		set_task_state(current,TASK_INTERRUPTIBLE);
+		if (atomic_read(var)) {
+			atomic_set(var,0);
+                        retval=0;
+			goto out;
+                }
+                if (qdio_get_micros()>>10>stop) {
+#ifdef QDIO_DBF_LIKE_HELL
+			sprintf(dbf_text,"%xtime",irq_ptr->irq);
+			QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+			retval=-ETIME;
+			goto out;
+		}
+                schedule_timeout(((stop-(qdio_get_micros()>>10))>>10)*HZ);
+        }
+ out:
+	set_task_state(current,TASK_RUNNING);
+	remove_wait_queue(&irq_ptr->wait_q,&current_wait_q);
+	return retval;
+}
+
+static void qdio_set_impl_params(qdio_irq_t *irq_ptr,
+				 unsigned int qib_param_field_format,
+			  /* pointer to 128 bytes or NULL, if no param field */
+				 unsigned char *qib_param_field,
+			  /* pointer to no_queues*128 words of data or NULL */
+				 unsigned int no_input_qs,
+				 unsigned int no_output_qs,
+				 unsigned long *input_slib_elements,
+				 unsigned long *output_slib_elements)
+{
+	int i,j;
+
+	if (!irq_ptr) return;
+
+	irq_ptr->qib.pfmt=qib_param_field_format;
+	if (qib_param_field)
+		memcpy(irq_ptr->qib.parm,qib_param_field,
+		       QDIO_MAX_BUFFERS_PER_Q);
+
+	if (input_slib_elements)
+		for (i=0;i<no_input_qs;i++) {
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++)
+				irq_ptr->input_qs[i]->slib->slibe[j].parms=
+					input_slib_elements[
+						i*QDIO_MAX_BUFFERS_PER_Q+j];
+		}
+	if (output_slib_elements)
+		for (i=0;i<no_output_qs;i++) {
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++)
+				irq_ptr->output_qs[i]->slib->slibe[j].parms=
+					output_slib_elements[
+						i*QDIO_MAX_BUFFERS_PER_Q+j];
+		}
+}
+
+
+
+static int qdio_alloc_qs(qdio_irq_t *irq_ptr,int no_input_qs,int no_output_qs,
+			 qdio_handler_t *input_handler,
+			 qdio_handler_t *output_handler,
+			 unsigned long int_parm,int q_format,
+			 unsigned long flags,
+			 void **inbound_sbals_array,
+			 void **outbound_sbals_array)
+{
+	qdio_q_t *q;
+	int i,j,result=0;
+	char dbf_text[20]; /* see qdio_initialize */
+	void *ptr;
+	int available;
+
+	for (i=0;i<no_input_qs;i++) {
+		q=kmalloc(sizeof(qdio_q_t),GFP_KERNEL);
+
+		if (!q) {
+			QDIO_PRINT_ERR("kmalloc of q failed!\n");
+			goto out;
+		}
+		memset(q,0,sizeof(qdio_q_t));
+
+		sprintf(dbf_text,"in-q%4x",i);
+		QDIO_DBF_TEXT0(0,setup,dbf_text);
+		QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+
+		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+		if (!q->slib) {
+			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
+			goto out;
+		}
+		memset(q->slib,0,PAGE_SIZE);
+		q->sl=(sl_t*)(((char*)q->slib)+PAGE_SIZE/2);
+
+		available=0;
+		if (flags&QDIO_INBOUND_0COPY_SBALS) {
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+				q->sbal[j]=*(inbound_sbals_array++);
+			}
+		} else for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+			if (!available) {
+				q->sbal[j]=kmalloc(PAGE_SIZE,GFP_KERNEL);
+				if (!q->sbal[j]) {
+					goto out;
+				}
+				available=PAGE_SIZE;
+				memset((void*)q->sbal[j],0,PAGE_SIZE);
+			} else {
+				q->sbal[j]=(volatile sbal_t *)
+					(((char*)q->sbal[j-1])+sizeof(sbal_t));
+			}
+			available-=sizeof(sbal_t);
+		}
+
+                q->queue_type=q_format;
+		q->int_parm=int_parm;
+		irq_ptr->input_qs[i]=q;
+		q->irq=irq_ptr->irq;
+		q->mask=1<<(31-i);
+		q->q_no=i;
+		q->is_input_q=1;
+		q->is_0copy_sbals_q=flags&QDIO_INBOUND_0COPY_SBALS;
+		q->first_to_check=0;
+		q->last_move_ftc=0;
+		q->handler=input_handler;
+		q->dev_st_chg_ind=irq_ptr->dev_st_chg_ind;
+
+		q->tasklet.data=(unsigned long)q;
+		q->tasklet.func=(void(*)(unsigned long))
+			(
+			(q_format==QDIO_IQDIO_QFMT)?&iqdio_inbound_processing:
+			&qdio_inbound_processing);
+
+/*		for (j=0;j<QDIO_STATS_NUMBER;j++)
+			q->timing.last_transfer_times[j]=(qdio_get_micros()/
+							  QDIO_STATS_NUMBER)*j;
+		q->timing.last_transfer_index=QDIO_STATS_NUMBER-1;
+*/
+
+		/* fill in slib */
+		if (i>0) irq_ptr->input_qs[i-1]->slib->nsliba=
+				 (unsigned long)(q->slib);
+		q->slib->sla=(unsigned long)(q->sl);
+		q->slib->slsba=(unsigned long)(&q->slsb.acc.val[0]);
+
+		/* fill in sl */
+		for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++)
+			q->sl->element[j].sbal=(unsigned long)(q->sbal[j]);
+
+		QDIO_DBF_TEXT2(0,setup,"sl-sb-b0");
+		ptr=(void*)q->sl;
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+		ptr=(void*)&q->slsb;
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+		ptr=(void*)q->sbal[0];
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+
+		/* fill in slsb */
+		for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+			set_slsb(&q->slsb.acc.val[j],
+		   		 SLSB_P_INPUT_NOT_INIT);
+/*			q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/
+		}
+	}
+
+	for (i=0;i<no_output_qs;i++) {
+		q=kmalloc(sizeof(qdio_q_t),GFP_KERNEL);
+
+		if (!q) {
+			goto out;
+		}
+		memset(q,0,sizeof(qdio_q_t));
+
+		sprintf(dbf_text,"outq%4x",i);
+		QDIO_DBF_TEXT0(0,setup,dbf_text);
+		QDIO_DBF_HEX0(0,setup,&q,sizeof(void*));
+
+		q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+		if (!q->slib) {
+			QDIO_PRINT_ERR("kmalloc of slib failed!\n");
+			goto out;
+		}
+		memset(q->slib,0,PAGE_SIZE);
+		q->sl=(sl_t*)(((char*)q->slib)+PAGE_SIZE/2);
+
+		available=0;
+		if (flags&QDIO_OUTBOUND_0COPY_SBALS) {
+			for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+				q->sbal[j]=*(outbound_sbals_array++);
+			}
+		} else for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+			if (!available) {
+				q->sbal[j]=kmalloc(PAGE_SIZE,GFP_KERNEL);
+				if (!q->sbal[j]) {
+					goto out;
+				}
+				available=PAGE_SIZE;
+				memset((void*)q->sbal[j],0,PAGE_SIZE);
+			} else {
+				q->sbal[j]=(volatile sbal_t *)
+					(((char*)q->sbal[j-1])+sizeof(sbal_t));
+			}
+			available-=sizeof(sbal_t);
+		}
+
+                q->queue_type=q_format;
+		q->int_parm=int_parm;
+		irq_ptr->output_qs[i]=q;
+		q->is_input_q=0;
+		q->is_0copy_sbals_q=flags&QDIO_OUTBOUND_0COPY_SBALS;
+		q->irq=irq_ptr->irq;
+		q->mask=1<<(31-i);
+		q->q_no=i;
+		q->first_to_check=0;
+		q->last_move_ftc=0;
+		q->handler=output_handler;
+
+		q->tasklet.data=(unsigned long)q;
+		q->tasklet.func=(void(*)(unsigned long))
+			&qdio_outbound_processing;
+
+		/* fill in slib */
+		if (i>0) irq_ptr->output_qs[i-1]->slib->nsliba=
+				 (unsigned long)(q->slib);
+		q->slib->sla=(unsigned long)(q->sl);
+		q->slib->slsba=(unsigned long)(&q->slsb.acc.val[0]);
+
+		/* fill in sl */
+		for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++)
+			q->sl->element[j].sbal=(unsigned long)(q->sbal[j]);
+
+		QDIO_DBF_TEXT2(0,setup,"sl-sb-b0");
+		ptr=(void*)q->sl;
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+		ptr=(void*)&q->slsb;
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+		ptr=(void*)q->sbal[0];
+		QDIO_DBF_HEX2(0,setup,&ptr,sizeof(void*));
+
+		/* fill in slsb */
+		for (j=0;j<QDIO_MAX_BUFFERS_PER_Q;j++) {
+			set_slsb(&q->slsb.acc.val[j],
+		   		 SLSB_P_OUTPUT_NOT_INIT);
+/*			q->sbal[j]->element[1].sbalf.i1.key=QDIO_STORAGE_KEY;*/
+		}
+	}
+
+	result=1;
+out:
+	return result;
+}
+
+static void qdio_fill_thresholds(qdio_irq_t *irq_ptr,
+				 unsigned int no_input_qs,
+				 unsigned int no_output_qs,
+				 unsigned int min_input_threshold,
+				 unsigned int max_input_threshold,
+				 unsigned int min_output_threshold,
+				 unsigned int max_output_threshold)
+{
+	int i;
+	qdio_q_t *q;
+
+	for (i=0;i<no_input_qs;i++) {
+		q=irq_ptr->input_qs[i];
+		q->timing.threshold=max_input_threshold;
+/*		for (j=0;j<QDIO_STATS_CLASSES;j++) {
+			q->threshold_classes[j].threshold=
+				min_input_threshold+
+				(max_input_threshold-min_input_threshold)/
+				QDIO_STATS_CLASSES;
+		}
+		qdio_use_thresholds(q,QDIO_STATS_CLASSES/2);*/
+	}
+	for (i=0;i<no_output_qs;i++) {
+		q=irq_ptr->output_qs[i];
+		q->timing.threshold=max_output_threshold;
+/*		for (j=0;j<QDIO_STATS_CLASSES;j++) {
+			q->threshold_classes[j].threshold=
+				min_output_threshold+
+				(max_output_threshold-min_output_threshold)/
+				QDIO_STATS_CLASSES;
+		}
+		qdio_use_thresholds(q,QDIO_STATS_CLASSES/2);*/
+	}
+}
+
+static int iqdio_thinint_handler(__u32 intparm)
+{
+#ifdef QDIO_DBF_LIKE_HELL
+	QDIO_DBF_TEXT4(0,trace,"thin_int");
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.thinints++;
+	perf_stats.start_time_inbound=NOW;
+#endif /* QDIO_PERFORMANCE_STATS */
+	/* VM will do the SVS for us */
+	if (!MACHINE_IS_VM) {
+		iqdio_clear_global_summary();
+	}
+
+	iqdio_inbound_checks();
+	iqdio_check_for_polling();
+	return 0;
+}
+
+static void qdio_set_state(qdio_irq_t *irq_ptr,int state)
+{
+	int i;
+	char dbf_text[15];
+
+	QDIO_DBF_TEXT5(0,trace,"newstate");
+	sprintf(dbf_text,"%4x%4x",irq_ptr->irq,state);
+	QDIO_DBF_TEXT5(0,trace,dbf_text);
+
+	irq_ptr->state=state;
+	for (i=0;i<irq_ptr->no_input_qs;i++)
+		irq_ptr->input_qs[i]->state=state;
+	for (i=0;i<irq_ptr->no_output_qs;i++)
+		irq_ptr->output_qs[i]->state=state;
+	mb();
+}
+
+static void qdio_handler(int irq,devstat_t *devstat,struct pt_regs *p)
+{
+	qdio_irq_t *irq_ptr;
+	qdio_q_t *q;
+	int i;
+	int cstat,dstat;
+	int rqparam;
+	char dbf_text[15]="qintXXXX";
+
+        cstat = devstat->cstat;
+        dstat = devstat->dstat;
+        rqparam=devstat->intparm;
+
+	*((int*)(&dbf_text[4]))=irq;
+	QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
+	
+	if (!rqparam) {
+		QDIO_PRINT_STUPID("got unsolicited interrupt in qdio " \
+				  "handler, irq 0x%x\n",irq);
+		return;
+	}
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) {
+		sprintf(dbf_text,"uint%4x",irq);
+		QDIO_DBF_TEXT2(1,trace,dbf_text);
+		QDIO_PRINT_ERR("received interrupt on unused irq 0x%04x!\n",
+			       irq);
+		return;
+	}
+
+	if (devstat->flag&DEVSTAT_FLAG_SENSE_AVAIL) {
+		sprintf(dbf_text,"sens%4x",irq);
+		QDIO_DBF_TEXT2(1,trace,dbf_text);
+		QDIO_DBF_HEX0(0,sense,&devstat->ii.irb,QDIO_DBF_SENSE_LEN);
+
+		QDIO_PRINT_WARN("sense data available on qdio channel.\n");
+		HEXDUMP16(WARN,"irb: ",&devstat->ii.irb);
+		HEXDUMP16(WARN,"sense data: ",&devstat->ii.sense.data[0]);
+	}
+
+	irq_ptr->io_result_cstat=ioinfo[irq]->devstat.cstat;
+	irq_ptr->io_result_dstat=ioinfo[irq]->devstat.dstat;
+	irq_ptr->io_result_flags=ioinfo[irq]->devstat.flag;
+
+	if ( (rqparam==QDIO_DOING_ACTIVATE) &&
+	     (cstat & SCHN_STAT_PCI) ) {
+#ifdef QDIO_PERFORMANCE_STATS
+		perf_stats.pcis++;
+		perf_stats.start_time_inbound=NOW;
+#endif /* QDIO_PERFORMANCE_STATS */
+		for (i=0;i<irq_ptr->no_input_qs;i++) {
+			q=irq_ptr->input_qs[i];
+			if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
+				qdio_mark_q(q);
+			else {
+#ifdef QDIO_PERFORMANCE_STATS
+				perf_stats.tl_runs--;
+#endif /* QDIO_PERFORMANCE_STATS */
+				qdio_inbound_processing(q);
+			}
+		}
+		if (irq_ptr->hydra_gives_outbound_pcis) {
+ 			for (i=0;i<irq_ptr->no_output_qs;i++) {
+ 				q=irq_ptr->output_qs[i];
+#ifdef QDIO_PERFORMANCE_STATS
+				perf_stats.tl_runs--;
+#endif /* QDIO_PERFORMANCE_STATS */
+				if (!qdio_is_outbound_q_done(q)) {
+					if (!irq_ptr->sync_done_on_outb_pcis) {
+						SYNC_MEMORY;
+					}
+					qdio_outbound_processing(q);
+				}
+			}
+		}
+		return;
+	}
+
+	if ( (rqparam==QDIO_DOING_ACTIVATE) &&
+	     (!cstat) &&
+	     (!dstat) ) {
+		rqparam=QDIO_DOING_CLEANUP;
+	}
+
+	if ( (rqparam==QDIO_DOING_ESTABLISH) &&
+	     ( (cstat) ||
+	       (dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ) ) {
+		sprintf(dbf_text,"ick1%4x",irq);
+		QDIO_DBF_TEXT2(1,trace,dbf_text);
+		QDIO_DBF_HEX2(0,trace,&rqparam,sizeof(int));
+		QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int));
+		QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int));
+		QDIO_PRINT_ERR("received check condition on establish " \
+			       "queues on irq 0x%x (cs=x%x, ds=x%x).\n",
+			       irq,cstat,dstat);
+		qdio_set_state(irq_ptr,QDIO_IRQ_STATE_STOPPED);
+		return;
+	}
+
+	if ( ( (rqparam==QDIO_DOING_ACTIVATE) &&
+	       (dstat==(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ) ||
+	     ( (rqparam==QDIO_DOING_CLEANUP) || (!rqparam) ) ) {
+		qdio_wakeup(&irq_ptr->interrupt_has_been_cleaned,irq_ptr);
+		return;
+	}
+
+	if ( (rqparam==QDIO_DOING_ACTIVATE) &&
+	     ( (cstat & ~SCHN_STAT_PCI) ||
+	       (dstat) ) ) {
+		sprintf(dbf_text,"ick2%4x",irq);
+		QDIO_DBF_TEXT2(1,trace,dbf_text);
+		QDIO_DBF_HEX2(0,trace,&rqparam,sizeof(int));
+		QDIO_DBF_HEX2(0,trace,&dstat,sizeof(int));
+		QDIO_DBF_HEX2(0,trace,&cstat,sizeof(int));
+		QDIO_PRINT_ERR("received check condition on activate " \
+			       "queues on irq 0x%x (cs=x%x, ds=x%x).\n",
+			       irq,cstat,dstat);
+		if (irq_ptr->no_input_qs) {
+			q=irq_ptr->input_qs[0];
+		} else if (irq_ptr->no_output_qs) {
+			q=irq_ptr->output_qs[0];
+		} else {
+			QDIO_PRINT_ERR("oops... no queue registered on irq " \
+				  "0x%x!?\n",irq);
+			goto omit_handler_call;
+		}
+		q->handler(q->irq,QDIO_STATUS_ACTIVATE_CHECK_CONDITION|
+			   QDIO_STATUS_LOOK_FOR_ERROR,
+			   0,0,0,-1,-1,q->int_parm);
+	omit_handler_call:
+		qdio_set_state(irq_ptr,QDIO_IRQ_STATE_STOPPED);
+		return;
+	}
+
+	qdio_wakeup(&irq_ptr->interrupt_has_arrived,irq_ptr);
+}
+
+/* this is for mp3 */
+int qdio_synchronize(int irq,unsigned int flags,
+		     unsigned int queue_number)
+{
+	unsigned int gpr2,gpr3;
+	int cc;
+	qdio_q_t *q;
+	qdio_irq_t *irq_ptr;
+	char dbf_text[15]="SyncXXXX";
+	void *ptr;
+
+	*((int*)(&dbf_text[4]))=irq;
+	QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
+	*((int*)(&dbf_text[0]))=flags;
+	*((int*)(&dbf_text[4]))=queue_number;
+	QDIO_DBF_HEX4(0,trace,dbf_text,QDIO_DBF_TRACE_LEN);
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return -ENODEV;
+
+	if (flags&QDIO_FLAG_SYNC_INPUT) {
+		q=irq_ptr->input_qs[queue_number];
+		if (!q) return -EINVAL;
+
+		gpr2=0;
+		gpr3=q->mask;
+	} else if (flags&QDIO_FLAG_SYNC_OUTPUT) {
+		q=irq_ptr->output_qs[queue_number];
+		if (!q) return -EINVAL;
+
+		gpr2=q->mask;
+		gpr3=0;
+	} else return -EINVAL;
+
+#ifdef QDIO_32_BIT
+	asm volatile (
+		"lhi	0,2	\n\t"
+		"lr	1,%1	\n\t"
+		"lr	2,%2	\n\t"
+		"lr	3,%3	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (gpr2), "d" (gpr3)
+		: "cc", "0", "1", "2", "3"
+		);
+#else /* QDIO_32_BIT */
+	asm volatile (
+		"lghi	0,2	\n\t"
+		"llgfr	1,%1	\n\t"
+		"llgfr	2,%2	\n\t"
+		"llgfr	3,%3	\n\t"
+		"siga   0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc)
+		: "d" (0x10000|q->irq), "d" (gpr2), "d" (gpr3)
+		: "cc", "0", "1", "2", "3"
+		);
+#endif /* QDIO_32_BIT */
+
+	ptr=&cc;
+	if (cc) QDIO_DBF_HEX3(0,trace,&ptr,sizeof(int));
+
+	return cc;
+}
+
+/* FIXME: this is never used in the kernel, why? */
+unsigned char qdio_get_slsb_state(int irq,unsigned int flag,
+				  unsigned int queue_number,
+				  unsigned int qidx)
+{
+	qdio_irq_t *irq_ptr;
+	qdio_q_t *q;
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return SLSB_ERROR_DURING_LOOKUP;
+
+	if (flag&QDIO_FLAG_SYNC_INPUT) {
+		q=irq_ptr->input_qs[queue_number];
+	} else if (flag&QDIO_FLAG_SYNC_OUTPUT) {
+		q=irq_ptr->output_qs[queue_number];
+	} else return SLSB_ERROR_DURING_LOOKUP;
+
+	return q->slsb.acc.val[qidx&(QDIO_MAX_BUFFERS_PER_Q-1)];
+}
+
+static int qdio_chsc(qdio_chsc_area_t *chsc_area)
+{
+	int cc;
+
+#ifdef QDIO_32_BIT
+	asm volatile (
+		".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) : "d" (chsc_area) : "cc"
+		);
+#else /* QDIO_32_BIT */
+	asm volatile (
+		".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) : "d" (chsc_area) : "cc"
+		);
+#endif /* QDIO_32_BIT */
+
+	return cc;
+}
+
+static unsigned char qdio_check_siga_needs(int sch)
+{
+	int resp_code,result;
+
+	memset(chsc_area,0,sizeof(qdio_chsc_area_t));
+	chsc_area->request_block.command_code1=0x0010; /* length */
+	chsc_area->request_block.command_code2=0x0024; /* op code */
+	chsc_area->request_block.first_sch=sch;
+	chsc_area->request_block.last_sch=sch;
+
+	result=qdio_chsc(chsc_area);
+
+	if (result) {
+		QDIO_PRINT_WARN("CHSC returned cc %i. Using all " \
+				"SIGAs for sch x%x.\n",
+				result,sch);
+		return -1; /* all flags set */
+	}
+
+	resp_code=chsc_area->request_block.operation_data_area.
+		store_qdio_data_response.response_code;
+	if (resp_code!=QDIO_CHSC_RESPONSE_CODE_OK) {
+		QDIO_PRINT_WARN("response upon checking SIGA needs " \
+				"is 0x%x. Using all SIGAs for sch x%x.\n",
+				resp_code,sch);
+		return -1; /* all flags set */
+	}
+	if (
+	    (!(chsc_area->request_block.operation_data_area.
+	       store_qdio_data_response.flags&CHSC_FLAG_QDIO_CAPABILITY)) ||
+	    (!(chsc_area->request_block.operation_data_area.
+	       store_qdio_data_response.flags&CHSC_FLAG_VALIDITY)) ||
+	    (chsc_area->request_block.operation_data_area.
+	     store_qdio_data_response.sch!=sch)
+	    ) {
+		QDIO_PRINT_WARN("huh? problems checking out sch x%x... " \
+				"using all SIGAs.\n",sch);
+		return CHSC_FLAG_SIGA_INPUT_NECESSARY |
+			CHSC_FLAG_SIGA_OUTPUT_NECESSARY |
+			CHSC_FLAG_SIGA_SYNC_NECESSARY; /* worst case */
+	}
+
+	return chsc_area->request_block.operation_data_area.
+		store_qdio_data_response.qdioac;
+}
+
+/* the chsc_area is locked by the lock in qdio_activate */
+static unsigned int iqdio_check_chsc_availability(void) {
+	int result;
+	int i;
+
+	memset(chsc_area,0,sizeof(qdio_chsc_area_t));
+	chsc_area->request_block.command_code1=0x0010;
+	chsc_area->request_block.command_code2=0x0010;
+	result=qdio_chsc(chsc_area);
+	if (result) {
+		QDIO_PRINT_WARN("Was not able to determine " \
+				"available CHSCs, cc=%i.\n",
+				result);
+		result=-EIO;
+		goto exit;
+	}
+	result=0;
+	i=chsc_area->request_block.operation_data_area.
+		store_qdio_data_response.response_code;
+	if (i!=1) {
+		QDIO_PRINT_WARN("Was not able to determine " \
+				"available CHSCs.\n");
+		result=-EIO;
+		goto exit;
+	}
+	/* 4: request block
+	 * 2: general char
+	 * 512: chsc char */
+	if ( (*(((unsigned int*)(chsc_area))+4+2+1)&0x00800000)!=0x00800000) {
+		QDIO_PRINT_WARN("Adapter interruption facility not " \
+				"installed.\n");
+		result=-ENOENT;
+		goto exit;
+	}
+	if ( (*(((unsigned int*)(chsc_area))+4+512+3)&0x00180000)!=
+	     0x00180000 ) {
+		QDIO_PRINT_WARN("Set Chan Subsys. Char. & Fast-CHSCs " \
+				"not available.\n");
+		result=-ENOENT;
+		goto exit;
+	}
+exit:
+	return result;
+}
+
+/* the chsc_area is locked by the lock in qdio_activate */
+static unsigned int iqdio_set_subchannel_ind(qdio_irq_t *irq_ptr,
+					     int reset_to_zero)
+{
+	unsigned long real_addr_local_summary_bit;
+	unsigned long real_addr_dev_st_chg_ind;
+	void *ptr;
+	char dbf_text[15];
+
+	unsigned int resp_code;
+	int result;
+
+	if (!irq_ptr->is_iqdio_irq) return -ENODEV;
+
+	if (reset_to_zero) {
+		real_addr_local_summary_bit=0;
+		real_addr_dev_st_chg_ind=0;
+	} else {
+		real_addr_local_summary_bit=
+			virt_to_phys((volatile void *)indicators);
+		real_addr_dev_st_chg_ind=
+			virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
+	}
+
+	memset(chsc_area,0,sizeof(qdio_chsc_area_t));
+	chsc_area->request_block.command_code1=0x0fe0;
+	chsc_area->request_block.command_code2=0x0021;
+	chsc_area->request_block.operation_code=0;
+	chsc_area->request_block.image_id=0;
+
+	chsc_area->request_block.operation_data_area.set_chsc.
+		summary_indicator_addr=real_addr_local_summary_bit;
+	chsc_area->request_block.operation_data_area.set_chsc.
+		subchannel_indicator_addr=real_addr_dev_st_chg_ind;
+	chsc_area->request_block.operation_data_area.set_chsc.
+		ks=QDIO_STORAGE_KEY;
+	chsc_area->request_block.operation_data_area.set_chsc.
+		kc=QDIO_STORAGE_KEY;
+	chsc_area->request_block.operation_data_area.set_chsc.
+		isc=IQDIO_THININT_ISC;
+	chsc_area->request_block.operation_data_area.set_chsc.
+		subsystem_id=(1<<16)+irq_ptr->irq;
+
+	result=qdio_chsc(chsc_area);
+	if (result) {
+		QDIO_PRINT_WARN("could not set indicators on irq x%x, " \
+				"cc=%i.\n",irq_ptr->irq,result);
+		return -EIO;
+	}
+
+	resp_code=chsc_area->response_block.response_code;
+	if (resp_code!=QDIO_CHSC_RESPONSE_CODE_OK) {
+		QDIO_PRINT_WARN("response upon setting indicators " \
+				"is 0x%x.\n",resp_code);
+		sprintf(dbf_text,"sidR%4x",resp_code);
+		QDIO_DBF_TEXT1(0,trace,dbf_text);
+		QDIO_DBF_TEXT1(0,setup,dbf_text);
+		ptr=&chsc_area->response_block;
+		QDIO_DBF_HEX2(1,setup,&ptr,QDIO_DBF_SETUP_LEN);
+		return -EIO;
+	}
+
+	QDIO_DBF_TEXT2(0,setup,"setscind");
+	QDIO_DBF_HEX2(0,setup,&real_addr_local_summary_bit,
+		      sizeof(unsigned long));
+	QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long));
+	return 0;
+}
+
+/* chsc_area would have to be locked if called from outside qdio_activate */
+static unsigned int iqdio_set_delay_target(qdio_irq_t *irq_ptr,
+       					   unsigned long delay_target)
+{
+	unsigned int resp_code;
+	int result;
+	void *ptr;
+	char dbf_text[15];
+
+	if (!irq_ptr->is_iqdio_irq) return -ENODEV;
+
+	memset(chsc_area,0,sizeof(qdio_chsc_area_t));
+	chsc_area->request_block.command_code1=0x0fe0;
+	chsc_area->request_block.command_code2=0x1027;
+	chsc_area->request_block.operation_data_area.set_chsc_fast.
+		delay_target=delay_target<<16;
+
+	result=qdio_chsc(chsc_area);
+	if (result) {
+		QDIO_PRINT_WARN("could not set delay target on irq x%x, " \
+				"cc=%i. Continuing.\n",irq_ptr->irq,result);
+		return -EIO;
+	}
+
+	resp_code=chsc_area->response_block.response_code;
+	if (resp_code!=QDIO_CHSC_RESPONSE_CODE_OK) {
+		QDIO_PRINT_WARN("response upon setting delay target " \
+				"is 0x%x. Continuing.\n",resp_code);
+		sprintf(dbf_text,"sdtR%4x",resp_code);
+		QDIO_DBF_TEXT1(0,trace,dbf_text);
+		QDIO_DBF_TEXT1(0,setup,dbf_text);
+		ptr=&chsc_area->response_block;
+		QDIO_DBF_HEX2(1,trace,&ptr,QDIO_DBF_TRACE_LEN);
+	}
+	QDIO_DBF_TEXT2(0,trace,"delytrgt");
+	QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long));
+	return 0;
+}
+
+int qdio_cleanup(int irq,int how)
+{
+	qdio_irq_t *irq_ptr;
+	int i,result;
+	int do_an_irqrestore=0;
+	unsigned long flags;
+	int timeout;
+	char dbf_text[15]="12345678";
+
+	result=0;
+	sprintf(dbf_text,"qcln%4x",irq);
+	QDIO_DBF_TEXT1(0,trace,dbf_text);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return -ENODEV;
+
+	my_spin_lock(&irq_ptr->setting_up_lock);
+
+	/* mark all qs as uninteresting */
+	for (i=0;i<irq_ptr->no_input_qs;i++) {
+		atomic_set(&irq_ptr->input_qs[i]->is_in_shutdown,1);
+	}
+	for (i=0;i<irq_ptr->no_output_qs;i++) {
+		atomic_set(&irq_ptr->output_qs[i]->is_in_shutdown,1);
+	}
+
+	tasklet_kill(&iqdio_tasklet);
+
+	for (i=0;i<irq_ptr->no_input_qs;i++) {
+		qdio_unmark_q(irq_ptr->input_qs[i]);
+		tasklet_kill(&irq_ptr->input_qs[i]->tasklet);
+		if (qdio_wait_for_no_use_count(&irq_ptr->input_qs[i]->
+					       use_count))
+			result=-EINPROGRESS;
+	}
+
+	for (i=0;i<irq_ptr->no_output_qs;i++) {
+		tasklet_kill(&irq_ptr->output_qs[i]->tasklet);
+		if (qdio_wait_for_no_use_count(&irq_ptr->output_qs[i]->
+					       use_count))
+			result=-EINPROGRESS;
+	}
+
+	atomic_set(&irq_ptr->interrupt_has_been_cleaned,0);
+
+	/* cleanup subchannel */
+	my_s390irq_spin_lock_irqsave(irq,flags);
+	if (how&QDIO_FLAG_CLEANUP_USING_CLEAR) {
+		clear_IO(irq_ptr->irq,QDIO_DOING_CLEANUP,0);
+		timeout=QDIO_CLEANUP_CLEAR_TIMEOUT;
+	} else if (how&QDIO_FLAG_CLEANUP_USING_HALT) {
+		halt_IO(irq_ptr->irq,QDIO_DOING_CLEANUP,0);
+		timeout=QDIO_CLEANUP_HALT_TIMEOUT;
+	} else { /* default behaviour */
+		halt_IO(irq_ptr->irq,QDIO_DOING_CLEANUP,0);
+		timeout=QDIO_CLEANUP_HALT_TIMEOUT;
+	}
+	my_s390irq_spin_unlock_irqrestore(irq,flags);
+
+	if (qdio_sleepon(&irq_ptr->interrupt_has_been_cleaned,
+			 timeout,irq_ptr)==-ETIME) {
+		my_s390irq_spin_lock_irqsave(irq,flags);
+		QDIO_PRINT_INFO("Did not get interrupt on %s_IO, " \
+				"irq=0x%x.\n",
+				(how==QDIO_FLAG_CLEANUP_USING_CLEAR)?
+				"clear":"halt",irq);
+		do_an_irqrestore=1;
+	}
+
+	if (irq_ptr->is_iqdio_irq) {
+		qdio_put_indicator((__u32*)irq_ptr->dev_st_chg_ind);
+		iqdio_set_subchannel_ind(irq_ptr,1); /* reset adapter
+							interrupt indicators */
+	}
+
+	/* exchange int handlers, if necessary */
+	if ((void*)ioinfo[irq]->irq_desc.handler
+	    ==(void*)qdio_handler) {
+		ioinfo[irq]->irq_desc.handler=
+			irq_ptr->original_int_handler;
+/*		irq_ptr->original_int_handler=NULL; */
+	}
+
+	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+
+	if (do_an_irqrestore)
+		my_s390irq_spin_unlock_irqrestore(irq,flags);
+
+	my_spin_unlock(&irq_ptr->setting_up_lock);
+
+	qdio_remove_irq_ptr(irq_ptr);
+	qdio_release_irq_memory(irq_ptr);
+	return result;
+}
+
+static unsigned long qdio_get_characteristics(int irq)
+{
+	qdio_irq_t *irq_ptr;
+	int result=0;
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return -ENODEV;
+
+	if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE) {
+		return -EBUSY;
+	}
+
+	if (irq_ptr->state==QDIO_IRQ_STATE_INACTIVE) {
+		result|=QDIO_STATE_INACTIVE;
+	} else if (irq_ptr->state==QDIO_IRQ_STATE_ESTABLISHED) {
+		result|=QDIO_STATE_ESTABLISHED;
+	} else if (irq_ptr->state==QDIO_IRQ_STATE_ACTIVE) {
+		result|=QDIO_STATE_ACTIVE;
+	} else if (irq_ptr->state==QDIO_IRQ_STATE_STOPPED) {
+		result|=QDIO_STATE_STOPPED;
+	}
+
+	if (irq_ptr->hydra_gives_outbound_pcis)
+		result|=QDIO_STATE_MUST_USE_OUTB_PCI;
+
+	return result;
+}
+
+int qdio_initialize(qdio_initialize_t *init_data)
+{
+	int i,ciw_cnt;
+	unsigned long saveflags;
+	qdio_irq_t *irq_ptr=NULL;
+	int result,result2;
+	int found;
+	char dbf_text[20]; /* if a printf would print out more than 8 chars */
+
+	down_interruptible(&init_sema);
+
+	sprintf(dbf_text,"qini%4x",init_data->irq);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_TEXT0(0,trace,dbf_text);
+	sprintf(dbf_text,"qfmt:%x",init_data->q_format);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_TEXT0(0,setup,init_data->adapter_name);
+	QDIO_DBF_HEX0(0,setup,init_data->adapter_name,8);
+	sprintf(dbf_text,"qpff%4x",init_data->qib_param_field_format);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_HEX0(0,setup,&init_data->qib_param_field,sizeof(char*));
+	QDIO_DBF_HEX0(0,setup,&init_data->input_slib_elements,sizeof(long*));
+	QDIO_DBF_HEX0(0,setup,&init_data->output_slib_elements,sizeof(long*));
+	sprintf(dbf_text,"miit%4x",init_data->min_input_threshold);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	sprintf(dbf_text,"mait%4x",init_data->min_input_threshold);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	sprintf(dbf_text,"miot%4x",init_data->max_output_threshold);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	sprintf(dbf_text,"maot%4x",init_data->max_output_threshold);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	sprintf(dbf_text,"niq:%4x",init_data->no_input_qs);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	sprintf(dbf_text,"noq:%4x",init_data->no_output_qs);
+	QDIO_DBF_TEXT0(0,setup,dbf_text);
+	QDIO_DBF_HEX0(0,setup,&init_data->input_handler,sizeof(void*));
+	QDIO_DBF_HEX0(0,setup,&init_data->output_handler,sizeof(void*));
+	QDIO_DBF_HEX0(0,setup,&init_data->int_parm,sizeof(long));
+	QDIO_DBF_HEX0(0,setup,&init_data->flags,sizeof(long));
+	QDIO_DBF_HEX0(0,setup,&init_data->input_sbal_addr_array,sizeof(void*));
+	QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
+
+	/* sanity checks */
+	if (qdio_get_irq_ptr(init_data->irq)) {
+		result=-EBUSY;
+		goto out;
+	}
+
+	if (ioinfo[init_data->irq]==INVALID_STORAGE_AREA) {
+		result=-ENODEV;
+		goto out;
+	}
+
+	if (!ioinfo[init_data->irq]) {
+		QDIO_PRINT_WARN("ioinfo[%i] is NULL!\n",init_data->irq);
+		result=-ENODEV;
+		goto out;
+	}
+
+#define DEVSTAT_FLAG_IRQ_QDIO ~0UL
+	if (!(ioinfo[init_data->irq]->devstat.flag&DEVSTAT_FLAG_IRQ_QDIO)) {
+		QDIO_PRINT_WARN("ioinfo[%i]->devstat.flag=0x%08x\n",
+				init_data->irq,
+				ioinfo[init_data->irq]->devstat.flag);
+		result=-ENODEV;
+		goto out;
+	}
+
+	if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
+	     (init_data->no_output_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
+	     ((init_data->no_input_qs) && (!init_data->input_handler)) ||
+	     ((init_data->no_output_qs) && (!init_data->output_handler)) ) {
+		result=-EINVAL;
+		goto out;
+	}
+
+	if ( (init_data->flags&QDIO_INBOUND_0COPY_SBALS)&&
+	     (!init_data->input_sbal_addr_array) ) {
+		result=-EINVAL;
+		goto out;
+	}
+	if ( (init_data->flags&QDIO_OUTBOUND_0COPY_SBALS)&&
+	     (!init_data->output_sbal_addr_array) ) {
+		result=-EINVAL;
+		goto out;
+	}
+
+	/* create irq */
+	irq_ptr=kmalloc(sizeof(qdio_irq_t),GFP_DMA);
+
+	QDIO_DBF_TEXT0(0,setup,"irq_ptr:");
+	QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
+
+	if (!irq_ptr) {
+		QDIO_PRINT_ERR("kmalloc of irq_ptr failed!\n");
+		result=-ENOMEM;
+		goto out;
+	}
+
+	memset(irq_ptr,0,sizeof(qdio_irq_t)); /* wipes qib.ac,
+						 required by ar7063 */
+
+	irq_ptr->qdr=kmalloc(sizeof(qdr_t),GFP_DMA);
+  	if (!(irq_ptr->qdr)) {
+   		kfree(irq_ptr->qdr);
+   		kfree(irq_ptr);
+    		QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
+     		result=-ENOMEM;
+      		goto out;
+       	}
+	memset(irq_ptr->qdr,0,sizeof(qdr_t));
+	QDIO_DBF_TEXT0(0,setup,"qdr:");
+	QDIO_DBF_HEX0(0,setup,&irq_ptr->qdr,sizeof(void*));
+
+	init_waitqueue_head(&irq_ptr->wait_q);
+
+	irq_ptr->int_parm=init_data->int_parm;
+
+	irq_ptr->irq=init_data->irq;
+	irq_ptr->no_input_qs=init_data->no_input_qs;
+	irq_ptr->no_output_qs=init_data->no_output_qs;
+
+	irq_ptr->is_iqdio_irq=(init_data->q_format==QDIO_IQDIO_QFMT)?1:0;
+
+	if (irq_ptr->is_iqdio_irq) {
+		irq_ptr->dev_st_chg_ind=qdio_get_indicator();
+		QDIO_DBF_HEX1(0,setup,&irq_ptr->dev_st_chg_ind,sizeof(void*));
+		if (!irq_ptr->dev_st_chg_ind) {
+			QDIO_PRINT_WARN("no indicator location available " \
+					"for irq 0x%x\n",irq_ptr->irq);
+			qdio_release_irq_memory(irq_ptr);
+			result=-ENOBUFS;
+			goto out;
+		}
+	}
+
+	/* defaults */
+	irq_ptr->commands.eq=DEFAULT_ESTABLISH_QS_CMD;
+	irq_ptr->commands.count_eq=DEFAULT_ESTABLISH_QS_COUNT;
+	irq_ptr->commands.aq=DEFAULT_ACTIVATE_QS_CMD;
+	irq_ptr->commands.count_aq=DEFAULT_ACTIVATE_QS_COUNT;
+
+	if (!qdio_alloc_qs(irq_ptr,init_data->no_input_qs,
+			   init_data->no_output_qs,
+			   init_data->input_handler,
+			   init_data->output_handler,init_data->int_parm,
+			   init_data->q_format,init_data->flags,
+			   init_data->input_sbal_addr_array,
+			   init_data->output_sbal_addr_array)) {
+		qdio_release_irq_memory(irq_ptr);
+		result=-ENOMEM;
+		goto out;
+	}
+
+	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_INACTIVE);
+
+	irq_ptr->setting_up_lock=SPIN_LOCK_UNLOCKED;
+
+	MOD_INC_USE_COUNT;
+	QDIO_DBF_TEXT3(0,setup,"MOD_INC_");
+
+	my_spin_lock(&irq_ptr->setting_up_lock);
+
+	qdio_insert_irq_ptr(irq_ptr);
+
+	qdio_fill_thresholds(irq_ptr,init_data->no_input_qs,
+			     init_data->no_output_qs,
+			     init_data->min_input_threshold,
+			     init_data->max_input_threshold,
+			     init_data->min_output_threshold,
+			     init_data->max_output_threshold);
+
+	/* fill in qdr */
+	irq_ptr->qdr->qfmt=init_data->q_format;
+	irq_ptr->qdr->iqdcnt=init_data->no_input_qs;
+	irq_ptr->qdr->oqdcnt=init_data->no_output_qs;
+	irq_ptr->qdr->iqdsz=sizeof(qdesfmt0_t)/4; /* size in words */
+	irq_ptr->qdr->oqdsz=sizeof(qdesfmt0_t)/4;
+
+	irq_ptr->qdr->qiba=(unsigned long)&irq_ptr->qib;
+	irq_ptr->qdr->qkey=QDIO_STORAGE_KEY;
+
+	/* fill in qib */
+	irq_ptr->qib.qfmt=init_data->q_format;
+	if (init_data->no_input_qs) irq_ptr->qib.isliba=
+				 (unsigned long)(irq_ptr->input_qs[0]->slib);
+	if (init_data->no_output_qs) irq_ptr->qib.osliba=(unsigned long)
+				  (irq_ptr->output_qs[0]->slib);
+	memcpy(irq_ptr->qib.ebcnam,init_data->adapter_name,8);
+
+	qdio_set_impl_params(irq_ptr,init_data->qib_param_field_format,
+			     init_data->qib_param_field,
+			     init_data->no_input_qs,
+			     init_data->no_output_qs,
+			     init_data->input_slib_elements,
+			     init_data->output_slib_elements);
+
+	/* first input descriptors, then output descriptors */
+	for (i=0;i<init_data->no_input_qs;i++) {
+		irq_ptr->input_qs[i]->is_iqdio_q=
+			(init_data->q_format==QDIO_IQDIO_QFMT)?1:0;
+
+		irq_ptr->qdr->qdf0[i].sliba=
+			(unsigned long)(irq_ptr->input_qs[i]->slib);
+
+		irq_ptr->qdr->qdf0[i].sla=
+			(unsigned long)(irq_ptr->input_qs[i]->sl);
+
+		irq_ptr->qdr->qdf0[i].slsba=
+			(unsigned long)(&irq_ptr->input_qs[i]->
+					slsb.acc.val[0]);
+
+		irq_ptr->qdr->qdf0[i].akey=QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i].bkey=QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i].ckey=QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
+	}
+
+	for (i=0;i<init_data->no_output_qs;i++) {
+		irq_ptr->output_qs[i]->is_iqdio_q=
+			(init_data->q_format==QDIO_IQDIO_QFMT)?1:0;
+
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].sliba=
+			(unsigned long)(irq_ptr->output_qs[i]->slib);
+
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].sla=
+			(unsigned long)(irq_ptr->output_qs[i]->sl);
+
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].slsba=
+			(unsigned long)(&irq_ptr->output_qs[i]->
+					slsb.acc.val[0]);
+
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].akey=
+			QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].bkey=
+			QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].ckey=
+			QDIO_STORAGE_KEY;
+		irq_ptr->qdr->qdf0[i+init_data->no_input_qs].dkey=
+			QDIO_STORAGE_KEY;
+	}
+	/* qdr, qib, sls, slsbs, slibs, sbales filled. */
+
+	my_s390irq_spin_lock_irqsave(irq_ptr->irq,saveflags);
+	/* keep track of original int handler */
+	irq_ptr->original_int_handler=ioinfo[irq_ptr->irq]->irq_desc.handler;
+
+	/* insert qdio int handler */
+	ioinfo[irq_ptr->irq]->irq_desc.handler=(void*)qdio_handler;
+
+	my_s390irq_spin_unlock_irqrestore(irq_ptr->irq,saveflags);
+
+#define TAKEOVER_CIW(x) irq_ptr->commands.##x=ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].cmd; irq_ptr->commands.count_##x=ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].count
+	/* get qdio commands */
+	found=0;
+	for (ciw_cnt=0;ciw_cnt<MAX_CIWS;ciw_cnt++) {
+		switch (ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].ct) {
+		case CIW_TYPE_RCD: TAKEOVER_CIW(rcd); break;
+		case CIW_TYPE_SII: TAKEOVER_CIW(sii); break;
+		case CIW_TYPE_RNI: TAKEOVER_CIW(rni); break;
+		case CIW_TYPE_EQUEUE: TAKEOVER_CIW(eq); found++; break;
+		case CIW_TYPE_AQUEUE: TAKEOVER_CIW(aq); found++; break;
+		}
+		if ( (ciw_cnt>0) &&
+		     (ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].ct==0) &&
+		     (ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].cmd==0) &&
+		     (ioinfo[irq_ptr->irq]->senseid.ciw[ciw_cnt].count) )
+			break;
+	}
+	if (found<2) {
+		QDIO_DBF_TEXT2(1,setup,"no ciws");
+		QDIO_PRINT_INFO("No CIWs found for QDIO commands. Trying to " \
+				"use defaults.\n");
+	}
+
+	/* the iqdio CHSC stuff */
+	if (irq_ptr->is_iqdio_irq) {
+/*		iqdio_enable_adapter_int_facility(irq_ptr);*/
+
+		if (iqdio_check_chsc_availability()) {
+			QDIO_PRINT_ERR("Not all CHSCs supported. " \
+				       "Continuing.\n");
+		}
+		result=iqdio_set_subchannel_ind(irq_ptr,0);
+		if (result) {
+			my_spin_unlock(&irq_ptr->setting_up_lock);
+			qdio_cleanup(irq_ptr->irq,
+				     QDIO_FLAG_CLEANUP_USING_CLEAR);
+			goto out2;
+		}
+		iqdio_set_delay_target(irq_ptr,IQDIO_DELAY_TARGET);
+	}
+
+	/* establish q */
+	irq_ptr->ccw.cmd_code=irq_ptr->commands.eq;
+	irq_ptr->ccw.flags=CCW_FLAG_SLI;
+	irq_ptr->ccw.count=irq_ptr->commands.count_eq;
+	irq_ptr->ccw.cda=QDIO_GET_ADDR(irq_ptr->qdr);
+
+	my_s390irq_spin_lock_irqsave(irq_ptr->irq,saveflags);
+	atomic_set(&irq_ptr->interrupt_has_arrived,0);
+
+	result=do_IO(irq_ptr->irq,&irq_ptr->ccw,QDIO_DOING_ESTABLISH,0,0);
+	if (result) {
+		result2=do_IO(irq_ptr->irq,&irq_ptr->ccw,
+			      QDIO_DOING_ESTABLISH,0,0);
+		sprintf(dbf_text,"eq:io%4x",result);
+		QDIO_DBF_TEXT2(1,setup,dbf_text);
+		if (result2) {
+			sprintf(dbf_text,"eq:io%4x",result);
+			QDIO_DBF_TEXT2(1,setup,dbf_text);
+		}
+		QDIO_PRINT_WARN("establish queues on irq %04x: do_IO " \
+                           "returned %i, next try returned %i\n",
+                           irq_ptr->irq,result,result2);
+		result=result2;
+	}
+
+	my_s390irq_spin_unlock_irqrestore(irq_ptr->irq,saveflags);
+
+	if (result) {
+		my_spin_unlock(&irq_ptr->setting_up_lock);
+		qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR);
+		goto out2;
+	}
+
+	result=qdio_sleepon(&irq_ptr->interrupt_has_arrived,
+			    QDIO_ESTABLISH_TIMEOUT,irq_ptr);
+
+	if (result) {
+		QDIO_PRINT_ERR("establish queues on irq %04x: timed out\n",
+			   irq_ptr->irq);
+		QDIO_DBF_TEXT2(1,setup,"eq:timeo");
+		my_spin_unlock(&irq_ptr->setting_up_lock);
+		qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR);
+		goto out2;
+	}
+
+	if (!(irq_ptr->io_result_dstat & DEV_STAT_DEV_END)) {
+		QDIO_DBF_TEXT2(1,setup,"eq:no de");
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_dstat,
+			      sizeof(irq_ptr->io_result_dstat));
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_cstat,
+			      sizeof(irq_ptr->io_result_cstat));
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_flags,
+			      sizeof(irq_ptr->io_result_flags));
+		QDIO_PRINT_ERR("establish queues on irq %04x: didn't get " \
+			       "device end: dstat=%02x, cstat=%02x, " \
+			       "flags=%02x\n",
+			       irq_ptr->irq,irq_ptr->io_result_dstat,
+			       irq_ptr->io_result_cstat,
+			       irq_ptr->io_result_flags);
+		my_spin_unlock(&irq_ptr->setting_up_lock);
+		qdio_cleanup(irq_ptr->irq,QDIO_FLAG_CLEANUP_USING_CLEAR);
+		result=-EIO;
+		goto out2;
+	}
+
+	if (irq_ptr->io_result_dstat & ~(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) {
+		QDIO_DBF_TEXT2(1,setup,"eq:badio");
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_dstat,
+			      sizeof(irq_ptr->io_result_dstat));
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_cstat,
+			      sizeof(irq_ptr->io_result_cstat));
+		QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_flags,
+			      sizeof(irq_ptr->io_result_flags));
+		QDIO_PRINT_ERR("establish queues on irq %04x: got " \
+			       "the following devstat: dstat=%02x, " \
+			       "cstat=%02x, flags=%02x\n",
+			       irq_ptr->irq,irq_ptr->io_result_dstat,
+			       irq_ptr->io_result_cstat,
+			       irq_ptr->io_result_flags);
+		result=-EIO;
+		goto out;
+	}
+
+	if (MACHINE_IS_VM)
+		irq_ptr->qdioac=qdio_check_siga_needs(irq_ptr->irq);
+	else { 
+                irq_ptr->qdioac=CHSC_FLAG_SIGA_INPUT_NECESSARY
+                        | CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
+        }
+	sprintf(dbf_text,"qdioac%2x",irq_ptr->qdioac);
+	QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+	sprintf(dbf_text,"qib ac%2x",irq_ptr->qib.ac);
+	QDIO_DBF_TEXT2(0,setup,dbf_text);
+
+	if (init_data->flags&QDIO_USE_OUTBOUND_PCIS) {
+		irq_ptr->hydra_gives_outbound_pcis=
+			irq_ptr->qib.ac&QIB_AC_OUTBOUND_PCI_SUPPORTED;
+	} else {
+		irq_ptr->hydra_gives_outbound_pcis=0;
+	}
+	irq_ptr->sync_done_on_outb_pcis=
+		irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS;
+
+	for (i=0;i<init_data->no_input_qs;i++) {
+		irq_ptr->input_qs[i]->siga_sync=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY;
+		irq_ptr->input_qs[i]->siga_in=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_INPUT_NECESSARY;
+		irq_ptr->input_qs[i]->siga_out=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
+		irq_ptr->input_qs[i]->siga_sync_done_on_thinints=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS;
+		irq_ptr->input_qs[i]->hydra_gives_outbound_pcis=
+			irq_ptr->hydra_gives_outbound_pcis;
+	}
+
+	for (i=0;i<init_data->no_output_qs;i++) {
+		irq_ptr->output_qs[i]->siga_sync=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_NECESSARY;
+		irq_ptr->output_qs[i]->siga_in=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_INPUT_NECESSARY;
+		irq_ptr->output_qs[i]->siga_out=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_OUTPUT_NECESSARY;
+		irq_ptr->output_qs[i]->siga_sync_done_on_thinints=
+			irq_ptr->qdioac&CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS;
+		irq_ptr->output_qs[i]->hydra_gives_outbound_pcis=
+			irq_ptr->hydra_gives_outbound_pcis;
+	}
+
+	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED);
+
+ out:
+	if (irq_ptr) {
+		my_spin_unlock(&irq_ptr->setting_up_lock);
+	}
+ out2:
+	up(&init_sema);
+
+	return result;
+}
+
+int qdio_activate(int irq,int flags)
+{
+	qdio_irq_t *irq_ptr;
+	int i,result=0,result2;
+	unsigned long saveflags;
+	char dbf_text[20]; /* see qdio_initialize */
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return -ENODEV;
+
+	my_spin_lock(&irq_ptr->setting_up_lock);
+	if (irq_ptr->state==QDIO_IRQ_STATE_INACTIVE) {
+		result=-EBUSY;
+		goto out;
+	}
+
+	sprintf(dbf_text,"qact%4x",irq);
+	QDIO_DBF_TEXT2(0,setup,dbf_text);
+	QDIO_DBF_TEXT2(0,trace,dbf_text);
+
+	/* activate q */
+	irq_ptr->ccw.cmd_code=irq_ptr->commands.aq;
+	irq_ptr->ccw.flags=CCW_FLAG_SLI;
+	irq_ptr->ccw.count=irq_ptr->commands.count_aq;
+	irq_ptr->ccw.cda=QDIO_GET_ADDR(0);
+
+	my_s390irq_spin_lock_irqsave(irq_ptr->irq,saveflags);
+	atomic_set(&irq_ptr->interrupt_has_arrived,0);
+
+	result=do_IO(irq_ptr->irq,&irq_ptr->ccw,QDIO_DOING_ACTIVATE,
+		     0,DOIO_REPORT_ALL|DOIO_DENY_PREFETCH);
+	if (result) {
+		result2=do_IO(irq_ptr->irq,&irq_ptr->ccw,
+			      QDIO_DOING_ACTIVATE,0,DOIO_REPORT_ALL);
+		sprintf(dbf_text,"aq:io%4x",result);
+		QDIO_DBF_TEXT2(1,setup,dbf_text);
+		if (result2) {
+			sprintf(dbf_text,"aq:io%4x",result);
+			QDIO_DBF_TEXT2(1,setup,dbf_text);
+		}
+		QDIO_PRINT_WARN("activate queues on irq %04x: do_IO " \
+                           "returned %i, next try returned %i\n",
+                           irq_ptr->irq,result,result2);
+		result=result2;
+	}
+
+	my_s390irq_spin_unlock_irqrestore(irq_ptr->irq,saveflags);
+	if (result) {
+		goto out;
+	}
+
+	if (!(flags&QDIO_FLAG_UNDER_INTERRUPT)) {
+		result=qdio_sleepon(&irq_ptr->interrupt_has_arrived,
+				    QDIO_ACTIVATE_TIMEOUT,irq_ptr);
+
+		if (result!=-ETIME) {
+			QDIO_DBF_TEXT2(1,setup,"aq:badio");
+			QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_dstat,
+				      sizeof(irq_ptr->io_result_dstat));
+			QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_cstat,
+				      sizeof(irq_ptr->io_result_cstat));
+			QDIO_DBF_HEX2(0,setup,&irq_ptr->io_result_flags,
+				      sizeof(irq_ptr->io_result_flags));
+			QDIO_PRINT_ERR("activate queues on irq %04x: got " \
+				       "the following devstat: dstat=%02x, " \
+				       "cstat=%02x, flags=%02x\n",
+				       irq_ptr->irq,irq_ptr->io_result_dstat,
+				       irq_ptr->io_result_cstat,
+				       irq_ptr->io_result_flags);
+			result=-EIO;
+			goto out;
+		} else { /* result is -ETIME, but timeout is ok for us */
+			result=0;
+		}
+	} else result=0;
+
+	for (i=0;i<irq_ptr->no_input_qs;i++) {
+		if (irq_ptr->is_iqdio_irq) {
+			/* that way we know, that, if we will
+			 * get interrupted
+			 * by iqdio_inbound_processing,
+			 * qdio_unmark_q will
+			 * not be called */
+			qdio_reserve_q(irq_ptr->input_qs[i]);
+			qdio_mark_iq(irq_ptr->input_qs[i]);
+			qdio_release_q(irq_ptr->input_qs[i]);
+		}
+	}
+
+	if (flags&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT) {
+		for (i=0;i<irq_ptr->no_input_qs;i++) {
+			irq_ptr->input_qs[i]->is_input_q|=
+				QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT;
+		}
+	}
+
+	qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ACTIVE);
+
+ out:
+	my_spin_unlock(&irq_ptr->setting_up_lock);
+
+	return result;
+}
+
+/* buffers filled forwards again to make Rick happy */
+static void qdio_do_qdio_fill_input(qdio_q_t *q,unsigned int qidx,
+				    unsigned int count,qdio_buffer_t *buffers)
+{
+	for (;;) {
+		if (!q->is_0copy_sbals_q) {
+			memcpy((void*)q->sbal[qidx],buffers,SBAL_SIZE);
+			q->qdio_buffers[qidx]=buffers;
+			buffers++;
+		}
+		set_slsb(&q->slsb.acc.val[qidx],SLSB_CU_INPUT_EMPTY);
+		count--;
+		if (!count) break;
+		qidx=(qidx+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+	}
+
+	/* not necessary, as the queues are synced during the SIGA read
+	SYNC_MEMORY;*/
+}
+
+static inline void qdio_do_qdio_fill_output(qdio_q_t *q,unsigned int qidx,
+					    unsigned int count,
+					    qdio_buffer_t *buffers)
+{
+	for (;;) {
+		if (!q->is_0copy_sbals_q) {
+			memcpy((void*)q->sbal[qidx],buffers,SBAL_SIZE);
+			q->qdio_buffers[qidx]=buffers;
+			buffers++;
+		}
+		set_slsb(&q->slsb.acc.val[qidx],SLSB_CU_OUTPUT_PRIMED);
+		count--;
+		if (!count) break;
+		qidx=(qidx+1)&(QDIO_MAX_BUFFERS_PER_Q-1);
+	}
+
+	/* SIGA write will sync the queues
+	SYNC_MEMORY;*/
+}
+
+/* count must be 1 in iqdio */
+int do_QDIO(int irq,unsigned int callflags,unsigned int queue_number,
+	    unsigned int qidx,unsigned int count,qdio_buffer_t *buffers)
+{
+	qdio_q_t *q;
+	qdio_irq_t *irq_ptr;
+	int result;
+	int used_elements;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	char dbf_text[20];
+
+	sprintf(dbf_text,"doQD%04x",irq);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if ( (qidx>QDIO_MAX_BUFFERS_PER_Q) ||
+	     (count>QDIO_MAX_BUFFERS_PER_Q) ||
+	     (queue_number>QDIO_MAX_QUEUES_PER_IRQ) )
+		return -EINVAL;
+
+	if (count==0) return 0;
+
+	irq_ptr=qdio_get_irq_ptr(irq);
+	if (!irq_ptr) return -ENODEV;
+
+#ifdef QDIO_DBF_LIKE_HELL
+	if (callflags&QDIO_FLAG_SYNC_INPUT)
+		QDIO_DBF_HEX3(0,trace,&irq_ptr->input_qs[queue_number],
+			      sizeof(void*));
+	else
+		QDIO_DBF_HEX3(0,trace,&irq_ptr->output_qs[queue_number],
+			      sizeof(void*));
+	sprintf(dbf_text,"flag%04x",callflags);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+	sprintf(dbf_text,"qi%02xct%02x",qidx,count);
+	QDIO_DBF_TEXT3(0,trace,dbf_text);
+	if ( ((callflags&QDIO_FLAG_SYNC_INPUT)&&
+	      (!irq_ptr->input_qs[queue_number]->is_0copy_sbals_q)) ||
+	     ((callflags&QDIO_FLAG_SYNC_OUTPUT)&&
+	      (!irq_ptr->output_qs[queue_number]->is_0copy_sbals_q)) )
+		QDIO_DBF_HEX5(0,sbal,buffers,256);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+	if (irq_ptr->state!=QDIO_IRQ_STATE_ACTIVE) {
+		return -EBUSY;
+	}
+
+	if (callflags&QDIO_FLAG_SYNC_INPUT) {
+		/* This is the inbound handling of queues */
+		q=irq_ptr->input_qs[queue_number];
+
+		used_elements=atomic_return_add(count,
+						&q->number_of_buffers_used);
+
+		qdio_do_qdio_fill_input(q,qidx,count,buffers);
+
+		if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&&
+		    (callflags&QDIO_FLAG_UNDER_INTERRUPT))
+			atomic_swap(&q->polling,0);
+
+		if (!used_elements) if (!(callflags&QDIO_FLAG_DONT_SIGA)) {
+			if (q->siga_in) {
+				result=qdio_siga_input(q);
+				if (result) {
+					if (q->siga_error)
+						q->error_status_flags|=
+							QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR;
+					q->error_status_flags|=
+						QDIO_STATUS_LOOK_FOR_ERROR;
+					q->siga_error=result;
+				}
+			}
+
+			qdio_mark_q(q);
+		}
+	} else if (callflags&QDIO_FLAG_SYNC_OUTPUT) {
+		/* This is the outbound handling of queues */
+#ifdef QDIO_PERFORMANCE_STATS
+		perf_stats.start_time_outbound=NOW;
+#endif /* QDIO_PERFORMANCE_STATS */
+		q=irq_ptr->output_qs[queue_number];
+
+		qdio_do_qdio_fill_output(q,qidx,count,buffers);
+
+		used_elements=atomic_return_add(count,
+						&q->number_of_buffers_used);
+
+		if (!(callflags&QDIO_FLAG_DONT_SIGA)) {
+			if (q->is_iqdio_q) {
+				/* one siga for every sbal */
+				while (count--) {
+					qdio_kick_outbound_q(q);
+				}
+
+				qdio_outbound_processing(q);
+			} else {
+				/* under VM, we do a SIGA sync
+				 * unconditionally */
+				SYNC_MEMORY;
+				else {
+					/* w/o shadow queues (else branch of
+					 * SYNC_MEMORY :-/ ), we try to
+					 * fast-requeue buffers */
+					if (q->slsb.acc.val
+					    [(qidx+QDIO_MAX_BUFFERS_PER_Q-1)
+					    &(QDIO_MAX_BUFFERS_PER_Q-1)]!=
+					    SLSB_CU_OUTPUT_PRIMED) {
+						qdio_kick_outbound_q(q);
+					} else {
+#ifdef QDIO_DBF_LIKE_HELL
+						QDIO_DBF_TEXT3(0,trace,
+							       "fast-req");
+#endif /* QDIO_DBF_LIKE_HELL */
+#ifdef QDIO_PERFORMANCE_STATS
+						perf_stats.fast_reqs++;
+#endif /* QDIO_PERFORMANCE_STATS */
+					}
+				}
+				/* only marking the q could take
+				 * too long, the upper layer
+				 * module could do a lot of
+				 * traffic in that time */
+				qdio_outbound_processing(q);
+			}
+		}
+
+#ifdef QDIO_PERFORMANCE_STATS
+		perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+		perf_stats.outbound_cnt++;
+#endif /* QDIO_PERFORMANCE_STATS */
+	} else {
+		QDIO_DBF_TEXT3(1,trace,"doQD:inv");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_perf_procfile_read(char *buffer,char **buffer_location,
+       				   off_t offset,int buffer_length,int *eof,
+				   void *data)
+{
+        int c=0;
+	qdio_irq_t *irq_ptr;
+
+        /* we are always called with buffer_length=4k, so we all
+           deliver on the first read */
+        if (offset>0) return 0;
+
+	/* FIXME: wtf are you trying to do? this is guaranteed to
+	 * fail, you even get a compiler warning! */
+	irq_ptr=first_irq;
+
+#define _OUTP_IT(x...) c+=sprintf(buffer+c,x)
+	_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
+	_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
+	_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
+	_OUTP_IT("Number of tasklet runs (total)                  : %u\n",
+		 perf_stats.tl_runs);
+	_OUTP_IT("\n");
+	_OUTP_IT("Number of SIGA sync's issued                    : %u\n",
+		 perf_stats.siga_syncs);
+	_OUTP_IT("Number of SIGA in's issued                      : %u\n",
+		 perf_stats.siga_ins);
+	_OUTP_IT("Number of SIGA out's issued                     : %u\n",
+		 perf_stats.siga_outs);
+	_OUTP_IT("Number of PCI's caught                          : %u\n",
+		 perf_stats.pcis);
+	_OUTP_IT("Number of adapter interrupts caught             : %u\n",
+		 perf_stats.thinints);
+	_OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA)  : %u\n",
+		 perf_stats.fast_reqs);
+	_OUTP_IT("\n");
+	_OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
+		 perf_stats.inbound_time);
+	_OUTP_IT("Number of inbound transfers                     : %u\n",
+		 perf_stats.inbound_cnt);
+	_OUTP_IT("Total time of all outbound do_QDIOs (us)        : %u\n",
+		 perf_stats.outbound_time);
+	_OUTP_IT("Number of do_QDIOs outbound                     : %u\n",
+		 perf_stats.outbound_cnt);
+	_OUTP_IT("\n");
+	while (irq_ptr) {
+		_OUTP_IT("Polling time on irq %4x                        " \
+			 ": %u\n",
+			 irq_ptr->irq,irq_ptr->input_qs[0]->timing.threshold);
+		irq_ptr=irq_ptr->next;
+	}
+
+        return c;
+}
+
+static struct proc_dir_entry *qdio_perf_proc_file;
+#endif /* QDIO_PERFORMANCE_STATS */
+
+static void qdio_add_procfs_entry(void)
+{
+#ifdef QDIO_PERFORMANCE_STATS
+        proc_perf_file_registration=0;
+	qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
+					      S_IFREG|0444,&proc_root);
+	if (qdio_perf_proc_file) {
+		qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read;
+	} else proc_perf_file_registration=-1;
+
+        if (proc_perf_file_registration)
+                QDIO_PRINT_WARN("was not able to register perf. " \
+				"proc-file (%i).\n",
+				proc_perf_file_registration);
+#endif /* QDIO_PERFORMANCE_STATS */
+}
+#ifdef MODULE
+static void qdio_remove_procfs_entry(void)
+{
+#ifdef QDIO_PERFORMANCE_STATS
+	perf_stats.tl_runs=0;
+
+        if (!proc_perf_file_registration) /* means if it went ok earlier */
+		remove_proc_entry(QDIO_PERF,&proc_root);
+#endif /* QDIO_PERFORMANCE_STATS */
+}
+#endif /* MODULE */
+
+static void iqdio_register_thinints(void)
+{
+	char dbf_text[20];
+	register_thinint_result=
+		s390_register_adapter_interrupt(&iqdio_thinint_handler);
+	if (register_thinint_result) {
+		sprintf(dbf_text,"regthn%x",(register_thinint_result&0xff));
+		QDIO_DBF_TEXT0(0,setup,dbf_text);
+		QDIO_PRINT_ERR("failed to register adapter handler " \
+			       "(rc=%i).\nAdapter interrupts might " \
+			       "not work. Continuing.\n",
+			       register_thinint_result);
+	}
+}
+
+#ifdef MODULE
+static void iqdio_unregister_thinints(void)
+{
+	if (!register_thinint_result)
+		s390_unregister_adapter_interrupt(&iqdio_thinint_handler);
+}
+#endif /* MODULE */
+
+static int qdio_get_qdio_memory(void)
+{
+	int i;
+	indicator_used[0]=1;
+
+	for (i=1;i<INDICATORS_PER_CACHELINE;i++)
+		indicator_used[i]=0;
+	indicators=(__u32*)kmalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
+				   GFP_KERNEL);
+       	if (!indicators) return -ENOMEM;
+	memset(indicators,0,sizeof(__u32)*(INDICATORS_PER_CACHELINE));
+
+	chsc_area=(qdio_chsc_area_t *)
+		kmalloc(sizeof(qdio_chsc_area_t),GFP_KERNEL);
+	QDIO_DBF_TEXT3(0,trace,"chscarea"); \
+	QDIO_DBF_HEX3(0,trace,&chsc_area,sizeof(void*)); \
+	if (!chsc_area) {
+		/* ahem... let's call it data area */
+		QDIO_PRINT_ERR("not enough memory for data area. Cannot " \
+			       "initialize QDIO.\n");
+		kfree(indicators);
+		return -ENOMEM;
+	}
+	memset(chsc_area,0,sizeof(qdio_chsc_area_t));
+	return 0;
+}
+
+#ifdef MODULE
+static void qdio_release_qdio_memory(void)
+{
+	kfree(chsc_area);
+	if (indicators) kfree(indicators);
+}
+#endif /* MODULE */
+
+int init_module(void); /* we want to use it in init_QDIO */
+
+static void qdio_unregister_dbf_views(void)
+{
+	if (qdio_dbf_setup)
+		debug_unregister(qdio_dbf_setup);
+	if (qdio_dbf_sbal)
+		debug_unregister(qdio_dbf_sbal);
+	if (qdio_dbf_sense)
+		debug_unregister(qdio_dbf_sense);
+	if (qdio_dbf_trace)
+		debug_unregister(qdio_dbf_trace);
+#ifdef QDIO_DBF_LIKE_HELL
+        if (qdio_dbf_slsb_out)
+                debug_unregister(qdio_dbf_slsb_out);
+        if (qdio_dbf_slsb_in)
+                debug_unregister(qdio_dbf_slsb_in);
+#endif /* QDIO_DBF_LIKE_HELL */
+}
+
+/* this is not __initfunc, as it is called from init_module */
+static int __init init_QDIO(void)
+{
+	int res;
+#if defined(MODULE)||defined(QDIO_PERFORMANCE_STATS)
+	void *ptr;
+#endif /* defined(MODULE)||defined(QDIO_PERFORMANCE_STATS) */
+
+	qdio_eyecatcher();
+
+	printk("qdio: loading %s\n",version);
+
+	res=qdio_get_qdio_memory();
+	if (res) return res;
+
+	sema_init(&init_sema,1);
+
+	qdio_dbf_setup=debug_register(QDIO_DBF_SETUP_NAME,
+				      QDIO_DBF_SETUP_INDEX,
+				      QDIO_DBF_SETUP_NR_AREAS,
+				      QDIO_DBF_SETUP_LEN);
+	if (!qdio_dbf_setup) goto oom;
+	debug_register_view(qdio_dbf_setup,&debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_setup,QDIO_DBF_SETUP_LEVEL);
+
+	qdio_dbf_sbal=debug_register(QDIO_DBF_SBAL_NAME,
+				     QDIO_DBF_SBAL_INDEX,
+				     QDIO_DBF_SBAL_NR_AREAS,
+				     QDIO_DBF_SBAL_LEN);
+	if (!qdio_dbf_sbal) goto oom;
+
+	debug_register_view(qdio_dbf_sbal,&debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_sbal,QDIO_DBF_SBAL_LEVEL);
+
+	qdio_dbf_sense=debug_register(QDIO_DBF_SENSE_NAME,
+				      QDIO_DBF_SENSE_INDEX,
+				      QDIO_DBF_SENSE_NR_AREAS,
+				      QDIO_DBF_SENSE_LEN);
+	if (!qdio_dbf_sense) goto oom;
+
+	debug_register_view(qdio_dbf_sense,&debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_sense,QDIO_DBF_SENSE_LEVEL);
+
+	qdio_dbf_trace=debug_register(QDIO_DBF_TRACE_NAME,
+				      QDIO_DBF_TRACE_INDEX,
+				      QDIO_DBF_TRACE_NR_AREAS,
+				      QDIO_DBF_TRACE_LEN);
+	if (!qdio_dbf_trace) goto oom;
+
+	debug_register_view(qdio_dbf_trace,&debug_hex_ascii_view);
+	debug_set_level(qdio_dbf_trace,QDIO_DBF_TRACE_LEVEL);
+
+#ifdef QDIO_DBF_LIKE_HELL
+        qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME,
+                                         QDIO_DBF_SLSB_OUT_INDEX,
+                                         QDIO_DBF_SLSB_OUT_NR_AREAS,
+                                         QDIO_DBF_SLSB_OUT_LEN);
+        if (!qdio_dbf_slsb_out) goto oom;
+        debug_register_view(qdio_dbf_slsb_out,&debug_hex_ascii_view);
+        debug_set_level(qdio_dbf_slsb_out,QDIO_DBF_SLSB_OUT_LEVEL);
+
+        qdio_dbf_slsb_in=debug_register(QDIO_DBF_SLSB_IN_NAME,
+                                        QDIO_DBF_SLSB_IN_INDEX,
+                                        QDIO_DBF_SLSB_IN_NR_AREAS,
+                                        QDIO_DBF_SLSB_IN_LEN);
+        if (!qdio_dbf_slsb_in) goto oom;
+        debug_register_view(qdio_dbf_slsb_in,&debug_hex_ascii_view);
+        debug_set_level(qdio_dbf_slsb_in,QDIO_DBF_SLSB_IN_LEVEL);
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_PERFORMANCE_STATS
+       	memset((void*)&perf_stats,0,sizeof(perf_stats));
+	QDIO_DBF_TEXT0(0,setup,"perfstat");
+	ptr=&perf_stats;
+	QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
+#endif /* QDIO_PERFORMANCE_STATS */
+
+#ifdef MODULE
+	QDIO_DBF_TEXT0(0,setup,"initmodl");
+	ptr=&init_module;
+	QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
+#endif /* MODULE */
+
+	qdio_add_procfs_entry();
+
+	iqdio_register_thinints();
+
+	return 0;
+ oom:
+	QDIO_PRINT_ERR("not enough memory for dbf.\n");
+	qdio_unregister_dbf_views();
+	return -ENOMEM;
+}
+
+#ifdef MODULE
+int init_module(void)
+{
+	return init_QDIO();
+}
+
+void cleanup_module(void)
+{
+	iqdio_unregister_thinints();
+
+	qdio_remove_procfs_entry();
+
+	qdio_release_qdio_memory();
+
+	qdio_unregister_dbf_views();
+
+  	printk("qdio: %s: module removed\n",version);
+}
+#else /* MODULE */
+static int __init initcall_QDIO(void)
+{
+	        return init_QDIO();
+}
+__initcall(initcall_QDIO);
+#endif /* MODULE */
+
+EXPORT_SYMBOL(qdio_initialize);
+EXPORT_SYMBOL(qdio_activate);
+EXPORT_SYMBOL(do_QDIO);
+EXPORT_SYMBOL(qdio_cleanup);
+EXPORT_SYMBOL(qdio_eyecatcher);
+EXPORT_SYMBOL(qdio_synchronize);
diff -Nru a/drivers/s390/s390dyn.c b/drivers/s390/s390dyn.c
--- a/drivers/s390/s390dyn.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/s390/s390dyn.c	Sat Jun  8 22:31:51 2002
@@ -1,5 +1,5 @@
 /*
- *  arch/s390/kernel/s390dyn.c
+ *  drivers/s390/s390dyn.c
  *   S/390 dynamic device attachment
  *
  *  S390 version
@@ -10,145 +10,151 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/smp_lock.h>
+#include <linux/errno.h>
 
 #include <asm/irq.h>
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 
 static struct list_head devreg_anchor = LIST_HEAD_INIT(devreg_anchor);
-static spinlock_t  dyn_lock           = SPIN_LOCK_UNLOCKED;
+static spinlock_t dyn_lock = SPIN_LOCK_UNLOCKED;
 
-static inline int s390_device_register_internal(devreg_t *drinfo)
+static inline int
+s390_device_register_internal(devreg_t * drinfo)
 {
 	struct list_head *p;
 
-        list_for_each(p, &devreg_anchor) {
-                devreg_t *pdevreg = list_entry(p, devreg_t, list);
-                
-                if (pdevreg == drinfo)
-                        return -EINVAL;
-                /*
-                 * We don't allow multiple drivers to register
-                 * for the same device number
-                 */
-                if (pdevreg->ci.devno == drinfo->ci.devno &&
-                    (pdevreg->flag & DEVREG_TYPE_DEVNO) &&
-                    (drinfo->flag & DEVREG_TYPE_DEVNO))
+	list_for_each(p, &devreg_anchor) {
+		devreg_t *pdevreg = list_entry(p, devreg_t, list);
+
+		if (pdevreg == drinfo)
+			return -EINVAL;
+		/*
+		 * We don't allow multiple drivers to register
+		 * for the same device number
+		 */
+		if (pdevreg->ci.devno == drinfo->ci.devno &&
+		    (pdevreg->flag & DEVREG_TYPE_DEVNO) &&
+		    (drinfo->flag & DEVREG_TYPE_DEVNO))
 			return -EBUSY;
 
-                if (drinfo->flag == (DEVREG_TYPE_DEVCHARS | 
+		if (drinfo->flag == (DEVREG_TYPE_DEVCHARS |
 				     DEVREG_EXACT_MATCH) &&
-                    !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc,
-		            sizeof(devreg_hc_t))) 
+		    !memcmp(&drinfo->ci.hc, &pdevreg->ci.hc,
+			    sizeof (devreg_hc_t)))
 			return -EBUSY;
-        }
+	}
+
+	/*
+	 * no collision found, enqueue
+	 */
+	list_add(&drinfo->list, &devreg_anchor);
 
-        /*
-         * no collision found, enqueue
-         */
-        list_add (&drinfo->list, &devreg_anchor);
-	
 	return 0;
 }
 
-int s390_device_register( devreg_t *drinfo )
+int
+s390_device_register(devreg_t * drinfo)
 {
 	unsigned long flags;
 	int ret;
 
 	if (drinfo == NULL ||
-            !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS)))
+	    !(drinfo->flag & (DEVREG_TYPE_DEVNO | DEVREG_TYPE_DEVCHARS)))
 		return -EINVAL;
 
-	spin_lock_irqsave (&dyn_lock, flags); 	
+	spin_lock_irqsave(&dyn_lock, flags);
 	ret = s390_device_register_internal(drinfo);
-	spin_unlock_irqrestore( &dyn_lock, flags ); 	
- 	
+	spin_unlock_irqrestore(&dyn_lock, flags);
+
 	return ret;
 }
 
-static inline int s390_device_unregister_internal(devreg_t *dreg)
+static inline int
+s390_device_unregister_internal(devreg_t * dreg)
 {
 	struct list_head *p;
 
-        list_for_each(p, &devreg_anchor) {
-                devreg_t *pdevreg = list_entry(p, devreg_t, list);
+	list_for_each(p, &devreg_anchor) {
+		devreg_t *pdevreg = list_entry(p, devreg_t, list);
 
 		if (pdevreg == dreg) {
-			list_del (&dreg->list);
+			list_del(&dreg->list);
 			return 0;
 		}
-        }
+	}
 	return -EINVAL;
 }
 
-int s390_device_unregister(devreg_t *dreg)
+int
+s390_device_unregister(devreg_t * dreg)
 {
-	unsigned long  flags;
+	unsigned long flags;
 	int ret;
 
 	if (dreg == NULL)
 		return -EINVAL;
 
-	spin_lock_irqsave(&dyn_lock, flags); 	
+	spin_lock_irqsave(&dyn_lock, flags);
 	ret = s390_device_unregister_internal(dreg);
-	spin_unlock_irqrestore(&dyn_lock, flags); 	
- 	
+	spin_unlock_irqrestore(&dyn_lock, flags);
+
 	return ret;
 }
 
-static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo)
+static inline devreg_t *
+s390_search_devreg_internal(ioinfo_t * ioinfo)
 {
 	struct list_head *p;
-	
-        list_for_each(p, &devreg_anchor) {
-                devreg_t *pdevreg = list_entry(p, devreg_t, list);
+
+	list_for_each(p, &devreg_anchor) {
+		devreg_t *pdevreg = list_entry(p, devreg_t, list);
 		senseid_t *sid;
 		int flag;
 
 		flag = pdevreg->flag;
 		sid = &ioinfo->senseid;
 		if (flag & DEVREG_TYPE_DEVNO) {
-                        if (ioinfo->ui.flags.dval != 1 ||
-		            ioinfo->devno != pdevreg->ci.devno)
+			if (ioinfo->ui.flags.dval != 1 ||
+			    ioinfo->devno != pdevreg->ci.devno)
 				continue;
 		} else if (flag & DEVREG_TYPE_DEVCHARS) {
-			if ( (flag & DEVREG_MATCH_CU_TYPE) &&
-			     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 )
+			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 )
+			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 )
+			if ((flag & DEVREG_MATCH_DEV_MODEL) &&
+			    pdevreg->ci.hc.dmode != sid->dev_model)
 				continue;
 		} else {
 			continue;
 		}
-		
+
 		return pdevreg;
 	}
 	return NULL;
 }
 
-devreg_t * s390_search_devreg( ioinfo_t *ioinfo )
+devreg_t *
+s390_search_devreg(ioinfo_t * ioinfo)
 {
-	unsigned long  flags;
+	unsigned long flags;
 	devreg_t *pdevreg;
 
 	if (ioinfo == NULL)
 		return NULL;
 
-	spin_lock_irqsave(&dyn_lock, flags); 	
+	spin_lock_irqsave(&dyn_lock, flags);
 	pdevreg = s390_search_devreg_internal(ioinfo);
-	spin_unlock_irqrestore(&dyn_lock, flags); 	
- 	
+	spin_unlock_irqrestore(&dyn_lock, flags);
+
 	return pdevreg;
 }
 
 EXPORT_SYMBOL(s390_device_register);
 EXPORT_SYMBOL(s390_device_unregister);
-
diff -Nru a/drivers/s390/s390io.c b/drivers/s390/s390io.c
--- a/drivers/s390/s390io.c	Sat Jun  8 22:31:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,7526 +0,0 @@
-/*
- *  drivers/s390/s390io.c
- *   S/390 common I/O routines
- *
- *  S390 version
- *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- *                             IBM Corporation
- *    Author(s): Ingo Adlung (adlung@de.ibm.com)
- *               Cornelia Huck (cohuck@de.ibm.com) 
- *    ChangeLog: 01/07/2001 Blacklist cleanup (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *               01/04/2001 Holger Smolinski (smolinsk@de.ibm.com)
- *                          Fixed lost interrupts and do_adapter_IO
- *               xx/xx/xxxx nnn          multiple changes not reflected
- *               03/12/2001 Ingo Adlung  blacklist= - changed to cio_ignore=  
- *               03/14/2001 Ingo Adlung  disable interrupts before start_IO
- *                                        in Path Group processing 
- *                                       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
- *               xx/xx/xxxx some bugfixes & cleanups
- *               08/02/2001 Cornelia Huck not already known devices can be blacklisted
- *                                        by piping to /proc/cio_ignore
- */
-
-#include <linux/module.h>
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif 
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/smp.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
-#include <asm/lowcore.h>
-#include <asm/idals.h>
-#include <asm/uaccess.h> 
-#include <asm/cpcmd.h>
-
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-#include <asm/debug.h>
-#include <asm/queue.h>
-
-#ifndef TRUE
-#define TRUE  1
-#define FALSE 0
-#endif
-
-#define SANITY_CHECK(irq) do { \
-if (irq > highest_subchannel || irq < 0) \
-		return (-ENODEV); \
-	if (ioinfo[irq] == INVALID_STORAGE_AREA) \
-		return (-ENODEV); \
-	} while(0) 
-
-#undef  CONFIG_DEBUG_IO
-#define CONFIG_DEBUG_CRW
-
-unsigned int           highest_subchannel;
-ioinfo_t              *ioinfo_head = NULL;
-ioinfo_t              *ioinfo_tail = NULL;
-ioinfo_t              *ioinfo[__MAX_SUBCHANNELS] = {
-	[0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
-};
-
-static atomic_t    sync_isc     = ATOMIC_INIT(-1);
-static int         sync_isc_cnt = 0;      // synchronous irq processing lock
-
-static spinlock_t  adapter_lock = SPIN_LOCK_UNLOCKED;
-                                          // adapter interrupt lock
-static psw_t      io_sync_wait;           // wait PSW for sync IO, prot. by sync_isc
-static int        cons_dev          = -1; // identify console device
-static int        init_IRQ_complete = 0;
-static int        cio_show_msg      = 0;
-static schib_t   *p_init_schib      = NULL;
-static irb_t     *p_init_irb        = NULL;
-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);
-#ifdef CONFIG_PROC_FS
-static void s390_redo_validation(void);
-#endif
-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);
-static int  s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int  s390_process_IRQ( unsigned int irq );
-static int  enable_subchannel( unsigned int irq);
-static int  disable_subchannel( unsigned int irq);
-
-#ifdef CONFIG_PROC_FS
-static int chan_proc_init( void );
-#endif 
-
-static inline void do_adapter_IO( __u32 intparm );
-
-int  s390_DevicePathVerification( int irq, __u8 domask );
-int  s390_register_adapter_interrupt( adapter_int_handler_t handler );
-int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler );
-
-extern int  do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int  enable_none(unsigned int irq);
-extern int  disable_none(unsigned int irq);
-
-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 */
-
-unsigned long s390_irq_count[NR_CPUS]; /* trace how many irqs have occured per cpu... */
-int cio_count_irqs = 1;       /* toggle use here... */
-
-/* 
- * "Blacklisting" of certain devices:
- * Device numbers given in the commandline as blacklist=... won't be known to Linux
- * These can be single devices or ranges of devices
- *
- * Introduced by Cornelia Huck <cohuck@de.ibm.com>
- * Most of it shamelessly taken from dasd.c 
- */
-
-typedef struct dev_blacklist_range_t {
-     struct dev_blacklist_range_t *next;  /* next range in list */
-     unsigned int from;                   /* beginning of range */
-     unsigned int to;                     /* end of range */
-     int  kmalloced;	
-    
-} dev_blacklist_range_t;
-
-static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
-static dev_blacklist_range_t *dev_blacklist_unused_head = NULL;
-
-static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
-static int nr_blacklisted_ranges = 0;
-
-/* Handling of the blacklist ranges */
-
-static inline void blacklist_range_destroy( dev_blacklist_range_t *range,int locked )
-{
-	 long flags;
-	 
-	 if(!locked)
-		 spin_lock_irqsave( &blacklist_lock, flags ); 
-	 if(!remove_from_list((list **)&dev_blacklist_range_head,(list *)range))
-		 BUG();
-	 nr_blacklisted_ranges--;
-	 if(range->kmalloced)
-		 kfree(range);
-	 else
-		 add_to_list((list **)&dev_blacklist_unused_head,(list *)range); 
-	 if(!locked)
-		 spin_unlock_irqrestore( &blacklist_lock, flags );
-}
-
-
-
-/* 
- * Function: blacklist_range_add
- * Creates a range from the specified arguments and appends it to the list of
- * blacklisted devices
- */
-
-static inline dev_blacklist_range_t *blacklist_range_add( int from, int to,int locked)
-{
- 
-     dev_blacklist_range_t *range = NULL;
-     unsigned long flags;
-
-     if (to && (from>to)) {
-	     printk(KERN_WARNING "Invalid blacklist range %x to %x, skipping\n", from, to);
-	     return NULL;
-     }
-     if(!locked)
-	     spin_lock_irqsave( &blacklist_lock, flags );
-     if(dev_blacklist_unused_head)
-	     range=(dev_blacklist_range_t *)
-		     remove_listhead((list **)&dev_blacklist_unused_head);
-     else if (init_IRQ_complete) {
-	     if((range = ( dev_blacklist_range_t *) 
-		 kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL)))
-		     range->kmalloced=1;
-     } else {
-	     if((range = ( dev_blacklist_range_t *) 
-		 alloc_bootmem( sizeof( dev_blacklist_range_t ) )))
-		     range->kmalloced=0;
-     }
-     if (range)
-     {
-	     add_to_list((list **)&dev_blacklist_range_head,(list *)range);
-	     range->from = from;
-	     if (to == 0) {           /* only a single device is given */
-		     range->to = from;
-	     } else {
-		     range->to = to;
-	     }
-	     nr_blacklisted_ranges++;
-     }
-     if(!locked)
-	     spin_unlock_irqrestore( &blacklist_lock, flags );
-     return range;
-}
-
-/* 
- * Function: blacklist_range_remove
- * Removes a range from the blacklist chain
- */
-
-static inline void blacklist_range_remove( int from, int to )
-{
-     dev_blacklist_range_t *temp;
-     long flags;
-
-     spin_lock_irqsave( &blacklist_lock, flags );
-     for ( temp = dev_blacklist_range_head; 
-	   (temp->from != from) && (temp->to != to);
-	   temp = temp->next );
-     blacklist_range_destroy( temp,1 );
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-}
-
-/* Parsing the commandline for blacklist parameters */
-
-/* 
- * Variable to hold the blacklisted devices given by the parameter line
- * blacklist=...
- */
-char *blacklist[256] = {NULL, };
-
-/*
- * Get the blacklist=... items from the parameter line
- */
-
-static void blacklist_split_parm_string (char *str)
-{
-	char *tmp = str;
-	int count = 0;
-	do {
-		char *end;
-		int len;
-		end = strchr (tmp, ',');
-		if (end == NULL) {
-			len = strlen (tmp) + 1;
-		} else {
-			len = (long) end - (long) tmp + 1;
-			*end = '\0';
-			end++;
-		}
-		blacklist[count] = alloc_bootmem (len * sizeof (char) );
-		if (blacklist == NULL) {
-			printk (KERN_WARNING "can't store blacklist= parameter no %d\n", count + 1);
-			break;
-		}
-		memset (blacklist[count], 0, len * sizeof (char));
-		memcpy (blacklist[count], tmp, len * sizeof (char));
-		count++;
-		tmp = end;
-	} while (tmp != NULL && *tmp != '\0');
-}
-
-/*
- * The blacklist parameters as one concatenated string
- */
-
-static char blacklist_parm_string[1024] __initdata = {0,};
-
-
-/* 
- * function: blacklist_strtoul
- * Strip leading '0x' and interpret the values as Hex
- */
-static inline int blacklist_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;
-}
-
-/*
- * Function: blacklist_parse
- * Parse the parameters given to blacklist=... 
- * Add the blacklisted devices to the blacklist chain
- */
-
-static inline void blacklist_parse( char **str )
-{
-     char *temp;
-     int from, to;
-
-     while (*str) {
-	  temp = *str;
-	  from = 0;
-	  to = 0;
-	  
-	  from = blacklist_strtoul( temp, &temp );
-	  if (*temp == '-') {
-	       temp++;
-	       to = blacklist_strtoul( temp, &temp );
-	  }
-	  if (!blacklist_range_add( from, to,0 )) {
-	       printk( KERN_WARNING "Blacklisting range from %X to %X failed!\n", from, to);
-	  }
-#ifdef CONFIG_DEBUG_IO
-	  printk( "Blacklisted range from %X to %X\n", from, to );
-#endif
-	  str++;
-     }
-}
-
-
-/*
- * Initialisation of blacklist 
- */
-
-void __init blacklist_init( void )
-{
-#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 );
-}
-
-
-/*
- * Get all the blacklist parameters from parameter line
- */
-
-void __init blacklist_setup (char *str, int *ints)
-{
-	int len = strlen (blacklist_parm_string);
-	if (len != 0) {
-		strcat (blacklist_parm_string, ",");
-	}
-	strcat (blacklist_parm_string, str);
-}
-
-int __init blacklist_call_setup (char *str)
-{
-        int dummy;
-#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 */
-       
-	return 1;
-}
-
-__setup ("cio_ignore=", blacklist_call_setup);
-
-/* Checking if devices are blacklisted */
-
-/*
- * Function: is_blacklisted
- * Returns 1 if the given devicenumber can be found in the blacklist, otherwise 0.
- */
-
-static inline int is_blacklisted( int devno )
-{
-     dev_blacklist_range_t *temp;
-     long flags;
-     int retval=0;
-
-     if (dev_blacklist_range_head == NULL) {  
-	  /* no blacklist */
-	  return 0;
-     }
-
-     spin_lock_irqsave( &blacklist_lock, flags ); 
-     temp = dev_blacklist_range_head;
-     while (temp) {
-	  if ((temp->from <= devno) && (temp->to >= devno)) {
-		  retval=1;                      /* Deviceno is blacklisted */
-		  break;
-	  }
-	  temp = temp->next;
-     }
-     spin_unlock_irqrestore( &blacklist_lock, flags );
-     return retval;
-}
-
-/*
- * 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;
-	unsigned long flags;
-
-	spin_lock_irqsave( &blacklist_lock, flags ); 
-	while (tmp) {
-		blacklist_range_destroy(tmp,1);
-		tmp = dev_blacklist_range_head;
-	}
-	spin_unlock_irqrestore( &blacklist_lock, flags );
-}
-
-/*
- * 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;
-	long flags;
-	int err = 0;
-
-	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;
-				}
-				spin_lock_irqsave( &blacklist_lock, flags ); 
-				range = dev_blacklist_range_head;
-				while (range != NULL) {
-					temp = range->next;
-					if ((from <= range->from) && (to >= range->to)) {
-						blacklist_range_destroy(range,1);
-						changed = 1;
-					} else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
-						blacklist_range_add(to+1, range->to,1);
-						blacklist_range_destroy(range,1);
-						changed = 1;
-					} else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
-						blacklist_range_add(range->from, from-1,1);
-						blacklist_range_destroy(range,1);
-						changed = 1;
-					} else if ((from > range->from) && (to < range->to)) {
-						blacklist_range_add(range->from, from-1,1);
-						blacklist_range_add(to+1, range->to,1);
-						blacklist_range_destroy(range,1);
-						changed = 1;
-					}
-					range = temp;
-				}
-				spin_unlock_irqrestore( &blacklist_lock, flags );
-				kfree(param);
-			}
-			if (changed)
-				s390_redo_validation();
-		}
-	} else if (strstr(tmp, "add ")) {
-		for (i=0;i<4;i++){
-			tmp++;
-		}
-		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;
-			}
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			
-			/*
-			 * Don't allow for already known devices to be
-			 * blacklisted
-			 * The criterion is a bit dumb, devices which once were
-			 * there but are already gone are also caught...
-			 */
-			
-			err = 0;
-			for (i=0; i<=highest_subchannel; i++) {
-				if (ioinfo[i]!=INVALID_STORAGE_AREA) {
-					if (   (ioinfo[i]->schib.pmcw.dev >= from)
-					    && (ioinfo[i]->schib.pmcw.dev <= to)  ) {
-						printk(KERN_WARNING "cio_ignore: Won't blacklist "
-						       "already known devices, skipping range "
-						       "%x to %x\n", from, to);
-						err = 1;
-						break;
-					}
-				}
-			}
-
-			/*
-			 * Note: We allow for overlapping ranges here, 
-			 * since the user might specify overlapping ranges
-			 * and we walk through all ranges when freeing anyway.
-			 */
-
-			if (!err) 
-				blacklist_range_add(from, to, 1);
-			
-			spin_unlock_irqrestore( &blacklist_lock, flags );
-			kfree(param);
-		}
-
-	} else {
-		printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
-		printk("or 'add <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)
-{
-	s32	cnt1,cnt2,maxcnt2;
-	u32	*currptr=(__u32 *)ptr;
-
-	printk("\n%s\n",str);
-
-	for(cnt1=0;cnt1<cnt;cnt1+=16)
-	{
-		printk("%08lX ",(unsigned long)currptr);
-		maxcnt2=cnt-cnt1;
-		if(maxcnt2>16)
-			maxcnt2=16;
-		for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
-			printk("%08X ",*currptr++);
-		printk("\n");
-	}
-}
-
-void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
-{
-	s32 cnt1, cnt2, maxcnt2;
-	u32 *currptr = (__u32 *)ptr;
-	char buffer[cnt*12];
-
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
-
-	for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
-		sprintf(buffer, "%08lX ", (unsigned long)currptr);
-		maxcnt2 = cnt - cnt1;
-		if (maxcnt2 > 16)
-			maxcnt2 = 16;
-		for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
-			sprintf(buffer, "%08X ", *currptr++);
-	}
-	debug_sprintf_event(cio_debug_msg_id, level, "%s\n",buffer);
-}
-
-static int __init cio_setup( char *parm )
-{
-	if ( !strcmp( parm, "yes") )
-	{
-		cio_show_msg = 1;
-	}
-	else if ( !strcmp( parm, "no") )
-	{
-		cio_show_msg = 0;
-	}
-	else
-	{
-		printk( "cio_setup : invalid cio_msg parameter '%s'", parm);
-
-	} /* endif */
-
-	return 1;
-}
-
-__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);
-
-#ifdef CONFIG_PROC_FS
-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( KERN_ERR "cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
-	}
-
-	return 1;
-}
-
-__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
-#endif
-
-/*
- * register for adapter interrupts
- *
- * With HiperSockets the zSeries architecture provides for
- *  means of adapter interrups, pseudo I/O interrupts that are
- *  not tied to an I/O subchannel, but to an adapter. However,
- *  it doesn't disclose the info how to enable/disable them, but
- *  to recognize them only. Perhaps we should consider them
- *  being shared interrupts, and thus build a linked list
- *  of adapter handlers ... to be evaluated ...
- */
-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 );
-
-	if ( handler == NULL )
-		ret = -EINVAL;
-	else if ( adapter_handler )
-		ret = -EBUSY;
-	else
-		adapter_handler = handler;
-  	
-	spin_unlock( &adapter_lock ); 	
-
-	return( ret);
-}
-
-
-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 ); 	
-
-	if ( handler == NULL )
-		ret = -EINVAL;
-	else if ( handler != adapter_handler )
-		ret = -EINVAL;
-	else
-		adapter_handler = NULL;
-  	
-	spin_unlock( &adapter_lock ); 	
-
-	return( ret);
-}
-
-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 )
-		(*adapter_handler)( intparm );
-
-	spin_unlock( &adapter_lock );
-
-	return;  	
-}
-
-/*
- * Note : internal use of irqflags SA_PROBE for NOT path grouping 
- *
- */
-int s390_request_irq_special( int                      irq,
-                              io_handler_func_t        io_handler,
-                              not_oper_handler_func_t  not_oper_handler,
-                              unsigned long            irqflags,
-                              const char              *devname,
-                              void                    *dev_id)
-{
-	int		retval = 0;
-	unsigned long	flags;
-	char            dbf_txt[15];
-	int             retry;
-
-	if (irq >= __MAX_SUBCHANNELS)
-		return -EINVAL;
-
-	if ( !io_handler || !dev_id )
-		return -EINVAL;
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-		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
-	 */
-	s390irq_spin_lock_irqsave( irq, flags);
-
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		retry = 5;
-		
-		ioinfo[irq]->irq_desc.handler = io_handler;
-		ioinfo[irq]->irq_desc.name    = devname;
-		ioinfo[irq]->irq_desc.dev_id  = dev_id;
-		ioinfo[irq]->ui.flags.ready   = 1;
-		
-		
-		do {
-			retval = enable_subchannel(irq);
-			if (retval) {
-				ioinfo[irq]->ui.flags.ready = 0;
-				break;
-			}
-			
-			stsch(irq,&ioinfo[irq]->schib);
-			if (ioinfo[irq]->schib.pmcw.ena) 
-				retry = 0;
-			else
-				retry--;
-
-		} while (retry);
-	}
-	else
-	{
-		/*
-		 *  interrupt already owned, and shared interrupts
-		 *   aren't supported on S/390.
-		 */
-		retval = -EBUSY;
-
-	} /* endif */
-
-	s390irq_spin_unlock_irqrestore(irq,flags);
-
-
-
-	if ( retval == 0 )
-	{
-		if ( !(irqflags & SA_PROBE))
-			s390_DevicePathVerification( irq, 0 );
-
-		ioinfo[irq]->ui.flags.newreq = 1;
-		ioinfo[irq]->nopfunc         = not_oper_handler;  	
-	}
-
-	return retval;
-}
-
-
-int s390_request_irq( unsigned int   irq,
-                      void           (*handler)(int, void *, struct pt_regs *),
-                      unsigned long  irqflags,
-                      const char    *devname,
-                      void          *dev_id)
-{
-	int ret;
-
-	ret = s390_request_irq_special( irq,
-                                   (io_handler_func_t)handler,
-                                   NULL,
-                                   irqflags,
-                                   devname,
-                                   dev_id);
-
-	if ( ret == 0 )
-	{
-		ioinfo[irq]->ui.flags.newreq = 0;
-
-	} /* endif */
-
-	return( ret);
-}
-
-void s390_free_irq(unsigned int irq, void *dev_id)
-{
-	unsigned long flags;
-	int          ret;
-
-	unsigned int count = 0;
-	char dbf_txt[15];
-
-	if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return;
-
-	} /* 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
-	if ( irq != cons_dev )
-	{
-		printk("Trying to free IRQ%d\n",irq);
-
-	} /* 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
-	 *  the IRQ is actually owned by the handler ...
-	 */
-	if ( ioinfo[irq]->ui.flags.ready )
-	{
-		if ( dev_id == ioinfo[irq]->irq_desc.dev_id  )
-		{
-			/* start deregister */
-			ioinfo[irq]->ui.flags.unready = 1;
-
-			/*
-			 * Try to stop IO first...
-			 * ... it seems disable_subchannel is sometimes
-			 * successfully called with IO still pending.
-			 */
-			halt_IO( irq,
-				 0xC8C1D3E3,
-				 DOIO_WAIT_FOR_INTERRUPT );
-
-			do
-			{
-				ret = disable_subchannel( irq);
-
-				count++;
-
-				if ( ret == -EBUSY )
-				{
-					int iret;
-
-					/*
-					 * kill it !
-					 * ... we first try sync and eventually
-					 *  try terminating the current I/O by
-					 *  an async request, twice halt, then
-					 *  clear.
-					 */
-					if ( count < 2 )
-					{              	
-						iret = halt_IO( irq,
-						                0xC8C1D3E3,
-						                DOIO_WAIT_FOR_INTERRUPT );
-   	
-						if ( iret == -EBUSY )
-						{
-							halt_IO( irq, 0xC8C1D3E3, 0);
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 200000 ); /* 200 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
-
-						} /* endif */
-					}
-					else
-					{
-						iret = clear_IO( irq,
-						                 0x40C3D3D9,
-						                 DOIO_WAIT_FOR_INTERRUPT );
-   	
-						if ( iret == -EBUSY )
-						{
-							clear_IO( irq, 0xC8C1D3E3, 0);
-							s390irq_spin_unlock_irqrestore( irq, flags);
-							udelay( 1000000 ); /* 1000 ms */
-							s390irq_spin_lock_irqsave( irq, flags);
-
-						} /* endif */
-
-					} /* endif */
-
-					if ( count == 2 )
-					{
-						/* give it a very last try ... */
-						disable_subchannel( irq);
-
-						if ( ioinfo[irq]->ui.flags.busy )
-					        {
-							printk( KERN_CRIT"free_irq(%04X) "
-							       "- device %04X busy, retry "
-							       "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 */
-						
-						break; /* sigh, let's give up ... */
-
-					} /* endif */
-
-				} /* endif */
-		
-			} while ( ret == -EBUSY );
-
-			ioinfo[irq]->ui.flags.ready   = 0;
-			ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
-
-			ioinfo[irq]->nopfunc = NULL;
-
-			s390irq_spin_unlock_irqrestore( irq, flags);
-		}
-		else
-		{
-			s390irq_spin_unlock_irqrestore( irq, flags);
-
-			printk( "free_irq(%04X) : error, "
-			        "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 */
-
-	}
-	else
-	{
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		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 */
-
-}
-
-/*
- * Generic enable/disable code
- */
-int disable_irq(unsigned int irq)
-{
-	unsigned long flags;
-	int           ret;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	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);
-
-	synchronize_irq();
-
-	return( ret);
-}
-
-int enable_irq(unsigned int irq)
-{
-	unsigned long flags;
-	int           ret;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	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);
-
-	return(ret);
-}
-
-/*
- * Enable IRQ by modifying the subchannel
- */
-static int enable_subchannel( unsigned int irq)
-{
-	int   ret = 0;
-	int   ccode;
-	int   retry = 5;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	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.
-	 */
-	if (  ioinfo[irq]->ui.flags.d_disable )
-	{
-		ioinfo[irq]->ui.flags.d_disable = 0;
-		ret                             = 0;
-	}
-	else
-	{
-		ccode = stsch(irq, &(ioinfo[irq]->schib) );
-
-		if ( ccode )
-		{
-			ret = -ENODEV;
-		}
-		else
-		{
-			ioinfo[irq]->schib.pmcw.ena = 1;
-
-			if ( irq == cons_dev )
-			{
-				ioinfo[irq]->schib.pmcw.isc = 7;
-			}
-			else	
-			{
-				ioinfo[irq]->schib.pmcw.isc = 3;
-
-			} /* endif */
-
-			do
-			{
-				ccode = msch( irq, &(ioinfo[irq]->schib) );
-
-				switch (ccode) {
-				case 0: /* ok */
-					ret = 0;
-					retry = 0;
-					break;
-
-				case 1: /* status pending */
-
-					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
-					ioinfo[irq]->ui.flags.s_pend = 0;
-
-					ret = -EIO;    /* might be overwritten */
-					               /* ... on re-driving    */
-					               /* ... the msch()       */
-					retry--;
-					break;
-
-				case 2: /* busy */
-					udelay(100);	/* allow for recovery */
-					ret = -EBUSY;
-					retry--;
-					break;
-
-				case 3: /* not oper */
-					ioinfo[irq]->ui.flags.oper = 0;
-					retry = 0;
-					ret = -ENODEV;
-					break;
-				}
-
-			} while ( retry );
-
-		} /* endif */
-
-	}  /* endif */
-
-	return( ret );
-}
-
-
-/*
- * Disable IRQ by modifying the subchannel
- */
-static int disable_subchannel( unsigned int irq)
-{
-	int  cc;          /* condition code */
-	int  ret = 0;     /* function return value */
-	int  retry = 5;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-	
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
-		/*
-		 * the disable function must not be called while there are
-		 *  requests pending for completion !
-		 */
-		ret = -EBUSY;
-	}
-	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
-		 *  irq is re-requested prior to the interrupt to occur.
-		 */
-		cc = stsch(irq, &(ioinfo[irq]->schib) );
-
-		if ( cc == 3 )
-		{
-			ioinfo[irq]->ui.flags.oper      = 0;
-			ioinfo[irq]->ui.flags.d_disable = 1;
-
-			ret = 0;
-		}
-		else // cc == 0
-		{
-			ioinfo[irq]->schib.pmcw.ena = 0;
-
-			do
-			{
-				cc = msch( irq, &(ioinfo[irq]->schib) );
-
-				switch (cc) {
-				case 0: /* ok */
-					retry = 0;
-					ret = 0;   
-					break;
-
-				case 1: /* status pending */
-					ioinfo[irq]->ui.flags.s_pend = 1;
-					s390_process_IRQ( irq );
-					ioinfo[irq]->ui.flags.s_pend = 0;
-
-					ret = -EIO; /* might be overwritten  */
-					            /* ... on re-driving the */
-					            /* ... msch() call       */
-					retry--;
-					break;
-
-				case 2: /* busy; this should not happen! */
-					printk( KERN_CRIT"disable_subchannel(%04X) "
-					        "- unexpected busy condition for "
-						"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);
-					retry = 0;
-					ret = -EBUSY;
-					break;
-
-				case 3: /* not oper */
-					/*
-					 * should hardly occur ?!
-					 */
-					ioinfo[irq]->ui.flags.oper      = 0;
-					ioinfo[irq]->ui.flags.d_disable = 1;
-					retry = 0;
-
-					ret = 0; /* if the device has gone we */
-					         /* ... don't need to disable */
-					         /* ... it anymore !          */
-					break;
-
-				} /* endswitch */
-
-			} while ( retry );
-
-		} /* endif */
-
-	} /* endif */
-
-	return( ret);
-}
-
-
-void s390_init_IRQ( void )
-{
-	unsigned long flags;     /* PSW flags */
-	long          cr6 __attribute__ ((aligned (8)));
-
-	asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
-
-	p_init_schib = alloc_bootmem_low( sizeof(schib_t));
-	p_init_irb   = alloc_bootmem_low( sizeof(irb_t));
-	
-	
-	/*
-	 * As we don't know about the calling environment
-	 *  we assure running disabled. Before leaving the
-	 *  function we resestablish the old environment.
-	 *
-	 * Note : as we don't need a system wide lock, therefore
-	 *        we shouldn't use cli(), but __cli() as this
-	 *        affects the current CPU only.
-	 */
-	__save_flags(flags);
-	__cli();
-
-	/*
-	 * disable all interrupts
-	 */
-	cr6 = 0;
-	__ctl_load( cr6, 6, 6);
-
-	s390_process_subchannels();
-
-	if (cio_count_irqs) {
-		int i;
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
-	}
-
-	/*
-	 * enable default I/O-interrupt sublass 3
-	 */
-	cr6 = 0x10000000;
-	__ctl_load( cr6, 6, 6);
-
-	s390_device_recognition_all();
-
-	init_IRQ_complete = 1;
-
-	__restore_flags(flags);
-
-	return;
-}
-
-
-/*
- * dummy handler, used during init_IRQ() processing for compatibility only
- */
-void  init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
-{
-   /* this is a dummy handler only ... */
-}
-
-
-int s390_start_IO( int            irq,      /* IRQ */
-                   ccw1_t        *cpa,      /* logical channel prog addr */
-                   unsigned long  user_intparm,  /* interruption parameter */
-                   __u8           lpm,      /* logical path mask */
-                   unsigned long  flag)     /* flags */
-{
-	int            ccode;
-	int            ret = 0;
-	char buffer[80];
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	/*
-	 * The flag usage is mutal exclusive ...
-	 */
-	if (    (flag & DOIO_EARLY_NOTIFICATION)
-	     && (flag & DOIO_REPORT_ALL     ) )
-	{
-		return( -EINVAL );
-
-	} /* 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
-	 */
-  	ioinfo[irq]->orb.intparm = (__u32)(long)&ioinfo[irq]->u_intparm;
-	ioinfo[irq]->orb.fmt     = 1;
-
-	ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
-	ioinfo[irq]->orb.spnd =  (flag & DOIO_ALLOW_SUSPEND ? TRUE : FALSE);
-	ioinfo[irq]->orb.ssic =  (    (flag & DOIO_ALLOW_SUSPEND )
-	                           && (flag & DOIO_SUPPRESS_INTER) );
-
-	if ( flag & DOIO_VALID_LPM )
-	{
-		ioinfo[irq]->orb.lpm = lpm;
-	}
-	else
-	{
-		ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
-
-	} /* endif */
-
-#ifdef CONFIG_ARCH_S390X
-	/* 
-	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
-	 */
-	ioinfo[irq]->orb.c64 = 1;
-	ioinfo[irq]->orb.i2k = 0;
-#endif
-
-	ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
-
-	/*
-	 * If sync processing was requested we lock the sync ISC, modify the
-	 *  device to present interrupts for this ISC only and switch the
-	 *  CPU to handle this ISC + the console ISC exclusively.
-	 */
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-	{
-		ret = enable_cpu_sync_isc( irq);
-	
-		if ( ret )
-		{
-			return( ret);
-		}
-
-	} /* endif */
-
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
-		ioinfo[irq]->ui.flags.repnone = 1;
-
-	} /* endif */
-
-	/*
-	 * Issue "Start subchannel" and process condition code
-	 */
-	ccode = ssch( irq, &(ioinfo[irq]->orb) );
-
-	switch ( ccode ) {
-	case 0:
-
-		if ( !ioinfo[irq]->ui.flags.w4sense )
-		{
-			/*
-			 * init the device driver specific devstat irb area
-			 *
-			 * Note : don´t clear saved irb info in case of sense !
-			 */
-			memset( &((devstat_t *)ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-				'\0', sizeof( irb_t) );
-		} /* endif */
-
-		memset( &ioinfo[irq]->devstat.ii.irb,
-		        '\0',
-		        sizeof( irb_t) );
-
-		/*
-		 * initialize device status information
-		 */
-		ioinfo[irq]->ui.flags.busy   = 1;
-		ioinfo[irq]->ui.flags.doio   = 1;
-
-		ioinfo[irq]->u_intparm       = user_intparm;
-		ioinfo[irq]->devstat.cstat   = 0;
-		ioinfo[irq]->devstat.dstat   = 0;
-		ioinfo[irq]->devstat.lpum    = 0;
-		ioinfo[irq]->devstat.flag    = DEVSTAT_START_FUNCTION;
-		ioinfo[irq]->devstat.scnt    = 0;
-
-		ioinfo[irq]->ui.flags.fast   = 0;
-		ioinfo[irq]->ui.flags.repall = 0;
-
-		/*
-		 * Check for either early (FAST) notification requests
-		 *  or if we are to return all interrupt info.
-		 * Default is to call IRQ handler at secondary status only
-		 */
-		if ( flag & DOIO_EARLY_NOTIFICATION )
-		{
-			ioinfo[irq]->ui.flags.fast = 1;
-		}
-		else if ( flag & DOIO_REPORT_ALL )
-		{
-			ioinfo[irq]->ui.flags.repall = 1;
-
-		} /* endif */
-
-		ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
-		/*
-		 * If synchronous I/O processing is requested, we have
-		 *  to wait for the corresponding interrupt to occur by
-		 *  polling the interrupt condition. However, as multiple
-		 *  interrupts may be outstanding, we must not just wait
-		 *  for the first interrupt, but must poll until ours
-		 *  pops up.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			psw_t            io_new_psw;
-			int              ccode;
-			uint64_t         time_start;    	
-			uint64_t         time_curr;    	
-
-			int              ready    = 0;
-			int              io_sub   = -1;
-			struct _lowcore *lc       = NULL;
-			int              do_retry = 1;
-
-			/*
-			 * We shouldn't perform a TPI loop, waiting for an
-			 *  interrupt to occur, but should load a WAIT PSW
-			 *  instead. Otherwise we may keep the channel subsystem
-			 *  busy, not able to present the interrupt. When our
-			 *  sync. interrupt arrived we reset the I/O old PSW to
-			 *  its original value.
-			 */
-			memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
-
-			ccode = iac();
-
-			switch (ccode) {
-			case 0:  		// primary-space
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_PRIM_SPACE_MODE
-				                    | _PSW_IO_WAIT;
-				break;
-			case 1:			// secondary-space
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_SEC_SPACE_MODE
-				                    | _PSW_IO_WAIT;
-				break;
-			case 2:			// access-register
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_ACC_REG_MODE
-				                    | _PSW_IO_WAIT;
-				break;
-			case 3:			// home-space	
-				io_sync_wait.mask =   _IO_PSW_MASK
-				                    | _PSW_HOME_SPACE_MODE
-				                    | _PSW_IO_WAIT;
-				break;
-			default:
-				panic( "start_IO() : unexpected "
-				       "address-space-control %d\n",
-				       ccode);
-				break;
-			} /* endswitch */
-
-			io_sync_wait.addr = FIX_PSW(&&io_wakeup);
-
-			/*
-			 * Martin didn't like modifying the new PSW, now we take
-			 *  a fast exit in do_IRQ() instead
-			 */
-			*(__u32 *)__LC_SYNC_IO_WORD  = 1;
-
-			asm volatile ("STCK %0" : "=m" (time_start));
-
-			time_start = time_start >> 32;
-
-			do
-			{
-				if ( flag & DOIO_TIMEOUT )
-				{
-					tpi_info_t tpi_info={0,};
-
-					do
-					{
-						if ( tpi(&tpi_info) == 1 )
-						{
-							io_sub = tpi_info.irq;
-							break;
-						}
-						else
-						{
-							udelay(100); /* usecs */
-							asm volatile ("STCK %0" : "=m" (time_curr));
-
-							if ( ((time_curr >> 32) - time_start ) >= 3 )
-								do_retry = 0;          							
-
-						} /* endif */
-				
-					} while ( do_retry );
-				}
-				else
-				{
-					__load_psw( io_sync_wait );
-
-io_wakeup:
-					io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
-				} /* endif */
-
- 				if ( do_retry )
-					ready = s390_process_IRQ( io_sub );
-
-				/*
-				 * surrender when retry count's exceeded ...
-				 */
-			} while ( !(     ( io_sub == irq )
-			              && ( ready  == 1   ))
-			            && do_retry             );
-
-			*(__u32 *)__LC_SYNC_IO_WORD = 0;
-
-			if ( !do_retry )
-				ret = -ETIMEDOUT;
-
-		} /* endif */
-
-		break;
-
-	case 1 :            /* status pending */
-
-		ioinfo[irq]->devstat.flag =   DEVSTAT_START_FUNCTION
-		                            | DEVSTAT_STATUS_PENDING;
-
-		/*
-		 * initialize the device driver specific devstat irb area
-		 */
-		memset( &((devstat_t *) ioinfo[irq]->irq_desc.dev_id)->ii.irb,
-		        '\0', sizeof( irb_t) );
-
-		/*
-		 * Let the common interrupt handler process the pending status.
-		 *  However, we must avoid calling the user action handler, as
-		 *  it won't be prepared to handle a pending status during
-		 *  do_IO() processing inline. This also implies that process_IRQ
-		 *  must terminate synchronously - especially if device sensing
-		 *  is required.
-		 */
-		ioinfo[irq]->ui.flags.s_pend   = 1;
-		ioinfo[irq]->ui.flags.busy     = 1;
-		ioinfo[irq]->ui.flags.doio     = 1;
-
-		s390_process_IRQ( irq );
-
-		ioinfo[irq]->ui.flags.s_pend   = 0;
-		ioinfo[irq]->ui.flags.busy     = 0;
-		ioinfo[irq]->ui.flags.doio     = 0;
-
-		ioinfo[irq]->ui.flags.repall   = 0;
-		ioinfo[irq]->ui.flags.w4final  = 0;
-
-		ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
-
-		/*
-		 * In multipath mode a condition code 3 implies the last path
-		 *  has gone, except we have previously restricted the I/O to
-		 *  a particular path. A condition code 1 (0 won't occur)
-		 *  results in return code EIO as well as 3 with another path
-		 *  than the one used (i.e. path available mask is non-zero).
-		 */
-		if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-		{
-			if ( flag & DOIO_VALID_LPM )
-			{
-				ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-			}
-			else
-			{
-				ioinfo[irq]->opm = 0;
-
-			} /* endif */
-	
-			if ( ioinfo[irq]->opm == 0 ) 	
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->ui.flags.oper  = 0;
-			}
-			else
-			{
-				ret = -EIO;
-
-			} /* endif */
-
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-
-#ifdef CONFIG_DEBUG_IO
-			{
-
-			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_displayhex( buffer,
-			                 &(ioinfo[irq]->devstat.ii.irb) ,
-			                 sizeof(irb_t));
-
-			sprintf( buffer, "s390_start_IO(%04X) - schib for "
-			         "device %04X, after status pending\n",
-			         irq,
-			         ioinfo[irq]->devstat.devno );
-
-			s390_displayhex( buffer,
-			                 &(ioinfo[irq]->schib) ,
-			                 sizeof(schib_t));
-
-
-			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_displayhex( buffer,
-					ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
-					ioinfo[irq]->irq_desc.dev_id->rescnt);
-
-			} /* 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
-		{
-			ret                         = -EIO;
-			ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-			ioinfo[irq]->ui.flags.oper  = 1;
-
-		} /* endif */
-
-		break;
-
-	case 2 :            /* busy */
-
-		ret = -EBUSY;
-		break;
-
-	default:            /* device/path not operational */
-		
-		if ( flag & DOIO_VALID_LPM )
-		{
-			ioinfo[irq]->opm &= ~lpm;
-		}
-		else
-		{
-			ioinfo[irq]->opm = 0;
-
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
-			ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-
-		} /* endif */
-
-		ret = -ENODEV;
-
-		memcpy( ioinfo[irq]->irq_desc.dev_id,
-		        &(ioinfo[irq]->devstat),
-		        sizeof( devstat_t) );
-
-
-#ifdef CONFIG_DEBUG_IO
-
-   			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_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 */
-
-	if ( flag & DOIO_WAIT_FOR_INTERRUPT)
-	{
-		disable_cpu_sync_isc( irq );
-
-	} /* endif */
-
-	if ( flag & DOIO_DONT_CALL_INTHDLR )
-	{
-		ioinfo[irq]->ui.flags.repnone = 0;
-
-   } /* endif */
-
-	return( ret);
-}
-
-int do_IO( int            irq,          /* IRQ */
-           ccw1_t        *cpa,          /* channel program address */
-           unsigned long  user_intparm, /* interruption parameter */
-           __u8           lpm,          /* logical path mask */
-           unsigned long  flag)         /* flags : see above */
-{
-	int ret = 0;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	/* handler registered ? or free_irq() in process already ? */
-	if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
-	{
-		return( -ENODEV );
-
-	} /* 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 ...
-	 */
-	if ( !ioinfo[irq]->ui.flags.busy )         /* last I/O completed ? */
-	{
-		ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
-	}
-	else if ( ioinfo[irq]->ui.flags.fast )
-	{
-		/*
-		 * If primary status was received and ending status is missing,
-		 *  the device driver won't be notified on the ending status
-		 *  if early (fast) interrupt notification was requested.
-		 *  Therefore we have to queue the next incoming request. If
-		 *  halt_IO() is issued while there is a request queued, a HSCH
-		 *  needs to be issued and the queued request must be deleted
-		 *  but its intparm must be returned (see halt_IO() processing)
-		 */
-		if (     ioinfo[irq]->ui.flags.w4final
-		      && !ioinfo[irq]->ui.flags.doio_q )
-		{
-			ioinfo[irq]->qflag    = flag;
-			ioinfo[irq]->qcpa     = cpa;
-			ioinfo[irq]->qintparm = user_intparm;
-			ioinfo[irq]->qlpm     = lpm;
-		}
-		else
-		{
-			ret = -EBUSY;
-
-		} /* endif */
-	}
-	else
-	{
-		ret = -EBUSY;
-
-	} /* endif */
-
-	return( ret );
-
-}
-
-/*
- * resume suspended I/O operation
- */
-int resume_IO( int irq)
-{
-	int ret = 0;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	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
-	 */
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
-		int ccode;
-
-		ccode = rsch( irq);
-
-		switch (ccode) {
-		case 0 :
-			break;
-
-		case 1 :
-		  	s390_process_IRQ( irq );
-			ret = -EBUSY;
-			break;
-
-		case 2 :
-			ret = -EINVAL;
-			break;
-
-		case 3 :
-			/*
-			 * useless to wait for request completion
-			 *  as device is no longer operational !
-			 */
-			ioinfo[irq]->ui.flags.oper = 0;
-			ioinfo[irq]->ui.flags.busy = 0;
-			ret                        = -ENODEV;
-			break;
-
-		} /* endswitch */          	
-		
-	}
-	else
-	{
-		ret = -ENOTCONN;
-
-	} /* endif  */
-
-	return( ret);
-}
-
-/*
- * Note: The "intparm" parameter is not used by the halt_IO() function
- *       itself, as no ORB is built for the HSCH instruction. However,
- *       it allows the device interrupt handler to associate the upcoming
- *       interrupt with the halt_IO() request.
- */
-int halt_IO( int           irq,
-             unsigned long user_intparm,
-             unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret;
-	int            ccode;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	/*
-	 * we only allow for halt_IO if the device has an I/O handler associated
-	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
-	}
-	/*
-	 * we ignore the halt_io() request if ending_status was received but
-	 *  a SENSE operation is waiting for completion.
-	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
-	}
-#if 0
-	/*
-	 * We don't allow for halt_io with a sync do_IO() requests pending.
-	 */
-	else if (    ioinfo[irq]->ui.flags.syncio
-	          && (flag & DOIO_WAIT_FOR_INTERRUPT))
-	{
-		ret = -EBUSY;
-	}
-#endif
-	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
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
-
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
-
-		} /* endif */
-
-		/*
-		 * Issue "Halt subchannel" and process condition code
-		 */
-		ccode = hsch( irq );
-
-		switch ( ccode ) {
-		case 0:
-
-			ioinfo[irq]->ui.flags.haltio = 1;
-
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_HALT_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
-
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_HALT_FUNCTION;
-
-			} /* endif */
-
-			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
-			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				psw_t            io_new_psw;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
-
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
-				memcpy( &io_new_psw,
-				        &lc->io_new_psw,
-				        sizeof(psw_t));
-
-				ccode = iac();
-
-				switch (ccode) {
-				case 0:  		// primary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_PRIM_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_SEC_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_ACC_REG_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_HOME_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "halt_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
-
-				io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
-
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
-
-				do
-				{
-
-					__load_psw( io_sync_wait );
-hio_wakeup:
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
-				   ready = s390_process_IRQ( io_sub );
-
-				} while ( !((io_sub == irq) && (ready == 1)) );
-
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
-
-			} /* endif */
-
-			ret = 0;
-			break;
-
-		case 1 :            /* status pending */
-	
-			ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
-			/*
-			 * initialize the device driver specific devstat irb area
-			 */
-			memset( &ioinfo[irq]->irq_desc.dev_id->ii.irb,
-			        '\0', sizeof( irb_t) );
-
-			/*
-			 * Let the common interrupt handler process the pending
-			 *  status. However, we must avoid calling the user
-			 *  action handler, as it won't be prepared to handle
-			 *  a pending status during do_IO() processing inline.
-			 *  This also implies that s390_process_IRQ must
-			 *  terminate synchronously - especially if device
-			 *  sensing is required.
-			 */
-			ioinfo[irq]->ui.flags.s_pend   = 1;
-			ioinfo[irq]->ui.flags.busy     = 1;
-			ioinfo[irq]->ui.flags.doio     = 1;
-
-			s390_process_IRQ( irq );
-			
-			ioinfo[irq]->ui.flags.s_pend   = 0;
-			ioinfo[irq]->ui.flags.busy     = 0;
-			ioinfo[irq]->ui.flags.doio     = 0;
-			ioinfo[irq]->ui.flags.repall   = 0;
-			ioinfo[irq]->ui.flags.w4final  = 0;
-
-			ioinfo[irq]->devstat.flag     |= DEVSTAT_FINAL_STATUS;
-
-			/*
-			 * In multipath mode a condition code 3 implies the last
-			 *  path has gone, except we have previously restricted
-			 *  the I/O to a particular path. A condition code 1
-			 *  (0 won't occur) results in return code EIO as well
-			 *  as 3 with another path than the one used (i.e. path available mask is non-zero).
-			 */
-			if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
-			{
-				ret                         = -ENODEV;
-				ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 0;
-			}
-			else
-			{
-				ret                         = -EIO;
-				ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
-				ioinfo[irq]->ui.flags.oper  = 1;
-
-			} /* endif */
-
-			break;
-
-		case 2 :            /* busy */
-
-			ret = -EBUSY;
-			break;
-
-		default:            /* device not operational */
-
-			ret = -ENODEV;
-			break;
-
-		} /* endswitch */
-
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
-
-		} /* endif */
-
-	} /* endif */
-
-	return( ret );
-}
-
-/*
- * Note: The "intparm" parameter is not used by the clear_IO() function
- *       itself, as no ORB is built for the CSCH instruction. However,
- *       it allows the device interrupt handler to associate the upcoming
- *       interrupt with the clear_IO() request.
- */
-int clear_IO( int           irq,
-              unsigned long user_intparm,
-              unsigned long flag)  /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
-	int            ret = 0;
-	int            ccode;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-	{
-		return( -ENODEV);
-   }
-
-	/*
-	 * we only allow for clear_IO if the device has an I/O handler associated
-	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = -ENODEV;
-	}
-	/*
-	 * we ignore the clear_io() request if ending_status was received but
-	 *  a SENSE operation is waiting for completion.
-	 */
-	else if ( ioinfo[irq]->ui.flags.w4sense )
-	{
-		ret = 0;
-	}
-#if 0
-	/*
-	 * We don't allow for clear_io with a sync do_IO() requests pending.
-	 *  Concurrent I/O is possible in SMP environments only, but the
-	 *  sync. I/O request can be gated to one CPU at a time only.
-	 */
-	else if ( ioinfo[irq]->ui.flags.syncio )
-	{
-		ret = -EBUSY;
-	}
-#endif
-	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
-		 *  and switch the CPU to handle this ISC + the console ISC
-		 *  exclusively.
-		 */
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			ret = enable_cpu_sync_isc( irq);
-
-			if ( ret )
-			{
-				return( ret);
-  	
-			} /* endif */
-
-		} /* endif */
-
-		/*
-		 * Issue "Clear subchannel" and process condition code
-		 */
-		ccode = csch( irq );
-
-		switch ( ccode ) {
-		case 0:
-
-			ioinfo[irq]->ui.flags.haltio = 1;
-
-			if ( !ioinfo[irq]->ui.flags.doio )
-			{
-				ioinfo[irq]->ui.flags.busy   = 1;
-				ioinfo[irq]->u_intparm       = user_intparm;
-				ioinfo[irq]->devstat.cstat   = 0;
-				ioinfo[irq]->devstat.dstat   = 0;
-				ioinfo[irq]->devstat.lpum    = 0;
-				ioinfo[irq]->devstat.flag    = DEVSTAT_CLEAR_FUNCTION;
-				ioinfo[irq]->devstat.scnt    = 0;
-
-			}
-			else
-			{
-				ioinfo[irq]->devstat.flag   |= DEVSTAT_CLEAR_FUNCTION;
-
-			} /* endif */
-
-			/*
-			 * If synchronous I/O processing is requested, we have
-			 *  to wait for the corresponding interrupt to occur by
-			 *  polling the interrupt condition. However, as multiple
-			 *  interrupts may be outstanding, we must not just wait
-			 *  for the first interrupt, but must poll until ours
-			 *  pops up.
-			 */
-			if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-			{
-				int              io_sub;
-				__u32            io_parm;
-				psw_t            io_new_psw;
-				int              ccode;
-  	
-				int              ready = 0;
-				struct _lowcore *lc    = NULL;
-
-				/*
-				 * We shouldn't perform a TPI loop, waiting for
-				 *  an interrupt to occur, but should load a
-				 *  WAIT PSW instead. Otherwise we may keep the
-				 *  channel subsystem busy, not able to present
-				 *  the interrupt. When our sync. interrupt
-				 *  arrived we reset the I/O old PSW to its
-				 *  original value.
-				 */
-				memcpy( &io_new_psw,
-				        &lc->io_new_psw,
-				        sizeof(psw_t));
-
-				ccode = iac();
-
-				switch (ccode) {
-				case 0:  		// primary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_PRIM_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 1:			// secondary-space
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_SEC_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 2:			// access-register
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_ACC_REG_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				case 3:			// home-space	
-					io_sync_wait.mask =   _IO_PSW_MASK
-					                    | _PSW_HOME_SPACE_MODE
-					                    | _PSW_IO_WAIT;
-					break;
-				default:
-					panic( "clear_IO() : unexpected "
-					       "address-space-control %d\n",
-					       ccode);
-					break;
-				} /* endswitch */
-
-				io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
-
-				/*
-				 * Martin didn't like modifying the new PSW, now we take
-				 *  a fast exit in do_IRQ() instead
-				 */
-				*(__u32 *)__LC_SYNC_IO_WORD  = 1;
-
-				do
-				{
-
-					__load_psw( io_sync_wait );
-cio_wakeup:
-				   io_parm = *(__u32 *)__LC_IO_INT_PARM;
-				   io_sub  = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
-				   ready = s390_process_IRQ( io_sub );
-
-				} while ( !((io_sub == irq) && (ready == 1)) );
-
-				*(__u32 *)__LC_SYNC_IO_WORD = 0;
-
-			} /* endif */
-
-			ret = 0;
-			break;
-
-		case 1 :            /* no status pending for csh */
-			BUG();
-			break;
-
-
-		case 2 :            /* no busy for csh*/
-			BUG();
-			break;
-
-		default:            /* device not operational */
-
-			ret = -ENODEV;
-			break;
-
-		} /* endswitch */
-
-		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
-		{
-			disable_cpu_sync_isc( irq );
-
-		} /* endif */
-
-	} /* endif */
-
-	return( ret );
-}
-
-
-/*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- *          SMP cross-CPU interrupts have their own specific
- *          handlers).
- *
- */
-asmlinkage void do_IRQ( struct pt_regs regs )
-{
-	/*
-	 * Get interrupt info from lowcore
-	 */
-	volatile tpi_info_t *tpi_info = (tpi_info_t*)(__LC_SUBCHANNEL_ID);
-	int cpu = smp_processor_id();
-
-	/*
-	 * take fast exit if CPU is in sync. I/O state
-	 *
-	 * Note: we have to turn off the WAIT bit and re-disable
-	 *       interrupts prior to return as this was the initial
-	 *       entry condition to synchronous I/O.
-	 */
- 	if (    *(__u32 *)__LC_SYNC_IO_WORD )
-	{
-		regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
-		return;
-	} /* endif */
-
-#ifdef CONFIG_FAST_IRQ
-	do {
-#endif /*  CONFIG_FAST_IRQ */
-		
-		/*
-		 * Non I/O-subchannel thin interrupts are processed differently
-		 */
-		if ( tpi_info->adapter_IO == 1 &&
-		     tpi_info->int_type == IO_INTERRUPT_TYPE )
-		{
-			irq_enter(cpu, -1);
-			do_adapter_IO( tpi_info->intparm );
-			irq_exit(cpu, -1);
-		} 
-		else 
-		{
-			unsigned int irq = tpi_info->irq;
-	
-			/*
-			 * fix me !!!
-			 *
-			 * instead of boxing the device, we need to schedule device
-			 * recognition, the interrupt stays pending. We need to
-			 * dynamically allocate an ioinfo structure, etc..
-			 */
-			if ( ioinfo[irq] == INVALID_STORAGE_AREA )
-			{
-				return;	/* this keeps the device boxed ... */
-			}
-	
-			irq_enter(cpu, irq);
-			s390irq_spin_lock( irq );
-			s390_process_IRQ( irq );
-			s390irq_spin_unlock( irq );
-			irq_exit(cpu, irq);
-		}
-
-#ifdef CONFIG_FAST_IRQ
-
-		/*
-		 * Are more interrupts pending?
-		 * If so, the tpi instruction will update the lowcore 
-		 * to hold the info for the next interrupt.
-		 */
-	} while ( tpi( NULL ) != 0 );
-
-#endif /*  CONFIG_FAST_IRQ */
-
-	return;
-}
-
-
-/*
- * s390_process_IRQ() handles status pending situations and interrupts
- *
- * Called by : do_IRQ()             - for "real" interrupts
- *             s390_start_IO, halt_IO()
- *                                  - status pending cond. after SSCH, or HSCH
- *             disable_subchannel() - status pending conditions (after MSCH)
- *
- * Returns: 0 - no ending status received, no further action taken
- *          1 - interrupt handler was called with ending status
- */
-int s390_process_IRQ( unsigned int irq )
-{
-	int                    ccode;      /* cond code from tsch() operation */
-	int                    irb_cc;     /* cond code from irb */
-	int                    sdevstat;   /* struct devstat size to copy */
-	unsigned int           fctl;       /* function control */
-	unsigned int           stctl;      /* status   control */
-	unsigned int           actl;       /* activity control */
-
-	int               issense         = 0;
-	int               ending_status   = 0;
-	int               allow4handler   = 1;
-	int               chnchk          = 0;
-	devstat_t        *dp;
-	devstat_t        *udp;
-
-	char dbf_txt[15];
-	char buffer[80];
-
-
-	if (cio_count_irqs) {
-		int cpu = smp_processor_id();
-		s390_irq_count[cpu]++;
-	}
-	
-	
-
-	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 ... */
-		tsch( irq, p_init_irb );
-		return( 1 );
-
-	} /* endif */
-
-	dp  = &ioinfo[irq]->devstat;
-	udp = ioinfo[irq]->irq_desc.dev_id;
-	
-
-	/*
-	 * It might be possible that a device was not-oper. at the time
-	 *  of free_irq() processing. This means the handler is no longer
-	 *  available when the device possibly becomes ready again. In
-	 *  this case we perform delayed disable_subchannel() processing.
-	 */
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		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 */
-
-	/*
-	 * retrieve the i/o interrupt information (irb),
-	 *  update the device specific status information
-	 *  and possibly call the interrupt handler.
-	 *
-	 * Note 1: At this time we don't process the resulting
-	 *         condition code (ccode) from tsch(), although
-	 *         we probably should.
-	 *
-	 * Note 2: Here we will have to check for channel
-	 *         check conditions and call a channel check
-	 *         handler.
-	 *
-	 * Note 3: If a start function was issued, the interruption
-	 *         parameter relates to it. If a halt function was
-	 *         issued for an idle device, the intparm must not
-	 *         be taken from lowcore, but from the devstat area.
-	 */
-	ccode = tsch( irq, &(dp->ii.irb) );
-
-	//
-	// We must only accumulate the status if the device is busy already
-	//
-	if ( ioinfo[irq]->ui.flags.busy )
-	{
-		dp->dstat   |= dp->ii.irb.scsw.dstat;
-		dp->cstat   |= dp->ii.irb.scsw.cstat;
-                dp->intparm  = ioinfo[irq]->u_intparm;
-
-	}
-	else
-	{
-		dp->dstat    = dp->ii.irb.scsw.dstat;
-		dp->cstat    = dp->ii.irb.scsw.cstat;
-
-		dp->flag     = 0;   // reset status flags
-		dp->intparm  = 0;
-
-	} /* endif */
-
-	dp->lpum = dp->ii.irb.esw.esw1.lpum;
-
-	/*
-	 * reset device-busy bit if no longer set in irb
-	 */
-	if (    (dp->dstat & DEV_STAT_BUSY                   ) 
-	     && ((dp->ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
-	{
-		dp->dstat &= ~DEV_STAT_BUSY;
-
-	} /* endif */
-
-	/*
-	 * Save residual count and CCW information in case primary and
-	 *  secondary status are presented with different interrupts.
-	 */
-	if ( dp->ii.irb.scsw.stctl
-	     & ( SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_INTER_STATUS ) ) {
-
-		/*
-		 * If the subchannel status shows status pending
-		 * and we received a check condition, the count
-		 * information is not meaningful.
-		 */
-		
-		 if ( !(    (dp->ii.irb.scsw.stctl & SCSW_STCTL_STATUS_PEND) 
-			 && (   dp->ii.irb.scsw.cstat 
-			      & (   SCHN_STAT_CHN_DATA_CHK
-				  | SCHN_STAT_CHN_CTRL_CHK
-				  | SCHN_STAT_INTF_CTRL_CHK
-				  | SCHN_STAT_PROG_CHECK
-				  | SCHN_STAT_PROT_CHECK
-				  | SCHN_STAT_CHAIN_CHECK )))) {
-
-			 dp->rescnt = dp->ii.irb.scsw.count;
-		 } else {
-			 dp->rescnt = SENSE_MAX_COUNT;
-		 }
-
-		dp->cpa    = dp->ii.irb.scsw.cpa;
-
-#ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( "s390_process_IRQ( %04X ) : "
-			        "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 */
-
-	irb_cc = dp->ii.irb.scsw.cc;
-
-	//
-	// check for any kind of channel or interface control check but don't
-	//  issue the message for the console device
-	//
-	if (    (dp->ii.irb.scsw.cstat
-	            & (  SCHN_STAT_CHN_DATA_CHK
-	               | SCHN_STAT_CHN_CTRL_CHK
-			 | SCHN_STAT_INTF_CTRL_CHK )))
-	{
-		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;
-
-	} /* endif */
-
-	if( dp->ii.irb.scsw.ectl==0)
-	{
-		issense=0;
-	}
-	else if (    (dp->ii.irb.scsw.stctl == SCSW_STCTL_STATUS_PEND)
-	          && (dp->ii.irb.scsw.eswf  == 0                     ))
-	{
-		issense = 0;
-	}
-	else if (   (dp->ii.irb.scsw.stctl ==
-		      (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_INTER_STATUS)) 
-		 && ((dp->ii.irb.scsw.actl & SCSW_ACTL_SUSPENDED) == 0)  )
-	{
-		issense = 0;
-	}
-	else
-	{
-		issense = dp->ii.irb.esw.esw0.erw.cons;
-
-	} /* endif */
-
-	if ( issense )
-	{
-		dp->scnt  = dp->ii.irb.esw.esw0.erw.scnt;
-		dp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
-                  	
-		sdevstat = sizeof( devstat_t);
-
-#ifdef CONFIG_DEBUG_IO
-		if ( irq != cons_dev )
-			printk( "s390_process_IRQ( %04X ) : "
-			        "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
-	{
-		/* don't copy the sense data area ! */
-		sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
-
-	} /* endif */
-
-	switch ( irb_cc ) {
-	case 1:      /* status pending */
-
-		dp->flag |= DEVSTAT_STATUS_PENDING;
-
-	case 0:      /* normal i/o interruption */
-
-		fctl  = dp->ii.irb.scsw.fctl;
-		stctl = dp->ii.irb.scsw.stctl;
-		actl  = dp->ii.irb.scsw.actl;
-
-		if ( chnchk )
-		{
-			sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
-			         "device %04X after channel check\n",
-			         irq,
-			         dp->devno );
-
-			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;
-
-		ending_status =    ( stctl & SCSW_STCTL_SEC_STATUS                          )
-			|| ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)         )
-			|| ( (fctl == SCSW_FCTL_HALT_FUNC)  && (stctl == SCSW_STCTL_STATUS_PEND) )
-			|| ( (fctl == SCSW_FCTL_CLEAR_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
-
-		/*
-		 * Check for unsolicited interrupts - for debug purposes only
-		 *
-		 * We only consider an interrupt as unsolicited, if the device was not
-		 *  actively in use (busy) and an interrupt other than an ALERT status
-		 *  was received.
-		 *
-		 * Note: We must not issue a message to the console, if the
-		 *       unsolicited interrupt applies to the console device
-		 *       itself !
-		 */
-		if (    !( stctl & SCSW_STCTL_ALERT_STATUS )
-		     &&  ( ioinfo[irq]->ui.flags.busy == 0 ) )
-		{
-#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,
-			         dp->devno,
-			         ending_status);
-
-			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 */
-
-		/*
-		 * take fast exit if no handler is available
-		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
-
-		/*
-		 * Check whether we must issue a SENSE CCW ourselves if there is no
-		 *  concurrent sense facility installed for the subchannel.
-		 *
-		 * Note: We should check for ioinfo[irq]->ui.flags.consns but VM
-		 *       violates the ESA/390 architecture and doesn't present an
-		 *       operand exception for virtual devices without concurrent
-		 *       sense facility available/supported when enabling the
-		 *       concurrent sense facility.
-		 */
-		if (    (    (dp->ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK )
-		          && (!issense                                    ) )
-		     || (ioinfo[irq]->ui.flags.delsense && ending_status    ) )
-		{
-			int            ret_io;
-			ccw1_t        *s_ccw  = &ioinfo[irq]->senseccw;
-			unsigned long  s_flag = 0;
-
-			if ( ending_status )
-			{
-				/*
-				 * We copy the current status information into the device driver
-				 *  status area. Then we can use the local devstat area for device
-				 *  sensing. When finally calling the IRQ handler we must not overlay
-				 *  the original device status but copy the sense data only.
-				 */
-				memcpy( udp, dp, sizeof( devstat_t) );
-
-				s_ccw->cmd_code = CCW_CMD_BASIC_SENSE;
-				s_ccw->cda      = (__u32)virt_to_phys( ioinfo[irq]->sense_data );
-				s_ccw->count    = SENSE_MAX_COUNT;
-				s_ccw->flags    = CCW_FLAG_SLI;
-
-				/*
-				 * If free_irq() or a sync do_IO/s390_start_IO() is in
-				 *  process we have to sense synchronously
-				 */
-				if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio )
-				{
-					s_flag = DOIO_WAIT_FOR_INTERRUPT;
-
-				} /* endif */
-
-				/*
-				 * Reset status info
-				 *
-				 * It does not matter whether this is a sync. or async.
-				 *  SENSE request, but we have to assure we don't call
-				 *  the irq handler now, but keep the irq in busy state.
-				 *  In sync. mode s390_process_IRQ() is called recursively,
-				 *  while in async. mode we re-enter do_IRQ() with the
-				 *  next interrupt.
-				 *
-				 * Note : this may be a delayed sense request !
-				 */
-				allow4handler                  = 0;
-
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
-				ioinfo[irq]->ui.flags.delsense = 0;
-
-				dp->cstat     = 0;
-				dp->dstat     = 0;
-				dp->rescnt    = SENSE_MAX_COUNT;
-
-				ioinfo[irq]->ui.flags.w4sense  = 1;
-			
-				ret_io = s390_start_IO( irq,
-				                        s_ccw,
-				                        0xE2C5D5E2,  // = SENSe
-				                        0,           // n/a
-				                        s_flag);
-			}
-			else
-			{
-				/*
-				 * we received an Unit Check but we have no final
-				 *  status yet, therefore we must delay the SENSE
-				 *  processing. However, we must not report this
-				 *  intermediate status to the device interrupt
-				 *  handler.
-				 */
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-
-				ioinfo[irq]->ui.flags.delsense = 1;
-				allow4handler                  = 0;
-
-			} /* endif */
-
-		} /* endif */
-
-		/*
-		 * we allow for the device action handler if .
-		 *  - we received ending status
-		 *  - the action handler requested to see all interrupts
-		 *  - we received an intermediate status
-		 *  - fast notification was requested (primary status)
-		 *  - unsollicited interrupts
-		 *
-		 */
-		if ( allow4handler )
-		{
-			allow4handler =    ending_status
-				|| ( ioinfo[irq]->ui.flags.repall                                      )
-				|| ( stctl & SCSW_STCTL_INTER_STATUS                                   )
-				|| ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) )
-				|| ( ioinfo[irq]->ui.flags.oper == 0                                   );
-
-		} /* endif */
-
-		/*
-		 * We used to copy the device status information right before
-		 *  calling the device action handler. However, in status
-		 *  pending situations during do_IO() or halt_IO(), as well as
-		 *  enable_subchannel/disable_subchannel processing we must
-		 *  synchronously return the status information and must not
-		 *  call the device action handler.
-		 *
-		 */
-		if ( allow4handler )
-		{
-			/*
-			 * if we were waiting for sense data we copy the sense
-			 *  bytes only as the original status information was
-			 *  saved prior to sense already.
-			 */
-			if ( ioinfo[irq]->ui.flags.w4sense )
-			{
-				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 (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;
-
-				if ( sense_count >= 0 )
-				{
-					memcpy( udp->ii.sense.data,
-					        ioinfo[irq]->sense_data,
-					        sense_count);
-				}
-				else
-				{
-					panic( "s390_process_IRQ(%04x) encountered "
-					       "negative sense count\n",
-					       irq);
-
-				} /* endif */
-			}
-			else
-			{
-				memcpy( udp, dp, sdevstat );
-
-			}  /* endif */
-
-		} /* endif */
-
-		/*
-		 * for status pending situations other than deferred interrupt
-		 *  conditions detected by s390_process_IRQ() itself we must not
-		 *  call the handler. This will synchronously be reported back
-		 *  to the caller instead, e.g. when detected during do_IO().
-		 */
-		if (    ioinfo[irq]->ui.flags.s_pend
-		     || ioinfo[irq]->ui.flags.unready
-		     || ioinfo[irq]->ui.flags.repnone )
-		{		
-			if ( ending_status )
-			{
-
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
-
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
-				udp->flag |= DEVSTAT_FINAL_STATUS;
-
-			} /* endif */
-
-			allow4handler = 0;
-
-		} /* endif */
-
-		/*
-		 * Call device action handler if applicable
-		 */
-		if ( allow4handler )
-		{
-
-			/*
-			 *  We only reset the busy condition when we are sure that no further
-			 *   interrupt is pending for the current I/O request (ending_status).
-			 */
-			if ( ending_status || !ioinfo[irq]->ui.flags.oper )
-			{
-				ioinfo[irq]->ui.flags.oper     = 1;  /* dev IS oper */
-
-				ioinfo[irq]->ui.flags.busy     = 0;
-				ioinfo[irq]->ui.flags.doio     = 0;
-				ioinfo[irq]->ui.flags.haltio   = 0;
-				ioinfo[irq]->ui.flags.fast     = 0;
-				ioinfo[irq]->ui.flags.repall   = 0;
-				ioinfo[irq]->ui.flags.w4final  = 0;
-
-				dp->flag  |= DEVSTAT_FINAL_STATUS;
-				udp->flag |= DEVSTAT_FINAL_STATUS;
-
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
-
-				//
-				// reset intparm after final status or we will badly present unsolicited
-				//  interrupts with a intparm value possibly no longer valid.
-				//
-				dp->intparm   = 0;
-
-				//
-				// Was there anything queued ? Start the pending channel program
-				//  if there is one.
-				//
-				if ( ioinfo[irq]->ui.flags.doio_q )
-				{
-					int ret;
-
-					ret = s390_start_IO( irq,
-					                     ioinfo[irq]->qcpa,
-					                     ioinfo[irq]->qintparm,
-						             ioinfo[irq]->qlpm,
-					                     ioinfo[irq]->qflag);
-
-					ioinfo[irq]->ui.flags.doio_q = 0;
-
-					/*
-					 * If s390_start_IO() failed call the device's interrupt
-					 *  handler, the IRQ related devstat area was setup by
-					 *  s390_start_IO() accordingly already (status pending
-					 *  condition).
-					 */
-					if ( ret )
-					{
-						ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
-
-					} /* endif */
-
-				} /* endif */
-
-			}
-			else
-			{
-				ioinfo[irq]->ui.flags.w4final = 1;
-
-				/*
-				 * Eventually reset subchannel PCI status and
-				 *  set the PCI or SUSPENDED flag in the user
-				 *  device status block if appropriate.
-				 */
-				if ( dp->cstat & SCHN_STAT_PCI )
-				{
-					udp->flag |= DEVSTAT_PCI;
-					dp->cstat &= ~SCHN_STAT_PCI;
-				}
-
-				if ( actl & SCSW_ACTL_SUSPENDED )
-				{
-					udp->flag |= DEVSTAT_SUSPENDED;
-
-				} /* endif */
-
-				ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
-
-			} /* endif */
-
-		} /* endif */
-
-		break;
-
-	case 3:      /* device/path not operational */
-
-		ioinfo[irq]->ui.flags.busy    = 0;
-		ioinfo[irq]->ui.flags.doio    = 0;
-		ioinfo[irq]->ui.flags.haltio  = 0;
-
-		dp->cstat    = 0;
-		dp->dstat    = 0;
-
-		if ( ioinfo[irq]->ulpm != ioinfo[irq]->opm )
-		{
-			/*
-			 * either it was the only path or it was restricted ...
-			 */
-			ioinfo[irq]->opm &= ~(ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum);
-		}
-		else
-		{
-			ioinfo[irq]->opm = 0;
-
-		} /* endif */
-	
-		if ( ioinfo[irq]->opm == 0 ) 	
-		{
-			ioinfo[irq]->ui.flags.oper  = 0;
-
-		} /* endif */
-
-		ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
-		/*
-		 * When we find a device "not oper" we save the status
-		 *  information into the device status area and call the
-		 *  device specific interrupt handler.
-		 *
-		 * Note: currently we don't have any way to reenable
-		 *       the device unless an unsolicited interrupt
-		 *       is presented. We don't check for spurious
-		 *       interrupts on "not oper" conditions.
-		 */
-
-		if (    ( ioinfo[irq]->ui.flags.fast    )
-		     && ( ioinfo[irq]->ui.flags.w4final ) )
-		{
-			/*
-			 * If a new request was queued already, we have
-			 *  to simulate the "not oper" status for the
-			 *  queued request by switching the "intparm" value
-			 *  and notify the interrupt handler.
-			 */
-			if ( ioinfo[irq]->ui.flags.doio_q )
-			{
-				ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm;
-
-			} /* endif */
-
-		} /* endif */
-
-		ioinfo[irq]->ui.flags.fast    = 0;
-		ioinfo[irq]->ui.flags.repall  = 0;
-		ioinfo[irq]->ui.flags.w4final = 0;
-
-		/*
-		 * take fast exit if no handler is available
-		 */
-		if ( !ioinfo[irq]->ui.flags.ready )
-			return( ending_status );     		
-
-		memcpy( udp, &(ioinfo[irq]->devstat), sdevstat );
-
-		ioinfo[irq]->devstat.intparm  = 0;
-
-		if ( !ioinfo[irq]->ui.flags.s_pend )
-		{
-			ioinfo[irq]->irq_desc.handler( irq, udp, NULL );
-
-		} /* endif */
-
-		ending_status    = 1;
-
-		break;
-
-	} /* endswitch */
-
-	return( ending_status );
-}
-
-/*
- * Set the special i/o-interruption sublass 7 for the
- *  device specified by parameter irq. There can only
- *  be a single device been operated on this special
- *  isc. This function is aimed being able to check
- *  on special device interrupts in disabled state,
- *  without having to delay I/O processing (by queueing)
- *  for non-console devices.
- *
- * Setting of this isc is done by set_cons_dev(), while
- *  reset_cons_dev() resets this isc and re-enables the
- *  default isc3 for this device. wait_cons_dev() allows
- *  to actively wait on an interrupt for this device in
- *  disabed state. When the interrupt condition is
- *  encountered, wait_cons_dev(9 calls do_IRQ() to have
- *  the console device driver processing the interrupt.
- */
-int set_cons_dev( int irq )
-{
-	int           ccode;
-	unsigned long cr6 __attribute__ ((aligned (8)));
-	int           rc = 0;
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	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
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
-			ioinfo[irq]->schib.pmcw.isc = 7;
-
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
-
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = irq;
-
-				/*
-				 * enable console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 |= 0x01000000;
-				__ctl_load( cr6, 6, 6);
-
-			} /* endif */
-
-		} /* endif */
-
-	} /* endif */
-
-	return( rc);
-}
-
-int reset_cons_dev( int irq)
-{
-	int     rc = 0;
-	int     ccode;
-	long    cr6 __attribute__ ((aligned (8)));
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	if ( cons_dev != -1  )
-	{
-		rc = -EBUSY;
-	}
-	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
-		 */
-		ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
-		if (ccode)
-		{
-			rc                         = -ENODEV;
-			ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-		}
-		else
-		{
-
-			ioinfo[irq]->schib.pmcw.isc = 3;
-
-			ccode = msch( irq, &(ioinfo[irq]->schib) );
-
-			if (ccode)
-			{
-				rc = -EIO;
-			}
-			else
-			{
-				cons_dev = -1;
-
-				/*
-				 * disable special console I/O-interrupt sublass 7
-				 */
-				__ctl_store( cr6, 6, 6);
-				cr6 &= 0xFEFFFFFF;
-				__ctl_load( cr6, 6, 6);
-
-			} /* endif */
-
-		} /* endif */
-
-	} /* endif */
-
-	return( rc);
-}
-
-int wait_cons_dev( int irq )
-{
-	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 ...
-		 */
-		if ( ioinfo[irq]->ui.flags.busy == 1 )
-		{
-			long cr6 __attribute__ ((aligned (8)));
-
-			/*
-			 * disable all, but isc 7 (console device)
-			 */
-			__ctl_store( cr6, 6, 6);
-			save_cr6  = cr6;
-			cr6      &= 0x01FFFFFF;
-			__ctl_load( cr6, 6, 6);
-
-			do {
-				tpi_info_t tpi_info = {0,};
-				if (tpi(&tpi_info) == 1) {
-					s390_process_IRQ( tpi_info.irq );
-				} else {
-					s390irq_spin_unlock(irq);
-					udelay(100);
-					s390irq_spin_lock(irq);
-				}
-				eieio();
-			} while (ioinfo[irq]->ui.flags.busy == 1);
-
-			/*
-			 * restore previous isc value
-			 */
-			cr6 = save_cr6;
-			__ctl_load( cr6, 6, 6);
-
-		} /* endif */
-
-	}
-	else
-	{
-		rc = EINVAL;
-
-	} /* endif */
-
-
-	return(rc);
-}
-
-
-int enable_cpu_sync_isc( int irq )
-{
-	int             ccode;
-	long            cr6 __attribute__ ((aligned (8)));
-
-	int             retry = 3;
-	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 */
-
-	if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( atomic_read( &sync_isc ) != irq )
-			atomic_compare_and_swap_spin( -1, irq, &sync_isc );
-
-		sync_isc_cnt++;
-		
-		if ( sync_isc_cnt > 255 ) /* fixme : magic number */
-		{
-			panic("Too many recursive calls to enable_sync_isc");
-
-		}
-		/*
-		 * we only run the STSCH/MSCH path for the first enablement
-		 */
-		else if ( sync_isc_cnt == 1 )
-		{
-			ioinfo[irq]->ui.flags.syncio = 1;
-
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
-			if ( !ccode )
-			{
-				ioinfo[irq]->schib.pmcw.isc = 5;
-
-				do
-				{
-					ccode = msch( irq,
-					              &(ioinfo[irq]->schib) );
-
-					switch (ccode) {
-					case 0: 
-						/*
-						 * enable special isc
-						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 |= 0x04000000;  // enable sync isc 5
-						cr6 &= 0xEFFFFFFF;  // disable standard isc 3
-						__ctl_load( cr6, 6, 6);
-						retry = 0;
-						break;
-					
-					case 1:
-						//
-						// process pending status
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						
-						rc = -EIO;  /* might be overwritten... */
-						retry--;
-						break;
-
-					case 2: /* busy */
-						retry = 0;
-						rc = -EBUSY; 
-						break;
-
-					case 3: /* not oper*/
-						retry = 0;
-						rc = -ENODEV; 
-						break;
-					
-					}
-
-				} while ( retry );
-
-			}
-			else
-			{
-				rc = -ENODEV;     // device is not-operational
-
-			} /* endif */
-
-		} /* endif */
-
-
-		if ( rc )	/* can only happen if stsch/msch fails */
-		{
-			sync_isc_cnt = 0;
-			atomic_set( &sync_isc, -1);
-		}
-	}
-	else
-	{
-#ifdef CONFIG_SYNC_ISC_PARANOIA
-		panic( "enable_sync_isc: called with invalid %x\n", irq );
-#endif
-
-		rc = -EINVAL;
-
-	} /* endif */
-
-	return( rc);
-}
-
-int disable_cpu_sync_isc( int irq)
-{
-	int     rc         = 0;
-	int     retry1     = 5;
-	int     retry2     = 5;
-	int     clear_pend = 0;
-
-	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 )
-	{
-		/*
-		 * We disable if we're the top user only, as we may
-		 *  run recursively ...	
-		 * We must not decrease the count immediately; during
-		 *  msch() processing we may face another pending
-		 *  status we have to process recursively (sync).
-		 */
-
-#ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != irq )
-			panic( "disable_sync_isc: called for %x while %x locked\n",
-				irq, atomic_read( &sync_isc ) );
-#endif
-
-		if ( sync_isc_cnt == 1 )
-		{
-			ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
-			ioinfo[irq]->schib.pmcw.isc = 3;
-
-			do
-			{
-			        retry2 = 5;
-				do
-				{
-					ccode = msch( irq, &(ioinfo[irq]->schib) );
-
-					switch ( ccode ) {
-					case 0:
-						/*
-						 * disable special interrupt subclass in CPU
-						 */
-						__ctl_store( cr6, 6, 6);
-						cr6 &= 0xFBFFFFFF; // disable sync isc 5
-						cr6 |= 0x10000000; // enable standard isc 3
-						__ctl_load( cr6, 6, 6);
-
-						retry2 = 0;
-						break;
-
-					case 1: /* status pending */
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq );
-						ioinfo[irq]->ui.flags.s_pend = 0;
-
-						retry2--;
-						break;
-
-					case 2: /* busy */
-					        retry2--;
-						udelay( 100); // give it time
-						break;
-						
-					default: /* not oper */
-						retry2 = 0;
-						break;
-					} /* endswitch */
-
-				} while ( retry2 );
-
-				retry1--;
-
-				/* try stopping it ... */
-				if ( (ccode) && !clear_pend )
-				{
-					clear_IO( irq, 0x00004711, 0 );
-					clear_pend = 1;
-               	
-				} /* endif */
-
-				udelay( 100);
-
-			} while ( retry1 && ccode );
-
-			ioinfo[irq]->ui.flags.syncio = 0;
-		
-			sync_isc_cnt = 0;	
-			atomic_set( &sync_isc, -1);
-
-		}
-		else
-		{
-			sync_isc_cnt--;
-
-		} /* endif */
-	}
-	else
-	{
-#ifdef CONFIG_SYNC_ISC_PARANOIA
-		if ( atomic_read( &sync_isc ) != -1 )
-			panic( "disable_sync_isc: called with invalid %x while %x locked\n", 
-				irq, atomic_read( &sync_isc ) );
-#endif
-
-		rc = -EINVAL;
-
-	} /* endif */
-
-	return( rc);
-}
-
-//
-// Input :
-//   devno - device number
-//   ps    - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16      devno,
-                             senseid_t *ps )
-{
-	diag210_t  *p_diag_data;
-	int        ccode;
-
-	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 );
-	}
-	else
-	{
-		p_diag_data = alloc_bootmem_low( sizeof( diag210_t));
-
-	} /* endif */
-
-	p_diag_data->vrdcdvno = devno;
-	p_diag_data->vrdclen  = sizeof( diag210_t);
-	ccode                 = diag210( (diag210_t *)virt_to_phys( p_diag_data ) );
-	ps->reserved          = 0xff;
-
-	switch (p_diag_data->vrdcvcla) {
-	case 0x80:
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 00:
-
-			ps->cu_type   = 0x3215;
-
-			break;
-
-		default:
-
-			error = 1;
-
-			break;
-
-		} /* endswitch */
-
-		break;
-
-	case 0x40:
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 0xC0:
-
-			ps->cu_type   = 0x5080;
-
-			break;
-
-		case 0x80:
-
-			ps->cu_type   = 0x2250;
-
-			break;
-
-		case 0x04:
-
-			ps->cu_type   = 0x3277;
-
-			break;
-
-		case 0x01:
-
-			ps->cu_type   = 0x3278;
-
-			break;
-
-		default:
-
-			error = 1;
-
-			break;
-
-		} /* endswitch */
-
-		break;
-
-	case 0x20:
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 0x84:
-
-			ps->cu_type   = 0x3505;
-
-			break;
-
-		case 0x82:
-
-			ps->cu_type   = 0x2540;
-
-			break;
-
-		case 0x81:
-
-			ps->cu_type   = 0x2501;
-
-			break;
-
-		default:
-
-			error = 1;
-
-			break;
-
-		} /* endswitch */
-
-		break;
-
-	case 0x10:
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 0x84:
-
-			ps->cu_type   = 0x3525;
-
-			break;
-
-		case 0x82:
-
-			ps->cu_type   = 0x2540;
-
-			break;
-
-		case 0x4F:
-		case 0x4E:
-		case 0x48:
-
-			ps->cu_type   = 0x3820;
-
-			break;
-
-		case 0x4D:
-		case 0x49:
-		case 0x45:
-
-			ps->cu_type   = 0x3800;
-
-			break;
-
-		case 0x4B:
-
-			ps->cu_type   = 0x4248;
-
-			break;
-
-		case 0x4A:
-
-			ps->cu_type   = 0x4245;
-
-			break;
-
-		case 0x47:
-
-			ps->cu_type   = 0x3262;
-
-			break;
-
-		case 0x43:
-
-			ps->cu_type   = 0x3203;
-
-			break;
-
-		case 0x42:
-
-			ps->cu_type   = 0x3211;
-
-			break;
-
-		case 0x41:
-
-			ps->cu_type   = 0x1403;
-
-			break;
-
-		default:
-
-			error = 1;
-
-			break;
-
-		} /* endswitch */
-
-		break;
-
-	case 0x08:
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 0x82:
-
-			ps->cu_type   = 0x3422;
-
-			break;
-
-		case 0x81:
-
-			ps->cu_type   = 0x3490;
-
-			break;
-
-		case 0x10:
-
-			ps->cu_type   = 0x3420;
-
-			break;
-
-		case 0x02:
-
-			ps->cu_type   = 0x3430;
-
-			break;
-
-		case 0x01:
-
-			ps->cu_type   = 0x3480;
-
-			break;
-
-		case 0x42:
-
-			ps->cu_type   = 0x3424;
-
-			break;
-
-		case 0x44:
-
-			ps->cu_type   = 0x9348;
-
-			break;
-
-		default:
-
-			error = 1;
-
-			break;
-
-		} /* endswitch */
-
-		break;
-
-	case 02: /* special device class ... */
-
-		switch (p_diag_data->vrdcvtyp) {
-		case 0x20: /* OSA */
-
-			ps->cu_type   = 0x3088;
-			ps->cu_model  = 0x60;
-
-			break;
-
-		default:
-
-			error = 1;
-      	break;
-
-		} /* endswitch */
-
-		break;
-
-	default:
-
-		error = 1;
-
-		break;
-
-	} /* endswitch */
-
-	if ( init_IRQ_complete )
-	{
-		kfree( p_diag_data );
-	}
-	else
-	{
-		free_bootmem( (unsigned long)p_diag_data, sizeof( diag210_t) );
-
-	} /* endif */
-
-	if ( error )
-	{
-		printk( "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 );
-		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 */
-
-}
-
-/*
- * This routine returns the characteristics for the device
- *  specified. Some old devices might not provide the necessary
- *  command code information during SenseID processing. In this
- *  case the function returns -EINVAL. Otherwise the function
- *  allocates a decice specific data buffer and provides the
- *  device characteristics together with the buffer size. Its
- *  the callers responability to release the kernel memory if
- *  not longer needed. In case of persistent I/O problems -EBUSY
- *  is returned.
- *
- *  The function may be called enabled or disabled. However, the
- *   caller must have locked the irq it is requesting data for.
- *
- * Note : It would have been nice to collect this information
- *         during init_IRQ() processing but this is not possible
- *
- *         a) without statically pre-allocation fixed size buffers
- *            as virtual memory management isn't available yet.
- *
- *         b) without unnecessarily increase system startup by
- *            evaluating devices eventually not used at all.
- */
-int read_dev_chars( int irq, void **buffer, int length )
-{
-	unsigned int  flags;
-	ccw1_t       *rdc_ccw;
-	devstat_t     devstat;
-	char         *rdc_buf;
-	int           devflag = 0;
-
-	int           ret      = 0;
-	int           emulated = 0;
-	int           retry    = 5;
-
-	char dbf_txt[15];
-
-	if ( !buffer || !length )
-	{
-		return( -EINVAL );
-
-	} /* endif */
-
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* 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
-	 *   also require to run disabled.
-	 *
-	 * Note : as no global lock is required, we must not use
-	 *        cli(), but __cli() instead.  	
-	 */
-	__save_flags(flags);
-	__cli();
-
-	rdc_ccw = &ioinfo[irq]->senseccw;
-
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		ret = request_irq( irq,
-		                   init_IRQ_handler,
-		                   SA_PROBE, "RDC", &devstat );
-
-		if ( !ret )
-		{
-			emulated = 1;
-
-		} /* endif */
-
-	} /* endif */
-
-	if ( !ret )
-	{
-		if ( ! *buffer )
-		{
-			rdc_buf  = kmalloc( length, GFP_KERNEL);
-		}
-		else
-		{
-			rdc_buf = *buffer;
-
-		} /* endif */
-
-		if ( !rdc_buf )
-		{
-			ret = -ENOMEM;
-		}
-		else
-		{
-			do
-			{
-				rdc_ccw->cmd_code = CCW_CMD_RDC;
-				rdc_ccw->count    = length;
-				rdc_ccw->flags    = CCW_FLAG_SLI;
-				ret = set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
-				if (!ret) {
-
-					memset( ioinfo[irq]->irq_desc.dev_id,
-						'\0',
-						sizeof( devstat_t));
-
-					ret = s390_start_IO( irq,
-							     rdc_ccw,
-							     0x00524443, // RDC
-							     0,          // n/a
-							     DOIO_WAIT_FOR_INTERRUPT
-							     | DOIO_DONT_CALL_INTHDLR );
-					retry--;
-					devflag = ioinfo[irq]->irq_desc.dev_id->flag;   
-					
-					clear_normalized_cda( rdc_ccw);  
-				} else {
-					udelay(100);  //wait for recovery
-					retry--;
-				}
-
-			} while (    ( retry                                     )
-			          && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
-		} /* endif */
-
-		if ( !retry )
-		{
-			ret = (ret==-ENOMEM)?-ENOMEM:-EBUSY;
-
-		} /* endif */
-
-		__restore_flags(flags);
-
-		/*
-		 * on success we update the user input parms
-		 */
-		if ( !ret )
-		{
-			*buffer = rdc_buf;
-
-		} /* endif */
-
-		if ( emulated )
-		{
-			free_irq( irq, &devstat);
-
-		} /* endif */
-
-	} /* endif */
-
-	return( ret );
-}
-
-/*
- *  Read Configuration data
- */
-int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
-{
-	unsigned long flags;
-	int           ciw_cnt;
-
-	int           found  = 0; // RCD CIW found
-	int           ret    = 0; // return code
-
-	char dbf_txt[15];
-
-	SANITY_CHECK(irq);
-
-	if ( !buffer || !length )
-	{
-		return( -EINVAL);
-	}
-	else if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-	}
-	else if ( ioinfo[irq]->ui.flags.esid == 0 )
-	{
-		return( -EOPNOTSUPP );
-
-	} /* 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
-	 */
-	
-	for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
-	{
-		if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
-		{
-			/*
-			 * paranoia check ...
-			 */
-			if ( ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0 )
-			{
-				found = 1;
-
-			} /* endif */
-
-			break;
-
-		} /* endif */
-
-	} /* endfor */
-
-	if ( found )
-	{
-		devstat_t  devstat;  /* inline device status area */
-		devstat_t *pdevstat;
-		int        ioflags;
-
-		ccw1_t    *rcd_ccw  = &ioinfo[irq]->senseccw;
-		char      *rcd_buf  = NULL;
-		int        emulated = 0; /* no i/O handler installed */
-		int        retry    = 5; /* retry count */
-
-		__save_flags(flags);
-		__cli();
-
-		if ( !ioinfo[irq]->ui.flags.ready )
-		{
-			pdevstat = &devstat;
-			ret      = request_irq( irq,
-			                        init_IRQ_handler,
-			                        SA_PROBE, "RCD", pdevstat );
-
-			if ( !ret )
-			{
-				emulated = 1;
-
-			} /* endif */
-		}
-		else
-		{
-			pdevstat = ioinfo[irq]->irq_desc.dev_id;
-
-		} /* endif */
-
-		if ( !ret )
-		{
-			if ( init_IRQ_complete )
-			{
-				rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
-				                   GFP_DMA);
-			}
-			else
-			{
-				rcd_buf = alloc_bootmem_low( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-
-   		} /* endif */
-
-			if ( rcd_buf == NULL )
-			{
-				ret = -ENOMEM;	
-
-			} /* endif */
-
-			if ( !ret )
-			{
-				memset( rcd_buf,
-				        '\0',
-				        ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-       	
-				do
-				{
-					rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
-					rcd_ccw->cda      = (__u32)virt_to_phys( rcd_buf );
-					rcd_ccw->count    = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
-					rcd_ccw->flags    = CCW_FLAG_SLI;
-
-					memset( pdevstat, '\0', sizeof( devstat_t));
-
-					if ( lpm )
-					{
-						ioflags = DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_VALID_LPM    					
-						          | DOIO_DONT_CALL_INTHDLR;
-					}
-					else
-					{
-						ioflags =   DOIO_WAIT_FOR_INTERRUPT
-						          | DOIO_DONT_CALL_INTHDLR;
-						             					
-					} /* endif */
-
-					ret = s390_start_IO( irq,
-					                     rcd_ccw,
-					                     0x00524344,  // == RCD
-					                     lpm,
-					                     ioflags );
-					switch ( ret ) {
-					case 0:
-					case -EIO:
-						
-						if ( !(pdevstat->flag & (   DEVSTAT_STATUS_PENDING
-									    | DEVSTAT_NOT_OPER
-									    | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
-						{
-							retry = 0;  // we got it ...
-						}
-						else
-						{
-							retry--;    // try again ...
-								
-						} /* endif */
-						
-						break;
-
-					default:   // -EBUSY, -ENODEV, ???
-						retry = 0;
-						
-					} /* endswitch */
-					
-				} while ( retry );
-
-			} /* endif */
-
-			__restore_flags( flags );
-
-		} /* endif */
-
-		/*
-		 * on success we update the user input parms
-		 */
-		if ( ret == 0 )
-		{
-			*length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
-			*buffer = rcd_buf;
-		}
-		else
-		{
-			if ( rcd_buf != NULL )
-			{
-				if ( init_IRQ_complete )
-				{
-					kfree( rcd_buf );
-				}
-				else
-				{
-					free_bootmem( (unsigned long)rcd_buf,
-					              ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-
-   			} /* endif */
-
-			} /* endif */
-
-			*buffer = NULL;
-			*length = 0;
-    	
-		} /* endif */
-
-		if ( emulated )
-			free_irq( irq, pdevstat);
-	}
-	else
-	{
-		ret = -EOPNOTSUPP;
-
-	} /* endif */
-
-	return( ret );
-
-}
-
-int get_dev_info( int irq, s390_dev_info_t * pdi)
-{
-	return( get_dev_info_by_irq( irq, pdi));
-}
-
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
-{
-	int ret_val = -ENODEV;
-
-	while ( pi!=NULL ) {
-		if ( pi->ui.flags.oper ) {
-			ret_val = pi->irq;
-			break;
-		} else {
-			pi = pi->next;
-		}
-	}
-
-	return ret_val;
-}
-
-
-int get_irq_first( void )
-{
-   int ret_irq;
-
-	if ( ioinfo_head )
-	{
-		if ( ioinfo_head->ui.flags.oper )
-		{
-			ret_irq = ioinfo_head->irq;
-		}
-		else if ( ioinfo_head->next )
-		{
-			ret_irq = get_next_available_irq( ioinfo_head->next );
-
-		}
-		else
-		{
-			ret_irq = -ENODEV;
-   	
-		} /* endif */
-	}
-	else
-	{
-		ret_irq = -ENODEV;
-
-	} /* endif */
-
-	return ret_irq;
-}
-
-int get_irq_next( int irq )
-{
-	int ret_irq;	
-
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		if ( ioinfo[irq]->next )
-		{
-			if ( ioinfo[irq]->next->ui.flags.oper )
-			{
-				ret_irq = ioinfo[irq]->next->irq;
-			}
-			else
-			{
-				ret_irq = get_next_available_irq( ioinfo[irq]->next );
-
-			} /* endif */
-		}
-		else
-		{
-			ret_irq = -ENODEV;     	
-
-		} /* endif */
-	}
-	else
-	{
-		ret_irq = -EINVAL;
-
-	} /* endif */
-
-	return ret_irq;
-}
-
-int get_dev_info_by_irq( int irq, s390_dev_info_t *pdi)
-{
-
-	SANITY_CHECK(irq);
-
-	if ( pdi == NULL )
-		return -EINVAL;
-
-	pdi->devno = ioinfo[irq]->schib.pmcw.dev;
-	pdi->irq   = irq;
-	
-	if (   ioinfo[irq]->ui.flags.oper
-	    && !ioinfo[irq]->ui.flags.unknown ) 
-	{
-		pdi->status = 0;
-		memcpy( &(pdi->sid_data),
-			&ioinfo[irq]->senseid,
-			sizeof( senseid_t));
-	}
-	else if ( ioinfo[irq]->ui.flags.unknown )
-	{
-		pdi->status = DEVSTAT_UNKNOWN_DEV;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
-		pdi->sid_data.cu_type = 0xFFFF;
-			
-	}
-	else
-	{
-		pdi->status = DEVSTAT_NOT_OPER;
-		memset( &(pdi->sid_data),
-			'\0',
-			sizeof( senseid_t));
-		pdi->sid_data.cu_type = 0xFFFF;
-		
-	} /* endif */
-	
-	if ( ioinfo[irq]->ui.flags.ready )
-		pdi->status |= DEVSTAT_DEVICE_OWNED;
-
-
-	return 0;
-}
-
-
-int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi)
-{
-	int i;
-	int rc = -ENODEV;
-
-	if ( devno > 0x0000ffff )
-		return -ENODEV;
-        if ( pdi == NULL )
-		return -EINVAL;
-
-	for ( i=0; i <= highest_subchannel; i++ ) {
-		
-		if (    ioinfo[i] != INVALID_STORAGE_AREA
-		     && ioinfo[i]->schib.pmcw.dev == devno )
-		{
-			
-			pdi->irq   = i;
-			pdi->devno = devno;
-			
-			if (    ioinfo[i]->ui.flags.oper
-			     && !ioinfo[i]->ui.flags.unknown )
-			{
-				pdi->status = 0;
-				memcpy( &(pdi->sid_data),
-					&ioinfo[i]->senseid,
-					sizeof( senseid_t));
-			}
-			else if ( ioinfo[i]->ui.flags.unknown )
-			{
-				pdi->status = DEVSTAT_UNKNOWN_DEV;
-
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
-
-				pdi->sid_data.cu_type = 0xFFFF;
-			}
-			else
-			{
-				pdi->status = DEVSTAT_NOT_OPER;
-				
-				memset( &(pdi->sid_data),
-					'\0',
-					sizeof( senseid_t));
-
-				pdi->sid_data.cu_type = 0xFFFF;
-
-			} /* endif */
-
-			if ( ioinfo[i]->ui.flags.ready )
-				pdi->status |= DEVSTAT_DEVICE_OWNED;
-
-			rc = 0; /* found */
-			break;
-
-		} /* endif */
-
-	} /* endfor */
-
-	return( rc);
-
-}
-
-int get_irq_by_devno( __u16 devno )
-{
-	int i;
-	int rc = -1;
-
-	if ( devno <= 0x0000ffff )
-	{
-		for ( i=0; i <= highest_subchannel; i++ )
-		{
-			if (    (ioinfo[i] != INVALID_STORAGE_AREA )
-			     && (ioinfo[i]->schib.pmcw.dev == devno)
-			     && (ioinfo[i]->schib.pmcw.dnv == 1    ) )
-			{
-				rc = i;
-				break;
-
-			} /* endif */
-
-		} /* endfor */
-	
-	} /* endif */
-
-	return( rc);
-}
-
-unsigned int get_devno_by_irq( int irq )
-{
-
-	if (    ( irq > highest_subchannel            )
-	     || ( irq < 0                             )
-	     || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
-	{
-		return -1;
-	
-	} /* endif */
-
-	/*
-	 * we don't need to check for the device be operational
-	 *  as the initial STSCH will always present the device
-	 *  number defined by the IOCDS regardless of the device
-	 *  existing or not. However, there could be subchannels
-	 *  defined who's device number isn't valid ...
-	 */
-	if ( ioinfo[irq]->schib.pmcw.dnv )
-		return( ioinfo[irq]->schib.pmcw.dev );
-	else
-		return -1;
-}
-
-/*
- * s390_device_recognition_irq
- *
- * Used for individual device recognition. Issues the device
- *  independant SenseID command to obtain info the device type.
- *
- */
-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
-	 *  operational only.
-	 */
-	if (    ( ioinfo[irq] != INVALID_STORAGE_AREA )	
-	     && ( ioinfo[irq]->schib.pmcw.st == 0     )
-	     && ( ioinfo[irq]->ui.flags.oper == 1     ) )
-	{
-		int       irq_ret;
-		devstat_t devstat;
-
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "INIT",
-		                       &devstat);
-
-		if ( !irq_ret )
-		{
-			ret = enable_cpu_sync_isc( irq );
-
-			if ( !ret ) 
-			{
-				ioinfo[irq]->ui.flags.unknown = 0;
-
-				memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
-
-				s390_SenseID( irq, &ioinfo[irq]->senseid, 0xff );
-#if 0	/* FIXME */
-				/*
-				 * We initially check the configuration data for
-				 *  those devices with more than a single path
-				 */
-				if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-				{
-					char     *prcd;
-					int       lrcd;
-
-					ret = read_conf_data( irq, (void **)&prcd, &lrcd, 0 );
-
-					if ( !ret )	// on success only ...
-					{
-						char buffer[80];
-#ifdef CONFIG_DEBUG_IO
-						sprintf( buffer,
-						         "RCD for device(%04X)/"
-						         "subchannel(%04X) returns :\n",
-						         ioinfo[irq]->schib.pmcw.dev,
-						         irq );
-
-						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 );
-						}
-						else
-						{
-							free_bootmem( (unsigned long)prcd, lrcd );
-
- 			  			} /* endif */
-
-					} /* endif */
-					
-				} /* endif */
-#endif
-
-				disable_cpu_sync_isc( irq );
-
-			} /* endif */  	
-
-			free_irq( irq, &devstat );
-
-		} /* endif */
-		
-	} /* endif */
-
-}
-
-/*
- * s390_device_recognition_all
- *
- * Used for system wide device recognition.
- *
- */
-void s390_device_recognition_all( void)
-{
-	int irq = 0; /* let's start with subchannel 0 ... */
-
-	do
-	{
-		s390_device_recognition_irq( irq );
-
-		irq ++;
-
-	} while ( irq <= highest_subchannel );
-
-}
-
-/*
- * 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 );
-						
-					} 
-				}
-#ifdef CONFIG_PROC_FS
-				if (cio_proc_devinfo) 
-					if (irq < MAX_CIO_PROCFS_ENTRIES) {
-						cio_procfs_device_create(ioinfo[irq]->devno);
-				}
-#endif
-			}
-		}
-		irq++;
-	} while (irq<=highest_subchannel);
-}
-
-/*
- * s390_search_devices
- *
- * Determines all subchannels available to the system.
- *
- */
-void s390_process_subchannels( void)
-{
-	int   ret;
-	int   irq = 0;   /* Evaluate all subchannels starting with 0 ... */
-
-	do
-	{
-		ret = s390_validate_subchannel( irq, 0);
-
-		if ( ret != -ENXIO)
-			irq++;
-	
-  	} while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
-
-	highest_subchannel = (--irq);
-
-	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);	
-}
-
-/*
- * s390_validate_subchannel()
- *
- * Process the subchannel for the requested irq. Returns 1 for valid
- *  subchannels, otherwise 0.
- */
-int s390_validate_subchannel( int irq, int enable )
-{
-
-	int      retry;     /* retry count for status pending conditions */
-	int      ccode;     /* condition code for stsch() only */
-	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)
-	 *  indicates that there aren't any more devices available.
-	 */
-	if (    ( init_IRQ_complete                   )
-	     && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
-	{
-		p_schib = &ioinfo[irq]->schib;
-	}
-	else
-	{
-		p_schib = p_init_schib;
-
-	} /* endif */
-
-	/*
-	 * If we knew the device before we assume the worst case ... 	
-	 */
-	if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-	{
-		ioinfo[irq]->ui.flags.oper = 0;
-		ioinfo[irq]->ui.flags.dval = 0;
-
-	} /* endif */
-
-	ccode = stsch( irq, p_schib);
-
-	if ( !ccode )
-	{
-		/*
-		 * ... just being curious we check for non I/O subchannels
-		 */
-		if ( p_schib->pmcw.st )
-		{
-			printk( "Subchannel %04X reports "
-			        "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;
-
-		} /* endif */
-
-		if ( p_schib->pmcw.dnv )
-		{
-		     if ( is_blacklisted( p_schib->pmcw.dev )) {
-			  /* 
-			   * This device must not be known to Linux. So we simply say that 
-			   * there is no device and return ENODEV.
-			   */
-#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 )
-			{	
-				if ( !init_IRQ_complete )
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)alloc_bootmem_low( sizeof(ioinfo_t));
-				}
-				else
-				{
-					ioinfo[irq] =
-					   (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
-				                           GFP_DMA );
-
-				} /* endif */
-
-				memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
-				memcpy( &ioinfo[irq]->schib,
-			           p_init_schib,
-			           sizeof( schib_t));
-			
-				/*
-				 * We have to insert the new ioinfo element
-				 *  into the linked list, either at its head,
-				 *  its tail or insert it.
-				 */
-				if ( ioinfo_head == NULL )  /* first element */
-				{
-					ioinfo_head = ioinfo[irq];
-					ioinfo_tail = ioinfo[irq];
-				}
-				else if ( irq < ioinfo_head->irq ) /* new head */
-				{
-					ioinfo[irq]->next = ioinfo_head;
-					ioinfo_head->prev = ioinfo[irq];
-					ioinfo_head       = ioinfo[irq];
-				}
-				else if ( irq > ioinfo_tail->irq ) /* new tail */
-				{
-					ioinfo_tail->next = ioinfo[irq];
-					ioinfo[irq]->prev = ioinfo_tail;
-					ioinfo_tail       = ioinfo[irq];
-				}
-				else /* insert element */
-				{
-					ioinfo_t *pi = ioinfo_head;
-
-					for (pi=ioinfo_head; pi!=NULL; pi=pi->next) {
-
-						if ( irq < pi->next->irq )
-						{
-							ioinfo[irq]->next = pi->next;
-							ioinfo[irq]->prev = pi;
-							pi->next->prev    = ioinfo[irq];
-							pi->next          = ioinfo[irq];
-							break;
-						
-						} /* endif */
-					}
-				} /* endif */
-
-			} /* endif */
-
-			// initialize some values ...	
-			ioinfo[irq]->ui.flags.pgid_supp = 1;
-
-			ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-			                   & ioinfo[irq]->schib.pmcw.pam
-			                   & ioinfo[irq]->schib.pmcw.pom;
-
-			if ( cio_show_msg )
-			{
-				printk( KERN_INFO"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);
-
-			} /* 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
-			 */
-			ioinfo[irq]->irq             = irq;
-			if(!ioinfo[irq]->ui.flags.ready)
-			{
-				ioinfo[irq]->nopfunc         = NULL;
-				ioinfo[irq]->ui.flags.busy   = 0;
-				ioinfo[irq]->ui.flags.dval   = 1;
-				ioinfo[irq]->devstat.intparm = 0;
-				
-			}
-			ioinfo[irq]->devstat.devno   = ioinfo[irq]->schib.pmcw.dev;
-			ioinfo[irq]->devno           = ioinfo[irq]->schib.pmcw.dev;
-
-			/*
-			 * We should have at least one CHPID ...
-			 */
-			if ( ioinfo[irq]->opm )
-			{
-				/*
-				 * We now have to initially ...
-				 *  ... set "interruption sublass"
-				 *  ... enable "concurrent sense"
-				 *  ... enable "multipath mode" if more than one
-				 *        CHPID is available. This is done regardless
-				 *        whether multiple paths are available for us.
-				 *
-				 * Note : we don't enable the device here, this is temporarily
-				 *        done during device sensing below.
-				 */
-				ioinfo[irq]->schib.pmcw.isc     = 3; /* could be smth. else */
-				ioinfo[irq]->schib.pmcw.csense  = 1; /* concurrent sense */
-				ioinfo[irq]->schib.pmcw.ena     = enable;
-				ioinfo[irq]->schib.pmcw.intparm =
-				                     ioinfo[irq]->schib.pmcw.dev;
-
-				if (    ( ioinfo[irq]->opm != 0x80 )
-				     && ( ioinfo[irq]->opm != 0x40 )
-				     && ( ioinfo[irq]->opm != 0x20 )
-				     && ( ioinfo[irq]->opm != 0x10 )
-				     && ( ioinfo[irq]->opm != 0x08 )
-				     && ( ioinfo[irq]->opm != 0x04 )
-				     && ( ioinfo[irq]->opm != 0x02 )
-				     && ( ioinfo[irq]->opm != 0x01 ) )
-				{
-					ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
-				} /* endif */
-
-				retry = 5;
-
-				do
-				{
-					ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-					switch (ccode2) {
-					case 0:  // successful completion
-						//
-						// concurrent sense facility available ...
-						//
-						ioinfo[irq]->ui.flags.oper   = 1;
-						ioinfo[irq]->ui.flags.consns = 1;
-						ret                          = 0;
-						break;
-      	
-					case 1:  // status pending
-						//
-						// How can we have a pending status as
-						//  device is disabled for interrupts ?
-						//  Anyway, process it ...
-						//
-						ioinfo[irq]->ui.flags.s_pend = 1;
-						s390_process_IRQ( irq);
-						ioinfo[irq]->ui.flags.s_pend = 0;
-						retry--;
-						ret = -EIO;
-						break;
-   	
-					case 2:  // busy
-						/*
-						 * we mark it not-oper as we can't
-						 *  properly operate it !
-						 */
-						ioinfo[irq]->ui.flags.oper = 0;
-						udelay( 100);	/* allow for recovery */
-						retry--;
-						ret = -EBUSY;
-						break;
-
-					case 3:  // not operational
-						ioinfo[irq]->ui.flags.oper = 0;
-						retry                      = 0;
-						ret = -ENODEV;
-						break;
-
-					default:
-#define PGMCHK_OPERAND_EXC      0x15
-
-						if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
-						{
-							/*
-							 * re-issue the modify subchannel without trying to
-							 *  enable the concurrent sense facility
-							 */
-							ioinfo[irq]->schib.pmcw.csense = 0;
-   	
-							ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
-							if ( ccode2 != 0 )
-							{
-								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;
-							}
-							else
-							{
-								ioinfo[irq]->ui.flags.oper   = 1;
-								ioinfo[irq]->ui.flags.consns = 0;
-								ret                          = 0;
-
-							} /* endif */
-						}
-						else
-						{
-							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;
-
-						} /* endif */
-   	
-						retry  = 0;
-						break;
-
-					} /* endswitch */
-
-				} while ( ccode2 && retry );
-
-				if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
-				{
-					printk( " ... msch() retry count for "
-					        "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 */
-			}
-			else
-			{
-				/* no path available ... */
-				ioinfo[irq]->ui.flags.oper = 0;
-				ret                        = -ENODEV;    	
-
-			} /* endif */
-		     }
-		}
-		else
-		{
-			ret = -ENODEV;
-
-		} /* endif */
-	}
-	else
-	{
-		ret = -ENXIO;
-
-	} /* endif */
-
-	return( ret );
-}
-
-/*
- * s390_SenseID
- *
- * Try to obtain the 'control unit'/'device type' information
- *  associated with the subchannel.
- *
- * The function is primarily meant to be called without irq
- *  action handler in place. However, it also allows for
- *  use with an action handler in place. If there is already
- *  an action handler registered assure it can handle the
- *  s390_SenseID() related device interrupts - interruption
- *  parameter used is 0x00E2C9C4 ( SID ).
- */
-int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
-{
-	ccw1_t    *sense_ccw;     /* ccw area for SenseID command */
-	senseid_t  isid;          /* internal sid */				
-	devstat_t  devstat;       /* required by request_irq() */
-	__u8       pathmask;      /* calulate path mask */
-	__u8       domask;        /* path mask to use */
-	int        inlreq;        /* inline request_irq() */
-	int        irq_ret;       /* return code */
-	devstat_t *pdevstat;      /* ptr to devstat in use */
-	int        retry;         /* retry count */
-	int        io_retry;      /* retry indicator */
-
-	senseid_t *psid     = sid;/* start with the external buffer */	
-	int        sbuffer  = 0;  /* switch SID data buffer */
-
-	char dbf_txt[15];
-
-	int failure = 0;          /* nothing went wrong yet */
-
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* 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);
-	}
-
-	inlreq = 0; /* to make the compiler quiet... */
-
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-
-		pdevstat = &devstat;
-
-		/*
-		 * Perform SENSE ID command processing. We have to request device
-		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
-		 *  requests and evaluate the devstat area on return therefore
-		 *  we don't need a real I/O handler in place.
-		 */
-		irq_ret = request_irq( irq, init_IRQ_handler, SA_PROBE, "SID", &devstat);
-
-		if ( irq_ret == 0 )
-			inlreq = 1;
-	}
-	else
-	{
-		inlreq   = 0;
-		irq_ret  = 0;
-		pdevstat = ioinfo[irq]->irq_desc.dev_id;
-
-  	} /* endif */
-
-	if ( irq_ret == 0 )
-	{
-		int i;
-
-		s390irq_spin_lock( irq);
-
-		if ( init_IRQ_complete )
-		{
-			sense_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			sense_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
-
-		} /* endif */
-
-		// more than one path installed ?
-		if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
-			sense_ccw[0].cda      = 0;
-			sense_ccw[0].count    = 0;
-			sense_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-
-			sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[1].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[1].count    = sizeof( senseid_t);
-			sense_ccw[1].flags    = CCW_FLAG_SLI;
-		}
-		else
-		{
-			sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
-			sense_ccw[0].cda      = (__u32)virt_to_phys( sid );
-			sense_ccw[0].count    = sizeof( senseid_t);
-			sense_ccw[0].flags    = CCW_FLAG_SLI;
-
-		} /* endif */
-
-		for ( i = 0 ; (i < 8) ; i++ )
-		{
-			pathmask = 0x80 >> i;						
-
-			domask = ioinfo[irq]->opm & pathmask;
-
-			if ( lpm )
-				domask &= lpm;
-
-			if ( domask )
-			{
-				failure = 0;
-				
-				psid->reserved   = 0;
-				psid->cu_type    = 0xFFFF;  /* initialize fields ... */
-				psid->cu_model   = 0;
-				psid->dev_type   = 0;
-				psid->dev_model  = 0;
-
-				retry            = 5;  /* retry count    */
-				io_retry         = 1;  /* enable retries */
-
-				/*
-				 * We now issue a SenseID request. In case of BUSY,
-				 *  STATUS PENDING or non-CMD_REJECT error conditions
-				 *  we run simple retries.
-				 */
-				do
-				{
-					memset( pdevstat, '\0', sizeof( devstat_t) );
-
-					irq_ret = s390_start_IO( irq,
-					                         sense_ccw,
-					                         0x00E2C9C4,  // == SID
-								 domask,
-					                         DOIO_WAIT_FOR_INTERRUPT
-					                          | DOIO_TIMEOUT
-					                          | DOIO_VALID_LPM
-					                          | DOIO_DONT_CALL_INTHDLR );
-
-
-					if ( psid->cu_type  == 0xFFFF )
-					{
-
-						failure = 1;
-
-						if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-						{
-#ifdef CONFIG_DEBUG_IO
-							printk( "SenseID : device %04X on "
-							        "Subchannel %04X "
-							        "reports pending status, "
-							        "retry : %d\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-								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 )
-						{
-							/*
-							 * if the device doesn't support the SenseID
-							 *  command further retries wouldn't help ...
-							 */
-							if (  pdevstat->ii.sense.data[0]
-							    & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
-							{
-#ifdef CONFIG_DEBUG_IO
-								printk( "SenseID : device %04X on "
-								        "Subchannel %04X "
-								        "reports cmd reject or "
-								        "intervention required\n",
-								        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 = 0;
-							}
-
-							else
-							{
-#ifdef CONFIG_DEBUG_IO							
-								printk( "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
-								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]);	    
-									if (psid->reserved != 0xFF) 
-										debug_sprintf_event(cio_debug_msg_id, 2,
-												    "SenseID was not properly "
-												    "executed!\n");
-								}
-							} /* endif */
-
-						}
-						else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
-							  || ( irq_ret        == -ENODEV         ) )
-						{
-#ifdef CONFIG_DEBUG_IO
-							printk( "SenseID : path %02X for "
-							        "device %04X on "
-							        "subchannel %04X "
-							        "is 'not operational'\n",
-							        domask,
-							        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;
-      	
-						}
-
-						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 "
-							        "returns %d, retry %d, "
-							        "status %04X\n",
-							        ioinfo[irq]->schib.pmcw.dev,
-							        irq,
-							        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 */
-
-					}
-					else   // we got it ...
-					{
-						if (psid->reserved != 0xFF) {
-							/* No, we failed after all... */
-							failure = 1;
-							retry--;
-
-						} else {
-					       
-							if ( !sbuffer )	// switch buffers
-							{
-								/*
-								 * we report back the
-								 *  first hit only
-								 */
-								psid = &isid;
-								
-								if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
-								{
-									sense_ccw[1].cda = (__u32)virt_to_phys( psid );
-								}
-								else
-								{
-									sense_ccw[0].cda = (__u32)virt_to_phys( psid );
-
-								} /* endif */
-
-								/*
-								 * if just the very first
-								 *  was requested to be
-								 *  sensed disable further
-								 *  scans.
-								 */	
-								if ( !lpm )
-									lpm = domask;
-								
-								sbuffer = 1;
-								
-							} /* endif */
-
-							if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
-							{
-								ioinfo[irq]->ui.flags.esid = 1;
-       							
-							} /* endif */
-
-							io_retry = 0;
-						
-						}
-
-					} /* endif */
-
-					if ( io_retry )
-					{
-						retry--;
-
-						if ( retry == 0 )
-						{
-							io_retry = 0;
-
-						} /* endif */
-      	
-					} /* endif */
-
-					if ((failure) && (io_retry)) {
-						/* reset fields... */
-
-						failure = 0;
-						
-						psid->reserved   = 0;
-						psid->cu_type    = 0xFFFF;  
-						psid->cu_model   = 0;
-						psid->dev_type   = 0;
-						psid->dev_model  = 0;
-					}
-						
-				} while ( (io_retry) );
-
- 			} /* endif - domask */
-
-		} /* endfor */
-
-		if ( init_IRQ_complete )
-		{
-			kfree( sense_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)sense_ccw, 2*sizeof(ccw1_t) );
-
-		} /* endif */
-
-		s390irq_spin_unlock( irq);
-
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
-
-		/*
-		 * if running under VM check there ... perhaps we should do
-		 *  only if we suffered a command reject, but it doesn't harm
-		 */
-		if (    ( sid->cu_type == 0xFFFF    )
-		     && ( MACHINE_IS_VM             ) )
-		{
-			VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
-			                        sid );
-		} /* endif */
-
-		if ( sid->cu_type == 0xFFFF )
-		{
-			/*
-			 * SenseID CU-type of 0xffff indicates that no device
-			 *  information could be retrieved (pre-init value).
-			 *
-			 * If we can't couldn't identify the device type we
-			 *  consider the device "not operational".
-			 */
-#ifdef CONFIG_DEBUG_IO
-			printk( "SenseID : unknown device %04X on subchannel %04X\n",
-			        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 */
-
-	
-		/*
-		 * Issue device info message if unit was operational .
-		 */
-		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);
-				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);
-				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 */
-
-		if ( !ioinfo[irq]->ui.flags.unknown )
-			irq_ret = 0;
-		else
-			irq_ret = -ENODEV;
-
-	} /* endif */
-
-   return( irq_ret );
-}
-
-static int __inline__ s390_SetMultiPath( int irq )
-{
-	int cc;
-
-	cc = stsch( irq, &ioinfo[irq]->schib );
-
-	if ( !cc )
-	{
-		ioinfo[irq]->schib.pmcw.mp = 1;     /* multipath mode */
-
-		cc = msch( irq, &ioinfo[irq]->schib );
-
-	} /* endif */
-
-	return( cc);
-}
-
-/*
- * Device Path Verification
- *
- * Path verification is accomplished by checking which paths (CHPIDs) are
- *  available. Further, a path group ID is set, if possible in multipath
- *  mode, otherwise in single path mode.
- *
- * Note : This function must not be called during normal device recognition,
- *         but during device driver initiated request_irq() processing only.
- */
-int s390_DevicePathVerification( int irq, __u8 usermask )
-{
-	int  ccode;
-	__u8 pathmask;
-	__u8 domask;
-
-	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 ...
-
-	} /* endif */
-
-	ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
-	if ( ccode )
-	{
-		ret = -ENODEV;
-	}
-	else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
-	{
-		/*
-		 * no error, just not required for single path only devices
-		 */	
-		ioinfo[irq]->ui.flags.pgid_supp = 0;
-		ret = 0;
-	}
-	else
-	{
-		int    i;
-		pgid_t pgid;
-		__u8   dev_path;
-		int    first  = 1;
-
-		ioinfo[irq]->opm =   ioinfo[irq]->schib.pmcw.pim
-		                   & ioinfo[irq]->schib.pmcw.pam
-		                   & ioinfo[irq]->schib.pmcw.pom;
-
-		if ( usermask )
-		{
-			dev_path = usermask;
-		}
-		else
-		{
-			dev_path = ioinfo[irq]->opm;
-
-		} /* endif */
-
-		/*
-		 * let's build a path group ID if we don't have one yet
-		 */
-		if ( ioinfo[irq]->ui.flags.pgid == 0)
-		{
-			ioinfo[irq]->pgid.cpu_addr  = *(__u16 *)__LC_CPUADDR;
-			ioinfo[irq]->pgid.cpu_id    = ((cpuid_t *)__LC_CPUID)->ident;
-			ioinfo[irq]->pgid.cpu_model = ((cpuid_t *)__LC_CPUID)->machine;
-			ioinfo[irq]->pgid.tod_high  = *(__u32 *)&irq_IPL_TOD;
-
-			ioinfo[irq]->ui.flags.pgid  = 1;
-
-		} /* endif */     		
-
-		memcpy( &pgid, &ioinfo[irq]->pgid, sizeof(pgid_t));
-
-		for ( i = 0; i < 8 && !ret ; i++)
-		{
-			pathmask = 0x80 >> i;						
-
-			domask = dev_path & pathmask;
-
-			if ( domask )
-			{
-				ret = s390_SetPGID( irq, domask, &pgid );
-
-				/*
-				 * For the *first* path we are prepared
-				 *  for recovery
-				 *
-				 *  - If we fail setting the PGID we assume its
-				 *     using  a different PGID already (VM) we
-				 *     try to sense.
-				 */
-				if ( ret == -EOPNOTSUPP && first )
-				{
-					*(int *)&pgid = 0;
-					
-					ret   = s390_SensePGID( irq, domask, &pgid);
-					first = 0;
-
-					if ( ret == 0 )
-					{
-						/*
-						 * Check whether we retrieved
-						 *  a reasonable PGID ...
-						 */	
-						if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
-						{
-							memcpy( &(ioinfo[irq]->pgid),
-							        &pgid,
-							        sizeof(pgid_t) );
-						}
-						else // ungrouped or garbage ...
-						{
-							ret = -EOPNOTSUPP;
-
-						} /* endif */
-					}
-					else
-					{
-						ioinfo[irq]->ui.flags.pgid_supp = 0;
-
-#ifdef CONFIG_DEBUG_IO
-						printk( "PathVerification(%04X) "
-						        "- Device %04X doesn't "
-						        " support path grouping\n",
-						        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 ) 
-				{
-#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 {
-#ifdef CONFIG_DEBUG_IO
-					printk( "PathVerification(%04X) "
-						"- Unexpected 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) - "
-								    "Unexpected error on device %04X\n",
-								    irq,
-								    ioinfo[irq]->schib.pmcw.dev);		    
-					
-					ioinfo[irq]->ui.flags.pgid_supp = 0;
-					
-				} /* endif */
-
-			} /* endif */
-			
-		} /* endfor */
-
-	} /* endif */
-
-	return ret;
-
-}
-
-/*
- * s390_SetPGID
- *
- * Set Path Group ID
- *
- */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
-{
-	ccw1_t    *spid_ccw;    /* ccw area for SPID command */
-	devstat_t  devstat;     /* required by request_irq() */
-	devstat_t *pdevstat = &devstat;
-        unsigned long flags;
-
-
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
-	int        mpath   = 1; /* try multi-path first */
-
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		/*
-		 * Perform SetPGID command processing. We have to request device
-		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
-		 *  requests and evaluate the devstat area on return therefore
-		 *  we don't need a real I/O handler in place.
-		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SPID",
-		                       pdevstat);
-
-		if ( irq_ret == 0 )
-			inlreq = 1;
-	}
-	else
-	{
-		pdevstat = ioinfo[irq]->irq_desc.dev_id;
-
-	} /* endif */
-
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
-
-		if ( init_IRQ_complete )
-		{
-			spid_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			spid_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
-
-		} /* endif */
-
-		spid_ccw[0].cmd_code = 0x5B;	/* suspend multipath reconnect */
-		spid_ccw[0].cda      = 0;
-		spid_ccw[0].count    = 0;
-		spid_ccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-
-		spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
-		spid_ccw[1].cda      = (__u32)virt_to_phys( pgid );
-		spid_ccw[1].count    = sizeof( pgid_t);
-		spid_ccw[1].flags    = CCW_FLAG_SLI;
-
-		pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
-
-		/*
-		 * We now issue a SetPGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
-		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
-
-			irq_ret = s390_start_IO( irq,
-			                         spid_ccw,
-			                         0xE2D7C9C4,  // == SPID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
-
-			if ( !irq_ret )
-			{
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( "SPID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        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);	    
-					retry--;
-					irq_ret = -EIO;
-				} /* endif */
-
-				if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
-				                         | DEVSTAT_FINAL_STATUS   ) )
-				{
-					retry = 0;	// successfully set ...
-					irq_ret = 0;
-				}
-				else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
-					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						if ( mpath )
-						{
-							pgid->inf.fc =   SPID_FUNC_SINGLE_PATH
-							               | SPID_FUNC_ESTABLISH;
-							mpath        = 0;
-							retry--;
-							irq_ret = -EIO;
-						}
-						else
-						{
-							irq_ret = -EOPNOTSUPP;
-							retry   = 0;			
-
-						} /* endif */
-					}
-					else
-					{
-#ifdef CONFIG_DEBUG_IO
-						printk( "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]);
-#endif
-
-						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--;
-						irq_ret = -EIO;
-		    
-					} /* endif */
-
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* 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;
-
-				} /* endif */
-			}
-			else if ( irq_ret != -ENODEV )
-			{
-				retry--;
-				irq_ret = -EIO;
-			}
-			else
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
-
-			} /* endif */
-
-		} while ( retry > 0 );
-
-
-		if ( init_IRQ_complete )
-		{
-			kfree( spid_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)spid_ccw, 2*sizeof(ccw1_t) );
-
-		} /* endif */
-
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
-
-	} /* endif */
-
-   return( irq_ret );
-}
-
-
-/*
- * s390_SensePGID
- *
- * Sense Path Group ID
- *
- */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
-{
-	ccw1_t    *snid_ccw;    /* ccw area for SNID command */
-	devstat_t  devstat;     /* required by request_irq() */
-	devstat_t *pdevstat = &devstat;
-
-	int        irq_ret = 0; /* return code */
-	int        retry   = 5; /* retry count */
-	int        inlreq  = 0; /* inline request_irq() */
-	unsigned long flags;
-
-	SANITY_CHECK(irq);
-
-	if ( ioinfo[irq]->ui.flags.oper == 0 )
-	{
-		return( -ENODEV );
-
-	} /* endif */
-
-	if ( !ioinfo[irq]->ui.flags.ready )
-	{
-		/*
-		 * Perform SENSE PGID command processing. We have to request device
-		 *  ownership and provide a dummy I/O handler. We issue sync. I/O
-		 *  requests and evaluate the devstat area on return therefore
-		 *  we don't need a real I/O handler in place.
-		 */
-		irq_ret = request_irq( irq,
-		                       init_IRQ_handler,
-		                       SA_PROBE,
-		                       "SNID",
-		                       pdevstat);
-
-		if ( irq_ret == 0 )
-			inlreq = 1;
-
-   }
-	else
-	{
-		pdevstat = ioinfo[irq]->irq_desc.dev_id;
-
-	} /* endif */
-
-	if ( irq_ret == 0 )
-	{
-		s390irq_spin_lock_irqsave( irq, flags);
-
-		if ( init_IRQ_complete )
-		{
-			snid_ccw = kmalloc( sizeof( ccw1_t), GFP_DMA);
-		}
-		else	
-		{
-			snid_ccw = alloc_bootmem_low( sizeof( ccw1_t));
-
-		} /* endif */
-
-		snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
-		snid_ccw->cda      = (__u32)virt_to_phys( pgid );
-		snid_ccw->count    = sizeof( pgid_t);
-		snid_ccw->flags    = CCW_FLAG_SLI;
-
-		/*
-		 * We now issue a SensePGID request. In case of BUSY
-		 *  or STATUS PENDING conditions we retry 5 times.
-		 */
-		do
-		{
-			memset( pdevstat, '\0', sizeof( devstat_t) );
-
-			irq_ret = s390_start_IO( irq,
-			                         snid_ccw,
-			                         0xE2D5C9C4,  // == SNID
-			                         lpm,         // n/a
-			                         DOIO_WAIT_FOR_INTERRUPT
-			                          | DOIO_VALID_LPM
-			                          | DOIO_DONT_CALL_INTHDLR );
-
-			if ( irq_ret == 0 )
-			{
-				if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
-				{
-					/*
-					 * If the device doesn't support the
-					 *  Sense Path Group ID command
-					 *  further retries wouldn't help ...
-					 */
-					if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
-					{
-						retry   = 0;
-						irq_ret = -EOPNOTSUPP;
-					}
-					else
-					{
-#ifdef CONFIG_DEBUG_IO
-						printk( "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]);
-
-#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--;
-						irq_ret = -EIO;
-
-					} /* endif */
-				}
-				else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
-				{
-					/* 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;
-					irq_ret = -EIO;
-
-				}
-				else
-				{
-					retry = 0; // success ...
-					irq_ret = 0;
-
-				} /* endif */
-			}
-			else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
-			{
-
-				if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
-				{
-#ifdef CONFIG_DEBUG_IO
-					printk( "SNID - Device %04X "
-					        "on Subchannel %04X "
-					        "reports pending status, "
-					        "retry : %d\n",
-					        ioinfo[irq]->schib.pmcw.dev,
-					        irq,
-					        retry);
-#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--;
-				irq_ret = -EIO;
-			}
-			else	// -ENODEV ...
-			{
-				retry = 0;
-				irq_ret = -ENODEV;
-
-			} /* endif */
-
-		} while ( retry > 0 );
-
-
-		if ( init_IRQ_complete )
-		{
-			kfree( snid_ccw );
-		}
-		else	
-		{
-			free_bootmem( (unsigned long)snid_ccw, sizeof(ccw1_t) );
-
-		} /* endif */
-
-		s390irq_spin_unlock_irqrestore( irq, flags);
-
-		/*
-		 * If we installed the irq action handler we have to
-		 *  release it too.
-		 */
-		if ( inlreq )
-			free_irq( irq, pdevstat);
-
-	} /* endif */
-
-   return( irq_ret );
-}
-
-/*
- * s390_do_crw_pending
- *
- * Called by the machine check handler to process CRW pending
- *  conditions. It may be a single CRW, or CRWs may be chained.
- *
- * Note : we currently process CRWs for subchannel source only
- */
-void s390_do_crw_pending( crwe_t *pcrwe )
-{
-	int irq;
-	int chpid;
-	int dev_oper = 0;
-	int dev_no   = -1;	
-	int lock     = 0;
-
-#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;
-
-		switch ( pcrwe->crw.rsc ) {	
-		case CRW_RSC_SCH :
-
-			irq = pcrwe->crw.rsid;
-
-#ifdef CONFIG_DEBUG_CRW
-			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 ...
-			 */
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				s390irq_spin_lock( irq );
-				lock = 1;
-
-				dev_oper = ioinfo[irq]->ui.flags.oper;
-
-				if ( ioinfo[irq]->ui.flags.dval )
-					dev_no = ioinfo[irq]->devno;
-
-				is_owned = ioinfo[irq]->ui.flags.ready;
-
-			} /* endif */
-
-#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 )
-				highest_subchannel = irq;
-
-#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
-			 *   should be allocated ...
-			 */
-			if ( lock )
-			{
-				s390irq_spin_unlock( irq );
-
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-#ifdef CONFIG_DEBUG_CRW
-				printk( "do_crw_pending : ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-					"%08lX\n",
-					(unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-					"%08X\n",
-				        (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-#endif
-				if (cio_debug_initialized)
-					debug_sprintf_event(cio_debug_crw_id, 4,
-							    "ioinfo at "
-#ifdef CONFIG_ARCH_S390X
-							    "%08lX\n",
-							    (unsigned long)ioinfo[irq]);
-#else /* CONFIG_ARCH_S390X */
-				                            "%08X\n",
-							    (unsigned)ioinfo[irq]);
-#endif /* CONFIG_ARCH_S390X */
-			} /* endif */
-
-
-			if ( ioinfo[irq] != INVALID_STORAGE_AREA )
-			{
-				if ( ioinfo[irq]->ui.flags.oper == 0 )
-				{
-					 not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
-#ifdef CONFIG_PROC_FS					 
-					 /* remove procfs entry */
-					 if (cio_proc_devinfo)
-						 cio_procfs_device_remove(dev_no);
-#endif
-					/*
-					 * If the device has gone
-					 *  call not oper handler        	
-					 */       	
-					 if (( dev_oper == 1 )
-					     && ( nopfunc != NULL))
-					{
-						
-						free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
-						nopfunc( irq,DEVSTAT_DEVICE_GONE );			
-
-					} /* endif */
-				}
-				else
-				{
-#ifdef CONFIG_DEBUG_CRW
-					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
-					 */
-					if ( dev_oper == 0 )
-					{
-						devreg_t *pdevreg;
-
-						pdevreg = s390_search_devreg( ioinfo[irq] );
-
-						if ( pdevreg != NULL )
-						{
-							if ( pdevreg->oper_func != NULL )
-								pdevreg->oper_func( irq, pdevreg );
-
-						} /* endif */
-#ifdef CONFIG_PROC_FS
-						/* add new procfs entry */
-						if (cio_proc_devinfo) 
-							if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
-								cio_procfs_device_create(ioinfo[irq]->devno);
-							}
-#endif
-					}
-					/*
-					 * ... it is and was operational, but
-					 *      the devno may have changed
-					 */
-					else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))   					
-					{
-#ifdef CONFIG_PROC_FS
-						int devno_old = ioinfo[irq]->devno;
-#endif
-						ioinfo[irq]->nopfunc( irq,
-						                      DEVSTAT_REVALIDATE );				
-#ifdef CONFIG_PROC_FS
-						/* remove old entry, add new */
-						if (cio_proc_devinfo) {
-							cio_procfs_device_remove(devno_old);
-							cio_procfs_device_create(ioinfo[irq]->devno);
-						}
-#endif
-					} /* endif */
-
-				} /* endif */
-#ifdef CONFIG_PROC_FS
-				/* get rid of dead procfs entries */
-				if (cio_proc_devinfo) 
-					cio_procfs_device_purge();
-#endif
-			} /* endif */
-
-			break;
-
-		case CRW_RSC_MONITOR :
-
-#ifdef CONFIG_DEBUG_CRW
-			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 :   	
-
-			chpid = pcrwe->crw.rsid;
-
-#ifdef CONFIG_DEBUG_CRW
-			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 : 	
-
-#ifdef CONFIG_DEBUG_CRW
-			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 :
-
-#ifdef CONFIG_DEBUG_CRW
-			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 :
-
-#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 */
-
-		pcrwe = pcrwe->crwe_next;
-
-	} /* endwhile */
-
-#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;
-}
-
-
-/* added by Holger Smolinski for reipl support in reipl.S */
-extern void do_reipl (int);
-void
-reipl ( int sch )
-{
-	int i;
-	s390_dev_info_t dev_info;
-
-	for ( i = 0; i <= highest_subchannel; i ++ ) 
-	{
-		if (    get_dev_info_by_irq( i, &dev_info ) == 0
-                    && (dev_info.status & DEVSTAT_DEVICE_OWNED) )
-		{
-			free_irq ( i, ioinfo[i]->irq_desc.dev_id );
-		}
-	}
-
-	if (MACHINE_IS_VM)
-		cpcmd("IPL", NULL, 0);
-	else
-		do_reipl( 0x10000 | sch );
-}
-
-
-/*
- * 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);
-
-#ifdef CONFIG_PROC_FS
-/* 
- * Display info on subchannels in /proc/subchannels. 
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
- */
-
-typedef struct {
-     char *data;
-     int len;
-} tempinfo_t;
-
-#define MIN(a,b) ((a)<(b)?(a):(b))
-
-static struct proc_dir_entry *chan_subch_entry;
-
-static int chan_subch_open( struct inode *inode, struct file *file)
-{
-     int rc = 0;
-     int size = 1;
-     int len = 0;
-     int i = 0;
-     int j = 0;
-     tempinfo_t *info;
-     
-     info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t));
-     if (info == NULL) {
-	  printk( KERN_WARNING "No memory available for data\n");
-	  return -ENOMEM;
-     } else {
-	  file->private_data = ( void * ) info;
-     }
-
-     size += (highest_subchannel+1) * 128;
-     info->data = (char *) vmalloc( size );
-     
-     if (size && info->data == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
-		vfree (info);
-		return -ENOMEM;
-	}
-     
-     len += sprintf( info->data+len, 
-		     "Device sch.  Dev Type/Model CU  in use  PIM PAM POM LPUM CHPIDs\n");
-     len += sprintf( info->data+len, 
-		     "--------------------------------------------------------------------------\n");
-
-     for ( i=0; i <= highest_subchannel; i++) {
-	  if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) {
-	       len += sprintf( info->data+len, 
-			       "%04X   %04X  ", 
-			       ioinfo[i]->schib.pmcw.dev, 
-			       i );
-	       if ( ioinfo[i]->senseid.dev_type != 0 ) {
-		    len += sprintf( info->data+len, 
-				    "%04X/%02X   %04X/%02X", 
-				    ioinfo[i]->senseid.dev_type,
-				    ioinfo[i]->senseid.dev_model, 
-				    ioinfo[i]->senseid.cu_type,
-				    ioinfo[i]->senseid.cu_model );
-	       } else {
-		    len += sprintf( info->data+len, 
-				    "          %04X/%02X", 
-				    ioinfo[i]->senseid.cu_type, 
-				    ioinfo[i]->senseid.cu_model );
-	       }
-	       if (ioinfo[i]->ui.flags.ready) {
-		    len += sprintf( info->data+len, "  yes " );
-	       } else {
-		    len += sprintf( info->data+len, "      " );
-	       }
-	       len += sprintf( info->data+len,
-			       "    %02X  %02X  %02X  %02X   ",
-			       ioinfo[i]->schib.pmcw.pim,
-			       ioinfo[i]->schib.pmcw.pam,
-			       ioinfo[i]->schib.pmcw.pom,
-			       ioinfo[i]->schib.pmcw.lpum );
-	       for ( j=0; j < 8; j++ ) {
-		    len += sprintf( info->data+len,
-				    "%02X",
-				    ioinfo[i]->schib.pmcw.chpid[j] );
-		    if (j==3) {
-			 len += sprintf( info->data+len, " " );
-		    }
-	       }
-	       len += sprintf( info->data+len, "\n" );
-	  }
-     }
-     info->len = len;
-
-     return rc;
-}
-
-static int chan_subch_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 chan_subch_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 struct file_operations chan_subch_file_ops =
-{
-     read:chan_subch_read,
-     open:chan_subch_open,
-     release:chan_subch_close,
-};
-
-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);
-
-void chan_proc_cleanup( void )
-{
-     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;
-     }
-}
-
-
-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 = PDE(inode)->data;
-
-	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 {
-			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 = PDE(inode)->data;
-
-	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 {
-			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 = PDE(inode)->data;
-	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 {
-			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->data = devno;
-				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->data = devno;
-				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->data = devno;
-				entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
-			} else {
-				printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-				remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-				kfree(entry);
-				rc = -ENOMEM;
-			}
-		} else {
-			printk( KERN_WARNING "Error, could not allocate procfs structure!\n");
-			kfree(entry);
-			rc = -ENOMEM;
-		}
-
-	} else {
-		printk( KERN_WARNING "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
- * add <range>,<range>,... will add a range of devices to blacklist -
- * but only for devices not already known
- */
-
-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;
-	long flags;
-
-	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 {
-			spin_lock_irqsave( &blacklist_lock, flags ); 
-			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;
-			}
-			spin_unlock_irqrestore( &blacklist_lock, flags );
-			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 ( KERN_DEBUG "/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);
-
-/*
- * Entry /proc/irq_count
- * display how many irqs have occured per cpu...
- */
-
-static struct proc_dir_entry *cio_irq_proc_entry;
-
-static int cio_irq_proc_open(struct inode *inode, struct file *file)
-{
-	int rc = 0;
-	int size = 1;
-	int len = 0;
-	tempinfo_t *info;
-	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 += NR_CPUS * 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 {
-			for (i=0; i< NR_CPUS; i++) {
-				if (s390_irq_count[i] != 0) 
-					len += sprintf(info->data+len, "%lx\n", s390_irq_count[i]);
-			}
-			info->len = len;
-		}
-	}
-	return rc;
-}
-
-static int cio_irq_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_irq_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 struct file_operations cio_irq_proc_file_ops = 
-	{
-		read:    cio_irq_proc_read,
-		open:    cio_irq_proc_open,
-		release: cio_irq_proc_close,
-	};
-
-static int cio_irq_proc_init(void)
-{
-
-	int i;
-
-	if (cio_count_irqs) {
-		for (i=0; i<NR_CPUS; i++) 
-			s390_irq_count[i]=0;
-		cio_irq_proc_entry = create_proc_entry("irq_count", S_IFREG|S_IRUGO, &proc_root);
-		cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
-	}
-
-	return 1;
-}
-
-__initcall(cio_irq_proc_init);	
-
-/* end of procfs stuff */
-#endif
-
-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);
-EXPORT_SYMBOL(resume_IO);
-EXPORT_SYMBOL(ioinfo);
-EXPORT_SYMBOL(get_dev_info_by_irq);
-EXPORT_SYMBOL(get_dev_info_by_devno);
-EXPORT_SYMBOL(get_irq_by_devno);
-EXPORT_SYMBOL(get_devno_by_irq);
-EXPORT_SYMBOL(get_irq_first);
-EXPORT_SYMBOL(get_irq_next);
-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 -Nru a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
--- a/drivers/s390/s390mach.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/s390/s390mach.c	Sat Jun  8 22:31:37 2002
@@ -1,7 +1,6 @@
 /*
- *  arch/s390/kernel/s390mach.c
- *   S/390 machine check handler,
- *            currently only channel-reports are supported
+ *  drivers/s390/s390mach.c
+ *   S/390 machine check handler
  *
  *  S390 version
  *    Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -22,104 +21,123 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
+#ifdef CONFIG_MACHCHK_WARNING
+#include <asm/signal.h>
+#endif
 
 #define S390_MACHCHK_DEBUG
 
-static int         s390_machine_check_handler( void * parm );
-static void        s390_enqueue_mchchk( mache_t *mchchk );
-static mache_t    *s390_dequeue_mchchk( void );
-static void        s390_enqueue_free_mchchk( mache_t *mchchk );
-static mache_t    *s390_dequeue_free_mchchk( void );
-static int         s390_collect_crw_info( void );
-
-static mache_t    *mchchk_queue_head = NULL;
-static mache_t    *mchchk_queue_tail = NULL;
-static mache_t    *mchchk_queue_free = NULL;
-static crwe_t     *crw_buffer_anchor = NULL;
-static spinlock_t  mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t  crw_queue_lock    = SPIN_LOCK_UNLOCKED;
+#ifdef S390_MACHCHK_DEBUG
+#define DBG printk
+#else				/* S390_MACHCHK_DEBUG */
+#define DBG(args,...) do {} while (0);
+#endif				/* S390_MACHCHK_DEBUG */
+
+static int s390_machine_check_handler(void *parm);
+static void s390_enqueue_mchchk(mache_t * mchchk);
+static mache_t *s390_dequeue_mchchk(void);
+static void s390_enqueue_free_mchchk(mache_t * mchchk);
+static mache_t *s390_dequeue_free_mchchk(void);
+static int s390_collect_crw_info(void);
+#ifdef CONFIG_MACHCHK_WARNING
+static int s390_post_warning(void);
+#endif
+
+static mache_t *mchchk_queue_head = NULL;
+static mache_t *mchchk_queue_tail = NULL;
+static mache_t *mchchk_queue_free = NULL;
+static crwe_t *crw_buffer_anchor = NULL;
+static spinlock_t mchchk_queue_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t crw_queue_lock = SPIN_LOCK_UNLOCKED;
 
 static struct semaphore s_sem;
 
+#ifdef CONFIG_MACHCHK_WARNING
+static int mchchk_wng_posted = 0;
+#endif
 
 /*
  * s390_init_machine_check
  *
  * initialize machine check handling
  */
-void s390_init_machine_check( void )
+void
+s390_init_machine_check(void)
 {
-	crwe_t  *pcrwe;	 /* CRW buffer element pointer */
-	mache_t *pmache;   /* machine check element pointer */
-
-	init_MUTEX_LOCKED( &s_sem );
-
-	pcrwe = kmalloc( MAX_CRW_PENDING * sizeof( crwe_t), GFP_KERNEL);
-
-	if ( pcrwe )
-	{
-		int i;
-
-		crw_buffer_anchor = pcrwe;
+	crwe_t *pcrwe;		/* CRW buffer element pointer */
+	mache_t *pmache;	/* machine check element pointer */
+	int i;
+
+	init_MUTEX_LOCKED(&s_sem);
+
+	pcrwe = kmalloc(MAX_CRW_PENDING * sizeof (crwe_t), GFP_KERNEL);
+
+	if (!pcrwe) 
+		panic("s390_init_machine_check: unable to obtain memory\n");
+
+	crw_buffer_anchor = pcrwe;
+	
+	for (i = 0; i < MAX_CRW_PENDING - 1; i++) {
+		pcrwe->crwe_next =
+			(crwe_t *) ((unsigned long) pcrwe + sizeof (crwe_t));
+		pcrwe = pcrwe->crwe_next;
+		
+	}
 
-		for ( i=0; i < MAX_CRW_PENDING-1; i++)
-		{
-			pcrwe->crwe_next = (crwe_t *)((unsigned long)pcrwe + sizeof(crwe_t));
-   		pcrwe            = pcrwe->crwe_next;
+	pcrwe->crwe_next = NULL;
 
-		} /* endfor */	
+	pmache = kmalloc(MAX_MACH_PENDING * sizeof (mache_t), GFP_KERNEL);
 
-		pcrwe->crwe_next = NULL;
+	if (!pmache) 
+		panic("s390_init_machine_check: unable to obtain memory\n");
 
+	for (i = 0; i < MAX_MACH_PENDING; i++) {
+		s390_enqueue_free_mchchk(pmache);
+		pmache =
+			(mache_t *) ((unsigned long) pmache + sizeof (mache_t));
+		
 	}
-	else
-	{
-		panic( "s390_init_machine_check : unable to obtain memory\n");		
+	
+	DBG(KERN_NOTICE "init_mach : starting machine check handler\n");
 
-	} /* endif */
+	kernel_thread(s390_machine_check_handler, &s_sem,
+		      CLONE_FS | CLONE_FILES);
 
-	pmache = kmalloc( MAX_MACH_PENDING * sizeof( mache_t), GFP_KERNEL);
+	ctl_clear_bit(14, 25);	/* disable damage MCH */
 
-	if ( pmache )
-	{
-		int i;
+	ctl_set_bit(14, 26);	/* enable degradation MCH */
+	ctl_set_bit(14, 27);	/* enable system recovery MCH */
 
-		for ( i=0; i < MAX_MACH_PENDING; i++)
-		{
-			s390_enqueue_free_mchchk( pmache );
-		   pmache = (mache_t *)((unsigned long)pmache + sizeof(mache_t));
+	ctl_set_bit(14, 28);	/* enable channel report MCH */
 
-		} /* endfor */	
-	}
-	else
-	{
-		panic( "s390_init_machine_check : unable to obtain memory\n");		
-
-	} /* endif */
+#ifdef CONFIG_MACHCK_WARNING
+	ctl_set_bit(14, 24);	/* enable warning MCH */
+#endif
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : starting machine check handler\n");
-#endif	
+	DBG(KERN_DEBUG "init_mach : machine check buffer : head = %08X\n",
+	    (unsigned) &mchchk_queue_head);
+	DBG(KERN_DEBUG "init_mach : machine check buffer : tail = %08X\n",
+	    (unsigned) &mchchk_queue_tail);
+	DBG(KERN_DEBUG "init_mach : machine check buffer : free = %08X\n",
+	    (unsigned) &mchchk_queue_free);
+	DBG(KERN_DEBUG "init_mach : CRW entry buffer anchor = %08X\n",
+	    (unsigned) &crw_buffer_anchor);
+	DBG(KERN_DEBUG "init_mach : machine check handler ready\n");
 
-	kernel_thread( s390_machine_check_handler, &s_sem, CLONE_FS | CLONE_FILES);
+	return;
+}
 
-	ctl_clear_bit( 14, 25 );  // disable damage MCH 	
-#if 1
-  	ctl_set_bit( 14, 28 );		// enable channel report MCH
-#endif
+static void
+s390_handle_damage(char *msg)
+{
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "init_mach : machine check buffer : head = %08X\n",
-            (unsigned)&mchchk_queue_head);
-	printk( "init_mach : machine check buffer : tail = %08X\n",
-            (unsigned)&mchchk_queue_tail);
-	printk( "init_mach : machine check buffer : free = %08X\n",
-            (unsigned)&mchchk_queue_free);
-	printk( "init_mach : CRW entry buffer anchor = %08X\n",
-            (unsigned)&crw_buffer_anchor);
-	printk( "init_mach : machine check handler ready\n");
-#endif	
+	unsigned long caller = (unsigned long) __builtin_return_address(0);
 
+	printk(KERN_EMERG "%s\n", msg);
+#ifdef CONFIG_SMP
+	smp_send_stop();
+#endif
+	disabled_wait(caller);
 	return;
 }
 
@@ -129,35 +147,77 @@
  * mchine check pre-processor, collecting the machine check info,
  *  queueing it and posting the machine check handler for processing.
  */
-void s390_do_machine_check( void )
+void
+s390_do_machine_check(void)
 {
-	int      crw_count;
-	mcic_t   mcic;
+	int crw_count;
+	mcic_t mcic;
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : starting ...\n");
-#endif
+	DBG(KERN_INFO "s390_do_machine_check : starting ...\n");
+
+	memcpy(&mcic, &S390_lowcore.mcck_interruption_code, sizeof (__u64));
+
+	if (mcic.mcc.mcd.sd)	/* system damage */
+		s390_handle_damage("received system damage machine check\n");
+
+	if (mcic.mcc.mcd.pd)	/* instruction processing damage */
+		s390_handle_damage
+		    ("received instruction processing damage machine check\n");
+
+	if (mcic.mcc.mcd.se)	/* storage error uncorrected */
+		s390_handle_damage
+		    ("received storage error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.sc)	/* storage error corrected */
+		printk(KERN_WARNING
+		       "received storage error corrected machine check\n");
+
+	if (mcic.mcc.mcd.ke)	/* storage key-error uncorrected */
+		s390_handle_damage
+		    ("received storage key-error uncorrected machine check\n");
+
+	if (mcic.mcc.mcd.ds && mcic.mcc.mcd.fa)	/* storage degradation */
+		s390_handle_damage
+		    ("received storage degradation machine check\n");
+
+	if (mcic.mcc.mcd.cp) {	/* CRW pending ? */
 
-	memcpy( &mcic,
-	        &S390_lowcore.mcck_interruption_code,
-	        sizeof(__u64));
- 		
-	if ( mcic.mcc.mcd.cp )	// CRW pending ?
-	{
 		crw_count = s390_collect_crw_info();
 
-		if ( crw_count )
-		{
-			up( &s_sem );
+		if (crw_count)
+			up(&s_sem);
 
-		} /* endif */
+	}
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * The warning may remain for a prolonged period on the bare iron.
+ * (actually till the machine is powered off, or until the problem is gone)
+ * So we just stop listening for the WARNING MCH and prevent continuously
+ * being interrupted.  One caveat is however, that we must do this per 
+ * processor and cannot use the smp version of ctl_clear_bit().
+ * On VM we only get one interrupt per virtally presented machinecheck.
+ * Though one suffices, we may get one interrupt per (virtual) processor. 
+ */
+	if (mcic.mcc.mcd.w) {	/* WARNING pending ? */
 
-	} /* endif */
+		/* 
+		 * Use single machine clear, as we cannot handle smp right now 
+		 */
+		__ctl_clear_bit(14, 24);	/* Disable WARNING MCH */
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "s390_do_machine_check : done \n");
+		if (!mchchk_wng_posted) {
+			mchchk_wng_posted = s390_post_warning();
+
+			if (mchchk_wng_posted)
+				up(&s_sem);
+
+		}
+
+	}
 #endif
 
+	DBG(KERN_INFO "s390_do_machine_check : done \n");
+
 	return;
 }
 
@@ -167,98 +227,95 @@
  * machine check handler, dequeueing machine check entries
  *  and processing them
  */
-static int s390_machine_check_handler( void *parm)
+static int
+s390_machine_check_handler(void *parm)
 {
 	struct semaphore *sem = parm;
-	unsigned long     flags;
-	mache_t          *pmache;
-
-	int               found = 0;
+	unsigned long flags;
+	mache_t *pmache;
 
-        /* set name to something sensible */
-        strcpy (current->comm, "kmcheck");
+	int found = 0;
 
+	/* set name to something sensible */
+	strcpy(current->comm, "kmcheck");
 
-        /* block all signals */
-        sigfillset(&current->blocked);
+	/* block all signals */
+	sigfillset(&current->blocked);
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "mach_handler : ready\n");
-#endif	
+	DBG(KERN_NOTICE "mach_handler : ready\n");
 
 	do {
 
-#ifdef S390_MACHCHK_DEBUG
-		printk( "mach_handler : waiting for wakeup\n");
-#endif	
+		DBG(KERN_NOTICE "mach_handler : waiting for wakeup\n");
 
-		down_interruptible( sem );
+		down_interruptible(sem);
 
-#ifdef S390_MACHCHK_DEBUG
-		printk( "\nmach_handler : wakeup ... \n");
-#endif	
-		found = 0; /* init ... */
+		DBG(KERN_NOTICE "\nmach_handler : wakeup ... \n");
+
+		found = 0;	/* init ... */
 
-		__save_flags( flags );
+		__save_flags(flags);
 		__cli();
 
 		do {
 
-		pmache = s390_dequeue_mchchk();
+			pmache = s390_dequeue_mchchk();
 
-		if ( pmache )
-		{
+			if (!pmache) {
+
+				/* unconditional surrender ... */
+				DBG(KERN_DEBUG
+				    "mach_handler : nothing to do, sleeping\n");
+				break;
+			}
+				
 			found = 1;
-		
-			if ( pmache->mcic.mcc.mcd.cp )
-			{
+			
+			if (pmache->mcic.mcc.mcd.cp) {
 				crwe_t *pcrwe_n;
 				crwe_t *pcrwe_h;
-
-				s390_do_crw_pending( pmache->mc.crwe );
-
+				
+				s390_do_crw_pending(pmache->mc.crwe);
+				
 				pcrwe_h = pmache->mc.crwe;
 				pcrwe_n = pmache->mc.crwe->crwe_next;
-
+				
 				pmache->mcic.mcc.mcd.cp = 0;
-				pmache->mc.crwe         = NULL;
-
-				spin_lock( &crw_queue_lock);
-
-				while ( pcrwe_h )
-				{
+				pmache->mc.crwe = NULL;
+				
+				spin_lock(&crw_queue_lock);
+				
+				while (pcrwe_h) {
 					pcrwe_h->crwe_next = crw_buffer_anchor;
-					crw_buffer_anchor  = pcrwe_h;
-					pcrwe_h            = pcrwe_n;
-
-					if ( pcrwe_h != NULL )
+					crw_buffer_anchor = pcrwe_h;
+					pcrwe_h = pcrwe_n;
+					
+					if (pcrwe_h != NULL)
 						pcrwe_n = pcrwe_h->crwe_next;
+					
+				}
+				
+				spin_unlock(&crw_queue_lock);
+				
+			}
+#ifdef CONFIG_MACHCHK_WARNING
+			if (pmache->mcic.mcc.mcd.w) {
+				kill_proc(1, SIGPWR, 1);	/* Send INIT the signal */
+				
+				DBG(KERN_DEBUG 
+				    "mach_handler : kill -SIGPWR init\n");
+			}
+#endif
+			
+			s390_enqueue_free_mchchk(pmache);
 
-				} /* endwhile */
-
-				spin_unlock( &crw_queue_lock);
-
-			} /* endif */
-
-			s390_enqueue_free_mchchk( pmache );
-		}
-		else
-		{
-
-			// unconditional surrender ...
-#ifdef S390_MACHCHK_DEBUG
-			printk( "mach_handler : nothing to do, sleeping\n");
-#endif	
-
-		} /* endif */	
-
-		} while ( pmache );
+		} while (pmache);
 
-		__restore_flags( flags );
+		__restore_flags(flags);
 
-	} while ( 1 );
+	} while (1);
 
-	return( 0);
+	return (0);
 }
 
 /*
@@ -271,31 +328,28 @@
  *  the head.
  *
  */
-static mache_t *s390_dequeue_mchchk( void )
+static mache_t *
+s390_dequeue_mchchk(void)
 {
 	mache_t *qe;
 
-	spin_lock( &mchchk_queue_lock );
+	spin_lock(&mchchk_queue_lock);
 
 	qe = mchchk_queue_tail;
 
-   if ( qe != NULL )
-   {
-      mchchk_queue_tail = qe->prev;
+	if (qe != NULL) {
+		mchchk_queue_tail = qe->prev;
 
-      if ( mchchk_queue_tail != NULL )
-      {
+		if (mchchk_queue_tail != NULL) {
 			mchchk_queue_tail->next = NULL;
-		}
-		else
-      {
+		} else {
 			mchchk_queue_head = NULL;
 
-      } /* endif */
+		}
 
-	} /* endif */
+	}
 
-	spin_unlock( &mchchk_queue_lock );
+	spin_unlock(&mchchk_queue_lock);
 
 	return qe;
 }
@@ -310,39 +364,36 @@
  *  the tail.
  *
  */
-static void s390_enqueue_mchchk( mache_t *pmache )
+static void
+s390_enqueue_mchchk(mache_t * pmache)
 {
-	spin_lock( &mchchk_queue_lock );
+	spin_lock(&mchchk_queue_lock);
 
-	if ( pmache != NULL )
-	{
+	if (pmache != NULL) {
 
-		if ( mchchk_queue_head == NULL )  /* first element */
-		{
-  			pmache->next      = NULL;
-  			pmache->prev      = NULL;
+		if (mchchk_queue_head == NULL) {	/* first element */
+			pmache->next = NULL;
+			pmache->prev = NULL;
 
 			mchchk_queue_head = pmache;
 			mchchk_queue_tail = pmache;
-		}
-		else /* new head */
-		{
-  			pmache->prev            = NULL;
-			pmache->next            = mchchk_queue_head;
+		} else {	/* new head */
+
+			pmache->prev = NULL;
+			pmache->next = mchchk_queue_head;
 
 			mchchk_queue_head->prev = pmache;
-			mchchk_queue_head       = pmache;
+			mchchk_queue_head = pmache;
 
-		} /* endif */
+		}
 
-	} /* endif */
+	}
 
-	spin_unlock( &mchchk_queue_lock );
+	spin_unlock(&mchchk_queue_lock);
 
 	return;
 }
 
-
 /*
  * s390_enqueue_free_mchchk
  *
@@ -353,21 +404,21 @@
  *  single linked list (forward concatenation).
  *
  */
-static void s390_enqueue_free_mchchk( mache_t *pmache )
+static void
+s390_enqueue_free_mchchk(mache_t * pmache)
 {
-	if ( pmache != NULL)
-	{
-		memset( pmache, '\0', sizeof( mache_t ));
+	if (pmache != NULL) {
+		memset(pmache, '\0', sizeof (mache_t));
+
+		spin_lock(&mchchk_queue_lock);
 
-		spin_lock( &mchchk_queue_lock );
-		
 		pmache->next = mchchk_queue_free;
 
 		mchchk_queue_free = pmache;
 
-		spin_unlock( &mchchk_queue_lock );
+		spin_unlock(&mchchk_queue_lock);
 
-	} /* endif */
+	}
 
 	return;
 }
@@ -382,21 +433,21 @@
  *  single linked list (forward concatenation).
  *
  */
-static mache_t *s390_dequeue_free_mchchk( void )
+static mache_t *
+s390_dequeue_free_mchchk(void)
 {
 	mache_t *qe;
 
-	spin_lock( &mchchk_queue_lock );
+	spin_lock(&mchchk_queue_lock);
 
 	qe = mchchk_queue_free;
 
-	if ( qe != NULL )
-	{
+	if (qe != NULL) {
 		mchchk_queue_free = qe->next;
 
-	} /* endif */
+	}
 
-	spin_unlock( &mchchk_queue_lock );
+	spin_unlock(&mchchk_queue_lock);
 
 	return qe;
 }
@@ -412,123 +463,131 @@
  *
  * Note : We must always be called disabled ...
  */
-static int s390_collect_crw_info( void )
+static int
+s390_collect_crw_info(void)
 {
-	crw_t    tcrw;     /* temporarily holds a CRW */
-	int      ccode;    /* condition code from stcrw() */
-	crwe_t  *pcrwe;    /* pointer to CRW buffer entry */
-
-	mache_t *pmache = NULL; /* ptr to mchchk entry */
-	int      chain  = 0;    /* indicate chaining */
-	crwe_t  *pccrw  = NULL; /* ptr to current CRW buffer entry */
-	int      count  = 0;    /* CRW count */
+	crw_t tcrw;		/* temporarily holds a CRW */
+	int ccode;		/* condition code from stcrw() */
+	crwe_t *pcrwe;		/* pointer to CRW buffer entry */
+
+	mache_t *pmache = NULL;	/* ptr to mchchk entry */
+	int chain = 0;		/* indicate chaining */
+	crwe_t *pccrw = NULL;	/* ptr to current CRW buffer entry */
+	int count = 0;		/* CRW count */
 
-#ifdef S390_MACHCHK_DEBUG
-	printk( "crw_info : looking for CRWs ...\n");
-#endif
+	DBG(KERN_DEBUG "crw_info : looking for CRWs ...\n");
 
-	do
-	{
-		ccode = stcrw( (__u32 *)&tcrw);
-
-		if ( ccode == 0 )
-		{
-			count++;
-			
-#ifdef S390_MACHCHK_DEBUG
-			printk( "crw_info : CRW reports "
-			        "slct=%d, oflw=%d, chn=%d, "
-			        "rsc=%X, anc=%d, erc=%X, "
-			        "rsid=%X\n",
-			        tcrw.slct,
-			        tcrw.oflw,
-			        tcrw.chn,
-			        tcrw.rsc,
-			        tcrw.anc,
-			        tcrw.erc,
-			        tcrw.rsid );
-#endif
-
-			/*
-			 * Dequeue a CRW entry from the free chain
-			 *  and process it ...
-			 */
-			spin_lock( &crw_queue_lock );
-
-			pcrwe = crw_buffer_anchor;
-
-			if ( pcrwe == NULL )
-			{
-				spin_unlock( &crw_queue_lock );
-				printk( KERN_CRIT"crw_info : "
-				        "no CRW buffer entries available\n");
-				break;
+	do {
+		ccode = stcrw((__u32 *) & tcrw);
 
-			} /* endif */
+		if (ccode != 0) 
+			break;
+		count++;
+		
+		DBG(KERN_DEBUG "crw_info : CRW reports "
+		    "slct=%d, oflw=%d, chn=%d, "
+		    "rsc=%X, anc=%d, erc=%X, "
+		    "rsid=%X\n",
+		    tcrw.slct,
+		    tcrw.oflw,
+		    tcrw.chn, tcrw.rsc, tcrw.anc, tcrw.erc, tcrw.rsid);
+		
+		/*
+		 * Dequeue a CRW entry from the free chain
+		 *  and process it ...
+		 */
+		spin_lock(&crw_queue_lock);
+		
+		pcrwe = crw_buffer_anchor;
+		
+		if (pcrwe == NULL) {
+			spin_unlock(&crw_queue_lock);
+			printk(KERN_CRIT "crw_info : "
+			       "no CRW buffer entries available\n");
+			break;
 			
-			crw_buffer_anchor = pcrwe->crwe_next;
-			pcrwe->crwe_next  = NULL;
-
-			spin_unlock( &crw_queue_lock );
-
-			memcpy( &(pcrwe->crw), &tcrw, sizeof(crw_t));
+		}
+		
+		crw_buffer_anchor = pcrwe->crwe_next;
+		pcrwe->crwe_next = NULL;
+		
+		spin_unlock(&crw_queue_lock);
+		
+		memcpy(&(pcrwe->crw), &tcrw, sizeof (crw_t));
+		
+		/*
+		 * If it is the first CRW, chain it to the mchchk
+		 *  buffer entry, otherwise to the last CRW entry.
+		 */
+		if (chain == 0) {
+			pmache = s390_dequeue_free_mchchk();
+			
+			if (!pmache) 
+				panic("crw_info: unable to dequeue "
+				      "free mchchk buffer");
 
+			memset(pmache, '\0', sizeof (mache_t));
+			
+			pmache->mcic.mcc.mcd.cp = 1;
+			pmache->mc.crwe = pcrwe;
+			pccrw = pcrwe;
+				
+		} else {
+			pccrw->crwe_next = pcrwe;
+			pccrw = pcrwe;
+			
+		}
+		
+		if (pccrw->crw.chn) {
+			
+			DBG(KERN_DEBUG "crw_info: "
+			    "chained CRWs pending ...\n\n");
+			
+			chain = 1;
+		} else {
+			chain = 0;
+			
 			/*
-			 * If it is the first CRW, chain it to the mchchk
-			 *  buffer entry, otherwise to the last CRW entry.
+			 * We can enqueue the mchchk buffer if
+			 *  there aren't more CRWs chained.
 			 */
-			if ( chain == 0 )
-			{
-				pmache = s390_dequeue_free_mchchk();
-
-				if ( pmache != NULL )
-				{
-					memset( pmache, '\0', sizeof(mache_t));
-
-					pmache->mcic.mcc.mcd.cp = 1;
-					pmache->mc.crwe         = pcrwe;
-					pccrw                   = pcrwe;
-
-				}
-				else
-				{
-					panic( "crw_info : "
-					       "unable to dequeue "
-					       "free mchchk buffer");				
+			s390_enqueue_mchchk(pmache);
+			
+		}
+		
 
-				} /* endif */
-			}
-			else
-			{
-				pccrw->crwe_next = pcrwe;
-				pccrw            = pcrwe;
+	} while (ccode == 0);
 
-			} /* endif */	
+	return (count);
+}
 
-			if ( pccrw->crw.chn )
-			{
-#ifdef S390_MACHCHK_DEBUG
-				printk( "crw_info : "
-				        "chained CRWs pending ...\n\n");
-#endif
-				chain = 1;
-			}
-			else
-			{
-				chain = 0;
+#ifdef CONFIG_MACHCHK_WARNING
+/*
+ * s390_post_warning
+ *
+ * Post a warning type machine check
+ *
+ * The function returns 1 when succesfull (panics otherwise)
+ */
+static int
+s390_post_warning(void)
+{
+	mache_t *pmache = NULL;	/* ptr to mchchk entry */
 
-				/*
-				 * We can enqueue the mchchk buffer if
-				 *  there aren't more CRWs chained.
-				 */
-				s390_enqueue_mchchk( pmache);
+	pmache = s390_dequeue_free_mchchk();
 
-			} /* endif */
+	if (!pmache) 
+		panic("post_warning : "
+		      "unable to dequeue free mchchk buffer");
 
-		} /* endif */
+	memset(pmache, '\0', sizeof (mache_t));
+	
+	pmache->mcic.mcc.mcd.w = 1;
+	
+	s390_enqueue_mchchk(pmache);
 
-	} while ( ccode == 0 );
+	DBG(KERN_DEBUG "post_warning : 1 warning machine check posted\n");
 
-	return( count );
+	return (1);
 }
-
+#endif
diff -Nru a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/s390/sysinfo.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,347 @@
+/*
+ *  drivers/s390/sysinfo.c
+ *
+ *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <asm/ebcdic.h>
+
+struct sysinfo_1_1_1
+{
+	char reserved_0[32];
+	char manufacturer[16];
+	char type[4];
+	char reserved_1[12];
+	char model[16];
+	char sequence[16];
+	char plant[4];
+};
+
+struct sysinfo_1_2_1
+{
+	char reserved_0[80];
+	char sequence[16];
+	char plant[4];
+	char reserved_1[2];
+	unsigned short cpu_address;
+};
+
+struct sysinfo_1_2_2
+{
+	char reserved_0[32];
+	unsigned int capability;
+	unsigned short cpus_total;
+	unsigned short cpus_configured;
+	unsigned short cpus_standby;
+	unsigned short cpus_reserved;
+	unsigned short adjustment[0];
+};
+
+struct sysinfo_2_2_1
+{
+	char reserved_0[80];
+	char sequence[16];
+	char plant[4];
+	unsigned short cpu_id;
+	unsigned short cpu_address;
+};
+
+struct sysinfo_2_2_2
+{
+	char reserved_0[32];
+	unsigned short lpar_number;
+	char reserved_1;
+	unsigned char characteristics;
+	#define LPAR_CHAR_DEDICATED	(1 << 7)
+	#define LPAR_CHAR_SHARED	(1 << 6)
+	#define LPAR_CHAR_LIMITED	(1 << 5)
+	unsigned short cpus_total;
+	unsigned short cpus_configured;
+	unsigned short cpus_standby;
+	unsigned short cpus_reserved;
+	char name[8];
+	unsigned int caf;
+	char reserved_2[16];
+	unsigned short cpus_dedicated;
+	unsigned short cpus_shared;
+};
+
+struct sysinfo_3_2_2
+{
+	char reserved_0[31];
+	unsigned char count;
+	struct
+	{
+		char reserved_0[4];
+		unsigned short cpus_total;
+		unsigned short cpus_configured;
+		unsigned short cpus_standby;
+		unsigned short cpus_reserved;
+		char name[8];
+		unsigned int caf;
+		char cpi[16];
+		char reserved_1[24];
+
+	} vm[8];
+};
+
+union s390_sysinfo
+{
+	struct sysinfo_1_1_1 sysinfo_1_1_1;
+	struct sysinfo_1_2_1 sysinfo_1_2_1;
+	struct sysinfo_1_2_2 sysinfo_1_2_2;
+	struct sysinfo_2_2_1 sysinfo_2_2_1;
+	struct sysinfo_2_2_2 sysinfo_2_2_2;
+	struct sysinfo_3_2_2 sysinfo_3_2_2;
+};
+
+static inline int stsi (void *sysinfo, 
+                        int fc, int sel1, int sel2)
+{
+	int cc, retv;
+
+#ifndef CONFIG_ARCH_S390X
+	__asm__ __volatile__ (	"lr\t0,%2\n"
+				"\tlr\t1,%3\n"
+				"\tstsi\t0(%4)\n"
+				"0:\tipm\t%0\n"
+				"\tsrl\t%0,28\n"
+				"1:lr\t%1,0\n"
+				".section .fixup,\"ax\"\n"
+				"2:\tlhi\t%0,3\n"
+				"\tbras\t1,3f\n"
+				"\t.long 1b\n"
+				"3:\tl\t1,0(1)\n"
+				"\tbr\t1\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"\t.align 4\n"
+				"\t.long 0b,2b\n"
+				".previous\n"
+				: "=d" (cc), "=d" (retv)
+				: "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) 
+				: "cc", "memory", "0", "1" );
+#else
+	__asm__ __volatile__ (	"lr\t0,%2\n"
+				"lr\t1,%3\n"
+				"\tstsi\t0(%4)\n"
+				"0:\tipm\t%0\n"
+				"\tsrl\t%0,28\n"
+				"1:lr\t%1,0\n"
+				".section .fixup,\"ax\"\n"
+				"2:\tlhi\t%0,3\n"
+				"\tjg\t1b\n"
+				".previous\n"
+				".section __ex_table,\"a\"\n"
+				"\t.align 8\n"
+				"\t.quad 0b,2b\n"
+				".previous\n"
+				: "=d" (cc), "=d" (retv)
+				: "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) 
+				: "cc", "memory", "0", "1" );
+#endif
+
+	return cc? -1 : retv;
+}
+
+static inline int stsi_0 (void)
+{
+	int rc = stsi (NULL, 0, 0, 0);
+	return rc == -1 ? rc : (((unsigned int)rc) >> 28);
+}
+
+static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info)
+{
+	int rc = stsi (info, 1, 1, 1);
+	if (rc != -1)
+	{
+		EBCASC (info->manufacturer, sizeof(info->manufacturer));
+		EBCASC (info->type, sizeof(info->type));
+		EBCASC (info->model, sizeof(info->model));
+		EBCASC (info->sequence, sizeof(info->sequence));
+		EBCASC (info->plant, sizeof(info->plant));
+	}
+	return rc == -1 ? rc : 0;
+}
+
+static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info)
+{
+	int rc = stsi (info, 1, 2, 1);
+	if (rc != -1)
+	{
+		EBCASC (info->sequence, sizeof(info->sequence));
+		EBCASC (info->plant, sizeof(info->plant));
+	}
+	return rc == -1 ? rc : 0;
+}
+
+static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info)
+{
+	int rc = stsi (info, 1, 2, 2);
+	return rc == -1 ? rc : 0;
+}
+
+static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info)
+{
+	int rc = stsi (info, 2, 2, 1);
+	if (rc != -1)
+	{
+		EBCASC (info->sequence, sizeof(info->sequence));
+		EBCASC (info->plant, sizeof(info->plant));
+	}
+	return rc == -1 ? rc : 0;
+}
+
+static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info)
+{
+	int rc = stsi (info, 2, 2, 2);
+	if (rc != -1)
+	{
+		EBCASC (info->name, sizeof(info->name));
+  	}
+	return rc == -1 ? rc : 0;
+}
+
+static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info)
+{
+	int rc = stsi (info, 3, 2, 2);
+	if (rc != -1)
+	{
+		int i;
+		for (i = 0; i < info->count; i++)
+		{
+			EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
+			EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
+		}
+	}
+	return rc == -1 ? rc : 0;
+}
+
+
+static int proc_read_sysinfo(char *page, char **start,
+                             off_t off, int count,
+                             int *eof, void *data)
+{
+	unsigned long info_page = get_free_page (GFP_KERNEL); 
+	union s390_sysinfo *info = (union s390_sysinfo *) info_page;
+	int len = 0;
+	int level;
+	int i;
+	
+	if (!info)
+		return 0;
+
+	level = stsi_0 ();
+
+	if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
+	{
+		len += sprintf (page+len, "Manufacturer:         %-16.16s\n",
+				info->sysinfo_1_1_1.manufacturer);
+		len += sprintf (page+len, "Type:                 %-4.4s\n",
+				info->sysinfo_1_1_1.type);
+		len += sprintf (page+len, "Model:                %-16.16s\n",
+				info->sysinfo_1_1_1.model);
+		len += sprintf (page+len, "Sequence Code:        %-16.16s\n",
+				info->sysinfo_1_1_1.sequence);
+		len += sprintf (page+len, "Plant:                %-4.4s\n",
+				info->sysinfo_1_1_1.plant);
+	}
+
+	if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
+	{
+		len += sprintf (page+len, "\n");
+		len += sprintf (page+len, "CPUs Total:           %d\n",
+				info->sysinfo_1_2_2.cpus_total);
+		len += sprintf (page+len, "CPUs Configured:      %d\n",
+				info->sysinfo_1_2_2.cpus_configured);
+		len += sprintf (page+len, "CPUs Standby:         %d\n",
+				info->sysinfo_1_2_2.cpus_standby);
+		len += sprintf (page+len, "CPUs Reserved:        %d\n",
+				info->sysinfo_1_2_2.cpus_reserved);
+	
+		len += sprintf (page+len, "Capability:           %d\n",
+				info->sysinfo_1_2_2.capability);
+
+		for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
+			len += sprintf (page+len, "Adjustment %02d-way:    %d\n",
+					i, info->sysinfo_1_2_2.adjustment[i-2]);
+	}
+
+	if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
+	{
+		len += sprintf (page+len, "\n");
+		len += sprintf (page+len, "LPAR Number:          %d\n",
+				info->sysinfo_2_2_2.lpar_number);
+
+		len += sprintf (page+len, "LPAR Characteristics: ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
+			len += sprintf (page+len, "Dedicated ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
+			len += sprintf (page+len, "Shared ");
+		if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
+			len += sprintf (page+len, "Limited ");
+		len += sprintf (page+len, "\n");
+	
+		len += sprintf (page+len, "LPAR Name:            %-8.8s\n",
+				info->sysinfo_2_2_2.name);
+	
+		len += sprintf (page+len, "LPAR Adjustment:      %d\n",
+				info->sysinfo_2_2_2.caf);
+	
+		len += sprintf (page+len, "LPAR CPUs Total:      %d\n",
+				info->sysinfo_2_2_2.cpus_total);
+		len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
+				info->sysinfo_2_2_2.cpus_configured);
+		len += sprintf (page+len, "LPAR CPUs Standby:    %d\n",
+				info->sysinfo_2_2_2.cpus_standby);
+		len += sprintf (page+len, "LPAR CPUs Reserved:   %d\n",
+				info->sysinfo_2_2_2.cpus_reserved);
+		len += sprintf (page+len, "LPAR CPUs Dedicated:  %d\n",
+				info->sysinfo_2_2_2.cpus_dedicated);
+		len += sprintf (page+len, "LPAR CPUs Shared:     %d\n",
+				info->sysinfo_2_2_2.cpus_shared);
+	}
+
+	if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
+	{
+		for (i = 0; i < info->sysinfo_3_2_2.count; i++)
+		{
+			len += sprintf (page+len, "\n");
+			len += sprintf (page+len, "VM%02d Name:            %-8.8s\n",
+					i, info->sysinfo_3_2_2.vm[i].name);
+			len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
+					i, info->sysinfo_3_2_2.vm[i].cpi);
+	
+			len += sprintf (page+len, "VM%02d Adjustment:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].caf);
+	
+			len += sprintf (page+len, "VM%02d CPUs Total:      %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_total);
+			len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_configured);
+			len += sprintf (page+len, "VM%02d CPUs Standby:    %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_standby);
+			len += sprintf (page+len, "VM%02d CPUs Reserved:   %d\n",
+					i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
+		}
+	}
+
+	free_page (info_page);
+        return len;
+}
+
+static __init int create_proc_sysinfo(void)
+{
+	create_proc_read_entry ("sysinfo", 0444, NULL, 
+				proc_read_sysinfo, NULL);
+	return 0;
+}
+
+__initcall(create_proc_sysinfo);
+
diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/scsi/dpt_i2o.c	Sat Jun  8 22:31:36 2002
@@ -1152,9 +1152,9 @@
 	// this code is taken from kernel/sched.c:interruptible_sleep_on_timeout
 	wait.task = current;
 	init_waitqueue_entry(&wait, current);
-	wq_write_lock_irqsave(&adpt_wq_i2o_post.lock,flags);
+	spin_lock_irqsave(&adpt_wq_i2o_post.lock, flags);
 	__add_wait_queue(&adpt_wq_i2o_post, &wait);
-	wq_write_unlock(&adpt_wq_i2o_post.lock);
+	spin_unlock(&adpt_wq_i2o_post.lock);
 
 	msg[2] |= 0x80000000 | ((u32)wait_data->id);
 	timeout *= HZ;
@@ -1167,9 +1167,9 @@
 			schedule_timeout(timeout*HZ);
 		spin_lock_irq(pHba->host->host_lock);
 	}
-	wq_write_lock_irq(&adpt_wq_i2o_post.lock);
+	spin_lock_irq(&adpt_wq_i2o_post.lock);
 	__remove_wait_queue(&adpt_wq_i2o_post, &wait);
-	wq_write_unlock_irqrestore(&adpt_wq_i2o_post.lock,flags);
+	spin_unlock_irqrestore(&adpt_wq_i2o_post.lock, flags);
 
 	if(status == -ETIMEDOUT){
 		printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit);
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/scsi/ide-scsi.c	Sat Jun  8 22:31:35 2002
@@ -229,10 +229,15 @@
 	printk("]\n");
 }
 
+static inline idescsi_scsi_t *idescsi_private(struct Scsi_Host *host)
+{
+	return (idescsi_scsi_t*) &host[1];
+}
+
 static int idescsi_end_request(struct ata_device *drive, struct request *rq, int uptodate)
 {
 	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = (struct atapi_packet_command *) rq->special;
 	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
 	u8 *scsi_buf;
@@ -289,7 +294,7 @@
 static ide_startstop_t idescsi_pc_intr(struct ata_device *drive, struct request *rq)
 {
 	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	u8 ireason;
 	int bcount;
 	struct atapi_packet_command *pc=scsi->pc;
@@ -372,7 +377,7 @@
 static ide_startstop_t idescsi_transfer_pc(struct ata_device *drive, struct request *rq)
 {
 	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	struct atapi_packet_command *pc = scsi->pc;
 	byte ireason;
 	ide_startstop_t startstop;
@@ -398,7 +403,7 @@
 		struct atapi_packet_command *pc)
 {
 	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(host);
 	int bcount;
 	int dma_ok = 0;
 
@@ -473,7 +478,6 @@
 	if (ide_unregister_subdriver (drive)) {
 		return 1;
 	}
-	kfree((idescsi_scsi_t *) host->hostdata[0]);
 	scsi_unregister(host);
 
 	return 0;
@@ -515,7 +519,7 @@
 
 static int idescsi_ioctl(Scsi_Device *dev, int cmd, void *arg)
 {
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) dev->host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(dev->host);
 
 	if (cmd == SG_SET_TRANSFORM) {
 		if (arg)
@@ -612,7 +616,7 @@
 static inline int should_transform(struct ata_device *drive, Scsi_Cmnd *cmd)
 {
 	struct Scsi_Host *host = drive->driver_data;
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(host);
 
 	if (major(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)
 		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
@@ -621,7 +625,7 @@
 
 static int idescsi_queue(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
 {
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) cmd->host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(cmd->host);
 	struct ata_device *drive = scsi->drive;
 	struct request *rq = NULL;
 	struct atapi_packet_command *pc = NULL;
@@ -691,7 +695,7 @@
 
 static int idescsi_bios(Disk *disk, kdev_t dev, int *parm)
 {
-	idescsi_scsi_t *scsi = (idescsi_scsi_t *) disk->device->host->hostdata[0];
+	idescsi_scsi_t *scsi = idescsi_private(disk->device->host);
 	struct ata_device *drive = scsi->drive;
 
 	if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
@@ -758,8 +762,7 @@
 	drive->driver_data = host;
 	drive->ready_stat = 0;
 
-	scsi = kmalloc(sizeof(*scsi), GFP_ATOMIC);
-	host->hostdata[0] = (unsigned long) scsi;
+	scsi = idescsi_private(host);
 	memset(scsi,0, sizeof (*scsi));
 	scsi->drive = drive;
 
diff -Nru a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl
--- a/drivers/scsi/script_asm.pl	Sat Jun  8 22:31:37 2002
+++ b/drivers/scsi/script_asm.pl	Sat Jun  8 22:31:37 2002
@@ -896,7 +896,8 @@
 open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
 open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
 
-print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$0." */\n";
+($_ = $0) =~ s:.*/::;
+print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n";
 print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
 $instructions = 0;
 for ($i = 0; $i < $#code; ) {
diff -Nru a/drivers/usb/class/Config.in b/drivers/usb/class/Config.in
--- a/drivers/usb/class/Config.in	Sat Jun  8 22:31:37 2002
+++ b/drivers/usb/class/Config.in	Sat Jun  8 22:31:37 2002
@@ -4,5 +4,6 @@
 comment 'USB Device Class drivers'
 dep_tristate '  USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND
 dep_tristate '  USB Bluetooth TTY support' CONFIG_USB_BLUETOOTH_TTY $CONFIG_USB
+dep_tristate '  USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB
 dep_tristate '  USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB
 dep_tristate '  USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB
diff -Nru a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
--- a/drivers/usb/class/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/usb/class/Makefile	Sat Jun  8 22:31:37 2002
@@ -6,6 +6,7 @@
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
+obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_PRINTER)	+= printer.o
 
 
diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/class/usb-midi.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,2228 @@
+/*
+  usb-midi.c  --  USB-MIDI driver
+
+  Copyright (C) 2001 
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  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 is based on:
+    - 'Universal Serial Bus Device Class Definition for MIDI Device'
+    - linux/drivers/sound/es1371.c, linux/drivers/usb/audio.c
+    - alsa/lowlevel/pci/cs64xx.c
+    - umidi.c for NetBSD
+ */
+
+/* ------------------------------------------------------------------------- */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/wrapper.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/sound.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+
+/** This declaration is missing from linux/usb.h **/
+extern int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size);
+
+#include "usb-midi.h"
+
+/* ------------------------------------------------------------------------- */
+
+/* More verbose on syslog */
+#undef MIDI_DEBUG
+
+#define MIDI_IN_BUFSIZ 1024
+
+#define HAVE_SUPPORT_USB_MIDI_CLASS
+
+#undef HAVE_SUPPORT_ALSA
+
+#undef MOD_INC_EACH_PROBE
+
+/* ------------------------------------------------------------------------- */
+
+static int singlebyte = 0;
+MODULE_PARM(singlebyte,"i");
+MODULE_PARM_DESC(singlebyte,"Enable sending MIDI messages with single message packet");
+
+static int maxdevices = 4;
+MODULE_PARM(maxdevices,"i");
+MODULE_PARM_DESC(maxdevices,"Max number of allocatable MIDI device");
+
+static int uvendor     = -1;
+MODULE_PARM(uvendor,"i");
+MODULE_PARM_DESC(uvendor, "The USB Vendor ID of a semi-compliant interface");
+
+static int uproduct    = -1;
+MODULE_PARM(uproduct,"i");
+MODULE_PARM_DESC(uproduct, "The USB Product ID of a semi-compliant interface");
+
+static int uinterface  = -1;
+MODULE_PARM(uinterface,"i");
+MODULE_PARM_DESC(uinterface, "The Interface number of a semi-compliant interface");
+
+static int ualt        = -1;
+MODULE_PARM(ualt,"i");
+MODULE_PARM_DESC(ualt, "The optional alternative setting of a semi-compliant interface");
+
+static int umin        = -1;
+MODULE_PARM(umin,"i");
+MODULE_PARM_DESC(umin, "The input endpoint of a semi-compliant interface");
+
+static int umout       = -1;
+MODULE_PARM(umout,"i");
+MODULE_PARM_DESC(umout, "The output endpoint of a semi-compliant interface");
+
+static int ucable      = -1;
+MODULE_PARM(ucable,"i");
+MODULE_PARM_DESC(ucable, "The cable number used for a semi-compliant interface");
+
+/** Note -- the usb_string() returns only Latin-1 characters.
+ * (unicode chars <= 255). To support Japanese, a unicode16LE-to-EUC or
+ * unicode16LE-to-JIS routine is needed to wrap around usb_get_string().
+ **/
+static unsigned short ulangid      = 0x0409; /** 0x0411 for Japanese **/
+MODULE_PARM(ulangid,"h");
+MODULE_PARM_DESC(ulangid, "The optional preferred USB Language ID for all devices");
+
+MODULE_AUTHOR("NAGANO Daisuke <breeze.nagano@nifty.ne.jp>");
+MODULE_DESCRIPTION("USB-MIDI driver");
+#if LINUX_VERSION_CODE  >= KERNEL_VERSION(2,4,14)
+MODULE_LICENSE("GPL");
+#endif
+
+/* ------------------------------------------------------------------------- */
+
+/** MIDIStreaming Class-Specific Interface Descriptor Subtypes **/
+
+#define MS_DESCRIPTOR_UNDEFINED	0
+#define MS_HEADER		1
+#define MIDI_IN_JACK		2
+#define MIDI_OUT_JACK		3
+/* Spec reads: ELEMENT */
+#define ELEMENT_DESCRIPTOR   	4
+
+#define MS_HEADER_LENGTH	7
+
+/** MIDIStreaming Class-Specific Endpoint Descriptor Subtypes **/
+
+#define DESCRIPTOR_UNDEFINED	0
+/* Spec reads: MS_GENERAL */
+#define MS_GENERAL_ENDPOINT	1
+
+/** MIDIStreaming MIDI IN and OUT Jack Types **/
+
+#define JACK_TYPE_UNDEFINED	0
+/* Spec reads: EMBEDDED */
+#define EMBEDDED_JACK		1
+/* Spec reads: EXTERNAL */
+#define EXTERNAL_JACK		2
+
+
+/* structure summary
+  
+      usb_midi_state     usb_device
+       |         |
+      *|        *|       per ep
+     in_ep     out_ep
+       |         |
+      *|        *|       per cable
+      min       mout
+       |         |       (cable to device pairing magic)
+       |         |
+       usb_midi_dev      dev_id (major,minor) == file->private_data
+
+*/
+
+/* usb_midi_state: corresponds to a USB-MIDI module */
+struct usb_midi_state {
+	struct list_head   mididev;
+	
+	struct usb_device *usbdev;
+	
+	struct list_head   midiDevList;
+	struct list_head   inEndpointList;
+	struct list_head   outEndpointList;
+	
+	spinlock_t         lock;
+	
+	unsigned int       count; /* usage counter */
+};
+
+/* midi_out_endpoint: corresponds to an output endpoint */
+struct midi_out_endpoint {
+	struct list_head  list;
+	
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+	
+	unsigned char     *buf;
+	int                bufWrPtr;
+	int                bufSize;
+	
+	struct urb       *urb;
+};
+
+/* midi_in_endpoint: corresponds to an input endpoint */
+struct midi_in_endpoint {
+	struct list_head   list;
+
+	struct usb_device *usbdev;
+	int                endpoint;
+	spinlock_t         lock;
+	wait_queue_head_t  wait;
+
+	struct usb_mididev *cables[16];	// cables open for read
+	int                 readers;	// number of cables open for read
+
+	struct urb        *urb;
+	unsigned char     *recvBuf;
+	int                recvBufSize;
+	int                urbSubmitted;	//FIXME: == readers > 0
+};
+
+/* usb_mididev: corresponds to a logical device */
+struct usb_mididev {
+	struct list_head       list;
+
+	struct usb_midi_state *midi;
+	int                    dev_midi;
+	mode_t                 open_mode;
+
+	struct {
+		struct midi_in_endpoint *ep;
+		int              cableId;
+		
+// as we are pushing data from usb_bulk_read to usb_midi_read,
+// we need a larger, cyclic buffer here.
+		unsigned char    buf[MIDI_IN_BUFSIZ];
+		int              bufRdPtr;
+		int              bufWrPtr;
+		int              bufRemains;
+	} min;
+
+	struct {
+		struct midi_out_endpoint *ep;
+		int              cableId;
+		
+		unsigned char    buf[3];
+		int              bufPtr;
+		int              bufRemains;
+		
+		int              isInExclusive;
+		unsigned char    lastEvent;
+	} mout;
+
+	int singlebyte;
+};
+
+/** Map the high nybble of MIDI voice messages to number of Message bytes.
+ * High nyble ranges from 0x8 to 0xe
+ */
+
+static int remains_80e0[] = {
+	3,	/** 0x8X Note Off **/
+	3,	/** 0x9X Note On **/
+	3,	/** 0xAX Poly-key pressure **/
+	3,	/** 0xBX Control Change **/
+	2,	/** 0xCX Program Change **/
+	2,	/** 0xDX Channel pressure **/
+	3 	/** 0xEX PitchBend Change **/
+};
+
+/** Map the messages to a number of Message bytes.
+ *
+ **/
+static int remains_f0f6[] = {
+	0,	/** 0xF0 **/
+	2,	/** 0XF1 **/
+	3,	/** 0XF2 **/
+	2,	/** 0XF3 **/
+	2,	/** 0XF4 (Undefined by MIDI Spec, and subject to change) **/
+	2,	/** 0XF5 (Undefined by MIDI Spec, and subject to change) **/
+	1	/** 0XF6 **/
+};
+
+/** Map the messages to a CIN (Code Index Number).
+ *
+ **/
+static int cin_f0ff[] = {
+	4,	/** 0xF0 System Exclusive Message Start (special cases may be 6 or 7) */
+	2,	/** 0xF1 **/
+	3,	/** 0xF2 **/
+	2,	/** 0xF3 **/
+	2,	/** 0xF4 **/
+	2,	/** 0xF5 **/
+	5,	/** 0xF6 **/
+	5,	/** 0xF7 End of System Exclusive Message (May be 6 or 7) **/
+	5,	/** 0xF8 **/
+	5,	/** 0xF9 **/
+	5,	/** 0xFA **/
+	5,	/** 0xFB **/
+	5,	/** 0xFC **/
+	5,	/** 0xFD **/
+	5,	/** 0xFE **/
+	5	/** 0xFF **/
+};
+
+/** Map MIDIStreaming Event packet Code Index Number (low nybble of byte 0)
+ * to the number of bytes of valid MIDI data.
+ *
+ * CIN of 0 and 1 are NOT USED in MIDIStreaming 1.0.
+ *
+ **/
+static int cin_to_len[] = {
+	0, 0, 2, 3,
+	3, 1, 2, 3,
+	3, 3, 3, 3,
+	2, 2, 3, 1
+};
+
+
+/* ------------------------------------------------------------------------- */
+
+static struct list_head mididevs = LIST_HEAD_INIT(mididevs);
+
+static DECLARE_MUTEX(open_sem);
+static DECLARE_WAIT_QUEUE_HEAD(open_wait);
+
+
+/* ------------------------------------------------------------------------- */
+
+static void usb_write_callback(struct urb *urb)
+{
+	struct midi_out_endpoint *ep = (struct midi_out_endpoint *)urb->context;
+
+	if ( waitqueue_active( &ep->wait ) )
+		wake_up_interruptible( &ep->wait );
+}
+
+
+static int usb_write( struct midi_out_endpoint *ep, unsigned char *buf, int len )
+{
+	struct usb_device *d;
+	int pipe;
+	int ret = 0;
+	int status;
+	int maxretry = 50;
+	
+	DECLARE_WAITQUEUE(wait,current);
+	init_waitqueue_head(&ep->wait);
+
+	d = ep->usbdev;
+	pipe = usb_sndbulkpipe(d, ep->endpoint);
+	FILL_BULK_URB( ep->urb, d, pipe, (unsigned char*)buf, len,
+		       (usb_complete_t)usb_write_callback, ep );
+
+	status = usb_submit_urb(ep->urb, GFP_KERNEL);
+    
+	if (status) {
+		printk(KERN_ERR "usbmidi: Cannot submit urb (%d)\n",status);
+		ret = -EFAULT;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	set_current_state( TASK_INTERRUPTIBLE );
+
+	while( ep->urb->status == -EINPROGRESS ) {
+		if ( maxretry-- < 0 ) {
+			printk(KERN_ERR "usbmidi: usb_bulk_msg timed out\n");
+			ret = -ETIME;
+			break;
+		}
+		interruptible_sleep_on_timeout( &ep->wait, 10 );
+	}
+	set_current_state( TASK_RUNNING );
+	remove_wait_queue( &ep->wait, &wait );
+
+	return ret;
+}
+
+
+/** Copy data from URB to In endpoint buf.
+ * Discard if CIN == 0 or CIN = 1.
+ *
+ *
+ **/
+
+static void usb_bulk_read(struct urb *urb)
+{
+	struct midi_in_endpoint *ep = (struct midi_in_endpoint *)(urb->context);
+	unsigned char *data = urb->transfer_buffer;
+	int i, l, wake;
+	unsigned long int flags;
+
+	if ( !ep->urbSubmitted ) {
+		return;
+	}
+
+	if ( (urb->status == 0) && (urb->actual_length > 0) ) {
+		wake = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+
+		for(l = 0; l < urb->actual_length; l += 4) {
+			int cin = (data[l]>>0)&0xf;
+			int cab = (data[l]>>4)&0xf;
+			struct usb_mididev *cable = ep->cables[cab];
+			if ( cable ) {
+				int len = cin_to_len[cin]; /** length of MIDI data **/
+				for (i = 0; i < len; i++) {
+					cable->min.buf[cable->min.bufWrPtr] = data[1+i];
+					cable->min.bufWrPtr = (cable->min.bufWrPtr+1)%MIDI_IN_BUFSIZ;
+					if (cable->min.bufRemains < MIDI_IN_BUFSIZ)
+						cable->min.bufRemains += 1;
+					else /** need to drop data **/
+						cable->min.bufRdPtr += (cable->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+					wake = 1;
+				}
+			}
+		}
+
+		spin_unlock_irqrestore( &ep->lock, flags );
+		if ( wake ) {
+			wake_up( &ep->wait );
+		}
+	}
+
+	/* urb->dev must be reinitialized on 2.4.x kernels */
+	urb->dev = ep->usbdev;
+
+	urb->actual_length = 0;
+	usb_submit_urb(urb, GFP_KERNEL);
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+/* This routine must be called with spin_lock */
+
+/** Wrapper around usb_write().
+ *  This routine must be called with spin_lock held on ep.
+ *  Called by midiWrite(), putOneMidiEvent(), and  usb_midi_write();
+ **/
+static int flush_midi_buffer( struct midi_out_endpoint *ep )
+{
+	int ret=0;
+
+	if ( ep->bufWrPtr > 0 ) {
+		ret = usb_write( ep, ep->buf, ep->bufWrPtr );
+		ep->bufWrPtr = 0;
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Given a MIDI Event, determine size of data to be attached to 
+ * USB-MIDI packet.
+ * Returns 1, 2 or 3.
+ * Called by midiWrite();
+ * Uses remains_80e0 and remains_f0f6;
+ **/
+static int get_remains(int event)
+{
+	int ret;
+
+	if ( event  < 0x80 ) {
+		ret = 1;
+	} else if ( event < 0xf0 ) {
+		ret = remains_80e0[((event-0x80)>>4)&0x0f];
+	} else if ( event < 0xf7 ) {
+		ret = remains_f0f6[event-0xf0];
+	} else {
+		ret = 1;
+	}
+
+	return ret;
+}
+
+/** Given the output MIDI data in the output buffer, computes a reasonable 
+ * CIN.
+ * Called by putOneMidiEvent().
+ **/
+static int get_CIN( struct usb_mididev *m )
+{
+	int cin;
+
+	if ( m->mout.buf[0] == 0xf7 ) {
+		cin = 5;
+	}
+	else if ( m->mout.buf[1] == 0xf7 ) {
+		cin = 6;
+	}
+	else if ( m->mout.buf[2] == 0xf7 ) {
+		cin = 7;
+	}
+	else {
+		if ( m->mout.isInExclusive == 1 ) {
+			cin = 4;
+		} else if ( m->mout.buf[0] < 0x80 ) {
+			/** One byte that we know nothing about. **/
+			cin = 0xF; 
+		} else if ( m->mout.buf[0] < 0xf0 ) {
+			/** MIDI Voice messages 0x8X to 0xEX map to cin 0x8 to 0xE. **/
+			cin = (m->mout.buf[0]>>4)&0x0f; 
+		}
+		else {
+			/** Special lookup table exists for real-time events. **/
+			cin = cin_f0ff[m->mout.buf[0]-0xf0];
+		}
+	}
+
+	return cin;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+
+/** Move data to USB endpoint buffer.
+ *
+ **/
+static int put_one_midi_event(struct usb_mididev *m)
+{
+	int cin;
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+
+	cin = get_CIN( m );
+	if ( cin > 0x0f || cin < 0 ) {
+		return -EINVAL;
+	}
+
+	spin_lock_irqsave( &ep->lock, flags );
+	ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) | cin;
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[0];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[1];
+	ep->buf[ep->bufWrPtr++] = m->mout.buf[2];
+	if ( ep->bufWrPtr >= ep->bufSize ) {
+		ret = flush_midi_buffer( ep );
+	}
+	spin_unlock_irqrestore( &ep->lock, flags);
+
+	m->mout.buf[0] = m->mout.buf[1] = m->mout.buf[2] = 0;
+	m->mout.bufPtr = 0;
+
+	return ret;
+}
+
+/** Write the MIDI message v on the midi device.
+ *  Called by usb_midi_write();
+ *  Responsible for packaging a MIDI data stream into USB-MIDI packets.
+ **/
+
+static int midi_write( struct usb_mididev *m, int v )
+{
+	unsigned long flags;
+	struct midi_out_endpoint *ep = m->mout.ep;
+	int ret=0;
+	unsigned char c = (unsigned char)v;
+	unsigned char sysrt_buf[4];
+
+	if ( m->singlebyte != 0 ) {
+		/** Simple code to handle the single-byte USB-MIDI protocol. */
+		spin_lock_irqsave( &ep->lock, flags );
+		if ( ep->bufWrPtr+4 > ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+			if ( !ret ) {
+				spin_unlock_irqrestore( &ep->lock, flags );
+				return ret;
+			}
+		}
+		ep->buf[ep->bufWrPtr++] = (m->mout.cableId<<4) |  0x0f; /* single byte */
+		ep->buf[ep->bufWrPtr++] = c;
+		ep->buf[ep->bufWrPtr++] = 0;
+		ep->buf[ep->bufWrPtr++] = 0;
+		if ( ep->bufWrPtr >= ep->bufSize ) {
+			ret = flush_midi_buffer( ep );
+		}
+		spin_unlock_irqrestore( &ep->lock, flags );
+
+		return ret;
+	}
+	/** Normal USB-MIDI protocol begins here. */
+
+	if ( c > 0xf7 ) {	/* system: Realtime messages */
+		/** Realtime messages are written IMMEDIATELY. */
+		sysrt_buf[0] = (m->mout.cableId<<4) | 0x0f;
+		sysrt_buf[1] = c;
+		sysrt_buf[2] = 0;
+		sysrt_buf[3] = 0;
+		spin_lock_irqsave( &ep->lock, flags );
+		ret = usb_write( ep, sysrt_buf, 4 );
+		spin_unlock_irqrestore( &ep->lock, flags );
+		/* m->mout.lastEvent = 0; */
+
+		return ret;
+	}
+
+	if ( c >= 0x80 ) {
+		if ( c < 0xf0 ) {
+			m->mout.lastEvent = c;
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 1;
+			m->mout.bufRemains = get_remains(c);
+		} else if ( c == 0xf7 && m->mout.isInExclusive == 1 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = 1;
+		} else if ( c > 0xf0 ) {
+			/* m->mout.lastEvent = 0; */
+			m->mout.isInExclusive = 0;
+			m->mout.bufRemains = get_remains(c);
+		}
+    
+	} else if ( m->mout.bufRemains == 0 && m->mout.isInExclusive == 0 ) {
+		if ( m->mout.lastEvent == 0 ) {
+			return 0; /* discard, waiting for the first event */
+		}
+		/** track status **/
+		m->mout.buf[0] = m->mout.lastEvent;
+		m->mout.bufPtr = 1;
+		m->mout.bufRemains = get_remains(m->mout.lastEvent)-1;
+	}
+  
+	m->mout.buf[m->mout.bufPtr++] = c;
+	m->mout.bufRemains--;
+	if ( m->mout.bufRemains == 0 || m->mout.bufPtr >= 3) {
+		ret = put_one_midi_event(m);
+	}
+
+	return ret;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Used to change the current read/write position in a file.
+ *  On success, the non-negative position is reported.
+ *  On failure, the negative of an error code is reported.
+ *
+ *  Because a MIDIStream is not a file, all seek operations are doomed to fail.
+ *
+ **/
+static loff_t usb_midi_llseek(struct file *file, loff_t offset, int origin)
+{
+	/** Tell user you cannot seek on a PIPE-like device. **/
+	return -ESPIPE;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: Block until count bytes have been read or an error occurs.
+ *
+ **/
+
+static ssize_t usb_midi_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *ep = m->min.ep;
+	ssize_t ret;
+	DECLARE_WAITQUEUE(wait, current);
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	add_wait_queue( &ep->wait, &wait );
+	ret = 0;
+	while( count > 0 ) {
+		int cnt;
+		int d = (int)count;
+
+		cnt = m->min.bufRemains;
+		if ( cnt > d ) {
+			cnt = d;
+		}
+
+		if ( cnt <= 0 ) {
+			if ( file->f_flags & O_NONBLOCK ) {
+				if (!ret) 
+					ret = -EAGAIN;
+				break;
+			}
+			__set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+			if (signal_pending(current)) {
+				if(!ret)
+					ret=-ERESTARTSYS;
+				break;
+			}
+			continue;
+		}
+
+		{
+			int i;
+			unsigned long flags; /* used to synchronize access to the endpoint */
+			spin_lock_irqsave( &ep->lock, flags );
+			for (i = 0; i < cnt; i++) {
+				if ( copy_to_user( buffer+i, m->min.buf+m->min.bufRdPtr, 1 ) ) {
+					if ( !ret )
+						ret = -EFAULT;
+					break;
+				}
+				m->min.bufRdPtr = (m->min.bufRdPtr+1)%MIDI_IN_BUFSIZ;
+				m->min.bufRemains -= 1;
+			}
+			spin_unlock_irqrestore( &ep->lock, flags );
+		}
+
+		count-=cnt;
+		buffer+=cnt;
+		ret+=cnt;
+
+		break;
+	}
+
+	remove_wait_queue( &ep->wait, &wait );
+	set_current_state(TASK_RUNNING);
+
+	return ret;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic Contract: Take MIDI data byte-by-byte and pass it to
+ *  writeMidi() which packages MIDI data into USB-MIDI stream.
+ *  Then flushMidiData() is called to ensure all bytes have been written
+ *  in a timely fashion.
+ *
+ **/
+
+static ssize_t usb_midi_write(struct file *file, const char *buffer, size_t count, loff_t *ppos)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	ssize_t ret;
+	unsigned long int flags;
+
+	if ( ppos != &file->f_pos ) {
+		return -ESPIPE;
+	}
+	if ( !access_ok(VERIFY_READ, buffer, count) ) {
+		return -EFAULT;
+	}
+	if ( count == 0 ) {
+		return 0;
+	}
+
+	ret = 0;
+	while( count > 0 ) {
+		unsigned char c;
+
+		if (copy_from_user((unsigned char *)&c, buffer, 1)) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		if( midi_write(m, (int)c) ) {
+			if ( ret == 0 )
+				ret = -EFAULT;
+			break;
+		}
+		count--;
+		buffer++;
+		ret++;
+	}
+
+	spin_lock_irqsave( &m->mout.ep->lock, flags );
+	if ( flush_midi_buffer(m->mout.ep) < 0 ) {
+		ret = -EFAULT;
+	}
+	spin_unlock_irqrestore( &m->mout.ep->lock, flags );
+
+	return ret;
+}
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract:  Wait (spin) until ready to read or write on the file.
+ *
+ **/
+static unsigned int usb_midi_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct midi_in_endpoint *iep = m->min.ep;
+	struct midi_out_endpoint *oep = m->mout.ep;
+	unsigned long flags;
+	unsigned int mask = 0;
+  
+	if ( file->f_mode & FMODE_READ ) {
+		poll_wait( file, &iep->wait, wait );
+		spin_lock_irqsave( &iep->lock, flags );
+		if ( m->min.bufRemains > 0 )
+			mask |= POLLIN | POLLRDNORM;
+		spin_unlock_irqrestore( &iep->lock, flags );
+	}
+
+	if ( file->f_mode & FMODE_WRITE ) {
+		poll_wait( file, &oep->wait, wait );
+		spin_lock_irqsave( &oep->lock, flags );
+		if ( oep->bufWrPtr < oep->bufSize )
+			mask |= POLLOUT | POLLWRNORM;
+		spin_unlock_irqrestore( &oep->lock, flags );
+	}
+
+	return mask;
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ * Basic contract: This is always the first operation performed on the
+ * device node. If no method is defined, the open succeeds without any
+ * notification given to the module.
+ *
+ **/
+
+static int usb_midi_open(struct inode *inode, struct file *file)
+{
+	int minor = minor(inode->i_rdev);
+	DECLARE_WAITQUEUE(wait, current);
+	struct list_head      *devs, *mdevs;
+	struct usb_midi_state *s;
+	struct usb_mididev    *m;
+	int flags;
+	int succeed = 0;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open minor= %d.\n", minor);
+#endif
+
+	for(;;) {
+		down(&open_sem);
+		for (devs = mididevs.next; devs != &mididevs; devs = devs->next) {
+			s = list_entry(devs, struct usb_midi_state, mididev);
+			for (mdevs = s->midiDevList.next; mdevs != &s->midiDevList; mdevs = mdevs->next) {
+				m = list_entry(mdevs, struct usb_mididev, list);
+				if ( !((m->dev_midi ^ minor) & ~0xf) )
+					goto device_found;
+			}
+		}
+		up(&open_sem);
+		return -ENODEV;
+
+	device_found:
+		if ( !s->usbdev ) {
+			up(&open_sem);
+			return -EIO;
+		}
+		if ( !(m->open_mode & file->f_mode) ) {
+			break;
+		}
+		if ( file->f_flags & O_NONBLOCK ) {
+			up(&open_sem);
+			return -EBUSY;
+		}
+		__set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue( &open_wait, &wait );
+		up(&open_sem);
+		schedule();
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue( &open_wait, &wait );
+		if ( signal_pending(current) ) {
+			return -ERESTARTSYS;
+		}
+	}
+
+	file->private_data = m;
+	spin_lock_irqsave( &s->lock, flags );
+
+	if ( !(m->open_mode & (FMODE_READ | FMODE_WRITE)) ) {
+		//FIXME: intented semantics unclear here
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_lock_init(&m->min.ep->lock);
+
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		spin_lock_init(&m->mout.ep->lock);
+	}
+
+	if ( (file->f_mode & FMODE_READ) && m->min.ep != NULL ) {
+		unsigned long int flagsep;
+		spin_lock_irqsave( &m->min.ep->lock, flagsep );
+		m->min.ep->cables[m->min.cableId] = m;
+		m->min.ep->readers += 1;
+		m->min.bufRdPtr       = 0;
+		m->min.bufWrPtr       = 0;
+		m->min.bufRemains     = 0;
+		spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+
+		if ( !(m->min.ep->urbSubmitted)) {
+
+			/* urb->dev must be reinitialized on 2.4.x kernels */
+			m->min.ep->urb->dev = m->min.ep->usbdev;
+
+			if ( usb_submit_urb(m->min.ep->urb, GFP_ATOMIC) ) {
+				printk(KERN_ERR "usbmidi: Cannot submit urb for MIDI-IN\n");
+			}
+			m->min.ep->urbSubmitted = 1;
+		}
+		m->open_mode |= FMODE_READ;
+		succeed = 1;
+	}
+
+	if ( (file->f_mode & FMODE_WRITE) && m->mout.ep != NULL ) {
+		m->mout.bufPtr        = 0;
+		m->mout.bufRemains    = 0;
+		m->mout.isInExclusive = 0;
+		m->mout.lastEvent     = 0;
+		m->open_mode |= FMODE_WRITE;
+		succeed = 1;
+	}
+
+	spin_unlock_irqrestore( &s->lock, flags );
+
+	s->count++;
+	up(&open_sem);
+
+	/** Changed to prevent extra increments to USE_COUNT. **/
+	if (!succeed) {
+		return -EBUSY;
+	}
+
+#if 0
+	printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor);
+#endif
+
+	/** Side-effect: module cannot be removed until USE_COUNT is 0. **/
+#ifndef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return 0; /** Success. **/
+}
+
+
+/** Basic operation on /dev/midiXX as registered through struct file_operations.
+ *
+ *  Basic contract: Close an opened file and deallocate anything we allocated.
+ *  Like open(), this can be missing. If open set file->private_data,
+ *  release() must clear it.
+ *
+ **/
+
+static int usb_midi_release(struct inode *inode, struct file *file)
+{
+	struct usb_mididev *m = (struct usb_mididev *)file->private_data;
+	struct usb_midi_state *s = (struct usb_midi_state *)m->midi;
+
+#if 0
+	printk(KERN_INFO "usb-midi: Close.\n");
+#endif
+
+	down(&open_sem);
+
+	if ( m->open_mode & FMODE_WRITE ) {
+		m->open_mode &= ~FMODE_WRITE;
+		usb_unlink_urb( m->mout.ep->urb );
+	}
+
+	if ( m->open_mode & FMODE_READ ) {
+	        unsigned long int flagsep;
+	        spin_lock_irqsave( &m->min.ep->lock, flagsep );
+                m->min.ep->cables[m->min.cableId] = 0; // discard cable
+                m->min.ep->readers -= 1;
+		m->open_mode &= ~FMODE_READ;
+		if ( m->min.ep->readers == 0 &&
+                     m->min.ep->urbSubmitted ) {
+			m->min.ep->urbSubmitted = 0;
+			usb_unlink_urb(m->min.ep->urb);
+		}
+	        spin_unlock_irqrestore( &m->min.ep->lock, flagsep );
+	}
+
+	s->count--;
+
+	up(&open_sem);
+	wake_up(&open_wait);
+
+	file->private_data = 0;
+	/** Sideeffect: Module cannot be removed until usecount is 0. */
+#ifndef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return 0;
+}
+
+static struct file_operations usb_midi_fops = {
+	llseek:		usb_midi_llseek,
+	read:		usb_midi_read,
+	write:		usb_midi_write,
+	poll:		usb_midi_poll,
+	open:		usb_midi_open,
+	release:	usb_midi_release,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns filled midi_in_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static struct midi_in_endpoint *alloc_midi_in_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_in_endpoint *ep;
+	int bufSize;
+	int pipe;
+
+	endPoint &= 0x0f; /* Silently force endPoint to lie in range 0 to 15. */
+
+	pipe =  usb_rcvbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipein(pipe) );
+	/* usb_pipein() = ! usb_pipeout() = true for an in Endpoint */
+
+	ep = (struct midi_in_endpoint *)kmalloc(sizeof(struct midi_in_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_in_endpoint) );
+//      this sets cables[] and readers to 0, too.
+//      for (i=0; i<16; i++) ep->cables[i] = 0; // discard cable
+//      ep->readers = 0;
+
+	ep->endpoint = endPoint;
+
+	ep->recvBuf = (unsigned char *)kmalloc(sizeof(unsigned char)*(bufSize), GFP_KERNEL);
+	if ( !ep->recvBuf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi in-endpoint urb\n");
+		kfree(ep->recvBuf);
+		kfree(ep);
+		return NULL;
+	}
+	FILL_BULK_URB( ep->urb, d, 
+		       usb_rcvbulkpipe(d, endPoint),
+		       (unsigned char *)ep->recvBuf, bufSize,
+		       (usb_complete_t)usb_bulk_read, ep );
+
+	/* ep->bufRdPtr     = 0; */
+	/* ep->bufWrPtr     = 0; */
+	/* ep->bufRemains   = 0; */
+	/* ep->urbSubmitted = 0; */
+	ep->recvBufSize  = bufSize;
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+static int remove_midi_in_endpoint( struct midi_in_endpoint *min )
+{
+	usb_unlink_urb( min->urb );
+	usb_free_urb( min->urb );
+	kfree( min->recvBuf );
+	kfree( min );
+
+	return 0;
+}
+
+/** Returns filled midi_out_endpoint structure or null on failure.
+ *
+ * Parameters:
+ *	d        - a usb_device
+ *	endPoint - An usb endpoint in the range 0 to 15.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct midi_out_endpoint *alloc_midi_out_endpoint( struct usb_device *d, int endPoint )
+{
+	struct midi_out_endpoint *ep = NULL;
+	int pipe;
+	int bufSize;
+
+	endPoint &= 0x0f;
+	pipe =  usb_sndbulkpipe( d, endPoint );
+	bufSize = usb_maxpacket( d, pipe, usb_pipeout(pipe) );
+
+	ep = (struct midi_out_endpoint *)kmalloc(sizeof(struct midi_out_endpoint), GFP_KERNEL);
+	if ( !ep ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint\n");
+		return NULL;
+	}
+	memset( ep, 0, sizeof(struct midi_out_endpoint) );
+
+	ep->endpoint = endPoint;
+	ep->buf = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !ep->buf ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint buffer\n");
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->urb = usb_alloc_urb(0, GFP_KERNEL); /* no ISO */
+	if ( !ep->urb ) {
+		printk(KERN_ERR "usbmidi: no memory for midi out-endpoint urb\n");
+		kfree(ep->buf);
+		kfree(ep);
+		return NULL;
+	}
+
+	ep->bufSize       = bufSize;
+	/* ep->bufWrPtr      = 0; */
+
+	init_waitqueue_head(&ep->wait);
+
+	return ep;
+}
+
+
+static int remove_midi_out_endpoint( struct midi_out_endpoint *mout )
+{
+	usb_unlink_urb( mout->urb );
+	usb_free_urb( mout->urb );
+	kfree( mout->buf );
+	kfree( mout );
+
+	return 0;
+}
+
+
+/** Returns a filled usb_mididev structure, registered as a Linux MIDI device.
+ *
+ * Returns null if memory is not available or the device cannot be registered.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+static struct usb_mididev *allocMidiDev(
+	struct usb_midi_state *s,
+	struct midi_in_endpoint *min,
+	struct midi_out_endpoint *mout,
+	int inCableId,
+	int outCableId )
+{
+	struct usb_mididev *m;
+
+	m = (struct usb_mididev *)kmalloc(sizeof(struct usb_mididev), GFP_KERNEL);
+	if (!m) {
+		printk(KERN_ERR "usbmidi: no memory for midi device\n");
+		return NULL;
+	}
+
+	memset(m, 0, sizeof(struct usb_mididev));
+
+	if ((m->dev_midi = register_sound_midi(&usb_midi_fops, -1)) < 0) {
+		printk(KERN_ERR "usbmidi: cannot register midi device\n");
+		kfree(m);
+		return NULL;
+	}
+
+	m->midi               = s;
+	/* m->open_mode          = 0; */
+
+	if ( min ) {
+		m->min.ep             = min;
+		m->min.ep->usbdev     = s->usbdev;
+		m->min.cableId        = inCableId;
+	}
+	/* m->min.bufPtr         = 0; */
+	/* m->min.bufRemains     = 0; */
+
+	if ( mout ) {
+		m->mout.ep            = mout;
+		m->mout.ep->usbdev    = s->usbdev;
+		m->mout.cableId       = outCableId;
+	}
+	/* m->mout.bufPtr        = 0; */
+	/* m->mout.bufRemains    = 0; */
+	/* m->mout.isInExclusive = 0; */
+	/* m->mout.lastEvent     = 0; */
+
+	m->singlebyte         = singlebyte;
+
+	return m;
+}
+
+
+static void release_midi_device( struct usb_midi_state *s )
+{
+	struct usb_mididev *m;
+	struct midi_in_endpoint *min;
+	struct midi_out_endpoint *mout;
+
+	if ( s->count > 0 ) {
+		up(&open_sem);
+		return;
+	}
+	up( &open_sem );
+	wake_up( &open_wait );
+
+	while(!list_empty(&s->inEndpointList)) {
+		min = list_entry(s->inEndpointList.next, struct midi_in_endpoint, list);
+		list_del(&min->list);
+		remove_midi_in_endpoint(min);
+	}
+
+	while(!list_empty(&s->outEndpointList)) {
+		mout = list_entry(s->outEndpointList.next, struct midi_out_endpoint, list);
+		list_del(&mout->list);
+		remove_midi_out_endpoint(mout);
+	}
+
+	while(!list_empty(&s->midiDevList)) {
+		m = list_entry(s->midiDevList.next, struct usb_mididev, list);
+		list_del(&m->list);
+		kfree(m);
+	}
+
+	kfree(s);
+
+	return;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+/** Utility routine to find a descriptor in a dump of many descriptors.
+ * Returns start of descriptor or NULL if not found. 
+ * descStart pointer to list of interfaces.
+ * descLength length (in bytes) of dump
+ * after (ignored if NULL) this routine returns only descriptors after "after"
+ * dtype (mandatory) The descriptor type.
+ * iface (ignored if -1) returns descriptor at/following given interface
+ * altSetting (ignored if -1) returns descriptor at/following given altSetting
+ *
+ *
+ *  Called by parseDescriptor(), find_csinterface_descriptor();
+ *
+ */
+static void *find_descriptor( void *descStart, unsigned int descLength, void *after, unsigned char dtype, int iface, int altSetting )
+{
+	unsigned char *p, *end, *next;
+	int interfaceNumber = -1, altSet = -1;
+
+	p = descStart;
+	end = p + descLength;
+	for( ; p < end; ) {
+		if ( p[0] < 2 )
+			return NULL;
+		next = p + p[0];
+		if ( next > end )
+			return NULL;
+		if ( p[1] == USB_DT_INTERFACE ) {
+			if ( p[0] < USB_DT_INTERFACE_SIZE )
+				return NULL;
+			interfaceNumber = p[2];
+			altSet = p[3];
+		}
+		if ( p[1] == dtype &&
+		     ( !after || ( p > (unsigned char *)after) ) &&
+		     ( ( iface == -1) || (iface == interfaceNumber) ) &&
+		     ( (altSetting == -1) || (altSetting == altSet) )) {
+			return p;
+		}
+		p = next;
+	}
+	return NULL;
+}
+
+/** Utility to find a class-specfic interface descriptor.
+ *  dsubtype is a descriptor subtype
+ *  Called by parseDescriptor();
+ **/
+static void *find_csinterface_descriptor(void *descStart, unsigned int descLength, void *after, u8 dsubtype, int iface, int altSetting)
+{
+	unsigned char *p;
+  
+	p = find_descriptor( descStart, descLength, after, USB_DT_CS_INTERFACE, iface, altSetting );
+	while ( p ) {
+		if ( p[0] >= 3 && p[2] == dsubtype )
+			return p;
+		p = find_descriptor( descStart, descLength, p, USB_DT_CS_INTERFACE, 
+				     iface, altSetting );
+	}
+	return NULL;
+}
+
+
+/** The magic of making a new usb_midi_device from config happens here.
+ *
+ * The caller is responsible for free-ing this return value (if not NULL).
+ *
+ **/
+static struct usb_midi_device *parse_descriptor( struct usb_device *d, unsigned char *buffer, int bufSize, unsigned int ifnum , unsigned int altSetting, int quirks)
+{
+	struct usb_midi_device *u;
+	unsigned char *p1;
+	unsigned char *p2;
+	unsigned char *next;
+	int iep, oep;
+	int length;
+	unsigned long longBits;
+	int pins, nbytes, offset, shift, jack;
+#ifdef HAVE_JACK_STRINGS
+	/** Jacks can have associated names.  **/
+	unsigned char jack2string[256];
+#endif
+
+	u = 0;
+	/* find audiocontrol interface */
+	p1 = find_csinterface_descriptor( buffer, bufSize, NULL,
+					  MS_HEADER, ifnum, altSetting);
+
+	if ( !p1 ) {
+		goto error_end;
+	}
+
+	if ( p1[0] < MS_HEADER_LENGTH ) {
+		goto error_end;
+	}
+
+	/* Assume success. Since the device corresponds to USB-MIDI spec, we assume
+	   that the rest of the USB 2.0 spec is obeyed. */
+
+	u = (struct usb_midi_device *)kmalloc( sizeof(struct usb_midi_device), GFP_KERNEL );
+	if ( !u ) {
+		return NULL;
+	}
+	u->deviceName = 0;
+	u->idVendor = d->descriptor.idVendor;
+	u->idProduct = d->descriptor.idProduct;
+	u->interface = ifnum;
+	u->altSetting = altSetting;
+	u->in[0].endpoint = -1;
+	u->in[0].cableId = -1;
+	u->out[0].endpoint = -1;
+	u->out[0].cableId = -1;
+
+
+	printk(KERN_INFO "usb-midi: Found MIDIStreaming device corresponding to Release %d.%02d of spec.\n",
+	       (p1[4] >> 4) * 10 + (p1[4] & 0x0f ),
+	       (p1[3] >> 4) * 10 + (p1[3] & 0x0f )
+		);
+
+	length = p1[5] | (p1[6] << 8);
+
+#ifdef HAVE_JACK_STRINGS
+	memset(jack2string, 0, sizeof(unsigned char) * 256);
+#endif
+
+	length -= p1[0];
+	for (p2 = p1 + p1[0]; length > 0; p2 = next) {
+		next = p2 + p2[0];
+		length -= p2[0];
+
+		if (p2[0] < 2 ) break;
+		if (p2[1] != USB_DT_CS_INTERFACE) break;
+		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5];
+#endif
+			printk(KERN_INFO "usb-midi: Found IN Jack 0x%02x %s\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
+		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
+			pins = p2[5];
+			if ( p2[0] < (6 + 2 * pins) ) continue;
+			jack = p2[4];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[5 + 2 * pins];
+#endif
+			printk(KERN_INFO "usb-midi: Found OUT Jack 0x%02x %s, %d pins\n",
+			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
+		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
+			pins = p2[4];
+			if ( p2[0] < (9 + 2 * pins ) ) continue;
+			nbytes = p2[8 + 2 * pins ];
+			if ( p2[0] < (10 + 2 * pins + nbytes) ) continue;
+			longBits = 0L;
+			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
+				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
+			}
+			jack = p2[3];
+#ifdef HAVE_JACK_STRINGS
+			jack2string[jack] = p2[9 + 2 * pins + nbytes];
+#endif
+			printk(KERN_INFO "usb-midi: Found ELEMENT 0x%02x, %d/%d pins in/out, bits: 0x%016lx\n",
+			       jack, pins, (int)(p2[5 + 2 * pins]), (long)longBits );
+		} else {
+		}
+	}
+
+	iep=0;
+	oep=0;
+
+	if (quirks==0) {
+		/* MIDISTREAM */
+		p2 = 0;
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+			p2 = find_descriptor(buffer, bufSize, p1, USB_DT_CS_ENDPOINT,
+					     ifnum, altSetting ); 
+
+			if ( p2 && next && ( p2 > next ) )
+				p2 = 0;
+
+			if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = p2[3]; /* not pins -- actually "cables" */
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	} else if (quirks==1) {
+		/* YAMAHA quirks */
+		for (p1 = find_descriptor(buffer, bufSize, NULL, USB_DT_ENDPOINT,
+					  ifnum, altSetting ); p1; p1 = next ) {
+			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
+					       ifnum, altSetting ); 
+	
+			if ( p1[0] < 7 ) continue;
+
+			if ( (p1[2] & 0x80) == 0x80 ) {
+				if ( iep < 15 ) {
+					pins = iep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->in[iep].endpoint = p1[2];
+					u->in[iep].cableId = ( 1 << pins ) - 1;
+					if ( u->in[iep].cableId ) iep ++;
+					if ( iep < 15 ) {
+						u->in[iep].endpoint = -1;
+						u->in[iep].cableId = -1;
+					}
+				}
+			} else {
+				if ( oep < 15 ) {
+					pins = oep+1;
+					if ( pins > 16 )
+						pins = 16;
+					u->out[oep].endpoint = p1[2];
+					u->out[oep].cableId = ( 1 << pins ) - 1;
+					if ( u->out[oep].cableId ) oep ++;
+					if ( oep < 15 ) {
+						u->out[oep].endpoint = -1;
+						u->out[oep].cableId = -1;
+					}
+				}
+			}
+	
+		}
+	}
+
+	if ( !iep && ! oep ) {
+		goto error_end;
+	}
+
+	return u;
+
+error_end:
+	if ( u ) kfree(u);
+	return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Returns number between 0 and 16.
+ *
+ **/
+static int on_bits( unsigned short v )
+{
+	int i;
+	int ret=0;
+
+	for ( i=0 ; i<16 ; i++ ) {
+		if ( v & (1<<i) ) ret++;
+	}
+
+	return ret;
+}
+
+
+/** USB-device will be interrogated for altSetting.
+ *
+ * Returns negative on error.
+ * Called by allocUsbMidiDev();
+ *
+ **/
+
+static int get_alt_setting( struct usb_device *d, int ifnum )
+{
+	int alts, alt=0;
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *ep;
+	int epin, epout;
+	int i;
+
+	alts = d->actconfig->interface[ifnum].num_altsetting;
+
+	for ( alt=0 ; alt<alts ; alt++ ) {
+		interface = &d->actconfig->interface[ifnum].altsetting[alt];
+		epin = -1;
+		epout = -1;
+
+		for ( i=0 ; i<interface->bNumEndpoints ; i++ ) {
+			ep = &interface->endpoint[i];
+			if ( (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ) {
+				continue;
+			}
+			if ( (ep->bEndpointAddress & USB_DIR_IN) && epin < 0 ) {
+				epin = i;
+			} else if ( epout < 0 ) {
+				epout = i;
+			}
+			if ( epin >= 0 && epout >= 0 ) {
+				return alt;
+			}
+		}
+	}
+
+	return -ENODEV;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+
+/** Returns 0 if successful in allocating and registering internal structures.
+ * Returns negative on failure.
+ * Calls allocMidiDev which additionally registers /dev/midiXX devices.
+ * Writes messages on success to indicate which /dev/midiXX is which physical
+ * endpoint.
+ *
+ **/
+static int alloc_usb_midi_device( struct usb_device *d, struct usb_midi_state *s, struct usb_midi_device *u )
+{
+	struct usb_mididev **mdevs=NULL;
+	struct midi_in_endpoint *mins[15], *min;
+	struct midi_out_endpoint *mouts[15], *mout;
+	int inDevs=0, outDevs=0;
+	int inEndpoints=0, outEndpoints=0;
+	int inEndpoint, outEndpoint;
+	int inCableId, outCableId;
+	int i;
+	int devices = 0;
+	int alt = 0;
+
+	/* Obtain altSetting or die.. */
+	alt = u->altSetting;
+	if ( alt < 0 ) {
+		alt = get_alt_setting( d, u->interface );
+	}
+	if ( alt < 0 ) { return -ENXIO; }
+
+	/* Configure interface */
+	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
+		return -ENXIO;
+	}
+
+	for ( i = 0 ; i < 15 ; i++ ) {
+		mins[i] = NULL;
+		mouts[i] = NULL;
+	}
+
+	/* Begin Allocation */
+	while( inEndpoints < 15
+	       && inDevs < maxdevices
+	       && u->in[inEndpoints].cableId >= 0 ) {
+		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
+		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
+		if ( mins[inEndpoints] == NULL ) { goto error_end; }
+		inEndpoints++;
+	}
+
+	while( outEndpoints < 15
+	       && outDevs < maxdevices
+	       && u->out[outEndpoints].cableId >= 0 ) {
+		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
+		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
+		if ( mouts[outEndpoints] == NULL ) { goto error_end; }
+		outEndpoints++;
+	}
+
+	devices = inDevs > outDevs ? inDevs : outDevs;
+	devices = maxdevices > devices ? devices : maxdevices;
+
+	/* obtain space for device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices
+				+ sizeof(char) * 256, GFP_KERNEL);
+	} else {
+		mdevs = (struct usb_mididev **)
+			kmalloc(sizeof(struct usb_mididevs *)*devices, GFP_KERNEL);
+	}
+
+	if ( !mdevs ) {
+		/* devices = 0; */
+		/* mdevs = NULL; */
+		goto error_end;
+	}
+	for ( i=0 ; i<devices ; i++ ) {
+		mdevs[i] = NULL;
+	}
+
+	/* obtain device name (iProduct) if not known. */
+	if ( ! u->deviceName ) {
+		u->deviceName = (char *) (mdevs + devices);
+		if ( ! d->have_langid && d->descriptor.iProduct) {
+			alt = usb_get_string(d, 0, 0, u->deviceName, 250);
+			if (alt < 0) {
+				printk(KERN_INFO "error getting string descriptor 0 (error=%d)\n", alt);
+			} else if (u->deviceName[0] < 4) {
+				printk(KERN_INFO "string descriptor 0 too short (length = %d)\n", alt);
+			} else {
+				printk(KERN_INFO "string descriptor 0 found (length = %d)\n", alt);
+				for(; alt >= 4; alt -= 2) {
+					i = u->deviceName[alt-2] | (u->deviceName[alt-1]<< 8);
+					printk(KERN_INFO "usb-midi: langid(%d) 0x%04x\n",
+					       (alt-4) >> 1, i);
+					if ( ( ( i ^ ulangid ) & 0xff ) == 0 ) {
+						d->have_langid = 1;
+						d->string_langid = i;
+						printk(KERN_INFO "usb-midi: langid(match) 0x%04x\n", i);
+						if ( i == ulangid )
+							break;
+					}
+				}
+			}
+		}
+		u->deviceName[0] = (char) 0;
+		if (d->descriptor.iProduct) {
+			printk(KERN_INFO "usb-midi: fetchString(%d)\n", d->descriptor.iProduct);
+			alt = usb_string(d, d->descriptor.iProduct, u->deviceName, 255);
+			if( alt < 0 ) {
+				u->deviceName[0] = (char) 0;
+			}
+			printk(KERN_INFO "usb-midi: fetchString = %d\n", alt);
+		} 
+		/* Failsafe */
+		if ( !u->deviceName[0] ) {
+			if ( d->descriptor.idVendor == USB_VENDOR_ID_ROLAND ) {
+				strcpy(u->deviceName, "Unknown Roland");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_STEINBERG  ) {
+				strcpy(u->deviceName, "Unknown Steinberg");
+			} else if ( d->descriptor.idVendor == USB_VENDOR_ID_YAMAHA ) {
+				strcpy(u->deviceName, "Unknown Yamaha");
+			} else {
+				strcpy(u->deviceName, "Unknown");
+			}
+		}
+	}
+
+	inEndpoint  = 0; inCableId  = -1;
+	outEndpoint = 0; outCableId = -1;
+
+	for ( i=0 ; i<devices ; i++ ) {
+		for ( inCableId ++ ;
+		      inEndpoint <15
+			      && mins[inEndpoint] 
+			      && !(u->in[inEndpoint].cableId & (1<<inCableId)) ;
+		      inCableId++ ) {
+			if ( inCableId >= 16 ) {
+				inEndpoint  ++;
+				inCableId  = 0;
+			}
+		}
+		min  = mins[inEndpoint];
+		for ( outCableId ++ ;
+		      outEndpoint <15
+			      && mouts[outEndpoint] 
+			      && !(u->out[outEndpoint].cableId & (1<<outCableId)) ;
+		      outCableId++ ) {
+			if ( outCableId >= 16 ) {
+				outEndpoint  ++;
+				outCableId  = 0;
+			}
+		}
+		mout = mouts[outEndpoint];
+
+		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
+		if ( mdevs[i] == NULL ) { goto error_end; }
+
+	}
+
+	/* Success! */
+	for ( i=0 ; i<devices ; i++ ) {
+		list_add_tail( &mdevs[i]->list, &s->midiDevList );
+	}
+	for ( i=0 ; i<inEndpoints ; i++ ) {
+		list_add_tail( &mins[i]->list, &s->inEndpointList );
+	}
+	for ( i=0 ; i<outEndpoints ; i++ ) {
+		list_add_tail( &mouts[i]->list, &s->outEndpointList );
+	}
+
+	printk(KERN_INFO "usbmidi: found [ %s ] (0x%04x:0x%04x), attached:\n", u->deviceName, u->idVendor, u->idProduct );
+	for ( i=0 ; i<devices ; i++ ) {
+		int dm = (mdevs[i]->dev_midi-2)>>4;
+		if ( mdevs[i]->mout.ep != NULL && mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%2d) out (ep:%02x cid:%2d bufsiz:%2d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		} else if ( mdevs[i]->min.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: in (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->min.ep->endpoint|USB_DIR_IN, mdevs[i]->min.cableId, mdevs[i]->min.ep->recvBufSize);
+		} else if ( mdevs[i]->mout.ep != NULL ) {
+			printk(KERN_INFO "usbmidi: /dev/midi%02d: out (ep:%02x cid:%2d bufsiz:%02d)\n", 
+			       dm,
+			       mdevs[i]->mout.ep->endpoint, mdevs[i]->mout.cableId, mdevs[i]->mout.ep->bufSize);
+		}
+	}
+
+	kfree(mdevs);
+	return 0;
+
+ error_end:
+	if ( mdevs != NULL && devices > 0 ) {
+		for ( i=0 ; i<devices ; i++ ) {
+			if ( mdevs[i] != NULL ) {
+				unregister_sound_midi( mdevs[i]->dev_midi );
+				kfree(mdevs[i]);
+			}
+		}
+		kfree(mdevs);
+	}
+
+	for ( i=0 ; i<15 ; i++ ) {
+		if ( mins[i] != NULL ) {
+			remove_midi_in_endpoint( mins[i] );
+		}
+		if ( mouts[i] != NULL ) {
+			remove_midi_out_endpoint( mouts[i] );
+		}
+	}
+
+	return -ENOMEM;
+}
+
+/* ------------------------------------------------------------------------- */
+
+/** Attempt to scan YAMAHA's device descriptor and detect correct values of
+ *  them.
+ *  Return 0 on succes, negative on failure.
+ *  Called by usb_midi_probe();
+ **/
+
+static int detect_yamaha_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	if (d->descriptor.idVendor != USB_VENDOR_ID_YAMAHA) {
+		return -EINVAL;
+	}
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != 255 ||
+		     interface->bInterfaceSubClass != 0 )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found YAMAHA USB-MIDI device on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 1);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** Scan table of known devices which are only partially compliant with 
+ * the MIDIStreaming specification.
+ * Called by usb_midi_probe();
+ *
+ **/
+
+static int detect_vendor_specific_device( struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s )
+{
+	struct usb_midi_device *u;
+	int i;
+	int ret = -ENXIO;
+
+	for ( i=0; i<VENDOR_SPECIFIC_USB_MIDI_DEVICES ; i++ ) {
+		u=&(usb_midi_devices[i]);
+    
+		if ( d->descriptor.idVendor != u->idVendor ||
+		     d->descriptor.idProduct != u->idProduct ||
+		     ifnum != u->interface )
+			continue;
+
+		ret = alloc_usb_midi_device( d, s, u );
+		break;
+	}
+
+	return ret;
+}
+
+
+/** Attempt to match any config of an interface to a MIDISTREAMING interface.
+ *  Returns 0 on success, negative on failure.
+ * Called by usb_midi_probe();
+ **/
+static int detect_midi_subclass(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_config_descriptor    *c = d->actconfig;
+	struct usb_interface_descriptor *interface;
+	struct usb_midi_device *u;
+	unsigned char buf[USB_DT_CONFIG_SIZE], *buffer;
+	int bufSize;
+	int i;
+	int alts=-1;
+	int ret;
+
+	for ( i=0 ; i < c->interface[ifnum].num_altsetting; i++ ) {
+		interface = c->interface[ifnum].altsetting + i;
+
+		if ( interface->bInterfaceClass != USB_CLASS_AUDIO ||
+		     interface->bInterfaceSubClass != USB_SUBCLASS_MIDISTREAMING )
+			continue;
+		alts = i;
+	}
+	if ( alts == -1 ) {
+		return -EINVAL;
+	}
+
+	printk(KERN_INFO "usb-midi: Found MIDISTREAMING on dev %04x:%04x, iface %d\n",
+	       d->descriptor.idVendor, d->descriptor.idProduct, ifnum);
+
+	for ( i=0 ; i < d->descriptor.bNumConfigurations ; i++ ) {
+		if ( d->config+i == c ) goto configfound;
+	}
+
+	printk(KERN_INFO "usb-midi: Config not found.\n");
+
+	return -EINVAL;
+
+ configfound:
+
+	/* this may not be necessary. */
+	if ( usb_set_configuration( d, c->bConfigurationValue ) < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not set config.\n");
+		return -EINVAL;
+	}
+
+	/* From USB Spec v2.0, Section 9.5.
+	   If the class or vendor specific descriptors use the same format
+	   as standard descriptors (e.g., start with a length byte and
+	   followed by a type byte), they must be returned interleaved with
+	   standard descriptors in the configuration information returned by
+	   a GetDescriptor(Configuration) request. In this case, the class
+	   or vendor-specific descriptors must follow a related standard
+	   descriptor they modify or extend.
+	*/
+
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buf, USB_DT_CONFIG_SIZE );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get config (error=%d).\n", ret);
+		return -EINVAL;
+	}
+	if ( buf[1] != USB_DT_CONFIG || buf[0] < USB_DT_CONFIG_SIZE ) {
+		printk(KERN_INFO "usb-midi: config not as expected.\n");
+		return -EINVAL;
+	}
+	bufSize = buf[2] | buf[3]<<8;
+	buffer = (unsigned char *)kmalloc(sizeof(unsigned char)*bufSize, GFP_KERNEL);
+	if ( !buffer ) {
+		printk(KERN_INFO "usb-midi: Could not allocate memory.\n");
+		return -EINVAL;
+	}
+	ret = usb_get_descriptor( d, USB_DT_CONFIG, i, buffer, bufSize );
+	if ( ret < 0 ) {
+		printk(KERN_INFO "usb-midi: Could not get full config (error=%d).\n", ret);
+		kfree(buffer);
+		return -EINVAL;
+	}
+
+	u = parse_descriptor( d, buffer, bufSize, ifnum, alts, 0);
+	kfree(buffer);
+	if ( u == NULL ) {
+		return -EINVAL;
+	}
+
+	ret = alloc_usb_midi_device( d, s, u );
+
+	kfree(u);
+
+	return ret;
+}
+
+
+/** When user has requested a specific device, match it exactly.
+ *
+ * Uses uvendor, uproduct, uinterface, ualt, umin, umout and ucable.
+ * Called by usb_midi_probe();
+ *
+ **/
+static int detect_by_hand(struct usb_device *d, unsigned int ifnum, struct usb_midi_state *s)
+{
+	struct usb_midi_device u;
+
+	if ( d->descriptor.idVendor != uvendor ||
+	     d->descriptor.idProduct != uproduct ||
+	     ifnum != uinterface ) {
+		return -EINVAL;
+	}
+
+	if ( ualt < 0 ) { ualt = -1; }
+
+	if ( umin   < 0 || umin   > 15 ) { umin   = 0x01 | USB_DIR_IN; }
+	if ( umout  < 0 || umout  > 15 ) { umout  = 0x01; }
+	if ( ucable < 0 || ucable > 15 ) { ucable = 0; }
+
+	u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name
+			     from device. */
+	u.idVendor   = uvendor;
+	u.idProduct  = uproduct;
+	u.interface  = uinterface;
+	u.altSetting = ualt;
+
+	u.in[0].endpoint    = umin;
+	u.in[0].cableId     = (1<<ucable);
+
+	u.out[0].endpoint   = umout;
+	u.out[0].cableId    = (1<<ucable);
+
+	return alloc_usb_midi_device( d, s, &u );
+}
+
+
+
+/* ------------------------------------------------------------------------- */
+
+static void *usb_midi_probe(struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id)
+{
+	struct usb_midi_state *s;
+
+	s = (struct usb_midi_state *)kmalloc(sizeof(struct usb_midi_state), GFP_KERNEL);
+	if ( !s ) { return NULL; }
+
+	memset( s, 0, sizeof(struct usb_midi_state) );
+	INIT_LIST_HEAD(&s->midiDevList);
+	INIT_LIST_HEAD(&s->inEndpointList);
+	INIT_LIST_HEAD(&s->outEndpointList);
+	s->usbdev = dev;
+	s->count  = 0;
+	spin_lock_init(&s->lock);
+
+	if (
+		detect_by_hand( dev, ifnum, s ) &&
+		detect_midi_subclass( dev, ifnum, s ) &&
+		detect_vendor_specific_device( dev, ifnum, s ) &&
+		detect_yamaha_device( dev, ifnum, s) ) {
+		kfree(s);
+		return NULL;
+	}
+
+	down(&open_sem);
+	list_add_tail(&s->mididev, &mididevs);
+	up(&open_sem);
+
+#ifdef MOD_INC_EACH_PROBE
+	MOD_INC_USE_COUNT;
+#endif
+
+	return s;
+}
+
+
+static void usb_midi_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct usb_midi_state *s = (struct usb_midi_state *)ptr;
+	struct list_head      *list;
+	struct usb_mididev    *m;
+
+	if ( s == (struct usb_midi_state *)-1 ) {
+		return;
+	}
+	if ( !s->usbdev ) {
+		return;
+	}
+	down(&open_sem);
+	list_del(&s->mididev);
+	INIT_LIST_HEAD(&s->mididev);
+	s->usbdev = NULL;
+
+	for ( list = s->midiDevList.next; list != &s->midiDevList; list = list->next ) {
+		m = list_entry(list, struct usb_mididev, list);
+		wake_up(&(m->min.ep->wait));
+		wake_up(&(m->mout.ep->wait));
+		if ( m->dev_midi >= 0 ) {
+			unregister_sound_midi(m->dev_midi);
+		}
+		m->dev_midi = -1;
+	}
+	release_midi_device(s);
+	wake_up(&open_wait);
+#ifdef MOD_INC_EACH_PROBE
+	MOD_DEC_USE_COUNT;
+#endif
+
+	return;
+}
+
+
+
+static struct usb_driver usb_midi_driver = {
+	name: "midi",
+	probe: usb_midi_probe,
+	disconnect: usb_midi_disconnect,
+	id_table:	NULL, 			/* check all devices */
+	driver_list: LIST_HEAD_INIT(usb_midi_driver.driver_list)
+};
+
+/* ------------------------------------------------------------------------- */
+
+int __init usb_midi_init(void)
+{
+	if ( usb_register(&usb_midi_driver) < 0 )
+		return -1;
+
+	return 0;
+
+}
+
+void __exit usb_midi_exit(void)
+{
+	usb_deregister(&usb_midi_driver);
+}
+
+module_init(usb_midi_init) ;
+module_exit(usb_midi_exit) ;
+
+#ifdef HAVE_ALSA_SUPPORT
+#define SNDRV_MAIN_OBJECT_FILE
+#include "../../include/driver.h"
+#include "../../include/control.h"
+#include "../../include/info.h"
+#include "../../include/cs46xx.h"
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_input_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_input_open(snd_rawmidi_substream_t * substream )
+{
+	return 0;
+}
+
+static void snd_usbmidi_input_trigger(snd_rawmidi_substream_t * substream, int up)
+{
+	return 0;
+}
+
+
+/* ------------------------------------------------------------------------- */
+
+static int snd_usbmidi_output_close(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static int snd_usbmidi_output_open(snd_rawmidi_substream_t * substream)
+{
+	return 0;
+}
+
+static void snd_usb_midi_output_trigger(snd_rawmidi_substream_t * substream,
+					int up)
+{
+	return 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static snd_rawmidi_ops_t snd_usbmidi_output =
+{
+        open:           snd_usbmidi_output_open,
+        close:          snd_usbmidi_output_close,
+        trigger:        snd_usbmidi_output_trigger,
+};
+static snd_rawmidi_ops_t snd_usbmidi_input =
+{
+        open:           snd_usbmidi_input_open,
+        close:          snd_usbmidi_input_close,
+        trigger:        snd_usbmidi_input_trigger,
+};
+
+int snd_usbmidi_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rrawmidi)
+{
+	snd_rawmidi_t *rmidi;
+	int err;
+
+	if (rrawmidi)
+		*rrawmidi = NULL;
+	if ((err = snd_rawmidi_new(chip->card, "USB-MIDI", device, 1, 1, &rmidi)) < 0)
+		return err;
+	strcpy(rmidi->name, "USB-MIDI");
+
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output );
+	snd_rawmidi_set_ops( rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_usbmidi_input );
+
+	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+	rmidi->private_data = chip;
+	chip->rmidi = rmidi;
+	if (rrawmidi)
+		*rrawmidi = NULL;
+
+	return 0;
+}
+
+int snd_usbmidi_create( snd_card_t * card,
+			struct pci_dev * pci,
+			usbmidi_t ** rchip )
+{
+	usbmidi_t *chip;
+	int err, idx;
+	snd_region_t *region;
+	static snd_device_opt_t ops = {
+		dev_free: snd_usbmidi_dev_free,
+	};
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc( usbmidi_t, 0, GFP_KERNEL );
+	if ( chip == NULL )
+		return -ENOMEM;
+}
+
+EXPORT_SYMBOL(snd_usbmidi_create);
+EXPORT_SYMBOL(snd_usbmidi_midi);
+#endif /* HAVE_ALSA_SUPPORT */
+
diff -Nru a/drivers/usb/class/usb-midi.h b/drivers/usb/class/usb-midi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/class/usb-midi.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,143 @@
+/*
+  usb-midi.h  --  USB-MIDI driver
+
+  Copyright (C) 2001
+      NAGANO Daisuke <breeze.nagano@nifty.ne.jp>
+
+  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_MIDI_H_
+#define _USB_MIDI_H_
+
+#ifndef USB_SUBCLASS_MIDISTREAMING
+#define USB_SUBCLASS_MIDISTREAMING	3
+#endif
+
+#define USB_DT_CS_DEVICE		0x21
+#define USB_DT_CS_CONFIG		0x22
+#define USB_DT_CS_STRING		0x23
+#define USB_DT_CS_INTERFACE		0x24
+#define USB_DT_CS_ENDPOINT		0x25
+
+/* ------------------------------------------------------------------------- */
+/* Roland MIDI Devices */
+
+#define USB_VENDOR_ID_ROLAND		0x0582
+#define USBMIDI_ROLAND_UA100G		0x0000
+#define USBMIDI_ROLAND_MPU64		0x0002
+#define USBMIDI_ROLAND_SC8850		0x0003
+#define USBMIDI_ROLAND_UM2		0x0005
+#define USBMIDI_ROLAND_UM1		0x0009
+#define USBMIDI_ROLAND_PC300		0x0008
+
+/* YAMAHA MIDI Devices */
+#define USB_VENDOR_ID_YAMAHA		0x0499
+#define USBMIDI_YAMAHA_MU1000		0x1001
+
+/* Steinberg MIDI Devices */
+#define USB_VENDOR_ID_STEINBERG		0x0763
+#define USBMIDI_STEINBERG_USB2MIDI	0x1001
+
+/* ------------------------------------------------------------------------- */
+/* Supported devices */
+
+struct usb_midi_endpoint {
+	int  endpoint;
+	int  cableId; /* if bit-n == 1 then cableId-n is enabled (n: 0 - 15) */
+};
+
+struct usb_midi_device {
+	char  *deviceName;
+
+	int    idVendor;
+	int    idProduct;
+	int    interface;
+	int    altSetting; /* -1: auto detect */
+
+	struct usb_midi_endpoint in[15];
+	struct usb_midi_endpoint out[15];
+};
+
+static struct usb_midi_device usb_midi_devices[] = {
+  { /* Roland UM-1 */
+    "Roland UM-1",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1, 2, -1,
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1,}, {-1, -1} },
+  },
+
+  { /* Roland UM-2 */
+    "Roland UM-2" ,
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2, 2, -1,
+    { { 0x81, 3 }, {-1, -1} },
+    { { 0x01, 3,}, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland UA-100 */
+    "Roland UA-100",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G, 2, -1,
+    { { 0x82, 7 }, {-1, -1} }, /** cables 0,1 and 2 for SYSEX **/
+    { { 0x02, 7 }, {-1, -1} },
+  },
+
+/** Next entry courtesy research by Michael Minn <michael@michaelminn.com> **/
+  { /* Roland SC8850 */
+    "Roland SC8850",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850, 2, -1,
+    { { 0x81, 15 }, {-1, -1} }, /** cables 0,1,2, and 3 **/
+    { { 0x01, 15 }, {-1, -1} },
+  },
+
+  { /* YAMAHA MU1000 */
+    "YAMAHA MU1000",
+    USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000, 0, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 15 }, {-1, -1} },
+  },
+  { /* Roland PC-300 */
+    "Roland PC-300",
+    USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300, 2, -1, 
+    { { 0x81, 1 }, {-1, -1} },
+    { { 0x01, 1 }, {-1, -1} },
+  }
+};
+
+#define VENDOR_SPECIFIC_USB_MIDI_DEVICES (sizeof(usb_midi_devices)/sizeof(struct usb_midi_device))
+
+/* for Hot-Plugging */
+
+static struct usb_device_id usb_midi_ids [] = {
+	{ match_flags: (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS),
+	  bInterfaceClass: USB_CLASS_AUDIO, bInterfaceSubClass: USB_SUBCLASS_MIDISTREAMING},
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM1    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UM2    ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_UA100G ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_PC300 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_ROLAND, USBMIDI_ROLAND_SC8850 ) },
+	{ USB_DEVICE( USB_VENDOR_ID_YAMAHA, USBMIDI_YAMAHA_MU1000 ) },
+/*	{ USB_DEVICE( USB_VENDOR_ID_STEINBERG, USBMIDI_STEINBERG_USB2MIDI ) },*/
+	{ } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_midi_ids);
+
+/* ------------------------------------------------------------------------- */
+#endif /* _USB_MIDI_H_ */
+
+
diff -Nru a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
--- a/drivers/usb/core/Makefile	Sat Jun  8 22:31:52 2002
+++ b/drivers/usb/core/Makefile	Sat Jun  8 22:31:52 2002
@@ -2,10 +2,14 @@
 # Makefile for USB Core files and filesystem
 #
 
-export-objs	:= usb.o hcd.o urb.o message.o config.o
+export-objs	:= usb.o hcd.o hcd-pci.o urb.o message.o config.o
 
 usbcore-objs	:= usb.o usb-debug.o hub.o hcd.o urb.o message.o \
 			config.o
+
+ifeq ($(CONFIG_PCI),y)
+	usbcore-objs	+= hcd-pci.o
+endif
 
 ifeq ($(CONFIG_USB_DEVICEFS),y)
 	usbcore-objs	+= devio.o inode.o drivers.o devices.o
diff -Nru a/drivers/usb/core/drivers.c b/drivers/usb/core/drivers.c
--- a/drivers/usb/core/drivers.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/core/drivers.c	Sat Jun  8 22:31:35 2002
@@ -35,7 +35,7 @@
  */
 
 #include <linux/fs.h>
-#include <linux/mm.h>
+#include <linux/gfp.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/smp_lock.h>
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/core/hcd-pci.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,347 @@
+/*
+ * (C) Copyright David Brownell 2000-2002
+ * 
+ * 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.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct hc_driver	*driver;
+	unsigned long		resource, len;
+	void			*base;
+	u8			latency, limit;
+	struct usb_hcd		*hcd;
+	int			retval, region;
+	char			buf [8], *bufp = buf;
+
+	if (!id || !(driver = (struct hc_driver *) id->driver_data))
+		return -EINVAL;
+
+	if (pci_enable_device (dev) < 0)
+		return -ENODEV;
+	
+        if (!dev->irq) {
+        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
+			dev->slot_name);
+   	        return -ENODEV;
+        }
+	
+	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
+		region = 0;
+		resource = pci_resource_start (dev, 0);
+		len = pci_resource_len (dev, 0);
+		if (!request_mem_region (resource, len, driver->description)) {
+			dbg ("controller already in use");
+			return -EBUSY;
+		}
+		base = ioremap_nocache (resource, len);
+		if (base == NULL) {
+			dbg ("error mapping memory");
+			retval = -EFAULT;
+clean_1:
+			release_mem_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+
+	} else { 				// UHCI
+		resource = len = 0;
+		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+				continue;
+
+			resource = pci_resource_start (dev, region);
+			len = pci_resource_len (dev, region);
+			if (request_region (resource, len,
+					driver->description))
+				break;
+		}
+		if (region == PCI_ROM_RESOURCE) {
+			dbg ("no i/o regions available");
+			return -EBUSY;
+		}
+		base = (void *) resource;
+	}
+
+	// driver->start(), later on, will transfer device from
+	// control by SMM/BIOS to control by Linux (if needed)
+
+	pci_set_master (dev);
+	hcd = driver->hcd_alloc ();
+	if (hcd == NULL){
+		dbg ("hcd alloc fail");
+		retval = -ENOMEM;
+clean_2:
+		if (driver->flags & HCD_MEMORY) {
+			iounmap (base);
+			goto clean_1;
+		} else {
+			release_region (resource, len);
+			err ("init %s fail, %d", dev->slot_name, retval);
+			return retval;
+		}
+	}
+	pci_set_drvdata(dev, hcd);
+	hcd->driver = driver;
+	hcd->description = driver->description;
+	hcd->pdev = dev;
+	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
+
+	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
+	if (latency) {
+		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
+		if (limit && limit < latency) {
+			dbg ("PCI latency reduced to max %d", limit);
+			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
+		}
+	}
+
+#ifndef __sparc__
+	sprintf (buf, "%d", dev->irq);
+#else
+	bufp = __irq_itoa(dev->irq);
+#endif
+	if (request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ, hcd->description, hcd)
+			!= 0) {
+		err ("request interrupt %s failed", bufp);
+		retval = -EBUSY;
+		driver->hcd_free (hcd);
+		goto clean_2;
+	}
+	hcd->irq = dev->irq;
+
+	hcd->regs = base;
+	hcd->region = region;
+	info ("irq %s, %s %p", bufp,
+		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+		base);
+
+	usb_bus_init (&hcd->self);
+	hcd->self.op = &usb_hcd_operations;
+	hcd->self.hcpriv = (void *) hcd;
+	hcd->self.bus_name = dev->slot_name;
+	hcd->product_desc = dev->name;
+
+	INIT_LIST_HEAD (&hcd->dev_list);
+
+	usb_register_bus (&hcd->self);
+
+	if ((retval = driver->start (hcd)) < 0)
+		usb_hcd_pci_remove (dev);
+
+	return retval;
+} 
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	struct usb_device	*hub;
+
+	hcd = pci_get_drvdata(dev);
+	if (!hcd)
+		return;
+	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+	if (in_interrupt ()) BUG ();
+
+	hub = hcd->self.root_hub;
+	hcd->state = USB_STATE_QUIESCING;
+
+	dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
+	usb_disconnect (&hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+	if (hcd->driver->flags & HCD_MEMORY) {
+		iounmap (hcd->regs);
+		release_mem_region (pci_resource_start (dev, 0),
+			pci_resource_len (dev, 0));
+	} else {
+		release_region (pci_resource_start (dev, hcd->region),
+			pci_resource_len (dev, hcd->region));
+	}
+
+	usb_deregister_bus (&hcd->self);
+	if (atomic_read (&hcd->self.refcnt) != 1)
+		err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
+
+	hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef	CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend.  Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain.  New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume().  The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME:  USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME:  resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = pci_get_drvdata(dev);
+	info ("suspend %s to state %d", hcd->self.bus_name, state);
+
+	pci_save_state (dev, hcd->pci_state);
+
+	// FIXME for all connected devices, leaf-to-root:
+	// driver->suspend()
+	// proposed "new 2.5 driver model" will automate that
+
+	/* driver may want to disable DMA etc */
+	retval = hcd->driver->suspend (hcd, state);
+	hcd->state = USB_STATE_SUSPENDED;
+
+ 	pci_set_power_state (dev, state);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+	struct usb_hcd		*hcd;
+	int			retval;
+
+	hcd = pci_get_drvdata(dev);
+	info ("resume %s", hcd->self.bus_name);
+
+	/* guard against multiple resumes (APM bug?) */
+	atomic_inc (&hcd->resume_count);
+	if (atomic_read (&hcd->resume_count) != 1) {
+		err ("concurrent PCI resumes for %s", hcd->self.bus_name);
+		retval = 0;
+		goto done;
+	}
+
+	retval = -EBUSY;
+	if (hcd->state != USB_STATE_SUSPENDED) {
+		dbg ("can't resume, not suspended!");
+		goto done;
+	}
+	hcd->state = USB_STATE_RESUMING;
+
+	pci_set_power_state (dev, 0);
+	pci_restore_state (dev, hcd->pci_state);
+
+	retval = hcd->driver->resume (hcd);
+	if (!HCD_IS_RUNNING (hcd->state)) {
+		dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
+		usb_hc_died (hcd);
+// FIXME:  recover, reset etc.
+	} else {
+		// FIXME for all connected devices, root-to-leaf:
+		// driver->resume ();
+		// proposed "new 2.5 driver model" will automate that
+	}
+
+done:
+	atomic_dec (&hcd->resume_count);
+	return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif	/* CONFIG_PM */
+
+
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Sat Jun  8 22:31:49 2002
+++ b/drivers/usb/core/hcd.c	Sat Jun  8 22:31:49 2002
@@ -23,24 +23,13 @@
  */
 
 #include <linux/config.h>
-#include <linux/version.h>
 #include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
+#include <linux/version.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/errno.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/completion.h>
 #include <linux/uts.h>			/* for UTS_SYSNAME */
+#include <asm/byteorder.h>
 
 
 #ifdef CONFIG_USB_DEBUG
@@ -52,12 +41,6 @@
 #include <linux/usb.h>
 #include "hcd.h"
 
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/byteorder.h>
-
 
 // #define USB_BANDWIDTH_MESSAGES
 
@@ -112,8 +95,6 @@
 /* used when updating hcd data */
 static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
 
-static struct usb_operations hcd_operations;
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -288,7 +269,7 @@
 /*
  * rh_string - provides manufacturer, product and serial strings for root hub
  * @id: the string ID number (1: serial number, 2: product, 3: vendor)
- * @pci_desc: PCI device descriptor for the relevant HC
+ * @hcd: the host controller for this root hub
  * @type: string describing our driver 
  * @data: return packet in UTF-16 LE
  * @len: length of the return packet
@@ -559,7 +540,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
 	unsigned long	flags;
 
@@ -589,8 +570,14 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* shared initialization code */
-static void usb_init_bus (struct usb_bus *bus)
+/**
+ * usb_bus_init - shared initialization code
+ * @bus: the bus structure being initialized
+ *
+ * This code is used to initialize a usb_bus structure, memory for which is
+ * separately managed.
+ */
+void usb_bus_init (struct usb_bus *bus)
 {
 	memset (&bus->devmap, 0, sizeof(struct usb_devmap));
 
@@ -609,6 +596,7 @@
 
 	atomic_set (&bus->refcnt, 1);
 }
+EXPORT_SYMBOL (usb_bus_init);
 
 /**
  * usb_alloc_bus - creates a new USB host controller structure
@@ -629,7 +617,7 @@
 	bus = kmalloc (sizeof *bus, GFP_KERNEL);
 	if (!bus)
 		return NULL;
-	usb_init_bus (bus);
+	usb_bus_init (bus);
 	bus->op = op;
 	return bus;
 }
@@ -924,327 +912,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef CONFIG_PCI
-
-/* PCI-based HCs are normal, but custom bus glue should be ok */
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
-static void hc_died (struct usb_hcd *hcd);
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-/**
- * usb_hcd_pci_probe - initialize PCI-based HCDs
- * @dev: USB Host Controller being probed
- * @id: pci hotplug id connecting controller to HCD framework
- * Context: !in_interrupt()
- *
- * Allocates basic PCI resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
- */
-int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
-{
-	struct hc_driver	*driver;
-	unsigned long		resource, len;
-	void			*base;
-	u8			latency, limit;
-	struct usb_hcd		*hcd;
-	int			retval, region;
-	char			buf [8], *bufp = buf;
-
-	if (!id || !(driver = (struct hc_driver *) id->driver_data))
-		return -EINVAL;
-
-	if (pci_enable_device (dev) < 0)
-		return -ENODEV;
-	
-        if (!dev->irq) {
-        	err ("Found HC with no IRQ.  Check BIOS/PCI %s setup!",
-			dev->slot_name);
-   	        return -ENODEV;
-        }
-	
-	if (driver->flags & HCD_MEMORY) {	// EHCI, OHCI
-		region = 0;
-		resource = pci_resource_start (dev, 0);
-		len = pci_resource_len (dev, 0);
-		if (!request_mem_region (resource, len, driver->description)) {
-			dbg ("controller already in use");
-			return -EBUSY;
-		}
-		base = ioremap_nocache (resource, len);
-		if (base == NULL) {
-			dbg ("error mapping memory");
-			retval = -EFAULT;
-clean_1:
-			release_mem_region (resource, len);
-			err ("init %s fail, %d", dev->slot_name, retval);
-			return retval;
-		}
-
-	} else { 				// UHCI
-		resource = len = 0;
-		for (region = 0; region < PCI_ROM_RESOURCE; region++) {
-			if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
-				continue;
-
-			resource = pci_resource_start (dev, region);
-			len = pci_resource_len (dev, region);
-			if (request_region (resource, len,
-					driver->description))
-				break;
-		}
-		if (region == PCI_ROM_RESOURCE) {
-			dbg ("no i/o regions available");
-			return -EBUSY;
-		}
-		base = (void *) resource;
-	}
-
-	// driver->start(), later on, will transfer device from
-	// control by SMM/BIOS to control by Linux (if needed)
-
-	pci_set_master (dev);
-	hcd = driver->hcd_alloc ();
-	if (hcd == NULL){
-		dbg ("hcd alloc fail");
-		retval = -ENOMEM;
-clean_2:
-		if (driver->flags & HCD_MEMORY) {
-			iounmap (base);
-			goto clean_1;
-		} else {
-			release_region (resource, len);
-			err ("init %s fail, %d", dev->slot_name, retval);
-			return retval;
-		}
-	}
-	pci_set_drvdata(dev, hcd);
-	hcd->driver = driver;
-	hcd->description = driver->description;
-	hcd->pdev = dev;
-	info ("%s @ %s, %s", hcd->description,  dev->slot_name, dev->name);
-
-	pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency);
-	if (latency) {
-		pci_read_config_byte (dev, PCI_MAX_LAT, &limit);
-		if (limit && limit < latency) {
-			dbg ("PCI latency reduced to max %d", limit);
-			pci_write_config_byte (dev, PCI_LATENCY_TIMER, limit);
-		}
-	}
-
-#ifndef __sparc__
-	sprintf (buf, "%d", dev->irq);
-#else
-	bufp = __irq_itoa(dev->irq);
-#endif
-	if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
-			!= 0) {
-		err ("request interrupt %s failed", bufp);
-		retval = -EBUSY;
-		driver->hcd_free (hcd);
-		goto clean_2;
-	}
-	hcd->irq = dev->irq;
-
-	hcd->regs = base;
-	hcd->region = region;
-	info ("irq %s, %s %p", bufp,
-		(driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
-		base);
-
-	usb_init_bus (&hcd->self);
-	hcd->self.op = &hcd_operations;
-	hcd->self.hcpriv = (void *) hcd;
-	hcd->self.bus_name = dev->slot_name;
-	hcd->product_desc = dev->name;
-
-	INIT_LIST_HEAD (&hcd->dev_list);
-
-	usb_register_bus (&hcd->self);
-
-	if ((retval = driver->start (hcd)) < 0)
-		usb_hcd_pci_remove (dev);
-
-	return retval;
-} 
-EXPORT_SYMBOL (usb_hcd_pci_probe);
-
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
-/**
- * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
- * @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_pci_probe(), first invoking
- * the HCD's stop() method.  It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
- *
- * Store this function in the HCD's struct pci_driver as remove().
- */
-void usb_hcd_pci_remove (struct pci_dev *dev)
-{
-	struct usb_hcd		*hcd;
-	struct usb_device	*hub;
-
-	hcd = pci_get_drvdata(dev);
-	if (!hcd)
-		return;
-	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
-
-	if (in_interrupt ()) BUG ();
-
-	hub = hcd->self.root_hub;
-	hcd->state = USB_STATE_QUIESCING;
-
-	dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
-	usb_disconnect (&hub);
-
-	hcd->driver->stop (hcd);
-	hcd->state = USB_STATE_HALT;
-
-	free_irq (hcd->irq, hcd);
-	if (hcd->driver->flags & HCD_MEMORY) {
-		iounmap (hcd->regs);
-		release_mem_region (pci_resource_start (dev, 0),
-			pci_resource_len (dev, 0));
-	} else {
-		release_region (pci_resource_start (dev, hcd->region),
-			pci_resource_len (dev, hcd->region));
-	}
-
-	usb_deregister_bus (&hcd->self);
-	if (atomic_read (&hcd->self.refcnt) != 1)
-		err ("usb_hcd_pci_remove %s, count != 1", hcd->self.bus_name);
-
-	hcd->driver->hcd_free (hcd);
-}
-EXPORT_SYMBOL (usb_hcd_pci_remove);
-
-
-#ifdef	CONFIG_PM
-
-/*
- * Some "sleep" power levels imply updating struct usb_driver
- * to include a callback asking hcds to do their bit by checking
- * if all the drivers can suspend.  Gets involved with remote wakeup.
- *
- * If there are pending urbs, then HCs will need to access memory,
- * causing extra power drain.  New sleep()/wakeup() PM calls might
- * be needed, beyond PCI suspend()/resume().  The root hub timer
- * still be accessing memory though ...
- *
- * FIXME:  USB should have some power budgeting support working with
- * all kinds of hubs.
- *
- * FIXME:  This assumes only D0->D3 suspend and D3->D0 resume.
- * D1 and D2 states should do something, yes?
- *
- * FIXME:  Should provide generic enable_wake(), calling pci_enable_wake()
- * for all supported states, so that USB remote wakeup can work for any
- * devices that support it (and are connected via powered hubs).
- *
- * FIXME:  resume doesn't seem to work right any more...
- */
-
-
-// 2.4 kernels have issued concurrent resumes (w/APM)
-// we defend against that error; PCI doesn't yet.
-
-/**
- * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
- * @dev: USB Host Controller being suspended
- *
- * Store this function in the HCD's struct pci_driver as suspend().
- */
-int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
-{
-	struct usb_hcd		*hcd;
-	int			retval;
-
-	hcd = pci_get_drvdata(dev);
-	info ("suspend %s to state %d", hcd->self.bus_name, state);
-
-	pci_save_state (dev, hcd->pci_state);
-
-	// FIXME for all connected devices, leaf-to-root:
-	// driver->suspend()
-	// proposed "new 2.5 driver model" will automate that
-
-	/* driver may want to disable DMA etc */
-	retval = hcd->driver->suspend (hcd, state);
-	hcd->state = USB_STATE_SUSPENDED;
-
- 	pci_set_power_state (dev, state);
-	return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_suspend);
-
-/**
- * usb_hcd_pci_resume - power management resume of a PCI-based HCD
- * @dev: USB Host Controller being resumed
- *
- * Store this function in the HCD's struct pci_driver as resume().
- */
-int usb_hcd_pci_resume (struct pci_dev *dev)
-{
-	struct usb_hcd		*hcd;
-	int			retval;
-
-	hcd = pci_get_drvdata(dev);
-	info ("resume %s", hcd->self.bus_name);
-
-	/* guard against multiple resumes (APM bug?) */
-	atomic_inc (&hcd->resume_count);
-	if (atomic_read (&hcd->resume_count) != 1) {
-		err ("concurrent PCI resumes for %s", hcd->self.bus_name);
-		retval = 0;
-		goto done;
-	}
-
-	retval = -EBUSY;
-	if (hcd->state != USB_STATE_SUSPENDED) {
-		dbg ("can't resume, not suspended!");
-		goto done;
-	}
-	hcd->state = USB_STATE_RESUMING;
-
-	pci_set_power_state (dev, 0);
-	pci_restore_state (dev, hcd->pci_state);
-
-	retval = hcd->driver->resume (hcd);
-	if (!HCD_IS_RUNNING (hcd->state)) {
-		dbg ("resume %s failure, retval %d", hcd->self.bus_name, retval);
-		hc_died (hcd);
-// FIXME:  recover, reset etc.
-	} else {
-		// FIXME for all connected devices, root-to-leaf:
-		// driver->resume ();
-		// proposed "new 2.5 driver model" will automate that
-	}
-
-done:
-	atomic_dec (&hcd->resume_count);
-	return retval;
-}
-EXPORT_SYMBOL (usb_hcd_pci_resume);
-
-#endif	/* CONFIG_PM */
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
 /*
  * Generic HC operations.
  */
@@ -1285,37 +952,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-static void hc_died (struct usb_hcd *hcd)
-{
-	struct list_head	*devlist, *urblist;
-	struct hcd_dev		*dev;
-	struct urb		*urb;
-	unsigned long		flags;
-	
-	/* flag every pending urb as done */
-	spin_lock_irqsave (&hcd_data_lock, flags);
-	list_for_each (devlist, &hcd->dev_list) {
-		dev = list_entry (devlist, struct hcd_dev, dev_list);
-		list_for_each (urblist, &dev->urb_list) {
-			urb = list_entry (urblist, struct urb, urb_list);
-			dbg ("shutdown %s urb %p pipe %x, current status %d",
-				hcd->self.bus_name, urb, urb->pipe, urb->status);
-			if (urb->status == -EINPROGRESS)
-				urb->status = -ESHUTDOWN;
-		}
-	}
-	urb = (struct urb *) hcd->rh_timer.data;
-	if (urb)
-		urb->status = -ESHUTDOWN;
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
-
-	if (urb)
-		rh_status_dequeue (hcd, urb);
-	hcd->driver->stop (hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-
 static void urb_unlink (struct urb *urb)
 {
 	unsigned long		flags;
@@ -1337,170 +973,21 @@
 }
 
 
-/* may be called in any context with a valid urb->dev usecount */
-/* caller surrenders "ownership" of urb */
-
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
 static int hcd_submit_urb (struct urb *urb, int mem_flags)
 {
 	int			status;
-	struct usb_hcd		*hcd;
-	struct hcd_dev		*dev;
+	struct usb_hcd		*hcd = urb->dev->bus->hcpriv;
+	struct hcd_dev		*dev = urb->dev->hcpriv;
 	unsigned long		flags;
-	int			pipe, temp, max;
 
-	if (!urb || urb->hcpriv || !urb->complete)
-		return -EINVAL;
-
-	urb->status = -EINPROGRESS;
-	urb->actual_length = 0;
-	urb->bandwidth = 0;
-	INIT_LIST_HEAD (&urb->urb_list);
-
-	if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
-		return -ENODEV;
-	hcd = urb->dev->bus->hcpriv;
-	dev = urb->dev->hcpriv;
 	if (!hcd || !dev)
 		return -ENODEV;
 
-	/* can't submit new urbs when quiescing, halted, ... */
-	if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
-		return -ESHUTDOWN;
-	pipe = urb->pipe;
-	temp = usb_pipetype (urb->pipe);
-	if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
-			usb_pipeout (pipe)))
-		return -EPIPE;
-
-	/* FIXME there should be a sharable lock protecting us against
-	 * config/altsetting changes and disconnects, kicking in here.
-	 */
-
-	/* Sanity check, so HCDs can rely on clean data */
-	max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
-	if (max <= 0) {
-		err ("bogus endpoint (bad maxpacket)");
-		return -EINVAL;
-	}
-
-	/* "high bandwidth" mode, 1-3 packets/uframe? */
-	if (urb->dev->speed == USB_SPEED_HIGH) {
-		int	mult;
-		switch (temp) {
-		case PIPE_ISOCHRONOUS:
-		case PIPE_INTERRUPT:
-			mult = 1 + ((max >> 11) & 0x03);
-			max &= 0x03ff;
-			max *= mult;
-		}
-	}
-
-	/* periodic transfers limit size per frame/uframe */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS: {
-		int	n, len;
-
-		if (urb->number_of_packets <= 0)		    
-			return -EINVAL;
-		for (n = 0; n < urb->number_of_packets; n++) {
-			len = urb->iso_frame_desc [n].length;
-			if (len < 0 || len > max) 
-				return -EINVAL;
-		}
-
-		}
-		break;
-	case PIPE_INTERRUPT:
-		if (urb->transfer_buffer_length > max)
-			return -EINVAL;
-	}
-
-	/* the I/O buffer must usually be mapped/unmapped */
-	if (urb->transfer_buffer_length < 0)
-		return -EINVAL;
-
-#ifdef DEBUG
-	/* stuff that drivers shouldn't do, but which shouldn't
-	 * cause problems in HCDs if they get it wrong.
-	 */
-	{
-	unsigned int	orig_flags = urb->transfer_flags;
-	unsigned int	allowed;
-
-	/* enforce simple/standard policy */
-	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
-	allowed |= USB_NO_FSBR;		// only affects UHCI
-	switch (temp) {
-	case PIPE_CONTROL:
-		allowed |= USB_DISABLE_SPD;
-		break;
-	case PIPE_BULK:
-		allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
-				| USB_ZERO_PACKET | URB_NO_INTERRUPT;
-		break;
-	case PIPE_INTERRUPT:
-		allowed |= USB_DISABLE_SPD;
-		break;
-	case PIPE_ISOCHRONOUS:
-		allowed |= USB_ISO_ASAP;
-		break;
-	}
-	urb->transfer_flags &= allowed;
-
-	/* fail if submitter gave bogus flags */
-	if (urb->transfer_flags != orig_flags) {
-		err ("BOGUS urb flags, %x --> %x",
-			orig_flags, urb->transfer_flags);
-		return -EINVAL;
-	}
-	}
-#endif
-	/*
-	 * Force periodic transfer intervals to be legal values that are
-	 * a power of two (so HCDs don't need to).
-	 *
-	 * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC
-	 * supports different values... this uses EHCI/UHCI defaults (and
-	 * EHCI can use smaller non-default values).
-	 */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS:
-	case PIPE_INTERRUPT:
-		/* too small? */
-		if (urb->interval <= 0)
-			return -EINVAL;
-		/* too big? */
-		switch (urb->dev->speed) {
-		case USB_SPEED_HIGH:	/* units are microframes */
-			// NOTE usb handles 2^15
-			if (urb->interval > (1024 * 8))
-				urb->interval = 1024 * 8;
-			temp = 1024 * 8;
-			break;
-		case USB_SPEED_FULL:	/* units are frames/msec */
-		case USB_SPEED_LOW:
-			if (temp == PIPE_INTERRUPT) {
-				if (urb->interval > 255)
-					return -EINVAL;
-				// NOTE ohci only handles up to 32
-				temp = 128;
-			} else {
-				if (urb->interval > 1024)
-					urb->interval = 1024;
-				// NOTE usb and ohci handle up to 2^15
-				temp = 1024;
-			}
-			break;
-		default:
-			return -EINVAL;
-		}
-		/* power of two? */
-		while (temp > urb->interval)
-			temp >>= 1;
-		urb->interval = temp;
-	}
-
-
 	/*
 	 * FIXME:  make urb timeouts be generic, keeping the HCD cores
 	 * as simple as possible.
@@ -1510,9 +997,6 @@
 	// hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
 	// It would catch submission paths for all urbs.
 
-	/* increment urb's reference count, we now control it. */
-	urb = usb_get_urb(urb);
-
 	/*
 	 * Atomically queue the urb,  first to our records, then to the HCD.
 	 * Access to urb->status is controlled by urb->lock ... changes on
@@ -1534,18 +1018,15 @@
 	if (status)
 		return status;
 
-	/* temporarily up refcount while queueing it in the HCD,
-	 * since we report some queuing/setup errors ourselves
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which now controls it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
 	 */
 	urb = usb_get_urb (urb);
 	if (urb->dev == hcd->self.root_hub)
 		status = rh_urb_enqueue (hcd, urb);
 	else
 		status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
-	/* urb->dev got nulled if hcd called giveback for us */
-	if (status && urb->dev)
-		urb_unlink (urb);
-	usb_put_urb (urb);
 	return status;
 }
 
@@ -1677,7 +1158,7 @@
 	spin_unlock_irqrestore (&urb->lock, flags);
 
 	if (urb == (struct urb *) hcd->rh_timer.data) {
-		rh_status_dequeue (hcd, urb);
+		usb_rh_status_dequeue (hcd, urb);
 		retval = 0;
 	} else {
 		retval = hcd->driver->urb_dequeue (hcd, urb);
@@ -1751,28 +1232,21 @@
 	return 0;
 }
 
-static struct usb_operations hcd_operations = {
+/**
+ * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
+ *
+ * When registering a USB bus through the HCD framework code, use this
+ * usb_operations vector.  The PCI glue layer does so automatically; only
+ * bus glue for non-PCI system busses will need to use this.
+ */
+struct usb_operations usb_hcd_operations = {
 	allocate:		hcd_alloc_dev,
 	get_frame_number:	hcd_get_frame_number,
 	submit_urb:		hcd_submit_urb,
 	unlink_urb:		hcd_unlink_urb,
 	deallocate:		hcd_free_dev,
 };
-
-/*-------------------------------------------------------------------------*/
-
-static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
-{
-	struct usb_hcd		*hcd = __hcd;
-	int			start = hcd->state;
-
-	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
-		return;
-
-	hcd->driver->irq (hcd);
-	if (hcd->state != start && hcd->state == USB_STATE_HALT)
-		hc_died (hcd);
-}
+EXPORT_SYMBOL (usb_hcd_operations);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1812,3 +1286,70 @@
 	usb_put_urb (urb);
 }
 EXPORT_SYMBOL (usb_hcd_giveback_urb);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_irq - hook IRQs to HCD framework (bus glue)
+ * @irq: the IRQ being raised
+ * @__hcd: pointer to the HCD whose IRQ is beinng signaled
+ * @r: saved hardware registers (not passed to HCD)
+ *
+ * When registering a USB bus through the HCD framework code, use this
+ * to handle interrupts.  The PCI glue layer does so automatically; only
+ * bus glue for non-PCI system busses will need to use this.
+ */
+void usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+	struct usb_hcd		*hcd = __hcd;
+	int			start = hcd->state;
+
+	if (unlikely (hcd->state == USB_STATE_HALT))	/* irq sharing? */
+		return;
+
+	hcd->driver->irq (hcd);
+	if (hcd->state != start && hcd->state == USB_STATE_HALT)
+		usb_hc_died (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_irq);
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hc_died - report abnormal shutdown of a host controller (bus glue)
+ * @hcd: pointer to the HCD representing the controller
+ *
+ * This is called by bus glue to report a USB host controller that died
+ * while operations may still have been pending.  It's called automatically
+ * by the PCI glue, so only glue for non-PCI busses should need to call it. 
+ */
+void usb_hc_died (struct usb_hcd *hcd)
+{
+	struct list_head	*devlist, *urblist;
+	struct hcd_dev		*dev;
+	struct urb		*urb;
+	unsigned long		flags;
+	
+	/* flag every pending urb as done */
+	spin_lock_irqsave (&hcd_data_lock, flags);
+	list_for_each (devlist, &hcd->dev_list) {
+		dev = list_entry (devlist, struct hcd_dev, dev_list);
+		list_for_each (urblist, &dev->urb_list) {
+			urb = list_entry (urblist, struct urb, urb_list);
+			dbg ("shutdown %s urb %p pipe %x, current status %d",
+				hcd->self.bus_name, urb, urb->pipe, urb->status);
+			if (urb->status == -EINPROGRESS)
+				urb->status = -ESHUTDOWN;
+		}
+	}
+	urb = (struct urb *) hcd->rh_timer.data;
+	if (urb)
+		urb->status = -ESHUTDOWN;
+	spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+	if (urb)
+		usb_rh_status_dequeue (hcd, urb);
+	hcd->driver->stop (hcd);
+}
+EXPORT_SYMBOL (usb_hc_died);
+
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Sat Jun  8 22:31:37 2002
+++ b/drivers/usb/core/hcd.h	Sat Jun  8 22:31:37 2002
@@ -50,9 +50,9 @@
 	int			irq;		/* irq allocated */
 	void			*regs;		/* device memory/io */
 
-#ifdef	CONFIG_PCI
 	/* a few non-PCI controllers exist, mostly for OHCI */
 	struct pci_dev		*pdev;		/* pci is typical */
+#ifdef	CONFIG_PCI
 	int			region;		/* pci region for regs */
 	u32			pci_state [16];	/* for PM state save */
 	atomic_t		resume_count;	/* multiple resumes issue */
@@ -161,6 +161,8 @@
 };
 
 extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_bus_init (struct usb_bus *bus);
+extern void usb_rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb);
 
 #ifdef CONFIG_PCI
 struct pci_dev;
@@ -178,6 +180,11 @@
 #endif /* CONFIG_PM */
 
 #endif /* CONFIG_PCI */
+
+/* generic bus glue, needed for host controllers that don't use PCI */
+extern struct usb_operations usb_hcd_operations;
+extern void usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+extern void usb_hc_died (struct usb_hcd *hcd);
 
 /* -------------------------------------------------------------------------- */
 
diff -Nru a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
--- a/drivers/usb/core/inode.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/core/inode.c	Sat Jun  8 22:31:35 2002
@@ -298,7 +298,7 @@
 
 static struct super_operations usbfs_ops = {
 	statfs:		simple_statfs,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 };
 
 static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/usb/core/message.c	Sat Jun  8 22:31:36 2002
@@ -36,7 +36,7 @@
 	add_wait_queue(&awd.wqh, &wait);
 
 	urb->context = &awd;
-	status = usb_submit_urb(urb, GFP_KERNEL);
+	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
 		// something went wrong
 		usb_free_urb(urb);
diff -Nru a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
--- a/drivers/usb/core/urb.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/core/urb.c	Sat Jun  8 22:31:35 2002
@@ -182,15 +182,170 @@
  */
 int usb_submit_urb(struct urb *urb, int mem_flags)
 {
+	int			pipe, temp, max;
+	struct usb_device	*dev;
+	struct usb_operations	*op;
+	int			is_out;
 
-	if (urb && urb->dev && urb->dev->bus && urb->dev->bus->op) {
-		if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) {
-			err("%s: pipe %x has invalid size (<= 0)", __FUNCTION__, urb->pipe);
+	if (!urb || urb->hcpriv || !urb->complete)
+		return -EINVAL;
+	if (!(dev = urb->dev) || !dev->bus || dev->devnum <= 0)
+		return -ENODEV;
+	if (!(op = dev->bus->op) || !op->submit_urb)
+		return -ENODEV;
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->bandwidth = 0;
+
+	/* Lots of sanity checks, so HCDs can rely on clean data
+	 * and don't need to duplicate tests
+	 */
+	pipe = urb->pipe;
+	temp = usb_pipetype (pipe);
+	is_out = usb_pipeout (pipe);
+
+	/* (actually HCDs may need to duplicate this, endpoint might yet
+	 * stall due to queued bulk/intr transactions that complete after
+	 * we check)
+	 */
+	if (usb_endpoint_halted (dev, usb_pipeendpoint (pipe), is_out))
+		return -EPIPE;
+
+	/* FIXME there should be a sharable lock protecting us against
+	 * config/altsetting changes and disconnects, kicking in here.
+	 * (here == before maxpacket, and eventually endpoint type,
+	 * checks get made.)
+	 */
+
+	max = usb_maxpacket (dev, pipe, is_out);
+	if (max <= 0) {
+		dbg ("%s: bogus endpoint %d-%s on usb-%s-%s (bad maxpacket %d)",
+			__FUNCTION__,
+			usb_pipeendpoint (pipe), is_out ? "OUT" : "IN",
+			dev->bus->bus_name, dev->devpath,
+			max);
+		return -EMSGSIZE;
+	}
+
+	/* "high bandwidth" mode, 1-3 packets/uframe? */
+	if (dev->speed == USB_SPEED_HIGH) {
+		int	mult;
+		switch (temp) {
+		case PIPE_ISOCHRONOUS:
+		case PIPE_INTERRUPT:
+			mult = 1 + ((max >> 11) & 0x03);
+			max &= 0x03ff;
+			max *= mult;
+		}
+	}
+
+	/* periodic transfers limit size per frame/uframe */
+	switch (temp) {
+	case PIPE_ISOCHRONOUS: {
+		int	n, len;
+
+		if (urb->number_of_packets <= 0)		    
+			return -EINVAL;
+		for (n = 0; n < urb->number_of_packets; n++) {
+			len = urb->iso_frame_desc [n].length;
+			if (len < 0 || len > max) 
+				return -EMSGSIZE;
+		}
+
+		}
+		break;
+	case PIPE_INTERRUPT:
+		if (urb->transfer_buffer_length > max)
 			return -EMSGSIZE;
+	}
+
+	/* the I/O buffer must be mapped/unmapped, except when length=0 */
+	if (urb->transfer_buffer_length < 0)
+		return -EMSGSIZE;
+
+#ifdef DEBUG
+	/* stuff that drivers shouldn't do, but which shouldn't
+	 * cause problems in HCDs if they get it wrong.
+	 */
+	{
+	unsigned int	orig_flags = urb->transfer_flags;
+	unsigned int	allowed;
+
+	/* enforce simple/standard policy */
+	allowed = USB_ASYNC_UNLINK;	// affects later unlinks
+	allowed |= USB_NO_FSBR;		// only affects UHCI
+	switch (temp) {
+	case PIPE_CONTROL:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_BULK:
+		allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+				| USB_ZERO_PACKET | URB_NO_INTERRUPT;
+		break;
+	case PIPE_INTERRUPT:
+		allowed |= USB_DISABLE_SPD;
+		break;
+	case PIPE_ISOCHRONOUS:
+		allowed |= USB_ISO_ASAP;
+		break;
+	}
+	urb->transfer_flags &= allowed;
+
+	/* fail if submitter gave bogus flags */
+	if (urb->transfer_flags != orig_flags) {
+		err ("BOGUS urb flags, %x --> %x",
+			orig_flags, urb->transfer_flags);
+		return -EINVAL;
+	}
+	}
+#endif
+	/*
+	 * Force periodic transfer intervals to be legal values that are
+	 * a power of two (so HCDs don't need to).
+	 *
+	 * FIXME want bus->{intr,iso}_sched_horizon values here.  Each HC
+	 * supports different values... this uses EHCI/UHCI defaults (and
+	 * EHCI can use smaller non-default values).
+	 */
+	switch (temp) {
+	case PIPE_ISOCHRONOUS:
+	case PIPE_INTERRUPT:
+		/* too small? */
+		if (urb->interval <= 0)
+			return -EINVAL;
+		/* too big? */
+		switch (dev->speed) {
+		case USB_SPEED_HIGH:	/* units are microframes */
+			// NOTE usb handles 2^15
+			if (urb->interval > (1024 * 8))
+				urb->interval = 1024 * 8;
+			temp = 1024 * 8;
+			break;
+		case USB_SPEED_FULL:	/* units are frames/msec */
+		case USB_SPEED_LOW:
+			if (temp == PIPE_INTERRUPT) {
+				if (urb->interval > 255)
+					return -EINVAL;
+				// NOTE ohci only handles up to 32
+				temp = 128;
+			} else {
+				if (urb->interval > 1024)
+					urb->interval = 1024;
+				// NOTE usb and ohci handle up to 2^15
+				temp = 1024;
+			}
+			break;
+		default:
+			return -EINVAL;
 		}
-		return urb->dev->bus->op->submit_urb(urb, mem_flags);
+		/* power of two? */
+		while (temp > urb->interval)
+			temp >>= 1;
+		urb->interval = temp;
 	}
-	return -ENODEV;
+
+	return op->submit_urb (urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/host/ohci-hcd.c	Sat Jun  8 22:31:35 2002
@@ -12,6 +12,9 @@
  * 
  * History:
  * 
+ * 2002/06/01 remember frame when HC won't see EDs any more; use that info
+ *	to fix urb unlink races caused by interrupt latency assumptions;
+ *	minor ED field and function naming updates
  * 2002/01/18 package as a patch for 2.5.3; this should match the
  *	2.4.17 kernel modulo some bugs being fixed.
  *
@@ -75,9 +78,9 @@
 #include <linux/interrupt.h>  /* for in_interrupt () */
 
 #ifdef CONFIG_USB_DEBUG
-	#define DEBUG
+#	define DEBUG
 #else
-	#undef DEBUG
+#	undef DEBUG
 #endif
 
 #include <linux/usb.h>
@@ -89,15 +92,6 @@
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 
-#ifdef CONFIG_PMAC_PBOOK
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
-#ifndef CONFIG_PM
-#	define CONFIG_PM
-#endif
-#endif
-
 /*
  * TO DO:
  *
@@ -106,7 +100,7 @@
  *	- lots more testing!!
  */
 
-#define DRIVER_VERSION "$Revision: 1.9 $"
+#define DRIVER_VERSION "2002-Jun-01"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
 
@@ -223,7 +217,7 @@
 		case PIPE_ISOCHRONOUS:
 			if (urb->transfer_flags & USB_ISO_ASAP) { 
 				urb->start_frame = ( (ed->state == ED_OPER)
-					? (ed->last_iso + 1)
+					? (ed->intriso.last_iso + 1)
 					: (le16_to_cpu (ohci->hcca->frame_no)
 						+ 10)) & 0xffff;
 			}	
@@ -287,7 +281,7 @@
 		}
 			
 		urb_priv->state = URB_DEL; 
-		ed_unlink (urb->dev, urb_priv->ed);
+		start_urb_unlink (ohci, urb_priv->ed);
 		spin_unlock_irqrestore (&ohci->lock, flags);
 	} else {
 		/*
@@ -408,7 +402,7 @@
   	__u32			mask;
   	unsigned int		fminterval;
   	struct usb_device	*udev;
-	
+
 	spin_lock_init (&ohci->lock);
 	ohci->disabled = 1;
 	ohci->sleeping = 0;
@@ -459,7 +453,7 @@
 
 	usb_connect (udev);
 	udev->speed = USB_SPEED_FULL;
-	if (usb_register_root_hub (udev, &ohci->hcd.pdev->dev) != 0) {
+	if (usb_register_root_hub (udev, ohci->parent_dev) != 0) {
 		usb_free_dev (udev); 
 		ohci->disabled = 1;
 // FIXME cleanup
@@ -508,16 +502,15 @@
   
 	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
-	// FIXME:  this assumes SOF (1/ms) interrupts don't get lost...
-	if (ints & OHCI_INTR_SF) { 
-		unsigned int frame = le16_to_cpu (ohci->hcca->frame_no) & 1;
+	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
+	 * when there's still unlinking to be done (next frame).
+	 */
+	spin_lock (&ohci->lock);
+	if (ohci->ed_rm_list)
+		finish_unlinks (ohci, le16_to_cpu (ohci->hcca->frame_no));
+	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list)
 		writel (OHCI_INTR_SF, &regs->intrdisable);	
-		if (ohci->ed_rm_list [!frame] != NULL) {
-			dl_del_list (ohci, !frame);
-		}
-		if (ohci->ed_rm_list [frame] != NULL)
-			writel (OHCI_INTR_SF, &regs->intrenable);	
-	}
+	spin_unlock (&ohci->lock);
 
 	writel (ints, &regs->intrstatus);
 	writel (OHCI_INTR_MIE, &regs->intrenable);	
@@ -543,167 +536,19 @@
 	
 	ohci_mem_cleanup (ohci);
 
-#ifdef CONFIG_PCI
 	pci_free_consistent (ohci->hcd.pdev, sizeof *ohci->hcca,
 		ohci->hcca, ohci->hcca_dma);
-#endif
 }
 
 /*-------------------------------------------------------------------------*/
 
-static int __devinit
-ohci_start (struct usb_hcd *hcd)
-{
-	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	int		ret;
-
-#ifdef CONFIG_PCI
-	if (hcd->pdev) {
-		ohci->hcca = pci_alloc_consistent (hcd->pdev,
-				sizeof *ohci->hcca, &ohci->hcca_dma);
-		if (!ohci->hcca)
-			return -ENOMEM;
-
-		/* AMD 756, for most chips (early revs), corrupts register
-		 * values on read ... so enable the vendor workaround.
-		 */
-		if (hcd->pdev->vendor == 0x1022
-				&& hcd->pdev->device == 0x740c) {
-			ohci->flags = OHCI_QUIRK_AMD756;
-			info ("%s: AMD756 erratum 4 workaround",
-				hcd->self.bus_name);
-		}
-
-		/* Apple's OHCI driver has a lot of bizarre workarounds
-		 * for this chip.  Evidently control and bulk lists
-		 * can get confused.  (B&W G3 models, and ...)
-		 */
-		else if (hcd->pdev->vendor == 0x1045
-				&& hcd->pdev->device == 0xc861) {
-			info ("%s: WARNING: OPTi workarounds unavailable",
-				hcd->self.bus_name);
-		}
-	}
-#else
-#	error "where's hcca coming from?"
-#endif /* CONFIG_PCI */
-
-        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
-	if ((ret = ohci_mem_init (ohci)) < 0) {
-		ohci_stop (hcd);
-		return ret;
-	}
-	ohci->regs = hcd->regs;
-
-	if (hc_reset (ohci) < 0) {
-		ohci_stop (hcd);
-		return -ENODEV;
-	}
-
-	if (hc_start (ohci) < 0) {
-		err ("can't start %s", ohci->hcd.self.bus_name);
-		ohci_stop (hcd);
-		return -EBUSY;
-	}
-
-#ifdef	DEBUG
-	ohci_dump (ohci, 1);
-#endif
-	return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_PM
-
-static int ohci_suspend (struct usb_hcd *hcd, u32 state)
-{
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
-	unsigned long		flags;
-	u16			cmd;
-
-	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
-		dbg ("can't suspend %s (state is %s)", hcd->self.bus_name,
-			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
-		return -EIO;
-	}
-
-	/* act as if usb suspend can always be used */
-	dbg ("%s: suspend to %d", hcd->self.bus_name, state);
-	ohci->sleeping = 1;
-
-	/* First stop processing */
-  	spin_lock_irqsave (&ohci->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 (&ohci->lock, flags);
-
-	/* Wait a frame or two */
-	mdelay (1);
-	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
-		mdelay (1);
-		
- #ifdef CONFIG_PMAC_PBOOK
-	if (_machine == _MACH_Pmac)
-		disable_irq (hcd->pdev->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);
-	(void) readl (&ohci->regs->control);
-	mdelay (500); /* No schedule here ! */
-
-	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
-		case OHCI_USB_RESET:
-			dbg ("%s suspend->reset ?", hcd->self.bus_name);
-			break;
-		case OHCI_USB_RESUME:
-			dbg ("%s suspend->resume ?", hcd->self.bus_name);
-			break;
-		case OHCI_USB_OPER:
-			dbg ("%s suspend->operational ?", hcd->self.bus_name);
-			break;
-		case OHCI_USB_SUSPEND:
-			dbg ("%s suspended", hcd->self.bus_name);
-			break;
-	}
-
-	/* In some rare situations, Apple's OHCI have happily trashed
-	 * memory during sleep. We disable its bus master bit during
-	 * suspend
-	 */
-	pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
-	cmd &= ~PCI_COMMAND_MASTER;
-	pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
-#ifdef CONFIG_PMAC_PBOOK
-	{
-	   	struct device_node	*of_node;
- 
-		/* Disable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (hcd->pdev);
-		if (of_node)
-			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
-	}
-#endif
-	return 0;
-}
-
-
 // FIXME:  this restart logic should be generic,
 // and handle full hcd state cleanup
 
 /* controller died; cleanup debris, then restart */
 /* must not be called from interrupt context */
 
+#ifdef CONFIG_PM
 static int hc_restart (struct ohci_hcd *ohci)
 {
 	int temp;
@@ -719,8 +564,7 @@
 	for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
 	
 	/* no EDs to remove */
-	ohci->ed_rm_list [0] = NULL;
-	ohci->ed_rm_list [1] = NULL;
+	ohci->ed_rm_list = NULL;
 
 	/* empty control and bulk lists */	 
 	ohci->ed_isotail     = NULL;
@@ -734,227 +578,26 @@
 		dbg ("restart %s completed", ohci->hcd.self.bus_name);
 	return 0;
 }
-
-static int ohci_resume (struct usb_hcd *hcd)
-{
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
-	int			temp;
-	int			retval = 0;
-	unsigned long		flags;
-
-#ifdef CONFIG_PMAC_PBOOK
-	{
-		struct device_node *of_node;
-
-		/* Re-enable USB PAD & cell clock */
-		of_node = pci_device_to_OF_node (hcd->pdev);
-		if (of_node)
-			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
-	}
-#endif
-	/* did we suspend, or were we powered off? */
-	ohci->hc_control = readl (&ohci->regs->control);
-	temp = ohci->hc_control & OHCI_CTRL_HCFS;
-
-#ifdef DEBUG
-	/* the registers may look crazy here */
-	ohci_dump_status (ohci);
 #endif
 
-	/* Re-enable bus mastering */
-	pci_set_master (ohci->hcd.pdev);
-	
-	switch (temp) {
-
-	case OHCI_USB_RESET:	// lost power
-		info ("USB restart: %s", hcd->self.bus_name);
-		retval = hc_restart (ohci);
-		break;
-
-	case OHCI_USB_SUSPEND:	// host wakeup
-	case OHCI_USB_RESUME:	// remote wakeup
-		info ("USB continue: %s from %s wakeup", hcd->self.bus_name,
-			 (temp == OHCI_USB_SUSPEND)
-				? "host" : "remote");
-		ohci->hc_control = OHCI_USB_RESUME;
-		writel (ohci->hc_control, &ohci->regs->control);
-		(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) {
-			err ("controller %s won't resume", hcd->self.bus_name);
-			ohci->disabled = 1;
-			retval = -EIO;
-			break;
-		}
-
-		/* 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 (&ohci->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_controltail)
-				ohci->hc_control |= OHCI_CTRL_CLE;
-			if (ohci->ed_bulktail)
-				ohci->hc_control |= OHCI_CTRL_BLE;
-		}
-		hcd->state = USB_STATE_READY;
-		writel (ohci->hc_control, &ohci->regs->control);
-
-		/* trigger a start-frame interrupt (why?) */
-		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 (&ohci->lock, flags);
-
- #ifdef CONFIG_PMAC_PBOOK
-		if (_machine == _MACH_Pmac)
-			enable_irq (hcd->pdev->irq);
- #endif
-		if (ohci->hcca->done_head)
-			dl_done_list (ohci, dl_reverse_done_list (ohci));
-		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
-
-		/* assume there are TDs on the bulk and control lists */
-		writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
-
-// ohci_dump_status (ohci);
-dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
-		break;
-
-	default:
-		warn ("odd PCI resume for %s", hcd->self.bus_name);
-	}
-	return retval;
-}
-
-#endif	/* CONFIG_PM */
-
-
 /*-------------------------------------------------------------------------*/
 
 static const char	hcd_name [] = "ohci-hcd";
 
-static const struct hc_driver ohci_driver = {
-	description:		hcd_name,
-
-	/*
-	 * generic hardware linkage
-	 */
-	irq:			ohci_irq,
-	flags:			HCD_MEMORY | HCD_USB11,
-
-	/*
-	 * basic lifecycle operations
-	 */
-	start:			ohci_start,
-#ifdef	CONFIG_PM
-	suspend:		ohci_suspend,
-	resume:			ohci_resume,
-#endif
-	stop:			ohci_stop,
-
-	/*
-	 * memory lifecycle (except per-request)
-	 */
-	hcd_alloc:		ohci_hcd_alloc,
-	hcd_free:		ohci_hcd_free,
-
-	/*
-	 * managing i/o requests and associated device resources
-	 */
-	urb_enqueue:		ohci_urb_enqueue,
-	urb_dequeue:		ohci_urb_dequeue,
-	free_config:		ohci_free_config,
-
-	/*
-	 * scheduling support
-	 */
-	get_frame_number:	ohci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	hub_status_data:	ohci_hub_status_data,
-	hub_control:		ohci_hub_control,
-};
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_LICENSE ("GPL");
 
-/*-------------------------------------------------------------------------*/
-
 #ifdef CONFIG_PCI
-
-/* There do exist non-PCI implementations of OHCI ...
- * Examples include the SA-1111 (ARM) and some MIPS
- * and related hardware.
- */
-
-static const struct pci_device_id __devinitdata pci_ids [] = { {
-
-	/* handle any USB OHCI controller */
-	class:		(PCI_CLASS_SERIAL_USB << 8) | 0x10,
-	class_mask:	~0,
-	driver_data:	(unsigned long) &ohci_driver,
-
-	/* no matter who makes it */
-	vendor:		PCI_ANY_ID,
-	device:		PCI_ANY_ID,
-	subvendor:	PCI_ANY_ID,
-	subdevice:	PCI_ANY_ID,
-
-	}, { /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE (pci, pci_ids);
-
-/* pci driver glue; this is a "new style" PCI driver module */
-static struct pci_driver ohci_pci_driver = {
-	name:		(char *) hcd_name,
-	id_table:	pci_ids,
-
-	probe:		usb_hcd_pci_probe,
-	remove:		usb_hcd_pci_remove,
-
-#ifdef	CONFIG_PM
-	suspend:	usb_hcd_pci_suspend,
-	resume:		usb_hcd_pci_resume,
+#include "ohci-pci.c"
 #endif
-};
-
- 
-static int __init ohci_hcd_init (void) 
-{
-	dbg (DRIVER_INFO);
-	dbg ("block sizes: ed %d td %d",
-		sizeof (struct ed), sizeof (struct td));
-	return pci_module_init (&ohci_pci_driver);
-}
-module_init (ohci_hcd_init);
 
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_cleanup (void) 
-{	
-	pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_cleanup);
-
-#endif /* CONFIG_PCI */
+#ifdef CONFIG_SA1111
+#include "ohci-sa1111.c"
+#endif
 
+#if !(defined(CONFIG_PCI) || defined(CONFIG_SA1111))
+#error "missing bus glue for ohci-hcd"
+#endif
diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
--- a/drivers/usb/host/ohci-mem.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/usb/host/ohci-mem.c	Sat Jun  8 22:31:51 2002
@@ -42,12 +42,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifndef CONFIG_PCI
-#	error "usb-ohci currently requires PCI-based controllers"
-	/* to support non-PCI OHCIs, you need custom bus/mem/... glue */
-#endif
-
-
 /* Recover a TD/ED using its collision chain */
 static inline void *
 dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma)
diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/ohci-pci.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,380 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * 
+ * [ Initialisation is based on Linus'  ]
+ * [ uhci code and gregs ohci fragments ]
+ * [ (C) Copyright 1999 Linus Torvalds  ]
+ * [ (C) Copyright 1999 Gregory P. Smith]
+ * 
+ * PCI Bus Glue
+ *
+ * This file is licenced under the GPL.
+ */
+ 
+#ifdef CONFIG_PMAC_PBOOK
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#ifndef CONFIG_PM
+#	define CONFIG_PM
+#endif
+#endif
+
+#ifndef CONFIG_PCI
+#error "This file is PCI bus glue.  CONFIG_PCI must be defined."
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_pci_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	if (hcd->pdev) {
+		ohci->hcca = pci_alloc_consistent (hcd->pdev,
+				sizeof *ohci->hcca, &ohci->hcca_dma);
+		if (!ohci->hcca)
+			return -ENOMEM;
+
+		/* AMD 756, for most chips (early revs), corrupts register
+		 * values on read ... so enable the vendor workaround.
+		 */
+		if (hcd->pdev->vendor == 0x1022
+				&& hcd->pdev->device == 0x740c) {
+			ohci->flags = OHCI_QUIRK_AMD756;
+			info ("%s: AMD756 erratum 4 workaround",
+				hcd->self.bus_name);
+		}
+
+		/* Apple's OHCI driver has a lot of bizarre workarounds
+		 * for this chip.  Evidently control and bulk lists
+		 * can get confused.  (B&W G3 models, and ...)
+		 */
+		else if (hcd->pdev->vendor == 0x1045
+				&& hcd->pdev->device == 0xc861) {
+			info ("%s: WARNING: OPTi workarounds unavailable",
+				hcd->self.bus_name);
+		}
+	}
+
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		ohci_stop (hcd);
+		return ret;
+	}
+	ohci->regs = hcd->regs;
+
+	ohci->parent_dev = &ohci->hcd.pdev->dev;
+
+	if (hc_reset (ohci) < 0) {
+		ohci_stop (hcd);
+		return -ENODEV;
+	}
+
+	if (hc_start (ohci) < 0) {
+		err ("can't start %s", ohci->hcd.self.bus_name);
+		ohci_stop (hcd);
+		return -EBUSY;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	unsigned long		flags;
+	u16			cmd;
+
+	if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
+		dbg ("can't suspend %s (state is %s)", hcd->self.bus_name,
+			hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
+		return -EIO;
+	}
+
+	/* act as if usb suspend can always be used */
+	dbg ("%s: suspend to %d", hcd->self.bus_name, state);
+	ohci->sleeping = 1;
+
+	/* First stop processing */
+  	spin_lock_irqsave (&ohci->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 (&ohci->lock, flags);
+
+	/* Wait a frame or two */
+	mdelay (1);
+	if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+		mdelay (1);
+		
+#ifdef CONFIG_PMAC_PBOOK
+	if (_machine == _MACH_Pmac)
+		disable_irq (hcd->pdev->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);
+	(void) readl (&ohci->regs->control);
+	mdelay (500); /* No schedule here ! */
+
+	switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+		case OHCI_USB_RESET:
+			dbg ("%s suspend->reset ?", hcd->self.bus_name);
+			break;
+		case OHCI_USB_RESUME:
+			dbg ("%s suspend->resume ?", hcd->self.bus_name);
+			break;
+		case OHCI_USB_OPER:
+			dbg ("%s suspend->operational ?", hcd->self.bus_name);
+			break;
+		case OHCI_USB_SUSPEND:
+			dbg ("%s suspended", hcd->self.bus_name);
+			break;
+	}
+
+	/* In some rare situations, Apple's OHCI have happily trashed
+	 * memory during sleep. We disable its bus master bit during
+	 * suspend
+	 */
+	pci_read_config_word (hcd->pdev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MASTER;
+	pci_write_config_word (hcd->pdev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+	{
+	   	struct device_node	*of_node;
+ 
+		/* Disable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (hcd->pdev);
+		if (of_node)
+			pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+	}
+#endif
+	return 0;
+}
+
+
+static int ohci_pci_resume (struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	int			temp;
+	int			retval = 0;
+	unsigned long		flags;
+
+#ifdef CONFIG_PMAC_PBOOK
+	{
+		struct device_node *of_node;
+
+		/* Re-enable USB PAD & cell clock */
+		of_node = pci_device_to_OF_node (hcd->pdev);
+		if (of_node)
+			pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
+	}
+#endif
+	/* did we suspend, or were we powered off? */
+	ohci->hc_control = readl (&ohci->regs->control);
+	temp = ohci->hc_control & OHCI_CTRL_HCFS;
+
+#ifdef DEBUG
+	/* the registers may look crazy here */
+	ohci_dump_status (ohci);
+#endif
+
+	/* Re-enable bus mastering */
+	pci_set_master (ohci->hcd.pdev);
+	
+	switch (temp) {
+
+	case OHCI_USB_RESET:	// lost power
+		info ("USB restart: %s", hcd->self.bus_name);
+		retval = hc_restart (ohci);
+		break;
+
+	case OHCI_USB_SUSPEND:	// host wakeup
+	case OHCI_USB_RESUME:	// remote wakeup
+		info ("USB continue: %s from %s wakeup", hcd->self.bus_name,
+			 (temp == OHCI_USB_SUSPEND)
+				? "host" : "remote");
+		ohci->hc_control = OHCI_USB_RESUME;
+		writel (ohci->hc_control, &ohci->regs->control);
+		(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) {
+			err ("controller %s won't resume", hcd->self.bus_name);
+			ohci->disabled = 1;
+			retval = -EIO;
+			break;
+		}
+
+		/* 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 (&ohci->lock, flags);
+		ohci->disabled = 0;
+		ohci->sleeping = 0;
+		ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
+		if (!ohci->ed_rm_list) {
+			if (ohci->ed_controltail)
+				ohci->hc_control |= OHCI_CTRL_CLE;
+			if (ohci->ed_bulktail)
+				ohci->hc_control |= OHCI_CTRL_BLE;
+		}
+		hcd->state = USB_STATE_READY;
+		writel (ohci->hc_control, &ohci->regs->control);
+
+		/* trigger a start-frame interrupt (why?) */
+		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 (&ohci->lock, flags);
+
+#ifdef CONFIG_PMAC_PBOOK
+		if (_machine == _MACH_Pmac)
+			enable_irq (hcd->pdev->irq);
+#endif
+		if (ohci->hcca->done_head)
+			dl_done_list (ohci, dl_reverse_done_list (ohci));
+		writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+
+		/* assume there are TDs on the bulk and control lists */
+		writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
+
+// ohci_dump_status (ohci);
+dbg ("sleeping = %d, disabled = %d", ohci->sleeping, ohci->disabled);
+		break;
+
+	default:
+		warn ("odd PCI resume for %s", hcd->self.bus_name);
+	}
+	return retval;
+}
+
+#endif	/* CONFIG_PM */
+
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_pci_hc_driver = {
+	description:		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	irq:			ohci_irq,
+	flags:			HCD_MEMORY | HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	start:			ohci_pci_start,
+#ifdef	CONFIG_PM
+	suspend:		ohci_pci_suspend,
+	resume:			ohci_pci_resume,
+#endif
+	stop:			ohci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	hcd_alloc:		ohci_hcd_alloc,
+	hcd_free:		ohci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	urb_enqueue:		ohci_urb_enqueue,
+	urb_dequeue:		ohci_urb_dequeue,
+	free_config:		ohci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	get_frame_number:	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	hub_status_data:	ohci_hub_status_data,
+	hub_control:		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+static const struct pci_device_id __devinitdata pci_ids [] = { {
+
+	/* handle any USB OHCI controller */
+	class:		(PCI_CLASS_SERIAL_USB << 8) | 0x10,
+	class_mask:	~0,
+	driver_data:	(unsigned long) &ohci_pci_hc_driver,
+
+	/* no matter who makes it */
+	vendor:		PCI_ANY_ID,
+	device:		PCI_ANY_ID,
+	subvendor:	PCI_ANY_ID,
+	subdevice:	PCI_ANY_ID,
+
+	}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ohci_pci_driver = {
+	name:		(char *) hcd_name,
+	id_table:	pci_ids,
+
+	probe:		usb_hcd_pci_probe,
+	remove:		usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	suspend:	usb_hcd_pci_suspend,
+	resume:		usb_hcd_pci_resume,
+#endif
+};
+
+ 
+static int __init ohci_hcd_pci_init (void) 
+{
+	dbg (DRIVER_INFO " (PCI)");
+	dbg ("block sizes: ed %d td %d",
+		sizeof (struct ed), sizeof (struct td));
+	return pci_module_init (&ohci_pci_driver);
+}
+module_init (ohci_hcd_pci_init);
+
+/*-------------------------------------------------------------------------*/
+
+static void __exit ohci_hcd_pci_cleanup (void) 
+{	
+	pci_unregister_driver (&ohci_pci_driver);
+}
+module_exit (ohci_hcd_pci_cleanup);
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/usb/host/ohci-q.c	Sat Jun  8 22:31:52 2002
@@ -15,7 +15,6 @@
 	if (last >= 0) {
 		int		i;
 		struct td	*td = urb_priv->td [0];
-#ifdef CONFIG_PCI
 		int		len = td->urb->transfer_buffer_length;
 		int		dir = usb_pipeout (td->urb->pipe)
 					? PCI_DMA_TODEVICE
@@ -36,10 +35,6 @@
 		if (len && td->data_dma)
 			pci_unmap_single (hc->hcd.pdev,
 					td->data_dma, len, dir);
-#else
-#	warning "assuming no buffer unmapping is needed"
-#endif
-
 		for (i = 0; i <= last; i++) {
 			td = urb_priv->td [i];
 			if (td)
@@ -90,7 +85,6 @@
 	urb_priv_t	*urb_priv = urb->hcpriv;
 	unsigned long	flags;
 
-#ifdef CONFIG_PCI
 // FIXME rewrite this resubmit path.  use pci_dma_sync_single()
 // and requeue more cheaply, and only if needed.
 // Better yet ... abolish the notion of automagic resubmission.
@@ -100,7 +94,6 @@
 		usb_pipeout (urb->pipe)
 			? PCI_DMA_TODEVICE
 			: PCI_DMA_FROMDEVICE);
-#endif
 	/* FIXME: MP race.  If another CPU partially unlinks
 	 * this URB (urb->status was updated, hasn't yet told
 	 * us to dequeue) before we call complete() here, an
@@ -208,8 +201,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
 				&& !ohci->sleeping
 				) {
 			ohci->hc_control |= OHCI_CTRL_CLE;
@@ -227,8 +219,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
 				&& !ohci->sleeping
 				) {
 			ohci->hc_control |= OHCI_CTRL_BLE;
@@ -238,18 +229,18 @@
 		break;
 
 	case PIPE_INTERRUPT:
-		load = ed->int_load;
-		interval = ep_2_n_interval (ed->int_period);
-		ed->int_interval = interval;
+		load = ed->intriso.intr_info.int_load;
+		interval = ep_2_n_interval (ed->intriso.intr_info.int_period);
+		ed->interval = interval;
 		int_branch = ep_int_balance (ohci, interval, load);
-		ed->int_branch = int_branch;
+		ed->intriso.intr_info.int_branch = int_branch;
 
 		for (i = 0; i < ep_rev (6, interval); i += inter) {
 			inter = 1;
 			for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i) + int_branch]); 
-				 (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval >= interval); 
+				 (*ed_p != 0) && ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval >= interval); 
 				ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+					inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval);
 			ed->hwNextED = *ed_p; 
 			*ed_p = cpu_to_le32 (ed->dma);
 		}
@@ -260,7 +251,7 @@
 
 	case PIPE_ISOCHRONOUS:
 		ed->hwNextED = 0;
-		ed->int_interval = 1;
+		ed->interval = 1;
 		if (ohci->ed_isotail != NULL) {
 			ohci->ed_isotail->hwNextED = cpu_to_le32 (ed->dma);
 			ed->ed_prev = ohci->ed_isotail;
@@ -270,7 +261,7 @@
 				for (ed_p = & (ohci->hcca->int_table [ep_rev (5, i)]); 
 					*ed_p != 0; 
 					ed_p = & ((dma_to_ed (ohci, le32_to_cpup (ed_p)))->hwNextED)) 
-						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->int_interval);
+						inter = ep_rev (6, (dma_to_ed (ohci, le32_to_cpup (ed_p)))->interval);
 				*ed_p = cpu_to_le32 (ed->dma);	
 			}	
 			ed->ed_prev = NULL;
@@ -311,7 +302,7 @@
  * the link from the ed still points to another operational ed or 0
  * so the HC can eventually finish the processing of the unlinked ed
  */
-static int ep_unlink (struct ohci_hcd *ohci, struct ed *ed) 
+static int start_ed_unlink (struct ohci_hcd *ohci, struct ed *ed) 
 {
 	int	i;
 
@@ -357,9 +348,9 @@
 		break;
 
 	case PIPE_INTERRUPT:
-		periodic_unlink (ohci, ed, ed->int_branch, ed->int_interval);
-		for (i = ed->int_branch; i < NUM_INTS; i += ed->int_interval)
-			ohci->ohci_int_load [i] -= ed->int_load;
+		periodic_unlink (ohci, ed, ed->intriso.intr_info.int_branch, ed->interval);
+		for (i = ed->intriso.intr_info.int_branch; i < NUM_INTS; i += ed->interval)
+			ohci->ohci_int_load [i] -= ed->intriso.intr_info.int_load;
 #ifdef OHCI_VERBOSE_DEBUG
 		ohci_dump_periodic (ohci, "UNLINK_INT");
 #endif
@@ -384,6 +375,10 @@
 
 	/* FIXME ED's "unlink" state is indeterminate;
 	 * the HC might still be caching it (till SOF).
+	 * - use ed_rm_list and finish_unlinks(), adding some state that
+	 *   prevents clobbering hw linkage before the appropriate SOF
+	 * - a speedup:  when only one urb is queued on the ed, save 1msec
+	 *   by making start_urb_unlink() use this routine to deschedule.
 	 */
 	ed->state = ED_UNLINK;
 	return 0;
@@ -464,8 +459,8 @@
 				<< 16);
 
   	if (ed->type == PIPE_INTERRUPT && ed->state == ED_UNLINK) {
-  		ed->int_period = interval;
-  		ed->int_load = load;
+  		ed->intriso.intr_info.int_period = interval;
+  		ed->intriso.intr_info.int_load = load;
   	}
 
 	spin_unlock_irqrestore (&ohci->lock, flags);
@@ -478,11 +473,8 @@
  * put the ep on the rm_list and stop the bulk or ctrl list 
  * real work is done at the next start frame (SF) hardware interrupt
  */
-static void ed_unlink (struct usb_device *usb_dev, struct ed *ed)
+static void start_urb_unlink (struct ohci_hcd *ohci, struct ed *ed)
 {    
-	unsigned int		frame;
-   	struct ohci_hcd		*ohci = hcd_to_ohci (usb_dev->bus->hcpriv);
-
 	/* already pending? */
 	if (ed->state & ED_URB_DEL)
 		return;
@@ -503,9 +495,15 @@
 			break;
 	}
 
-	frame = le16_to_cpu (ohci->hcca->frame_no) & 0x1;
-	ed->ed_rm_list = ohci->ed_rm_list [frame];
-	ohci->ed_rm_list [frame] = ed;
+	/* SF interrupt might get delayed; record the frame counter value that
+	 * indicates when the HC isn't looking at it, so concurrent unlinks
+	 * behave.  frame_no wraps every 2^16 msec, and changes right before
+	 * SF is triggered.
+	 */
+	ed->tick = le16_to_cpu (ohci->hcca->frame_no) + 1;
+
+	ed->ed_rm_list = ohci->ed_rm_list;
+	ohci->ed_rm_list = ed;
 
 	/* enable SOF interrupt */
 	if (!ohci->sleeping) {
@@ -558,7 +556,7 @@
 	td->hwINFO = cpu_to_le32 (info);
 	if ((td->ed->type) == PIPE_ISOCHRONOUS) {
 		td->hwCBP = cpu_to_le32 (data & 0xFFFFF000);
-		td->ed->last_iso = info & 0xffff;
+		td->ed->intriso.last_iso = info & 0xffff;
 	} else {
 		td->hwCBP = cpu_to_le32 (data); 
 	}			
@@ -605,16 +603,11 @@
 	urb_priv->td_cnt = 0;
 
 	if (data_len) {
-#ifdef CONFIG_PCI
 		data = pci_map_single (ohci->hcd.pdev,
-			urb->transfer_buffer, data_len,
-			usb_pipeout (urb->pipe)
-				? PCI_DMA_TODEVICE
-				: PCI_DMA_FROMDEVICE
-			);
-#else
-#	error "what dma addr to use"
-#endif
+				       urb->transfer_buffer, data_len,
+				       usb_pipeout (urb->pipe)
+				       ? PCI_DMA_TODEVICE
+				       : PCI_DMA_FROMDEVICE);
 	} else
 		data = 0;
 
@@ -662,14 +655,10 @@
 			/* control requests don't use toggle state  */
 			info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
 			td_fill (ohci, info,
-#ifdef CONFIG_PCI
 				pci_map_single (ohci->hcd.pdev,
-					urb->setup_packet, 8,
-					PCI_DMA_TODEVICE),
-#else
-#	error "what dma addr to use"				
-#endif
-				8, urb, cnt++); 
+						urb->setup_packet, 8,
+						PCI_DMA_TODEVICE),
+				 8, urb, cnt++); 
 			if (data_len > 0) {  
 				info = TD_CC | TD_R | TD_T_DATA1;
 				info |= usb_pipeout (urb->pipe)
@@ -816,10 +805,12 @@
 			if (td_list->ed->hwHeadP & ED_H) {
 				if (urb_priv && ((td_list->index + 1)
 						< urb_priv->length)) {
+#ifdef OHCI_VERBOSE_DEBUG
 					dbg ("urb %p TD %d of %d, patch ED",
 						td_list->urb,
 						1 + td_list->index,
 						urb_priv->length);
+#endif
 					td_list->ed->hwHeadP = 
 			    (urb_priv->td [urb_priv->length - 1]->hwNextTD
 				    & __constant_cpu_to_le32 (TD_MASK))
@@ -841,27 +832,37 @@
 
 /*-------------------------------------------------------------------------*/
 
-/* there are some pending requests to unlink 
- * - some URBs/TDs if urb_priv->state == URB_DEL
- */
-static void dl_del_list (struct ohci_hcd *ohci, unsigned int frame)
+/* wrap-aware logic stolen from <linux/jiffies.h> */
+#define tick_before(t1,t2) ((((s16)(t1))-((s16)(t2))) < 0)
+
+/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
+static void finish_unlinks (struct ohci_hcd *ohci, u16 tick)
 {
-	unsigned long	flags;
-	struct ed	*ed;
-	__u32		edINFO;
-	__u32		tdINFO;
-	struct td	*td = NULL, *td_next = NULL,
-			*tdHeadP = NULL, *tdTailP;
-	__u32		*td_p;
+	struct ed	*ed, **last;
 	int		ctrl = 0, bulk = 0;
 
-	spin_lock_irqsave (&ohci->lock, flags);
-
-	for (ed = ohci->ed_rm_list [frame]; ed != NULL; ed = ed->ed_rm_list) {
+	for (last = &ohci->ed_rm_list, ed = *last; ed != NULL; ed = *last) {
+		struct td	*td, *td_next, *tdHeadP, *tdTailP;
+		u32		*td_p;
+		int		unlinked;
+
+		/* only take off EDs that the HC isn't using, accounting for
+		 * frame counter wraps.  completion callbacks might prepend
+		 * EDs to the list, they'll be checked next irq.
+		 */
+		if (tick_before (tick, ed->tick)) {
+			last = &ed->ed_rm_list;
+			continue;
+		}
+		*last = ed->ed_rm_list;
+		ed->ed_rm_list = 0;
+		unlinked = 0;
 
+		/* unlink urbs from first one requested to queue end;
+		 * leave earlier urbs alone
+		 */
 		tdTailP = dma_to_td (ohci, le32_to_cpup (&ed->hwTailP));
 		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
-		edINFO = le32_to_cpup (&ed->hwINFO);
 		td_p = &ed->hwHeadP;
 
 		for (td = tdHeadP; td != tdTailP; td = td_next) {
@@ -870,8 +871,11 @@
 
 			td_next = dma_to_td (ohci,
 				le32_to_cpup (&td->hwNextTD));
-			if ((urb_priv->state == URB_DEL)) {
-				tdINFO = le32_to_cpup (&td->hwINFO);
+			if (unlinked || (urb_priv->state == URB_DEL)) {
+				u32 tdINFO = le32_to_cpup (&td->hwINFO);
+
+				unlinked = 1;
+
 				/* HC may have partly processed this TD */
 				if (TD_CC_GET (tdINFO) < 0xE)
 					td_done (urb, td);
@@ -880,22 +884,32 @@
 
 				/* URB is done; clean up */
 				if (++ (urb_priv->td_cnt) == urb_priv->length) {
-     					spin_unlock_irqrestore (&ohci->lock,
-						flags);
+					if (urb->status == -EINPROGRESS)
+						urb->status = -ECONNRESET;
+     					spin_unlock (&ohci->lock);
 					finish_urb (ohci, urb);
-					spin_lock_irqsave (&ohci->lock, flags);
+					spin_lock (&ohci->lock);
 				}
 			} else {
 				td_p = &td->hwNextTD;
 			}
 		}
 
+		/* FIXME actually want four cases here:
+		 * (a) finishing URB unlink
+		 *     [a1] no URBs queued, so start ED unlink
+		 *     [a2] some (earlier) URBs still linked, re-enable
+		 * (b) finishing ED unlink
+		 *     [b1] no URBs queued, ED is truly idle now
+		 *     [b2] URBs now queued, link ED back into schedule
+		 * right now we only have (a)
+		 */
 		ed->state &= ~ED_URB_DEL;
 		tdHeadP = dma_to_td (ohci, le32_to_cpup (&ed->hwHeadP));
 
 		if (tdHeadP == tdTailP) {
 			if (ed->state == ED_OPER)
-				ep_unlink (ohci, ed);
+				start_ed_unlink (ohci, ed);
 			td_free (ohci, tdTailP);
 			ed->hwINFO = ED_SKIP;
 			ed->state = ED_NEW;
@@ -918,7 +932,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) {
 			if (ohci->ed_controltail)
 				ohci->hc_control |= OHCI_CTRL_CLE;
 			if (ohci->ed_bulktail)
@@ -926,9 +940,6 @@
 			writel (ohci->hc_control, &ohci->regs->control);   
 		}
 	}
-
-   	ohci->ed_rm_list [frame] = NULL;
-   	spin_unlock_irqrestore (&ohci->lock, flags);
 }
 
 
@@ -939,7 +950,7 @@
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is dl_del_list(), which unlinks URBs by scanning EDs, instead of
+ * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
  * scanning the (re-reversed) donelist as this does.
  */
 static void dl_done_list (struct ohci_hcd *ohci, struct td *td)
@@ -960,7 +971,7 @@
 		/* If all this urb's TDs are done, call complete().
 		 * Interrupt transfers are the only special case:
 		 * they're reissued, until "deleted" by usb_unlink_urb
-		 * (real work done in a SOF intr, by dl_del_list).
+		 * (real work done in a SOF intr, by finish_unlinks).
 		 */
   		if (urb_priv->td_cnt == urb_priv->length) {
 			int	resubmit;
@@ -980,7 +991,7 @@
 		if ((ed->hwHeadP & __constant_cpu_to_le32 (TD_MASK))
 					== ed->hwTailP
 				&& (ed->state == ED_OPER)) 
-			ep_unlink (ohci, ed);
+			start_ed_unlink (ohci, ed);
     		td = td_next;
   	}  
 	spin_unlock_irqrestore (&ohci->lock, flags);
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/host/ohci-sa1111.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,358 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Hewlett-Packard Company
+ * 
+ * SA1111 Bus Glue
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Rusell King et al.
+ *
+ * This file is licenced under the GPL.
+ */
+ 
+#include <asm/hardware.h>
+#include <asm/arch/assabet.h>
+#include <asm/arch/badge4.h>
+#include <asm/hardware/sa1111.h>
+
+#ifndef CONFIG_SA1111
+#error "This file is SA-1111 bus glue.  CONFIG_SA1111 must be defined."
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void sa1111_start_hc(void)
+{
+	unsigned int usb_rst = 0;
+
+	printk(KERN_DEBUG __FILE__ 
+	       ": starting SA-1111 OHCI USB Controller\n");
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		badge4_set_5V(BADGE4_5V_USB, 1);
+	}
+#endif
+
+	if (machine_is_xp860() ||
+	    machine_has_neponset() ||
+	    machine_is_pfs168() ||
+	    machine_is_badge4())
+		usb_rst = USB_RESET_PWRSENSELOW | USB_RESET_PWRCTRLLOW;
+
+	/*
+	 * Configure the power sense and control lines.  Place the USB
+	 * host controller in reset.
+	 */
+	USB_RESET = usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+
+	/*
+	 * Now, carefully enable the USB clock, and take
+	 * the USB host controller out of reset.
+	 */
+	SKPCR |= SKPCR_UCLKEN;
+	udelay(11);
+	USB_RESET = usb_rst;
+}
+
+static void sa1111_stop_hc(void)
+{
+	printk(KERN_DEBUG __FILE__ 
+	       ": stopping SA-1111 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+
+	/*
+	 * Stop the USB clock.
+	 */
+	SKPCR &= ~SKPCR_UCLKEN;
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4()) {
+		/* Disable power to the USB bus */
+		badge4_set_5V(BADGE4_5V_USB, 0);
+	}
+#endif
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+#if 0
+static void dump_hci_status(const char *label)
+{
+	unsigned long status = USB_STATUS; 
+
+	dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
+	     ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+	     ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+	     ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+	     ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+	     ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
+
+static void usb_hcd_sa1111_hcim_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+	//dump_hci_status("irq");
+
+#if 0
+	/* may work better this way -- need to investigate further */
+	if (USB_STATUS & USB_STATUS_NIRQHCIM) {
+		//dbg ("not normal HC interrupt; ignoring");
+		return;
+	}
+#endif
+
+	usb_hcd_irq(irq, __hcd, r);
+}
+
+/*-------------------------------------------------------------------------*/
+
+void usb_hcd_sa1111_remove (struct usb_hcd *);
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+
+/**
+ * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_sa1111_probe (const struct hc_driver *driver, struct usb_hcd **hcd_out)
+{
+	int retval;
+	struct usb_hcd *hcd = 0;
+
+	if (!sa1111)
+		return -ENODEV;
+
+	if (!request_mem_region(_USB_OHCI_OP_BASE, 
+				_USB_EXTENT, hcd_name)) {
+		dbg("request_mem_region failed");
+		return -EBUSY;
+	}
+
+	sa1111_start_hc();
+
+	hcd = driver->hcd_alloc ();
+	if (hcd == NULL){
+		dbg ("hcd_alloc failed");
+		retval = -ENOMEM;
+		goto err1;
+	}
+
+	hcd->driver = (struct hc_driver *) driver;
+	hcd->description = driver->description;
+	hcd->irq = NIRQHCIM;
+	hcd->regs = (void *) &USB_OHCI_OP_BASE;
+	hcd->pdev = SA1111_FAKE_PCIDEV;
+
+	set_irq_type(NIRQHCIM, IRQT_RISING);
+	retval = request_irq (NIRQHCIM, usb_hcd_sa1111_hcim_irq, SA_INTERRUPT,
+			      hcd->description, hcd);
+	if (retval != 0) {
+		dbg("request_irq failed");
+		retval = -EBUSY;
+		goto err2;
+	}
+
+	info ("%s (SA-1111) at 0x%p, irq %d\n",
+	      hcd->description, hcd->regs, hcd->irq);
+
+	usb_bus_init (&hcd->self);
+	hcd->self.op = &usb_hcd_operations;
+	hcd->self.hcpriv = (void *) hcd;
+	hcd->self.bus_name = "SA-1111";
+	hcd->product_desc = "SA-1111 OHCI";
+
+	INIT_LIST_HEAD (&hcd->dev_list);
+
+	usb_register_bus (&hcd->self);
+
+	if ((retval = driver->start (hcd)) < 0) 
+	{
+		usb_hcd_sa1111_remove(hcd);
+		return retval;
+	}
+
+	*hcd_out = hcd;
+	return 0;
+
+ err2:
+	if (hcd) driver->hcd_free(hcd);
+ err1:
+	sa1111_stop_hc();
+	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+	return retval;
+}
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_hcd_sa1111_remove (struct usb_hcd *hcd)
+{
+	struct usb_device	*hub;
+	void *base;
+
+	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
+
+	if (in_interrupt ()) BUG ();
+
+	hub = hcd->self.root_hub;
+	hcd->state = USB_STATE_QUIESCING;
+
+	dbg ("%s: roothub graceful disconnect", hcd->self.bus_name);
+	usb_disconnect (&hub);
+
+	hcd->driver->stop (hcd);
+	hcd->state = USB_STATE_HALT;
+
+	free_irq (hcd->irq, hcd);
+
+	usb_deregister_bus (&hcd->self);
+	if (atomic_read (&hcd->self.refcnt) != 1)
+		err (__FUNCTION__ ": %s, count != 1", hcd->self.bus_name);
+
+	base = hcd->regs;
+	hcd->driver->hcd_free (hcd);
+
+	sa1111_stop_hc();
+	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __devinit
+ohci_sa1111_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
+
+	if (hcd->pdev) {
+		ohci->hcca = pci_alloc_consistent (hcd->pdev,
+				sizeof *ohci->hcca, &ohci->hcca_dma);
+		if (!ohci->hcca)
+			return -ENOMEM;
+	}
+
+        memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
+	if ((ret = ohci_mem_init (ohci)) < 0) {
+		ohci_stop (hcd);
+		return ret;
+	}
+	ohci->regs = hcd->regs;
+
+	ohci->parent_dev = &sa1111->dev;
+
+	if (hc_reset (ohci) < 0) {
+		ohci_stop (hcd);
+		return -ENODEV;
+	}
+
+	if (hc_start (ohci) < 0) {
+		err ("can't start %s", ohci->hcd.self.bus_name);
+		ohci_stop (hcd);
+		return -EBUSY;
+	}
+
+#ifdef	DEBUG
+	ohci_dump (ohci, 1);
+#endif
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_sa1111_hc_driver = {
+	description:		hcd_name,
+
+	/*
+	 * generic hardware linkage
+	 */
+	irq:			ohci_irq,
+	flags:			HCD_USB11,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	start:			ohci_sa1111_start,
+#ifdef	CONFIG_PM
+	/* suspend:		ohci_sa1111_suspend,  -- tbd */
+	/* resume:		ohci_sa1111_resume,   -- tbd */
+#endif
+	stop:			ohci_stop,
+
+	/*
+	 * memory lifecycle (except per-request)
+	 */
+	hcd_alloc:		ohci_hcd_alloc,
+	hcd_free:		ohci_hcd_free,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	urb_enqueue:		ohci_urb_enqueue,
+	urb_dequeue:		ohci_urb_dequeue,
+	free_config:		ohci_free_config,
+
+	/*
+	 * scheduling support
+	 */
+	get_frame_number:	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	hub_status_data:	ohci_hub_status_data,
+	hub_control:		ohci_hub_control,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Only one SA-1111 ever exists. */
+static struct usb_hcd *the_sa1111_hcd;
+
+static int __init ohci_hcd_sa1111_init (void) 
+{
+	dbg (DRIVER_INFO " (SA-1111)");
+	dbg ("block sizes: ed %d td %d",
+		sizeof (struct ed), sizeof (struct td));
+
+	the_sa1111_hcd = 0;
+	return usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, &the_sa1111_hcd);
+}
+module_init (ohci_hcd_sa1111_init);
+
+
+static void __exit ohci_hcd_sa1111_cleanup (void) 
+{	
+	if (the_sa1111_hcd) {
+		usb_hcd_sa1111_remove(the_sa1111_hcd);
+		the_sa1111_hcd = 0;
+	}
+}
+module_exit (ohci_hcd_sa1111_cleanup);
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Sat Jun  8 22:31:52 2002
+++ b/drivers/usb/host/ohci.h	Sat Jun  8 22:31:52 2002
@@ -27,22 +27,29 @@
 	__u32			hwNextED;	/* next ED in list */
 
 	/* rest are purely for the driver's use */
-	struct ed		*ed_prev;  
-	__u8			int_period;
-	__u8			int_branch;
-	__u8			int_load; 
-	__u8			int_interval;
-	__u8			state;			// ED_{NEW,UNLINK,OPER}
+	dma_addr_t		dma;		/* addr of ED */
+	struct ed		*ed_prev;	/* for non-interrupt EDs */
+
+	u8			type; 		/* PIPE_{BULK,...} */
+	u8			interval;	/* interrupt, isochronous */
+	union {
+		struct intr_info {		/* interrupt */
+			u8	int_period;
+			u8	int_branch;
+			u8	int_load; 
+		} intr_info;
+		u16		last_iso;	/* isochronous */
+	} intriso;
+
+	u8			state;		/* ED_{NEW,UNLINK,OPER} */
 #define ED_NEW 		0x00		/* unused, no dummy td */
 #define ED_UNLINK 	0x01		/* dummy td, maybe linked to hc */
 #define ED_OPER		0x02		/* dummy td, _is_ linked to hc */
 #define ED_URB_DEL  	0x08		/* for unlinking; masked in */
 
-	__u8			type; 
-	__u16			last_iso;
+	/* HC may see EDs on rm_list until next frame (frame_no == tick) */
+	u16			tick;
 	struct ed		*ed_rm_list;
-
-	dma_addr_t		dma;			/* addr of ED */
 } __attribute__ ((aligned(16)));
 
 #define ED_MASK	((u32)~0x0f)		/* strip hw status in low addr bits */
@@ -324,6 +331,11 @@
 struct ohci_hcd {
 	spinlock_t		lock;
 
+        /*
+	 * parent device
+	 */
+        struct device		*parent_dev;
+
 	/*
 	 * I/O memory used to communicate with the HC (uncached);
 	 */
@@ -335,18 +347,16 @@
 	struct ohci_hcca	*hcca;
 	dma_addr_t		hcca_dma;
 
-	struct ed		*ed_rm_list [2];	/* to be removed */
+	struct ed		*ed_rm_list;		/* to be removed */
 
 	struct ed		*ed_bulktail;		/* last in bulk list */
 	struct ed		*ed_controltail;	/* last in ctrl list */
  	struct ed		*ed_isotail;		/* last in iso list */
 
-#ifdef CONFIG_PCI
 	struct pci_pool		*td_cache;
 	struct pci_pool		*ed_cache;
 	struct hash_list_t	td_hash [TD_HASH_SIZE];
 	struct hash_list_t	ed_hash [ED_HASH_SIZE];
-#endif
 
 	/*
 	 * driver state
diff -Nru a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
--- a/drivers/usb/host/uhci-hcd.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/usb/host/uhci-hcd.c	Sat Jun  8 22:31:52 2002
@@ -1502,10 +1502,6 @@
 		break;
 	case PIPE_ISOCHRONOUS:
 		if (urb->bandwidth == 0) {	/* not yet checked/allocated */
-			if (urb->number_of_packets <= 0) {
-				ret = -EINVAL;
-				break;
-			}
 			bustime = usb_check_bandwidth(urb->dev, urb);
 			if (bustime < 0) {
 				ret = bustime;
@@ -2515,7 +2511,7 @@
 	suspend:		uhci_suspend,
 	resume:			uhci_resume,
 #endif
-	stop:			uhci_stop,
+	stop:			__devexit_p(uhci_stop),
 
 	hcd_alloc:		uhci_hcd_alloc,
 	hcd_free:		uhci_hcd_free,
diff -Nru a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
--- a/drivers/usb/host/uhci-hub.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/usb/host/uhci-hub.c	Sat Jun  8 22:31:36 2002
@@ -52,7 +52,7 @@
 	outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
 
 
-// FIXME: Shouldn't this return the length of the data too?
+/* size of returned buffer is part of USB spec */
 static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 			u16 wIndex, char *buf, u16 wLength)
 {
diff -Nru a/drivers/usb/host/usb-ohci-pci.c b/drivers/usb/host/usb-ohci-pci.c
--- a/drivers/usb/host/usb-ohci-pci.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/usb/host/usb-ohci-pci.c	Sat Jun  8 22:31:51 2002
@@ -21,6 +21,12 @@
 #endif
 #endif
 
+int __devinit
+hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
+	    ohci_t **ohci, const char *name, const char *slot_name);
+extern void hc_remove_ohci(ohci_t *ohci);
+extern int hc_start (ohci_t * ohci, struct device *parent_dev);
+extern int hc_reset (ohci_t * ohci);
 
 /*-------------------------------------------------------------------------*/
 
@@ -103,7 +109,8 @@
 	ohci->ed_controltail = NULL;
 	ohci->ed_bulktail    = NULL;
 
-	if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
+	if ((temp = hc_reset (ohci)) < 0 || 
+	    (temp = hc_start (ohci, &ohci->ohci_dev->dev)) < 0) {
 		err ("can't restart usb-%s, %d", ohci->ohci_dev->slot_name, temp);
 	} else
 		dbg ("restart usb-%s completed", ohci->ohci_dev->slot_name);
@@ -171,6 +178,7 @@
 ohci_pci_remove (struct pci_dev *dev)
 {
 	ohci_t		*ohci = (ohci_t *) pci_get_drvdata(dev);
+	void		*membase = ohci->regs;
 
 	dbg ("remove %s controller usb-%s%s%s",
 		hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS),
@@ -181,6 +189,9 @@
 
 	hc_remove_ohci(ohci);
 
+ 	/* unmap the IO address space */
+ 	iounmap (membase);
+ 
 	release_mem_region (pci_resource_start (dev, 0), pci_resource_len (dev, 0));
 }
 
diff -Nru a/drivers/usb/host/usb-ohci-sa1111.c b/drivers/usb/host/usb-ohci-sa1111.c
--- a/drivers/usb/host/usb-ohci-sa1111.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/host/usb-ohci-sa1111.c	Sat Jun  8 22:31:35 2002
@@ -12,6 +12,7 @@
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
+#include <linux/pci.h>
 #include <linux/errno.h>
 
 #include <asm/hardware.h>
@@ -27,6 +28,9 @@
 hc_add_ohci(struct pci_dev *dev, int irq, void *membase, unsigned long flags,
 	    ohci_t **ohci, const char *name, const char *slot_name);
 extern void hc_remove_ohci(ohci_t *ohci);
+extern int hc_start (ohci_t * ohci, struct device *parent_dev);
+extern int hc_reset (ohci_t * ohci);
+
 
 static ohci_t *sa1111_ohci;
 
@@ -34,6 +38,15 @@
 {
 	unsigned int usb_rst = 0;
 
+	printk(KERN_DEBUG __FILE__ 
+	       ": starting SA-1111 OHCI USB Controller\n");
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4())
+		/* power the bus */
+		badge4_set_5V(BADGE4_5V_USB, 1);
+#endif
+
 	if (machine_is_xp860() ||
 	    machine_has_neponset() ||
 	    machine_is_pfs168() ||
@@ -55,6 +68,28 @@
 	USB_RESET = usb_rst;
 }
 
+static void __exit sa1111_ohci_unconfigure(void)
+{
+	printk(KERN_DEBUG __FILE__ 
+	       ": stopping SA-1111 OHCI USB Controller\n");
+
+	/*
+	 * Put the USB host controller into reset.
+	 */
+	USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
+
+	/*
+	 * Stop the USB clock.
+	 */
+	SKPCR &= ~SKPCR_UCLKEN;
+
+#ifdef CONFIG_SA1100_BADGE4
+	if (machine_is_badge4())
+		badge4_set_5V(BADGE4_5V_USB, 0);
+#endif
+}
+
+
 static int __init sa1111_ohci_init(void)
 {
 	int ret;
@@ -65,66 +100,54 @@
 	/*
 	 * Request memory resources.
 	 */
-//	if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci"))
-//		return -EBUSY;
+	if (!request_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT, "usb-ohci"))
+		return -EBUSY;
 
 	sa1111_ohci_configure();
 
 	/*
 	 * Initialise the generic OHCI driver.
 	 */
-	ret = hc_add_ohci((struct pci_dev *)1, NIRQHCIM,
+	sa1111_ohci = 0;
+	ret = hc_add_ohci(SA1111_FAKE_PCIDEV, NIRQHCIM,
 			  (void *)&USB_OHCI_OP_BASE, 0, &sa1111_ohci,
 			  "usb-ohci", "sa1111");
 
-	if (ret == 0) {
-		if (hc_start (sa1111_ohci, &sa1111->dev) < 0) {
-			err ("can't start usb-%s", sa1111_ohci->slot_name);
-			hc_remove_ohci (sa1111_ohci);
-			return -EBUSY;
-		}
+	if (ret || !sa1111_ohci) {
+		sa1111_ohci = 0;
+		sa1111_ohci_unconfigure();
+		release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+		return -EBUSY;
+	}
 
-#ifdef	DEBUG
-		ohci_dump (ohci, 1);
-#endif
-#ifdef CONFIG_SA1100_BADGE4
-		if (machine_is_badge4()) {
-			/* found the controller, so now power the bus */
-			badge4_set_5V(BADGE4_5V_USB, 1);
-		}
-#endif
+	if (hc_start (sa1111_ohci, &sa1111->dev) < 0) {
+		err ("can't start usb-%s", sa1111_ohci->slot_name);
+		hc_remove_ohci (sa1111_ohci);
+		sa1111_ohci = 0;
+		sa1111_ohci_unconfigure();
+		release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+		return -EBUSY;
 	}
-//	else
-//		release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
 
-	return ret;
+	return 0;
 }
 
 static void __exit sa1111_ohci_exit(void)
 {
-	hc_remove_ohci(sa1111_ohci);
+	printk(KERN_DEBUG __FUNCTION__ ": cleaning up\n");
 
-	/*
-	 * Put the USB host controller into reset.
-	 */
-	USB_RESET |= USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET;
-
-	/*
-	 * Stop the USB clock.
-	 */
-	SKPCR &= ~SKPCR_UCLKEN;
+	if (sa1111_ohci) {
+		hc_remove_ohci(sa1111_ohci);
+		sa1111_ohci = 0;
+	}
 
-	/*
-	 * Release memory resources.
-	 */
-//	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
+	sa1111_ohci_unconfigure();
+	release_mem_region(_USB_OHCI_OP_BASE, _USB_EXTENT);
 
-#ifdef CONFIG_SA1100_BADGE4
-	if (machine_is_badge4()) {
-		badge4_set_5V(BADGE4_5V_USB, 0);
-	}
-#endif
+	printk(KERN_DEBUG __FUNCTION__ ": exiting\n");
 }
 
 module_init(sa1111_ohci_init);
 module_exit(sa1111_ohci_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/usb/host/usb-ohci.c b/drivers/usb/host/usb-ohci.c
--- a/drivers/usb/host/usb-ohci.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/usb/host/usb-ohci.c	Sat Jun  8 22:31:36 2002
@@ -66,7 +66,12 @@
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/interrupt.h>  /* for in_interrupt() */
-#undef DEBUG
+
+#ifdef CONFIG_USB_DEBUG
+#	define DEBUG
+#else
+#	undef DEBUG
+#endif
 #include <linux/usb.h>
 
 #include <asm/io.h>
@@ -2391,7 +2396,11 @@
 		return NULL;
 	}
 	ohci->bus->hcpriv = (void *) ohci;
+#ifdef CONFIG_PCI
 	ohci->bus->bus_name = dev->slot_name;
+#else
+	ohci->bus->bus_name = "ohci-hc";
+#endif
 
 	return ohci;
 } 
@@ -2430,9 +2439,6 @@
 
 	ohci_mem_cleanup (ohci);
     
-	/* unmap the IO address space */
-	iounmap (ohci->regs);
-
 	pci_free_consistent (ohci->ohci_dev, sizeof *ohci->hcca,
 		ohci->hcca, ohci->hcca_dma);
 	kfree (ohci);
diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c
--- a/drivers/usb/media/konicawc.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/usb/media/konicawc.c	Sat Jun  8 22:31:35 2002
@@ -268,7 +268,7 @@
 
 static void konicawc_isoc_irq(struct urb *urb)
 {
-	int i, len = 0;
+	int i, ret, len = 0;
 	uvd_t *uvd = urb->context;
 	struct konicawc *cam = (struct konicawc *)uvd->user_data;
 
@@ -276,17 +276,17 @@
 	if (!CAMERA_IS_OPERATIONAL(uvd))
 		return;
 
-	if (urb->actual_length > 32) {
-		cam->last_data_urb = urb;
-		return;
-	}
-
 	if (!uvd->streaming) {
 		if (debug >= 1)
 			info("Not streaming, but interrupt!");
 		return;
 	}
 
+	if (urb->actual_length > 32) {
+		cam->last_data_urb = urb;
+		goto urb_done_with;
+	}
+
 	uvd->stats.urb_count++;
 	if (urb->actual_length <= 0)
 		goto urb_done_with;
@@ -296,25 +296,23 @@
 		len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
 		for (i = 0; i < FRAMES_PER_DESC; i++) {
 			cam->last_data_urb->iso_frame_desc[i].status = 0;
-			cam->last_data_urb->iso_frame_desc[i].actual_length = 0;
 		}
 		cam->last_data_urb = NULL;
 	}
 	uvd->stats.urb_length = len;
-	if (len <= 0) {
-		goto urb_done_with;
-	}
-
-	/* Here we got some data */
 	uvd->stats.data_count += len;
-	RingQueue_WakeUpInterruptible(&uvd->dp);
+	if(len)
+		RingQueue_WakeUpInterruptible(&uvd->dp);
 
 urb_done_with:
-
 	for (i = 0; i < FRAMES_PER_DESC; i++) {
 		urb->iso_frame_desc[i].status = 0;
-		urb->iso_frame_desc[i].actual_length = 0;
 	}
+	urb->dev = uvd->dev;
+	urb->status = 0;
+	ret = usb_submit_urb(urb, GFP_KERNEL);
+	if(ret)
+		err("usb_submit_urb error (%d)", ret);
 	return;
 }
 
@@ -346,6 +344,7 @@
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+		urb->interval = 1;
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = uvd->sbuf[i].data;
 		urb->complete = konicawc_isoc_irq;
@@ -360,6 +359,7 @@
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
+		urb->interval = 1;
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = cam->sts_buf[i];
 		urb->complete = konicawc_isoc_irq;
@@ -373,17 +373,6 @@
 
 	cam->last_data_urb = NULL;
 	
-	/* Link URBs into a ring so that they invoke each other infinitely */
-	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		if ((i+1) < USBVIDEO_NUMSBUF) {
-			cam->sts_urb[i]->next = uvd->sbuf[i].urb;
-			uvd->sbuf[i].urb->next = cam->sts_urb[i+1];
-		} else {
-			cam->sts_urb[i]->next = uvd->sbuf[i].urb;
-			uvd->sbuf[i].urb->next = cam->sts_urb[0];
-		}
-	}
-
 	/* Submit all URBs */
 	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
 		errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
--- a/drivers/usb/media/ov511.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/usb/media/ov511.c	Sat Jun  8 22:31:37 2002
@@ -61,7 +61,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.60 for Linux 2.5"
+#define DRIVER_VERSION "v1.60a for Linux 2.5"
 #define EMAIL "mmcclell@bigfoot.com"
 #define DRIVER_AUTHOR "Mark McClelland <mmcclell@bigfoot.com> & Bret Wallach \
 	& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
@@ -3882,7 +3882,10 @@
 		}
 	}
 
+	/* Resubmit this URB */
 	urb->dev = ov->dev;
+	if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
+		err("usb_submit_urb() ret %d", i);
 
 	return;
 }
@@ -3967,6 +3970,7 @@
 		urb->complete = ov51x_isoc_irq;
 		urb->number_of_packets = FRAMES_PER_DESC;
 		urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
+		urb->interval = 1;
 		for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
 			urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
 			urb->iso_frame_desc[fx].length = ov->packet_size;
@@ -3974,10 +3978,6 @@
 	}
 
 	ov->streaming = 1;
-
-	ov->sbuf[OV511_NUMSBUF - 1].urb->next = ov->sbuf[0].urb;
-	for (n = 0; n < OV511_NUMSBUF - 1; n++)
-		ov->sbuf[n].urb->next = ov->sbuf[n+1].urb;
 
 	for (n = 0; n < OV511_NUMSBUF; n++) {
 		ov->sbuf[n].urb->dev = ov->dev;
diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c
--- a/drivers/usb/media/pwc-if.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/usb/media/pwc-if.c	Sat Jun  8 22:31:51 2002
@@ -749,6 +749,9 @@
 	}
 	if (awake)
 		wake_up_interruptible(&pdev->frameq);
+
+	urb->dev = pdev->udev;
+	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
 
@@ -784,7 +787,7 @@
 			break;
 		}
 	
-	if (pdev->vmax_packet_size < 0) {
+	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
 		Err("Failed to find packet size for video endpoint in current alternate setting.\n");
 		return -ENFILE; /* Odd error, that should be noticable */
 	}
@@ -815,7 +818,7 @@
 	for (i = 0; i < MAX_ISO_BUFS; i++) {
 		urb = pdev->sbuf[i].urb;
 
-		urb->next = pdev->sbuf[(i + 1) % MAX_ISO_BUFS].urb;
+		urb->interval = 1; // devik
 		urb->dev = udev;
 	        urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
 		urb->transfer_flags = USB_ISO_ASAP;
@@ -826,8 +829,8 @@
 		urb->start_frame = 0;
 		urb->number_of_packets = ISO_FRAMES_PER_DESC;
 		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
-			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
-			urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE;
+			urb->iso_frame_desc[j].offset = j * pdev->vmax_packet_size;
+			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
 		}
 	}
 
@@ -858,7 +861,7 @@
 		usb_set_interface(pdev->udev, 0, 0);
 	/* Unlinking ISOC buffers one by one */
 	for (i = MAX_ISO_BUFS - 1; i >= 0; i--) {
-		pdev->sbuf[i].urb->next = NULL;
+		//pdev->sbuf[i].urb->next = NULL;
 		usb_unlink_urb(pdev->sbuf[i].urb);
 		usb_free_urb(pdev->sbuf[i].urb);
 		pdev->sbuf[i].urb = NULL;
diff -Nru a/drivers/usb/media/usbvideo.c b/drivers/usb/media/usbvideo.c
--- a/drivers/usb/media/usbvideo.c	Sat Jun  8 22:31:43 2002
+++ b/drivers/usb/media/usbvideo.c	Sat Jun  8 22:31:43 2002
@@ -1802,7 +1802,7 @@
 
 static void usbvideo_IsocIrq(struct urb *urb)
 {
-	int i, len;
+	int i, ret, len;
 	uvd_t *uvd = urb->context;
 
 	/* We don't want to do anything if we are about to be removed! */
@@ -1844,6 +1844,11 @@
 		urb->iso_frame_desc[i].status = 0;
 		urb->iso_frame_desc[i].actual_length = 0;
 	}
+	urb->status = 0;
+	urb->dev = uvd->dev;
+	ret = usb_submit_urb (urb, GFP_KERNEL);
+	if(ret)
+		err("usb_submit_urb error (%d)", ret);
 	return;
 }
 
@@ -1889,6 +1894,7 @@
 		urb->dev = dev;
 		urb->context = uvd;
 		urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
+		urb->interval = 1;
 		urb->transfer_flags = USB_ISO_ASAP;
 		urb->transfer_buffer = uvd->sbuf[i].data;
 		urb->complete = usbvideo_IsocIrq;
@@ -1898,14 +1904,6 @@
 			urb->iso_frame_desc[j].offset = k;
 			urb->iso_frame_desc[j].length = uvd->iso_packet_len;
 		}
-	}
-
-	/* Link URBs into a ring so that they invoke each other infinitely */
-	for (i=0; i < USBVIDEO_NUMSBUF; i++) {
-		if ((i+1) < USBVIDEO_NUMSBUF)
-			uvd->sbuf[i].urb->next = uvd->sbuf[i+1].urb;
-		else
-			uvd->sbuf[i].urb->next = uvd->sbuf[0].urb;
 	}
 
 	/* Submit all URBs */
diff -Nru a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c
--- a/drivers/usb/misc/emi26.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/usb/misc/emi26.c	Sat Jun  8 22:31:37 2002
@@ -13,6 +13,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/usb.h>
 
 #define MAX_INTEL_HEX_RECORD_LENGTH 16
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Sat Jun  8 22:31:51 2002
+++ b/drivers/usb/storage/unusual_devs.h	Sat Jun  8 22:31:51 2002
@@ -106,9 +106,9 @@
  * This entry is needed because the device reports Sub=ff 
  */
 UNUSUAL_DEV(  0x04da, 0x0901, 0x0100, 0x0200,
-               "Panasonic",
-               "LS-120 Camera",
-               US_SC_UFI, US_PR_CBI, NULL, 0),
+		"Panasonic",
+		"LS-120 Camera",
+		US_SC_UFI, US_PR_CBI, NULL, 0),
 
 /* Reported by Peter Wächtler <pwaechtler@loewe-komp.de> */
 UNUSUAL_DEV(  0x04ce, 0x0002, 0x0074, 0x0074,
@@ -230,7 +230,7 @@
 		US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE),
 
 UNUSUAL_DEV(  0x054c, 0x0032, 0x0000, 0x9999,
-                "Sony",
+		"Sony",
 		"Memorystick MSC-U01N",
 		US_SC_UFI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN | US_FL_START_STOP ),
@@ -261,34 +261,34 @@
 
 #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 ),
+		"In-System",
+		"USB/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 ),
+		"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 ),
+		"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 ),
+		"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 ),
+		"Sony",
+		"Portable USB Harddrive V2",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
 #endif
 
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
@@ -342,18 +342,18 @@
 /* Submitted by kedar@centillium
  * Needed for START_STOP flag, but that is unconfirmed */
 UNUSUAL_DEV( 0x0686, 0x4006, 0x0001, 0x0001,
-                "Minolta",
-                "Dimage S304",
-                US_SC_SCSI, US_PR_BULK, NULL,
-                US_FL_START_STOP ),
+		"Minolta",
+		"Dimage S304",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 /* Submitted by f.brugmans@hccnet.nl
  * Needed for START_STOP flag */
 UNUSUAL_DEV( 0x0686, 0x4007, 0x0001, 0x0001,
-                "Minolta",
-                "Dimage S304",
-                US_SC_SCSI, US_PR_BULK, NULL,
-                US_FL_START_STOP ),
+		"Minolta",
+		"Dimage S304",
+		US_SC_SCSI, US_PR_BULK, NULL,
+		US_FL_START_STOP ),
 
 UNUSUAL_DEV(  0x0693, 0x0002, 0x0100, 0x0100, 
 		"Hagiwara",
@@ -378,10 +378,10 @@
 		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 ),
+		"Sandisk",
+		"ImageMate SDDR-12",
+		US_SC_SCSI, US_PR_CB, NULL,
+		US_FL_SINGLE_LUN ),
 
 #ifdef CONFIG_USB_STORAGE_SDDR09
 UNUSUAL_DEV(  0x0781, 0x0200, 0x0000, 0x9999, 
@@ -393,9 +393,9 @@
 
 #ifdef CONFIG_USB_STORAGE_FREECOM
 UNUSUAL_DEV(  0x07ab, 0xfc01, 0x0000, 0x9999,
-                "Freecom",
-                "USB-IDE",
-                US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
+		"Freecom",
+		"USB-IDE",
+		US_SC_QIC, US_PR_FREECOM, freecom_init, 0),
 #endif
 
 UNUSUAL_DEV(  0x07af, 0x0004, 0x0100, 0x0133, 
@@ -473,7 +473,7 @@
 		US_SC_SCSI, US_PR_DATAFAB, NULL,
 		US_FL_MODE_XLATE ),
 #endif
-
+		
 #ifdef CONFIG_USB_STORAGE_SDDR55
 /* Contributed by Peter Waechtler */
 UNUSUAL_DEV( 0x07c4, 0xa103, 0x0000, 0x9999,
@@ -491,10 +491,10 @@
  *   of the SCSI layer ourselves.
  */
 UNUSUAL_DEV( 0x07cf, 0x1001, 0x1000, 0x9009,
-                "Casio",
-                "QV DigitalCamera",
-                US_SC_8070, US_PR_CB, NULL,
-                US_FL_FIX_INQUIRY ),
+		"Casio",
+		"QV DigitalCamera",
+		US_SC_8070, US_PR_CB, NULL,
+		US_FL_FIX_INQUIRY ),
 
 UNUSUAL_DEV(  0x097a, 0x0001, 0x0000, 0x0001,
 		"Minds@Work",
@@ -510,10 +510,10 @@
 
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x0bf6, 0xa001, 0x0100, 0x0110,
-                "ATI",
-                "USB Cable 205",
-                US_SC_ISD200, US_PR_BULK, isd200_Initialization,
-                0 ),
+		"ATI",
+		"USB Cable 205",
+		US_SC_ISD200, US_PR_BULK, isd200_Initialization,
+		0 ),
 #endif
 
 /* EasyDisk support. Submitted by Stanislav Karchebny <berk@madfire.net> */
diff -Nru a/drivers/video/Config.in b/drivers/video/Config.in
--- a/drivers/video/Config.in	Sat Jun  8 22:31:49 2002
+++ b/drivers/video/Config.in	Sat Jun  8 22:31:49 2002
@@ -236,25 +236,25 @@
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_AMIGA" = "y" -o \
 	   "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_CYBER" = "y" -o \
 	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \
-	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
-	   "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" ]; then 
+	   "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
+	   "$CONFIG_FB_BWTWO" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_MFB y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \
 	      "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_CYBER" = "m" -o \
 	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \
-	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_TX3912" = "m" -o \
-	      "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "m" ]; then 
+	      "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
+	      "$CONFIG_FB_BWTWO" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_MFB m
 	 fi
       fi
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
-	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then 
+	   "$CONFIG_FB_SA1100" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB2 y
 	 define_tristate CONFIG_FBCON_CFB4 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_TX3912" = "m" ]; then 
+	      "$CONFIG_FB_SA1100" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB2 m
 	    define_tristate CONFIG_FBCON_CFB4 m
 	 fi
@@ -262,7 +262,7 @@
       if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_ATARI" = "y" -o \
 	   "$CONFIG_FB_ATY" = "y" -o "$CONFIG_FB_MAC" = "y" -o \
 	   "$CONFIG_FB_OF" = "y" -o "$CONFIG_FB_TGA" = "y" -o \
-	   "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_PM3" = "y" -o \
 	   "$CONFIG_FB_TCX" = "y" -o "$CONFIG_FB_CGTHREE" = "y" -o \
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
 	   "$CONFIG_FB_CGFOURTEEN" = "y" -o "$CONFIG_FB_TRIDENT" = "y" -o \
@@ -273,15 +273,13 @@
 	   "$CONFIG_FB_P9100" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_SGIVW" = "y" -o "$CONFIG_FB_CYBER2000" = "y" -o \
-	   "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_SIS" = "y" -o \
-	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
-	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" ]; then 
+	   "$CONFIG_FB_SA1100" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB8 y
       else
 	 if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_ATARI" = "m" -o \
 	      "$CONFIG_FB_ATY" = "m" -o "$CONFIG_FB_MAC" = "m" -o \
 	      "$CONFIG_FB_OF" = "m" -o "$CONFIG_FB_TGA" = "m" -o \
-	      "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
+	      "$CONFIG_FB_SIS" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
 	      "$CONFIG_FB_TCX" = "m" -o "$CONFIG_FB_CGTHREE" = "m" -o \
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
 	      "$CONFIG_FB_CGFOURTEEN" = "m" -o "$CONFIG_FB_TRIDENT" = "m" -o \
@@ -290,16 +288,14 @@
               "$CONFIG_FB_IGA" = "m" -o "$CONFIG_FB_MATROX" = "m" -o \
 	      "$CONFIG_FB_CT65550" = "m" -o "$CONFIG_FB_PM2" = "m" -o \
 	      "$CONFIG_FB_P9100" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
-	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_TX3912" = "m" -o \
+	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
 	      "$CONFIG_FB_SGIVW" = "m" -o "$CONFIG_FB_CYBER2000" = "m" -o \
-	      "$CONFIG_FB_PMAG_BA" = "m" -o "$CONFIG_FB_PMAGB_B" = "m" -o \
-	      "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" ]; then 
+	      "$CONFIG_FB_SA1100" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB8 m
 	 fi
       fi
       if [ "$CONFIG_FB_ATARI" = "y" -o "$CONFIG_FB_ATY" = "y" -o \
-	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \
+	   "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_PVR2" = "y" -o \
 	   "$CONFIG_FB_TRIDENT" = "y" -o "$CONFIG_FB_TBOX" = "y" -o \
 	   "$CONFIG_FB_VOODOO1" = "y" -o "$CONFIG_FB_RADEON" = "y" -o \
 	   "$CONFIG_FB_CONTROL" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \
@@ -309,12 +305,11 @@
 	   "$CONFIG_FB_PM2" = "y" -o "$CONFIG_FB_SGIVW" = "y" -o \
 	   "$CONFIG_FB_RIVA" = "y" -o "$CONFIG_FB_ATY128" = "y" -o \
 	   "$CONFIG_FB_CYBER2000" = "y" -o "$CONFIG_FB_PM3" = "y"  -o \
-	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \
-	   "$CONFIG_FB_PVR2" = "y" ]; then 
+	   "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" ]; then 
 	 define_tristate CONFIG_FBCON_CFB16 y
       else
 	 if [ "$CONFIG_FB_ATARI" = "m" -o "$CONFIG_FB_ATY" = "m" -o \
-	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \
+	      "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_PVR2" = "m" -o \
 	      "$CONFIG_FB_TRIDENT" = "m" -o "$CONFIG_FB_TBOX" = "m" -o \
 	      "$CONFIG_FB_VOODOO1" = "m" -o "$CONFIG_FB_PM3" = "m" -o \
 	      "$CONFIG_FB_CONTROL" = "m" -o "$CONFIG_FB_CLGEN" = "m" -o \
@@ -324,8 +319,7 @@
 	      "$CONFIG_FB_PM2" = "m" -o "$CONFIG_FB_SGIVW" = "m" -o \
 	      "$CONFIG_FB_RIVA" = "m" -o "$CONFIG_FB_ATY128" = "m" -o \
 	      "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \
-	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \
-	      "$CONFIG_FB_PVR2" = "m" ]; then 
+	      "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" ]; then 
 	    define_tristate CONFIG_FBCON_CFB16 m
 	 fi
       fi
@@ -374,7 +368,9 @@
 	   "$CONFIG_FB_HP300" = "y" -o "$CONFIG_FB_Q40" = "y" -o \
 	   "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_G364" = "y" -o \
 	   "$CONFIG_FB_VIRTUAL" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \
-	   "$CONFIG_FB_3DFX" = "y" ]; then
+	   "$CONFIG_FB_PMAG_BA" = "y" -o "$CONFIG_FB_PMAGB_B" = "y" -o \
+	   "$CONFIG_FB_3DFX" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \
+	   "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_APOLLO" = "y" ]; then
 	 define_tristate CONFIG_FBCON_ACCEL y
       else
 	 if [ "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_HIT" = "m" -o \
diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile
--- a/drivers/video/Makefile	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/Makefile	Sat Jun  8 22:31:36 2002
@@ -7,13 +7,13 @@
 # All of the (potential) objects that export symbols.
 # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'.
 
-export-objs    := fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
-		  fbcon-afb.o fbcon-ilbm.o fbcon-accel.o \
-		  fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
-		  fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
-		  fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
-		  fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
-		  cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
+export-objs    	:= fbmem.o fbcmap.o fbcon.o fbmon.o modedb.o \
+		   fbcon-afb.o fbcon-ilbm.o fbcon-accel.o \
+		   fbcon-vga.o fbcon-iplan2p2.o fbcon-iplan2p4.o \
+		   fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \
+		   fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \
+		   fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \
+		   cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o
 
 # Each configuration option enables a list of files.
 
@@ -43,18 +43,18 @@
 obj-$(CONFIG_FB_AMIGA)            += amifb.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
-obj-$(CONFIG_FB_APOLLO)           += dnfb.o
+obj-$(CONFIG_FB_APOLLO)           += dnfb.o cfbfillrect.o cfbimgblt.o
 obj-$(CONFIG_FB_Q40)              += q40fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_ATARI)            += atafb.o
 obj-$(CONFIG_FB_ATY128)           += aty128fb.o
 obj-$(CONFIG_FB_RADEON)		  += radeonfb.o
-obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o
+obj-$(CONFIG_FB_NEOMAGIC)         += neofb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_IGA)              += igafb.o
 obj-$(CONFIG_FB_CONTROL)          += controlfb.o
 obj-$(CONFIG_FB_PLATINUM)         += platinumfb.o
 obj-$(CONFIG_FB_VALKYRIE)         += valkyriefb.o
 obj-$(CONFIG_FB_CT65550)          += chipsfb.o
-obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o
+obj-$(CONFIG_FB_ANAKIN)           += anakinfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CLPS711X)         += clps711xfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 obj-$(CONFIG_FB_CYBER)            += cyberfb.o
 obj-$(CONFIG_FB_CYBER2000)        += cyber2000fb.o
@@ -83,10 +83,10 @@
 obj-$(CONFIG_FB_P9100)            += p9100fb.o sbusfb.o
 obj-$(CONFIG_FB_LEO)              += leofb.o sbusfb.o
 obj-$(CONFIG_FB_STI)	          += stifb.o sticore.o
-obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o
-obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o
-obj-$(CONFIG_FB_MAXINE)           += maxinefb.o
-obj-$(CONFIG_FB_TX3912)           += tx3912fb.o
+obj-$(CONFIG_FB_PMAG_BA)          += pmag-ba-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_PMAGB_B)          += pmagb-b-fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_MAXINE)           += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
+obj-$(CONFIG_FB_TX3912)           += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
 
 obj-$(CONFIG_FB_MATROX)		  += matrox/
 obj-$(CONFIG_FB_RIVA)		  += riva/
@@ -124,13 +124,12 @@
 obj-$(CONFIG_FBCON_STI)           += fbcon-sti.o
 obj-$(CONFIG_FBCON_ACCEL)	  += fbcon-accel.o
 
+host-progs := ../conmakehash
+
 include $(TOPDIR)/Rules.make
 
 clean:
 	rm -f core *.o *.a *.s
-
-../conmakehash: ../conmakehash.c
-	$(HOSTCC) $(HOSTCFLAGS) -o ../conmakehash ../conmakehash.c
 
 promcon_tbl.c: prom.uni ../char/conmakehash
 	../char/conmakehash prom.uni | \
diff -Nru a/drivers/video/anakinfb.c b/drivers/video/anakinfb.c
--- a/drivers/video/anakinfb.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/video/anakinfb.c	Sat Jun  8 22:31:51 2002
@@ -21,7 +21,6 @@
 #include <asm/io.h>
 
 #include <video/fbcon.h>
-#include <video/fbcon-cfb16.h>
 
 static u32 colreg[16];
 static struct fb_info fb_info;
@@ -84,7 +83,8 @@
 	memset(&display, 0, sizeof(struct display));
 
 	strcpy(fb_info.modename, anakinfb_fix.id);
-	fb_info.node = fb_info.currcon = -1;
+	fb_info.node = NODEV;
+	fb_info.currcon = -1;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 	fb_info.fbops = &anakinfb_ops;
 	fb_info.var = anakinfb_var;
diff -Nru a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
--- a/drivers/video/aty128fb.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/video/aty128fb.c	Sat Jun  8 22:31:37 2002
@@ -1659,7 +1659,7 @@
 {
     struct fb_var_screeninfo var;
     u32 dac;
-    int j, k;
+    int j, k, size;
     u8 chip_rev;
     const struct aty128_chip_info *aci = &aty128_pci_probe_list[0];
     char *video_card = "Rage128";
@@ -1771,6 +1771,9 @@
     aty128_init_engine(&info->default_par, info);
 
     board_list = aty128_board_list_add(board_list, info);
+
+    size = (fb_display[con].var.bits_per_pixel <= 8) ? 256 : 32;
+    fb_alloc_cmap(info->fb_info.cmap, size, 0);	
 
     if (register_framebuffer(&info->fb_info) < 0)
 	return 0;
diff -Nru a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
--- a/drivers/video/cfbcopyarea.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/video/cfbcopyarea.c	Sat Jun  8 22:31:37 2002
@@ -31,7 +31,7 @@
 void cfb_copyarea(struct fb_info *p, struct fb_copyarea *area)
 {
 	int x2, y2, lineincr, shift, shift_right, shift_left, old_dx, old_dy;
-	int n, j, linesize = p->fix.line_length, bpl = sizeof(unsigned long);
+	int j, linesize = p->fix.line_length, bpl = sizeof(unsigned long);
 	unsigned long start_index, end_index, start_mask, end_mask, last;
 	unsigned long *dst = NULL, *src = NULL;
 	char *src1, *dst1;
@@ -102,7 +102,7 @@
 			end_mask = -1 << ((bpl - end_index) << 3);
 			n -= end_index;
 		}
-		n = n / bpl;
+		n /= bpl;
 
 		if (n <= 0) {
 			if (start_mask) {
diff -Nru a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
--- a/drivers/video/cfbimgblt.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/video/cfbimgblt.c	Sat Jun  8 22:31:35 2002
@@ -107,12 +107,11 @@
 				dst++;
 			}
 		
-			if (n) {	
+			if (n) {
+				end_mask = 0;	
 				for (j = n; j > 0; j--) {
-					end_mask = 0;
-	
 					if (test_bit(l, src))
-						end_mask |= (tmp >> (p->var.bits_per_pixel*(k-1)));
+						end_mask |= (tmp >> (p->var.bits_per_pixel*(j-1)));
 					l--;
 					if (l < 0) { l = 7; src++; }
 				}
@@ -125,9 +124,6 @@
 	} else {
 		/* Draw the penguin */
 		n = ((image->width * p->var.bits_per_pixel) >> 3);
-		//shift = ((unsigned long) dst1 & (bpl -1));		
 		end_mask = 0;
-	
-	//	n = n/bpl;
 	}
 }
diff -Nru a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
--- a/drivers/video/clps711xfb.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/clps711xfb.c	Sat Jun  8 22:31:36 2002
@@ -203,6 +203,9 @@
 	fb_get_cmap:	gen_get_cmap,
 	fb_setcolreg:	clps7111fb_setcolreg,
 	fb_blank:	clps7111fb_blank,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 static int 
diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/cyber2000fb.c	Sat Jun  8 22:31:36 2002
@@ -1729,8 +1729,9 @@
 }
 
 static struct pci_device_id cyberpro_pci_table[] __devinitdata = {
-	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
+//	Not yet
+//	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
+//		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_IGA_1682 },
 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2000,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, ID_CYBERPRO_2000 },
 	{ PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_2010,
diff -Nru a/drivers/video/dn_accel.h b/drivers/video/dn_accel.h
--- a/drivers/video/dn_accel.h	Sat Jun  8 22:31:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,9 +0,0 @@
-#ifndef _DN_ACCEL_H_
-#define _DN_ACCEL_H_
-
-#include <linux/fb.h>
-
-void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
-	       int x_count, int y_count);
-
-#endif
diff -Nru a/drivers/video/dn_cfb4.c b/drivers/video/dn_cfb4.c
--- a/drivers/video/dn_cfb4.c	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,492 +0,0 @@
-#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/delay.h>
-#include <linux/interrupt.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/apollohw.h>
-#include <linux/fb.h>
-#include <linux/module.h>
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include "dn_accel.h"
-
-/* apollo video HW definitions */
-
-/*
- * Control Registers.   IOBASE + $x
- *
- * Note: these are the Memory/IO BASE definitions for a mono card set to the
- * alternate address
- *
- * Control 3A and 3B serve identical functions except that 3A
- * deals with control 1 and 3b deals with Color LUT reg.
- */
-
-#define AP_IOBASE       0x3d0          /* Base address of 1 plane board. */
-#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
-#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
-#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
-#define AP_ROP_1        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
-#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
-#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
-#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
-#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
-#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
-#define AP_LUT_RED     isaIO2mem(AP_IOBASE+9) /* Red Lookup Table register. Write */
-#define AP_LUT_GREEN  isaIO2mem(AP_IOBASE+0xb) /* Green Lookup Table register. Write */
-#define AP_LUT_BLUE   isaIO2mem(AP_IOBASE+0xd) /* Blue Lookup Table register. Write */
-#define AP_AD_CHANNEL   isaIO2mem(AP_IOBASE+0xf) /* A/D Result/Channel register. Read/Write */
-
-
-#define FRAME_BUFFER_START 0x0A0000
-#define FRAME_BUFFER_LEN 0x20000
-
-/* CREG 0 */
-#define VECTOR_MODE 0x40 /* 010x.xxxx */
-#define DBLT_MODE   0x80 /* 100x.xxxx */
-#define NORMAL_MODE 0xE0 /* 111x.xxxx */
-#define SHIFT_BITS  0x1F /* xxx1.1111 */
-        /* other bits are Shift value */
-
-/* CREG 1 */
-#define AD_BLT      0x80 /* 1xxx.xxxx */
-
-#define ROP_EN          0x10 /* xxx1.xxxx */
-#define DST_EQ_SRC      0x00 /* xxx0.xxxx */
-#define nRESET_SYNC     0x08 /* xxxx.1xxx */
-#define SYNC_ENAB       0x02 /* xxxx.xx1x */
-
-#define BLANK_DISP      0x00 /* xxxx.xxx0 */
-#define ENAB_DISP       0x01 /* xxxx.xxx1 */
-
-#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
-
-/* CREG 2B */
-
-/*
- * Following 3 defines are common to 1, 4 and 8 plane.
- */
-
-#define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
-#define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
-#define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
- one plane of image mem */
-
-/* CREG 3A/CREG 3B */
-#       define RESET_CREG 0x80 /* 1000.0000 */
-
-/* ROP REG  -  all one nibble */
-/*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
-#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
-#define DEST_ZERO               0x0
-#define SRC_AND_DEST    0x1
-#define SRC_AND_nDEST   0x2
-#define SRC                             0x3
-#define nSRC_AND_DEST   0x4
-#define DEST                    0x5
-#define SRC_XOR_DEST    0x6
-#define SRC_OR_DEST             0x7
-#define SRC_NOR_DEST    0x8
-#define SRC_XNOR_DEST   0x9
-#define nDEST                   0xA
-#define SRC_OR_nDEST    0xB
-#define nSRC                    0xC
-#define nSRC_OR_DEST    0xD
-#define SRC_NAND_DEST   0xE
-#define DEST_ONE                0xF
-
-#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
-
-
-/* frame buffer operations */
-
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
-			 struct fb_info *info);
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
-			 struct fb_info *info);
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info);
-static int dn_fb_blank(int blank,struct fb_info *info);
-
-static int dnfbcon_switch(int con,struct fb_info *info);
-static int dnfbcon_updatevar(int con,struct fb_info *info);
-
-static void dn_fb_set_disp(int con,struct fb_info *info);
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-static struct fb_ops dn_fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	dn_fb_get_fix,
-	fb_get_var:	dn_fb_get_var,
-	fb_set_var:	dn_fb_set_var,
-	fb_get_cmap:	dn_fb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_blank:	dn_fb_blank,
-};
-
-#define NUM_TOTAL_MODES 1
-struct fb_var_screeninfo dn_fb_predefined[] = {
-
-	{ 0, },
-
-};
-
-static char dn_fb_name[]="Apollo ";
-
-/* accel stuff */
-#define USE_DN_ACCEL
-
-static struct display_switch dispsw_apollofb;
-
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info) {
-
-	strcpy(fix->id,"Apollo Color4");
-	fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
-	fix->smem_len=FRAME_BUFFER_LEN;
-	fix->type=FB_TYPE_PACKED_PIXELS;
-	fix->type_aux=0;
-	fix->visual=FB_VISUAL_MONO10;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-        fix->line_length=128;
-
-	return 0;
-
-}
-        
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-		
-	var->xres=1024;
-	var->yres=800;
-	var->xres_virtual=1024;
-	var->yres_virtual=1024;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel=1;
-	var->grayscale=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->height=-1;
-	var->width=-1;
-	var->pixclock=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	var->sync=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-
-	return 0;
-
-}
-
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-
-        printk("fb_set_var\n");
-	if(var->xres!=1024) 
-		return -EINVAL;
-	if(var->yres!=800)
-		return -EINVAL;
-	if(var->xres_virtual!=1024)
-		return -EINVAL;
-	if(var->yres_virtual!=1024)
-		return -EINVAL;
-	if(var->xoffset!=0)
-		return -EINVAL;
-	if(var->yoffset!=0)
-		return -EINVAL;
-	if(var->bits_per_pixel!=1)
-		return -EINVAL;
-	if(var->grayscale!=0)
-		return -EINVAL;
-	if(var->nonstd!=0)
-		return -EINVAL;
-	if(var->activate!=0)
-		return -EINVAL;
-	if(var->pixclock!=0)
-		return -EINVAL;
-	if(var->left_margin!=0)
-		return -EINVAL;
-	if(var->right_margin!=0)
-		return -EINVAL;
-	if(var->hsync_len!=0)
-		return -EINVAL;
-	if(var->vsync_len!=0)
-		return -EINVAL;
-	if(var->sync!=0)
-		return -EINVAL;
-	if(var->vmode!=FB_VMODE_NONINTERLACED)
-		return -EINVAL;
-
-	return 0;
-
-}
-
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info) {
-
-	printk("get cmap not supported\n");
-
-	return -EINVAL;
-}
-
-static void dn_fb_set_disp(int con, struct fb_info *info) {
-
-  struct fb_fix_screeninfo fix;
-  struct display *display;
-
-
-  dn_fb_get_fix(&fix,con, info);
-
-  if (con>=0)
-	display=&fb_display[con];
-  else
-	display=&disp[0];
-
-  if(con==-1) 
-    con=0;
-
-   display->visual = fix.visual;
-   display->type = fix.type;
-   display->type_aux = fix.type_aux;
-   display->ypanstep = fix.ypanstep;
-   display->ywrapstep = fix.ywrapstep;
-   display->can_soft_blank = 1;
-   display->inverse = 0;
-   display->line_length = fix.line_length;
-   display->scrollmode = SCROLL_YREDRAW;
-#ifdef FBCON_HAS_MFB
-   display->dispsw = &fbcon_mfb;
-#else
-   display->dispsw=&fbcon_dummy;
-#endif
-
-}
-  
-unsigned long dnfb_init(unsigned long mem_start) {
-
-	int err;
-
-printk("dn_fb_init\n");
-
-	fb_info.changevar=NULL;
-	strcpy(&fb_info.modename[0],dn_fb_name);
-	fb_info.fontname[0]=0;
-	fb_info.disp=disp;
-	fb_info.switch_con=&dnfbcon_switch;
-	fb_info.updatevar=&dnfbcon_updatevar;
-	fb_info.node = NODEV;
-	fb_info.fbops = &dn_fb_ops;
-   	fb_info.screen_base = (u_char *)fix.smem_start;
-	printk("screenbase: %lx\n",fix.smem_start);
-	fb_info.currcon = -1;
-	fb_info.flags = FBINFO_FLAG_DEFAULT;	
-
-        dn_fb_get_var(&disp[0].var,0, &fb_info);
-	dn_fb_set_disp(-1, &fb_info);
-
-printk("dn_fb_init: register\n");
-	err=register_framebuffer(&fb_info);
-	if(err < 0) {
-		panic("unable to register apollo frame buffer\n");
-	}
- 
-	/* now we have registered we can safely setup the hardware */
-
-        outb(RESET_CREG,  AP_CONTROL_3A);
-        outb(NORMAL_MODE, AP_CONTROL_0); 
-        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
-        outb(S_DATA_PLN,  AP_CONTROL_2);
-        outw(SWAP(0x3), AP_ROP_1);
-
-        printk("apollo frame buffer alive and kicking !\n");
-
-
-	return mem_start;
-
-}	
-
-	
-static int dnfbcon_switch(int con,  struct fb_info *info) { 
-
-	info->currcon = con;
-	
-	return 0;
-
-}
-
-static int dnfbcon_updatevar(int con,  struct fb_info *info) {
-
-	return 0;
-
-}
-
-static int dn_fb_blank(int blank,  struct fb_info *info)
-{
-	if (blank)
-        	outb(0x0,  AP_CONTROL_3A);
-	else 
-	        outb(0x1,  AP_CONTROL_3A);
-	return 0;
-}
-
-void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
-               int x_count, int y_count) {
-
-	int incr,y_delta,pre_read=0,x_end,x_word_count;
-	ushort *src,dummy;
-	uint start_mask,end_mask,dest;
-	short i,j;
-
-	incr=(y_dest<=y_src) ? 1 : -1 ;
-
-	src=(ushort *)(p->fb_info.screen_base+ y_src*p->next_line+(x_src >> 4));
-	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
-	
-	if(incr>0) {
-		y_delta=(p->next_line*8)-x_src-x_count;
-		x_end=x_dest+x_count-1;
-		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
-		start_mask=0xffff0000 >> (x_dest & 0xf);
-		end_mask=0x7ffff >> (x_end & 0xf);
-		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) < (x_src & 0xf))
-			pre_read=1;
-	}
-	else {
-		y_delta=-((p->next_line*8)-x_src-x_count);
-		x_end=x_dest-x_count+1;
-		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
-		start_mask=0x7ffff >> (x_dest & 0xf);
-		end_mask=0xffff0000 >> (x_end & 0xf);
-		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) > (x_src & 0xf))
-			pre_read=1;
-	}
-
-	for(i=0;i<y_count;i++) {
-			
-		if(pre_read) {
-			dummy=*src;
-			src+=incr;
-		}
-
-		if(x_word_count) {
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			src+=incr;
-			dest+=incr;
-			outb(0,AP_WRITE_ENABLE);
-
-			for(j=1;j<(x_word_count-1);j++) {
-				*src=dest;
-				src+=incr;	
-				dest+=incr;
-			}
-
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
-		}
-		else {
-			outb(start_mask | end_mask, AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
-		}
-		src+=(y_delta/16);
-		dest+=(y_delta/16);
-	}
-	outb(NORMAL_MODE,AP_CONTROL_0);
-}
-
-static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
-		      int height, int width)
-{
-
-   int fontheight,fontwidth;
-
-    fontheight=fontheight(p);
-    fontwidth=fontwidth(p);
-
-#ifdef USE_DN_ACCEL
-    dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
-	      height*fontheight);
-#else
-    u_char *src, *dest;
-    u_int rows;
-
-    if (sx == 0 && dx == 0 && width == p->next_line) {
-	src = p->fb_info.screen_base+sy*fontheight*width;
-	dest = p->fb_info.screen_base+dy*fontheight*width;
-	mymemmove(dest, src, height*fontheight*width);
-    } else if (dy <= sy) {
-	src = p->fb_info.screen_base+sy*fontheight*p->next_line+sx;
-	dest = p->fb_info.screen_base+dy*fontheight*p->next_line+dx;
-	for (rows = height*fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src += p->next_line;
-	    dest += p->next_line;
-	}
-    } else {
-	src = p->fb_info.screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
-	dest = p->fb_info.screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
-	for (rows = height*fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src -= p->next_line;
-	    dest -= p->next_line;
-	}
-    }
-#endif
-}
-
-static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
-		      int height, int width)
-{
-	fbcon_mfb_clear(conp,p,sy,sx,height,width);
-}
-
-static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
-		     int xx)
-{
-	fbcon_mfb_putc(conp,p,c,yy,xx);
-}
-
-static void putcs_apollofb(struct vc_data *conp, struct display *p, const unsigned short *s,
-		      int count, int yy, int xx)
-{
-	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
-}
-
-static void rev_char_apollofb(struct display *p, int xx, int yy)
-{
-	fbcon_mfb_revc(p,xx,yy);
-}
-
-static struct display_switch dispsw_apollofb = {
-    setup:		fbcon_mfb_setup,
-    bmove:		bmove_apollofb,
-    clear:		clear_apollofb,
-    putc:		putc_apollofb,
-    putcs:		putcs_apollofb,
-    revc:		rev_char_apollofb,
-    fontwidthmask:	FONTWIDTH(8)
-};
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/dn_cfb8.c b/drivers/video/dn_cfb8.c
--- a/drivers/video/dn_cfb8.c	Sat Jun  8 22:31:35 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,540 +0,0 @@
-#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/delay.h>
-#include <linux/interrupt.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/amigahw.h>
-#include <asm/amigaints.h>
-#include <asm/apollohw.h>
-#include <linux/fb.h>
-#include <linux/module.h>
-#include "dn_accel.h"
-#include "fbcon.h"
-#include "fbcon-mfb.h"
-
-/* apollo video HW definitions */
-
-/*
- * Control Registers.   IOBASE + $x
- *
- * Note: these are the Memory/IO BASE definitions for a mono card set to the
- * alternate address
- *
- * Control 3A and 3B serve identical functions except that 3A
- * deals with control 1 and 3b deals with Color LUT reg.
- */
-
-#define AP_IOBASE       0x3d0          /* Base address of 1 plane board. */
-#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
-#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
-#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
-#define AP_ROP_0        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
-#define AP_ROP_1        isaIO2mem(AP_IOBASE+4) /* Raster Operation reg. Write Word */
-#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+6) /* Diagnostic Memory Request. Write Word */
-#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
-#define AP_LUT_DATA     isaIO2mem(AP_IOBASE+9) /* Control Register 0.  Read/Write */
-#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
-#define AP_LUT_CONTROL  isaIO2mem(AP_IOBASE+0xb) /* Control Register 1.  Read/Write */
-#define AP_CONTROL_2A   isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
-#define AP_CONTROL_2B   isaIO2mem(AP_IOBASE+0xd) /* Control Register 2. Read/Write */
-#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
-#define AP_CONTROL_3B   isaIO2mem(AP_IOBASE+0xf) /* Control Register 3a. Read/Write */
-
-
-#define FRAME_BUFFER_START 0x0A0000
-#define FRAME_BUFFER_LEN 0x20000
-
-/* CREG 0 */
-#define VECTOR_MODE 0x40 /* 010x.xxxx */
-#define DBLT_MODE   0x80 /* 100x.xxxx */
-#define NORMAL_MODE 0xE0 /* 111x.xxxx */
-#define SHIFT_BITS  0x1F /* xxx1.1111 */
-        /* other bits are Shift value */
-
-/* CREG 1 */
-#define AD_BLT      0x80 /* 1xxx.xxxx */
-
-#define ROP_EN          0x10 /* xxx1.xxxx */
-#define DST_EQ_SRC      0x00 /* xxx0.xxxx */
-#define nRESET_SYNC     0x08 /* xxxx.1xxx */
-#define SYNC_ENAB       0x02 /* xxxx.xx1x */
-
-#define BLANK_DISP      0x00 /* xxxx.xxx0 */
-#define ENAB_DISP       0x01 /* xxxx.xxx1 */
-
-#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
-
-/* CREG 2B */
-
-/*
- * Following 3 defines are common to 1, 4 and 8 plane.
- */
-
-#define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
-#define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
-#define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
- one plane of image mem */
-
-/* CREG 3A/CREG 3B */
-#       define RESET_CREG 0x80 /* 1000.0000 */
-
-/* ROP REG  -  all one nibble */
-/*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
-#define ROP(r2,r3,r0,r1) ( (U_SHORT)((r0)|((r1)<<4)|((r2)<<8)|((r3)<<12)) )
-#define DEST_ZERO               0x0
-#define SRC_AND_DEST    0x1
-#define SRC_AND_nDEST   0x2
-#define SRC                             0x3
-#define nSRC_AND_DEST   0x4
-#define DEST                    0x5
-#define SRC_XOR_DEST    0x6
-#define SRC_OR_DEST             0x7
-#define SRC_NOR_DEST    0x8
-#define SRC_XNOR_DEST   0x9
-#define nDEST                   0xA
-#define SRC_OR_nDEST    0xB
-#define nSRC                    0xC
-#define nSRC_OR_DEST    0xD
-#define SRC_NAND_DEST   0xE
-#define DEST_ONE                0xF
-
-#define SWAP(A) ((A>>8) | ((A&0xff) <<8))
-
-
-/* frame buffer operations */
-
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
-			 struct fb_info *info);
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
-			 struct fb_info *info);
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info);
-static int dn_fb_blank(int blank,struct fb_info *info);
-
-
-static int dnfbcon_switch(int con,struct fb_info *info);
-static int dnfbcon_updatevar(int con,struct fb_info *info);
-
-static void dn_fb_set_disp(int con,struct fb_info *info);
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
-static struct fb_ops dn_fb_ops = {
-	owner:		THIS_MODULE,
-	fb_get_fix:	dn_fb_get_fix,
-	fb_get_var:	dn_fb_get_var,
-	fb_set_var:	dn_fb_set_var,
-	fb_get_cmap:	dn_fb_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_blank:	dn_fb_blank,
-};
-
-#define NUM_TOTAL_MODES 1
-struct fb_var_screeninfo dn_fb_predefined[] = {
-
-	{ 0, },
-
-};
-
-static char dn_fb_name[]="Apollo ";
-
-/* accel stuff */
-#define USE_DN_ACCEL
-
-static struct display_switch dispsw_apollofb;
-
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info) {
-
-	strcpy(fix->id,"Apollo Color8");
-	fix->smem_start=(char*)(FRAME_BUFFER_START+IO_BASE);
-	fix->smem_len=FRAME_BUFFER_LEN;
-	fix->type=FB_TYPE_PACKED_PIXELS;
-	fix->type_aux=0;
-	fix->visual=FB_VISUAL_MONO10;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-        fix->line_length=128;
-
-	return 0;
-
-}
-        
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-		
-	var->xres=1024;
-	var->yres=800;
-	var->xres_virtual=1024;
-	var->yres_virtual=1024;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel=1;
-	var->grayscale=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->height=-1;
-	var->width=-1;
-	var->pixclock=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	var->sync=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-
-	return 0;
-
-}
-
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-
-        printk("fb_set_var\n");
-	if(var->xres!=1024) 
-		return -EINVAL;
-	if(var->yres!=800)
-		return -EINVAL;
-	if(var->xres_virtual!=1024)
-		return -EINVAL;
-	if(var->yres_virtual!=1024)
-		return -EINVAL;
-	if(var->xoffset!=0)
-		return -EINVAL;
-	if(var->yoffset!=0)
-		return -EINVAL;
-	if(var->bits_per_pixel!=1)
-		return -EINVAL;
-	if(var->grayscale!=0)
-		return -EINVAL;
-	if(var->nonstd!=0)
-		return -EINVAL;
-	if(var->activate!=0)
-		return -EINVAL;
-	if(var->pixclock!=0)
-		return -EINVAL;
-	if(var->left_margin!=0)
-		return -EINVAL;
-	if(var->right_margin!=0)
-		return -EINVAL;
-	if(var->hsync_len!=0)
-		return -EINVAL;
-	if(var->vsync_len!=0)
-		return -EINVAL;
-	if(var->sync!=0)
-		return -EINVAL;
-	if(var->vmode!=FB_VMODE_NONINTERLACED)
-		return -EINVAL;
-
-	return 0;
-
-}
-
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info) {
-
-	printk("get cmap not supported\n");
-
-	return -EINVAL;
-}
-
-static void dn_fb_set_disp(int con, struct fb_info *info) {
-
-  struct fb_fix_screeninfo fix;
-
-  dn_fb_get_fix(&fix,con, info);
-  if(con==-1) 
-    con=0;
-
-   disp[con].visual = fix.visual;
-   disp[con].type = fix.type;
-   disp[con].type_aux = fix.type_aux;
-   disp[con].ypanstep = fix.ypanstep;
-   disp[con].ywrapstep = fix.ywrapstep;
-   disp[con].can_soft_blank = 1;
-   disp[con].inverse = 0;
-   disp[con].line_length = fix.line_length;
-   disp[con].dispsw = &dispsw_apollofb;
-}
-  
-unsigned long dn_fb_init(unsigned long mem_start) {
-
-	int err;
-       
-	printk("dn_fb_init\n");
-
-	fb_info.changevar=NULL;
-	strcpy(&fb_info.modename[0],dn_fb_name);
-	fb_info.fontname[0]=0;
-	fb_info.disp=disp;
-	fb_info.switch_con=&dnfbcon_switch;
-	fb_info.updatevar=&dnfbcon_updatevar;
-	fb_info.node = NODEV;
-	fb_info.currcon = -1;
-	fb_info.fbops = &dn_fb_ops;
-	printk("screenbase: %p\n",fix.smem_start);
-	
-printk("dn_fb_init: register\n");
-	err=register_framebuffer(&fb_info);
-	if(err < 0) {
-		panic("unable to register apollo frame buffer\n");
-	}
- 
-	/* now we have registered we can safely setup the hardware */
-
-        outb(RESET_CREG,  AP_CONTROL_3A);
-        outb(RESET_CREG,  AP_CONTROL_3B);
-        outw(0x0,  AP_WRITE_ENABLE);
-        outb(NORMAL_MODE, AP_CONTROL_0); 
-        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
-        outb(0,  AP_CONTROL_2A);
-        outb(S_DATA_PLN,  AP_CONTROL_2B);
-        outw(SWAP(0x3), AP_ROP_1);
-
-        printk("apollo frame buffer alive and kicking !\n");
-
-        dn_fb_get_var(&disp[0].var,0, &fb_info);
-
-	dn_fb_set_disp(-1, &fb_info);
-   	fb_info.screen_base = (u_char *)fix.smem_start;
-	return mem_start;
-}	
-
-	
-static int dnfbcon_switch(int con,  struct fb_info *info) { 
-
-	info->currcon = con;
-	
-	return 0;
-
-}
-
-static int dnfbcon_updatevar(int con,  struct fb_info *info) {
-
-	return 0;
-
-}
-
-static int dn_fb_blank(int blank, struct fb_info *info)
-{
-	if (blank)
-        	outb(0x0,  AP_CONTROL_3A);
-	else
-	        outb(0x1,  AP_CONTROL_3A);
-	return 0;
-
-}
-
-void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
-               int x_count, int y_count) {
-
-	int incr,y_delta,pre_read=0,x_end,x_word_count;
-	ushort *src,dummy;
-	uint start_mask,end_mask,dest;
-	short i,j;
-
-	incr=(y_dest<=y_src) ? 1 : -1 ;
-
-	src=(ushort *)(p->fb_info.screen_base+ y_src*p->next_line+(x_src >> 4));
-	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
-	
-	if(incr>0) {
-		y_delta=(p->next_line*8)-x_src-x_count;
-		x_end=x_dest+x_count-1;
-		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
-		start_mask=0xffff0000 >> (x_dest & 0xf);
-		end_mask=0x7ffff >> (x_end & 0xf);
-		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) < (x_src & 0xf))
-			pre_read=1;
-	}
-	else {
-		y_delta=-((p->next_line*8)-x_src-x_count);
-		x_end=x_dest-x_count+1;
-		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
-		start_mask=0x7ffff >> (x_dest & 0xf);
-		end_mask=0xffff0000 >> (x_end & 0xf);
-		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) > (x_src & 0xf))
-			pre_read=1;
-	}
-
-	for(i=0;i<y_count;i++) {
-			
-		if(pre_read) {
-			dummy=*src;
-			src+=incr;
-		}
-
-		if(x_word_count) {
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			src+=incr;
-			dest+=incr;
-			outb(0,AP_WRITE_ENABLE);
-
-			for(j=1;j<(x_word_count-1);j++) {
-				*src=dest;
-				src+=incr;	
-				dest+=incr;
-			}
-
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
-		}
-		else {
-			outb(start_mask | end_mask, AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
-		}
-		src+=(y_delta/16);
-		dest+=(y_delta/16);
-	}
-	outb(NORMAL_MODE,AP_CONTROL_0);
-}
-
-static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
-		      int height, int width)
-{
-
-#ifdef USE_DN_ACCEL
-    dn_bitblt(p,sx,sy*p->fontheight,dx,dy*p->fontheight,width*p->fontwidth,
-	      height*p->fontheight);
-#else
-    u_char *src, *dest;
-    u_int rows;
-
-    if (sx == 0 && dx == 0 && width == p->next_line) {
-	src = p->fb_info.screen_base+sy*p->fontheight*width;
-	dest = p->fb_info.screen_base+dy*p->fontheight*width;
-	mymemmove(dest, src, height*p->fontheight*width);
-    } else if (dy <= sy) {
-	src = p->fb_info.screen_base+sy*p->fontheight*p->next_line+sx;
-	dest = p->fb_info.screen_base+dy*p->fontheight*p->next_line+dx;
-	for (rows = height*p->fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src += p->next_line;
-	    dest += p->next_line;
-	}
-    } else {
-	src = p->fb_info.screen_base+((sy+height)*p->fontheight-1)*p->next_line+sx;
-	dest = p->fb_info.screen_base+((dy+height)*p->fontheight-1)*p->next_line+dx;
-	for (rows = height*p->fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src -= p->next_line;
-	    dest -= p->next_line;
-	}
-    }
-#endif
-}
-
-static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
-		      int height, int width)
-{
-    u_char *dest;
-    u_int rows;
-
-    dest = p->fb_info.screen_base+sy*p->fontheight*p->next_line+sx;
-
-    if (sx == 0 && width == p->next_line)
-	if (attr_reverse(p,conp))
-	    mymemset(dest, height*p->fontheight*width);
-	else
-	    mymemclear(dest, height*p->fontheight*width);
-    else
-	for (rows = height*p->fontheight; rows--; dest += p->next_line)
-	    if (attr_reverse(p,conp))
-		mymemset(dest, width);
-	    else
-		mymemclear_small(dest, width);
-}
-
-static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
-		     int xx)
-{
-    u_char *dest, *cdat;
-    u_int rows, bold, revs, underl;
-    u_char d;
-
-    c &= 0xff;
-
-    dest = p->fb_info.screen_base+yy*p->fontheight*p->next_line+xx;
-    cdat = p->fontdata+c*p->fontheight;
-    bold = attr_bold(p,conp);
-    revs = attr_reverse(p,conp);
-    underl = attr_underline(p,conp);
-
-    for (rows = p->fontheight; rows--; dest += p->next_line) {
-	d = *cdat++;
-	if (underl && !rows)
-	    d = 0xff;
-	else if (bold)
-	    d |= d>>1;
-	if (revs)
-	    d = ~d;
-	*dest = d;
-    }
-}
-
-static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
-		      int count, int yy, int xx)
-{
-    u_char *dest, *dest0, *cdat;
-    u_int rows, bold, revs, underl;
-    u_char c, d;
-
-    dest0 = p->fb_info.screen_base+yy*p->fontheight*p->next_line+xx;
-    bold = attr_bold(p,conp);
-    revs = attr_reverse(p,conp);
-    underl = attr_underline(p,conp);
-
-    while (count--) {
-	c = scr_readw(s++);
-	dest = dest0++;
-	cdat = p->fontdata+c*p->fontheight;
-	for (rows = p->fontheight; rows--; dest += p->next_line) {
-	    d = *cdat++;
-	    if (underl && !rows)
-		d = 0xff;
-	    else if (bold)
-		d |= d>>1;
-	    if (revs)
-		d = ~d;
-	    *dest = d;
-	}
-    }
-}
-
-static void rev_char_apollofb(struct display *p, int xx, int yy)
-{
-    u_char *dest;
-    u_int rows;
-
-    dest = p->fb_info.screen_base+yy*p->fontheight*p->next_line+xx;
-    for (rows = p->fontheight; rows--; dest += p->next_line)
-	*dest = ~*dest;
-}
-
-static struct display_switch dispsw_apollofb = {
-    setup:		fbcon_mfb_setup,
-    bmove:		bmove_apollofb,
-    clear:		clear_apollofb,
-    putc:		putc_apollofb,
-    putcs:		putcs_apollofb,
-    revc:		rev_char_apollofb,
-    fontwidthmask:	FONTWIDTH(8)
-};
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/dnfb.c b/drivers/video/dnfb.c
--- a/drivers/video/dnfb.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/video/dnfb.c	Sat Jun  8 22:31:37 2002
@@ -14,9 +14,8 @@
 #include <asm/apollohw.h>
 #include <linux/fb.h>
 #include <linux/module.h>
-#include "dn_accel.h"
+
 #include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
 
 /* apollo video HW definitions */
 
@@ -30,45 +29,45 @@
  * deals with control 1 and 3b deals with Color LUT reg.
  */
 
-#define AP_IOBASE       0x3b0          /* Base address of 1 plane board. */
-#define AP_STATUS       isaIO2mem(AP_IOBASE+0) /* Status register.  Read */
-#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0) /* Write Enable Register Write */
-#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1) /* Device ID Register. Read */
-#define AP_ROP_1        isaIO2mem(AP_IOBASE+2) /* Raster Operation reg. Write Word */
-#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4) /* Diagnostic Memory Request. Write Word */
-#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8) /* Control Register 0.  Read/Write */
-#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa) /* Control Register 1.  Read/Write */
-#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe) /* Control Register 3a. Read/Write */
-#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc) /* Control Register 2. Read/Write */
+#define AP_IOBASE       0x3b0	/* Base address of 1 plane board. */
+#define AP_STATUS       isaIO2mem(AP_IOBASE+0)	/* Status register.  Read */
+#define AP_WRITE_ENABLE isaIO2mem(AP_IOBASE+0)	/* Write Enable Register Write */
+#define AP_DEVICE_ID    isaIO2mem(AP_IOBASE+1)	/* Device ID Register. Read */
+#define AP_ROP_1        isaIO2mem(AP_IOBASE+2)	/* Raster Operation reg. Write Word */
+#define AP_DIAG_MEM_REQ isaIO2mem(AP_IOBASE+4)	/* Diagnostic Memory Request. Write Word */
+#define AP_CONTROL_0    isaIO2mem(AP_IOBASE+8)	/* Control Register 0.  Read/Write */
+#define AP_CONTROL_1    isaIO2mem(AP_IOBASE+0xa)	/* Control Register 1.  Read/Write */
+#define AP_CONTROL_3A   isaIO2mem(AP_IOBASE+0xe)	/* Control Register 3a. Read/Write */
+#define AP_CONTROL_2    isaIO2mem(AP_IOBASE+0xc)	/* Control Register 2. Read/Write */
 
 
 #define FRAME_BUFFER_START 0x0FA0000
 #define FRAME_BUFFER_LEN 0x40000
 
 /* CREG 0 */
-#define VECTOR_MODE 0x40 /* 010x.xxxx */
-#define DBLT_MODE   0x80 /* 100x.xxxx */
-#define NORMAL_MODE 0xE0 /* 111x.xxxx */
-#define SHIFT_BITS  0x1F /* xxx1.1111 */
-        /* other bits are Shift value */
+#define VECTOR_MODE 0x40	/* 010x.xxxx */
+#define DBLT_MODE   0x80	/* 100x.xxxx */
+#define NORMAL_MODE 0xE0	/* 111x.xxxx */
+#define SHIFT_BITS  0x1F	/* xxx1.1111 */
+	/* other bits are Shift value */
 
 /* CREG 1 */
-#define AD_BLT      0x80 /* 1xxx.xxxx */
-#define NORMAL      0x80 /* 1xxx.xxxx */   /* What is happening here ?? */
-#define INVERSE     0x00 /* 0xxx.xxxx */   /* Clearing this reverses the screen */
-#define PIX_BLT     0x00 /* 0xxx.xxxx */
-
-#define AD_HIBIT        0x40 /* xIxx.xxxx */
-
-#define ROP_EN          0x10 /* xxx1.xxxx */
-#define DST_EQ_SRC      0x00 /* xxx0.xxxx */
-#define nRESET_SYNC     0x08 /* xxxx.1xxx */
-#define SYNC_ENAB       0x02 /* xxxx.xx1x */
+#define AD_BLT      0x80	/* 1xxx.xxxx */
+#define NORMAL      0x80 /* 1xxx.xxxx */	/* What is happening here ?? */
+#define INVERSE     0x00 /* 0xxx.xxxx */	/* Clearing this reverses the screen */
+#define PIX_BLT     0x00	/* 0xxx.xxxx */
+
+#define AD_HIBIT        0x40	/* xIxx.xxxx */
+
+#define ROP_EN          0x10	/* xxx1.xxxx */
+#define DST_EQ_SRC      0x00	/* xxx0.xxxx */
+#define nRESET_SYNC     0x08	/* xxxx.1xxx */
+#define SYNC_ENAB       0x02	/* xxxx.xx1x */
 
-#define BLANK_DISP      0x00 /* xxxx.xxx0 */
-#define ENAB_DISP       0x01 /* xxxx.xxx1 */
+#define BLANK_DISP      0x00	/* xxxx.xxx0 */
+#define ENAB_DISP       0x01	/* xxxx.xxx1 */
 
-#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP) /* no reset sync */
+#define NORM_CREG1      (nRESET_SYNC | SYNC_ENAB | ENAB_DISP)	/* no reset sync */
 
 /* CREG 2 */
 
@@ -76,13 +75,13 @@
  * Following 3 defines are common to 1, 4 and 8 plane.
  */
 
-#define S_DATA_1s   0x00 /* 00xx.xxxx */ /* set source to all 1's -- vector drawing */
-#define S_DATA_PIX  0x40 /* 01xx.xxxx */ /* takes source from ls-bits and replicates over 16 bits */
-#define S_DATA_PLN  0xC0 /* 11xx.xxxx */ /* normal, each data access =16-bits in
- one plane of image mem */
+#define S_DATA_1s   0x00 /* 00xx.xxxx */	/* set source to all 1's -- vector drawing */
+#define S_DATA_PIX  0x40 /* 01xx.xxxx */	/* takes source from ls-bits and replicates over 16 bits */
+#define S_DATA_PLN  0xC0 /* 11xx.xxxx */	/* normal, each data access =16-bits in
+						   one plane of image mem */
 
 /* CREG 3A/CREG 3B */
-#       define RESET_CREG 0x80 /* 1000.0000 */
+#       define RESET_CREG 0x80	/* 1000.0000 */
 
 /* ROP REG  -  all one nibble */
 /*      ********* NOTE : this is used r0,r1,r2,r3 *********** */
@@ -111,385 +110,169 @@
 #define outw(a,d) *(unsigned short *)a=d
 #endif
 
+static struct fb_info fb_info;
+static struct display disp;
 
 /* frame buffer operations */
 
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con, 
-			 struct fb_info *info);
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int isactive,
-			 struct fb_info *info);
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info);
-static int dn_fb_blank(int blank,struct fb_info *info);
-
-static int dnfbcon_switch(int con,struct fb_info *info);
-static int dnfbcon_updatevar(int con,struct fb_info *info);
+static int dn_fb_blank(int blank, struct fb_info *info);
+static void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area);
 
-static void dn_fb_set_disp(int con,struct fb_info *info);
-
-static struct display disp[MAX_NR_CONSOLES];
-static struct fb_info fb_info;
 static struct fb_ops dn_fb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	dn_fb_get_fix,
-	fb_get_var:	dn_fb_get_var,
-	fb_set_var:	dn_fb_set_var,
-	fb_get_cmap:	dn_fb_get_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
 	fb_set_cmap:	gen_set_cmap,
-	fb_blank:	dn_fb_blank,
+	fb_blank:	dnfb_blank,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	dnfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
-#define NUM_TOTAL_MODES 1
-struct fb_var_screeninfo dn_fb_predefined[] = {
-
-	{ 0, },
-
+struct fb_var_screeninfo dnfb_var __initdata = {
+	xres:		1280,
+	yres:		1024,
+	xres_virtual:	2048,
+	yres_virtual:	1024,
+	bits_per_pixel:	1,
+	height:		-1,
+	width:		-1,
+	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-static char dn_fb_name[]="Apollo ";
-
-/* accel stuff */
-#define USE_DN_ACCEL
-
-static struct display_switch dispsw_apollofb;
-
-static int dn_fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info) {
-
-	strcpy(fix->id,"Apollo Mono");
-	fix->smem_start=(FRAME_BUFFER_START+IO_BASE);
-	fix->smem_len=FRAME_BUFFER_LEN;
-	fix->type=FB_TYPE_PACKED_PIXELS;
-	fix->type_aux=0;
-	fix->visual=FB_VISUAL_MONO10;
-	fix->xpanstep=0;
-	fix->ypanstep=0;
-	fix->ywrapstep=0;
-        fix->line_length=256;
-
-	return 0;
-
-}
-        
-static int dn_fb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-		
-	var->xres=1280;
-	var->yres=1024;
-	var->xres_virtual=2048;
-	var->yres_virtual=1024;
-	var->xoffset=0;
-	var->yoffset=0;
-	var->bits_per_pixel=1;
-	var->grayscale=0;
-	var->nonstd=0;
-	var->activate=0;
-	var->height=-1;
-	var->width=-1;
-	var->pixclock=0;
-	var->left_margin=0;
-	var->right_margin=0;
-	var->hsync_len=0;
-	var->vsync_len=0;
-	var->sync=0;
-	var->vmode=FB_VMODE_NONINTERLACED;
-
-	return 0;
-
-}
-
-static int dn_fb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info) {
-
-        printk("fb_set_var\n");
-	if(var->xres!=1280) 
-		return -EINVAL;
-	if(var->yres!=1024)
-		return -EINVAL;
-	if(var->xres_virtual!=2048)
-		return -EINVAL;
-	if(var->yres_virtual!=1024)
-		return -EINVAL;
-	if(var->xoffset!=0)
-		return -EINVAL;
-	if(var->yoffset!=0)
-		return -EINVAL;
-	if(var->bits_per_pixel!=1)
-		return -EINVAL;
-	if(var->grayscale!=0)
-		return -EINVAL;
-	if(var->nonstd!=0)
-		return -EINVAL;
-	if(var->activate!=0)
-		return -EINVAL;
-	if(var->pixclock!=0)
-		return -EINVAL;
-	if(var->left_margin!=0)
-		return -EINVAL;
-	if(var->right_margin!=0)
-		return -EINVAL;
-	if(var->hsync_len!=0)
-		return -EINVAL;
-	if(var->vsync_len!=0)
-		return -EINVAL;
-	if(var->sync!=0)
-		return -EINVAL;
-	if(var->vmode!=FB_VMODE_NONINTERLACED)
-		return -EINVAL;
-
-	return 0;
-
-}
-
-static int dn_fb_get_cmap(struct fb_cmap *cmap,int kspc,int con,
-			  struct fb_info *info) {
-
-	printk("get cmap not supported\n");
-
-	return -EINVAL;
-}
-
-static void dn_fb_set_disp(int con, struct fb_info *info) {
-
-  struct fb_fix_screeninfo fix;
-  struct display *display;
-  
-  dn_fb_get_fix(&fix,con, info);
-
-  if (con>=0)
-	display=&fb_display[con];
-  else
-	display=&disp[0];
-
-  if(con==-1) 
-    con=0;
-
-   display->visual = fix.visual;
-   display->type = fix.type;
-   display->type_aux = fix.type_aux;
-   display->ypanstep = fix.ypanstep;
-   display->ywrapstep = fix.ywrapstep;
-   display->can_soft_blank = 1;
-   display->inverse = 0;
-   display->line_length = fix.line_length;
-#ifdef FBCON_HAS_MFB
-   display->dispsw = &fbcon_mfb;
-#else
-   display->dispsw=&fbcon_dummy;
-#endif
-
-}
-  
-unsigned long __init dnfb_init(unsigned long mem_start) {
-
-	int err;
-       
-
-	fb_info.changevar=NULL;
-	strcpy(&fb_info.modename[0],dn_fb_name);
-	fb_info.fontname[0]=0;
-	fb_info.disp=disp;
-	fb_info.switch_con=&dnfbcon_switch;
-	fb_info.updatevar=&dnfbcon_updatevar;
-	fb_info.node = NODEV;
-	fb_info.fbops = &dn_fb_ops;
-	fb_info.currcon = -1;
-	
-        dn_fb_get_var(&disp[0].var,0, &fb_info);
-
-	dn_fb_set_disp(-1, &fb_info);
-
-   	fb_info.screen_base = (u_char *)fix.smem_start;
-	
-	err=register_framebuffer(&fb_info);
-	if(err < 0) {
-		panic("unable to register apollo frame buffer\n");
-	}
- 
-	/* now we have registered we can safely setup the hardware */
-
-        outb(RESET_CREG,  AP_CONTROL_3A);
-        outw(0x0,  AP_WRITE_ENABLE);
-        outb(NORMAL_MODE, AP_CONTROL_0); 
-        outb((AD_BLT | DST_EQ_SRC | NORM_CREG1),  AP_CONTROL_1);
-        outb(S_DATA_PLN,  AP_CONTROL_2);
-        outw(SWAP(0x3), AP_ROP_1);
-
-        printk("apollo frame buffer alive and kicking !\n");
-
-
-	return mem_start;
-
-}	
-
-	
-static int dnfbcon_switch(int con,  struct fb_info *info) { 
-
-	info->currcon = con;
-	return 0;
-}
-
-static int dnfbcon_updatevar(int con,  struct fb_info *info) {
-
-	return 0;
-
-}
+static struct fb_fix_screeninfo dnfb_fix __initdata = {
+	id:		"Apollo Mono",
+	smem_start:	(FRAME_BUFFER_START + IO_BASE),
+	smem_len:	FRAME_BUFFER_LEN,
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_MONO10,
+	line_length:	256,
+};
 
-static int dn_fb_blank(int blank, struct fb_info *info)
+static int dnfb_blank(int blank, struct fb_info *info)
 {
 	if (blank)
-        	outb(0x0,  AP_CONTROL_3A);
+		outb(0x0, AP_CONTROL_3A);
 	else
-	        outb(0x1,  AP_CONTROL_3A);
+		outb(0x1, AP_CONTROL_3A);
 	return 0;
 }
 
-void dn_bitblt(struct display *p,int x_src,int y_src, int x_dest, int y_dest,
-               int x_count, int y_count) {
+static 
+void dnfb_copyarea(struct fb_info *info, struct fb_copyarea *area)
+{
 
-	int incr,y_delta,pre_read=0,x_end,x_word_count;
-	ushort *src,dummy;
-	uint start_mask,end_mask,dest;
-	short i,j;
-
-	incr=(y_dest<=y_src) ? 1 : -1 ;
-
-	src=(ushort *)(p->fb_info.screen_base+ y_src*p->next_line+(x_src >> 4));
-	dest=y_dest*(p->next_line >> 1)+(x_dest >> 4);
-	
-	if(incr>0) {
-		y_delta=(p->next_line*8)-x_src-x_count;
-		x_end=x_dest+x_count-1;
-		x_word_count=(x_end>>4) - (x_dest >> 4) + 1;
-		start_mask=0xffff0000 >> (x_dest & 0xf);
-		end_mask=0x7ffff >> (x_end & 0xf);
-		outb((((x_dest & 0xf) - (x_src &0xf))  % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) < (x_src & 0xf))
-			pre_read=1;
-	}
-	else {
-		y_delta=-((p->next_line*8)-x_src-x_count);
-		x_end=x_dest-x_count+1;
-		x_word_count=(x_dest>>4) - (x_end >> 4) + 1;
-		start_mask=0x7ffff >> (x_dest & 0xf);
-		end_mask=0xffff0000 >> (x_end & 0xf);
-		outb(((-((x_src & 0xf) - (x_dest &0xf))) % 16)|(0x4 << 5),AP_CONTROL_0);
-		if((x_dest & 0xf) > (x_src & 0xf))
-			pre_read=1;
+	int incr, y_delta, pre_read = 0, x_end, x_word_count;
+	int x_count, y_count;
+	ushort *src, dummy;
+	uint start_mask, end_mask, dest;
+	short i, j;
+
+	incr = (area->dy <= area->sy) ? 1 : -1;
+
+	src =
+	    (ushort *) (info->screen_base + area->sy * info->fix.next_line +
+			(area->sx >> 4));
+	dest = area->dy * (info->fix.next_line >> 1) + (area->dx >> 4);
+
+	if (incr > 0) {
+		y_delta = (info->fix.next_line * 8) - area->sx - x_count;
+		x_end = area->dx + x_count - 1;
+		x_word_count = (x_end >> 4) - (area->dx >> 4) + 1;
+		start_mask = 0xffff0000 >> (area->dx & 0xf);
+		end_mask = 0x7ffff >> (x_end & 0xf);
+		outb((((area->dx & 0xf) - (area->sx & 0xf)) % 16) | (0x4 << 5),
+		     AP_CONTROL_0);
+		if ((area->dx & 0xf) < (area->sx & 0xf))
+			pre_read = 1;
+	} else {
+		y_delta = -((info->fix.next_line * 8) - area->sx - x_count);
+		x_end = area->dx - x_count + 1;
+		x_word_count = (area->dx >> 4) - (x_end >> 4) + 1;
+		start_mask = 0x7ffff >> (area->dx & 0xf);
+		end_mask = 0xffff0000 >> (x_end & 0xf);
+		outb(((-((area->sx & 0xf) - (area->dx & 0xf))) %
+		      16) | (0x4 << 5), AP_CONTROL_0);
+		if ((area->dx & 0xf) > (area->sx & 0xf))
+			pre_read = 1;
 	}
 
-	for(i=0;i<y_count;i++) {
+	for (i = 0; i < y_count; i++) {
 
 		outb(0xc | (dest >> 16), AP_CONTROL_3A);
-			
-		if(pre_read) {
-			dummy=*src;
-			src+=incr;
+
+		if (pre_read) {
+			dummy = *src;
+			src += incr;
 		}
 
-		if(x_word_count) {
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			src+=incr;
-			dest+=incr;
-			outb(0,AP_WRITE_ENABLE);
-
-			for(j=1;j<(x_word_count-1);j++) {
-				*src=dest;
-				src+=incr;	
-				dest+=incr;
+		if (x_word_count) {
+			outb(start_mask, AP_WRITE_ENABLE);
+			*src = dest;
+			src += incr;
+			dest += incr;
+			outb(0, AP_WRITE_ENABLE);
+
+			for (j = 1; j < (x_word_count - 1); j++) {
+				*src = dest;
+				src += incr;
+				dest += incr;
 			}
 
-			outb(start_mask,AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
-		}
-		else {
+			outb(start_mask, AP_WRITE_ENABLE);
+			*src = dest;
+			dest += incr;
+			src += incr;
+		} else {
 			outb(start_mask | end_mask, AP_WRITE_ENABLE);
-			*src=dest;
-			dest+=incr;
-			src+=incr;
+			*src = dest;
+			dest += incr;
+			src += incr;
 		}
-		src+=(y_delta/16);
-		dest+=(y_delta/16);
+		src += (y_delta / 16);
+		dest += (y_delta / 16);
 	}
-	outb(NORMAL_MODE,AP_CONTROL_0);
+	outb(NORMAL_MODE, AP_CONTROL_0);
 }
 
-static void bmove_apollofb(struct display *p, int sy, int sx, int dy, int dx,
-		      int height, int width)
-{
 
-    int fontheight,fontwidth;
+unsigned long __init dnfb_init(unsigned long mem_start)
+{
+	int err;
 
-    fontheight=fontheight(p);
-    fontwidth=fontwidth(p);
+	strcpy(&fb_info.modename, dnfb_fix);
+	fb_info.changevar = NULL;
+	fb_info.fontname[0] = 0;
+	fb_info.disp = &disp;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
+	fb_info.node = NODEV;
+	fb_info.fbops = &dn_fb_ops;
+	fb_info.currcon = -1;
+	fb_info.fix = dnfb_fix;
+	fb_info.var = dnfb_var;
 
-#ifdef USE_DN_ACCEL
-    dn_bitblt(p,sx,sy*fontheight,dx,dy*fontheight,width*fontwidth,
-	      height*fontheight);
-#else
-    u_char *src, *dest;
-    u_int rows;
-
-    if (sx == 0 && dx == 0 && width == p->next_line) {
-	src = p->fb_info.screen_base+sy*fontheight*width;
-	dest = p->fb_info.screen_base+dy*fontheight*width;
-	mymemmove(dest, src, height*fontheight*width);
-    } else if (dy <= sy) {
-	src = p->fb_info.screen_base+sy*fontheight*next_line+sx;
-	dest = p->fb_info.screen_base+dy*fontheight*next_line+dx;
-	for (rows = height*fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src += p->next_line;
-	    dest += p->next_line;
-	}
-    } else {
-	src = p->fb_info.screen_base+((sy+height)*fontheight-1)*p->next_line+sx;
-	dest = p->fb_info.screen_base+((dy+height)*fontheight-1)*p->next_line+dx;
-	for (rows = height*fontheight; rows--;) {
-	    mymemmove(dest, src, width);
-	    src -= p->next_line;
-	    dest -= p->next_line;
-	}
-    }
-#endif
-}
+	fb_alloc_cmap(&fb_info.cmap, 2, 0);
+	gen_set_disp(-1, &fb_info);
 
-static void clear_apollofb(struct vc_data *conp, struct display *p, int sy, int sx,
-		      int height, int width)
-{
-	fbcon_mfb_clear(conp,p,sy,sx,height,width);
-}
+	fb_info.screen_base = (u_char *) fb_info.fix.smem_start;
 
-static void putc_apollofb(struct vc_data *conp, struct display *p, int c, int yy,
-		     int xx)
-{
-	fbcon_mfb_putc(conp,p,c,yy,xx);
-}
+	err = register_framebuffer(&fb_info);
+	if (err < 0)
+		panic("unable to register apollo frame buffer\n");
 
-static void putcs_apollofb(struct vc_data *conp, struct display *p, const char *s,
-		      int count, int yy, int xx)
-{
-	fbcon_mfb_putcs(conp,p,s,count,yy,xx);
-}
+	/* now we have registered we can safely setup the hardware */
+	outb(RESET_CREG, AP_CONTROL_3A);
+	outw(0x0, AP_WRITE_ENABLE);
+	outb(NORMAL_MODE, AP_CONTROL_0);
+	outb((AD_BLT | DST_EQ_SRC | NORM_CREG1), AP_CONTROL_1);
+	outb(S_DATA_PLN, AP_CONTROL_2);
+	outw(SWAP(0x3), AP_ROP_1);
 
-static void rev_char_apollofb(struct display *p, int xx, int yy)
-{
-	fbcon_mfb_revc(p,xx,yy);
+	printk("apollo frame buffer alive and kicking !\n");
+	return mem_start;
 }
-
-static struct display_switch dispsw_apollofb = {
-    setup:		fbcon_mfb_setup,
-    bmove:		bmove_apollofb,
-    clear:		clear_apollofb,
-    putc:		putc_apollofb,
-    putcs:		putcs_apollofb,
-    revc:		rev_char_apollofb,
-    fontwidthmask:	FONTWIDTH(8)
-};
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
--- a/drivers/video/fbcmap.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/video/fbcmap.c	Sat Jun  8 22:31:37 2002
@@ -150,7 +150,7 @@
     else
 	tooff = from->start-to->start;
     size = to->len-tooff;
-    if (size > from->len-fromoff)
+    if (size > (int) (from->len - fromoff))
 	size = from->len-fromoff;
     if (size <= 0)
 	return;
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/video/fbmem.c	Sat Jun  8 22:31:35 2002
@@ -132,6 +132,7 @@
 extern int pmagbbfb_init(void);
 extern void maxinefb_init(void);
 extern int tx3912fb_init(void);
+extern int tx3912fb_setup(char*);
 extern int radeonfb_init(void);
 extern int radeonfb_setup(char*);
 extern int e1355fb_init(void);
@@ -300,7 +301,7 @@
 	{ "hitfb", hitfb_init, NULL },
 #endif
 #ifdef CONFIG_FB_TX3912
-	{ "tx3912", tx3912fb_init, NULL },
+	{ "tx3912", tx3912fb_init, tx3912fb_setup },
 #endif
 #ifdef CONFIG_FB_E1355
 	{ "e1355fb", e1355fb_init, e1355fb_setup },
diff -Nru a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c
--- a/drivers/video/matrox/matroxfb_crtc2.c	Sat Jun  8 22:31:37 2002
+++ b/drivers/video/matrox/matroxfb_crtc2.c	Sat Jun  8 22:31:37 2002
@@ -383,7 +383,7 @@
 		chgvar = 0;
 	p->var = *var;
 	/* cmap */
-	ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(m2info->video.vbase);
+	m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase);
 	p->visual = visual;
 	p->ypanstep = 1;
 	p->ywrapstep = 0;
diff -Nru a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
--- a/drivers/video/maxinefb.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/maxinefb.c	Sat Jun  8 22:31:36 2002
@@ -23,7 +23,6 @@
  *
  */
 
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -42,48 +41,32 @@
 /* whether are really running on a maxine, KM                       */
 #include <asm/bootinfo.h>
 
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
-
-static struct display disp;
 static struct fb_info fb_info;
-
-unsigned long fb_start, fb_size = 1024 * 768, fb_line_length = 1024;
-unsigned long fb_regs;
-unsigned char fb_bitmask;
+static struct display disp;
 
 static struct fb_var_screeninfo maxinefb_defined = {
-	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
-	0, 0,			/* virtual -> visible no offset */
-	0,			/* depth -> load bits_per_pixel */
-	0,			/* greyscale ? */
-	{0, 0, 0},		/* R */
-	{0, 0, 0},		/* G */
-	{0, 0, 0},		/* B */
-	{0, 0, 0},		/* transparency */
-	0,			/* standard pixel format */
-	FB_ACTIVATE_NOW,
-	274, 195,		/* 14" monitor */
-	FB_ACCEL_NONE,
-	0L, 0L, 0L, 0L, 0L,
-	0L, 0L, 0,		/* No sync info */
-	FB_VMODE_NONINTERLACED,
-	{0, 0, 0, 0, 0, 0}
-};
-
-struct maxinefb_par {
+	xres:		1024,
+	yres:		768,
+	xres_virtual:	1024,
+	yres_virtual:	768,
+	bits_per_pixel:	8,
+	activate:	FB_ACTIVATE_NOW,
+	height:		-1,
+	width:		-1,
+	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-struct maxinefb_par current_par;
+static struct fb_fix_screeninfo maxinefb_fix = {
+	id:		"Maxine onboard graphics 1024x768x8",
+	smem_len:	(1024*768),
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	line_length:	1024,
+}
 
 /* Reference to machine type set in arch/mips/dec/prom/identify.c, KM */
 extern unsigned long mips_machtype;
 
-
 /* Handle the funny Inmos RamDAC/video controller ... */
 
 void maxinefb_ims332_write_register(int regno, register unsigned int val)
@@ -109,212 +92,41 @@
 	return (j & 0xffff) | ((k & 0xff00) << 8);
 }
 
-
-static void maxinefb_encode_var(struct fb_var_screeninfo *var,
-				struct maxinefb_par *par)
-{
-	int i = 0;
-	var->xres = 1024;
-	var->yres = 768;
-	var->xres_virtual = 1024;
-	var->yres_virtual = 768;
-	var->xoffset = 0;
-	var->yoffset = 0;
-	var->bits_per_pixel = 8;
-	var->grayscale = 0;
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	var->transp.msb_right = 0;
-	var->nonstd = 0;
-	var->activate = 1;
-	var->height = -1;
-	var->width = -1;
-	var->vmode = FB_VMODE_NONINTERLACED;
-	var->pixclock = 0;
-	var->sync = 0;
-	var->left_margin = 0;
-	var->right_margin = 0;
-	var->upper_margin = 0;
-	var->lower_margin = 0;
-	var->hsync_len = 0;
-	var->vsync_len = 0;
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-}
-
-static void maxinefb_get_par(struct maxinefb_par *par)
-{
-	*par = current_par;
-}
-
-static int maxinefb_fb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
-
-static int maxinefb_do_fb_set_var(struct fb_var_screeninfo *var,
-				  int isactive)
-{
-	struct maxinefb_par par;
-
-	maxinefb_get_par(&par);
-	maxinefb_encode_var(var, &par);
-	return 0;
-}
-
-
-/* Get the palette */
-
-static int maxinefb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
-{
-	unsigned int i;
-	unsigned long hw_colorvalue = 0;	/* raw color value from the register */
-	unsigned int length;
-
-	if (((cmap->start) + (cmap->len)) >= 256) {
-		length = 256 - (cmap->start);
-	} else {
-		length = cmap->len;
-	}
-	for (i = 0; i < length; i++) {
-		hw_colorvalue =
-		    maxinefb_ims332_read_register(IMS332_REG_COLOR_PALETTE
-						  + cmap->start + i);
-		(cmap->red[i]) = ((hw_colorvalue & 0x0000ff));
-		(cmap->green[i]) = ((hw_colorvalue & 0x00ff00) >> 8);
-		(cmap->blue[i]) = ((hw_colorvalue & 0xff0000) >> 16);
-
-	}
-	return 0;
-}
-
-
 /* Set the palette */
-
-static int maxinefb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
+static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			      unsigned blue, unsigned transp, struct fb_info *info)
 {
-	unsigned int i;
-	unsigned long hw_colorvalue;	/* value to be written into the palette reg. */
-	unsigned short cmap_red;
-	unsigned short cmap_green;
-	unsigned short cmap_blue;
-	unsigned int length;
-
-	hw_colorvalue = 0;
-	if (((cmap->start) + (cmap->len)) >= 256) {
-		length = 256 - (cmap->start);
-	} else {
-		length = cmap->len;
-	}
+	/* value to be written into the palette reg. */
+	unsigned long hw_colorvalue = 0;
 
-	for (i = 0; i < length; i++) {
-		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
-		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
-		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
-
-		hw_colorvalue =
-		    (cmap_blue << 16) + (cmap_green << 8) + (cmap_red);
-		maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE +
-					       cmap->start + i,
-					       hw_colorvalue);
-	}
+	red   >>= 8;	/* The cmap fields are 16 bits    */
+	green >>= 8;	/* wide, but the harware colormap */
+	blue  >>= 8;	/* registers are only 8 bits wide */
+
+	hw_colorvalue = (blue << 16) + (green << 8) + (red);
+	
+	maxinefb_ims332_write_register(IMS332_REG_COLOR_PALETTE + regno,
+				       hw_colorvalue);
 	return 0;
 }
 
-static int maxinefb_get_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	struct maxinefb_par par;
-	if (con == -1) {
-		maxinefb_get_par(&par);
-		maxinefb_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
-	return 0;
-}
-
-
-static int maxinefb_set_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	int err;
-
-	if ((err = maxinefb_do_fb_set_var(var, 1)))
-		return err;
-	return 0;
-}
-static void maxinefb_encode_fix(struct fb_fix_screeninfo *fix,
-				struct maxinefb_par *par)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "maxinefb");
-	/* fix->id is a char[16], so a maximum of 15 characters, KM */
-
-	fix->smem_start = (char *) fb_start;	/* display memory base address, KM */
-	fix->smem_len = fb_size;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = fb_line_length;
-}
-
-static int maxinefb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			    struct fb_info *info)
-{
-	struct maxinefb_par par;
-	maxinefb_get_par(&par);
-	maxinefb_encode_fix(fix, &par);
-	return 0;
-}
-
-static int maxinefb_switch(int con, struct fb_info *info)
-{
-	maxinefb_do_fb_set_var(&fb_display[con].var, 1);
-	info->currcon = con;
-	return 0;
-}
-
-static void maxinefb_set_disp(int con)
-{
-	struct fb_fix_screeninfo fix;
-	struct display *display;
-
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	maxinefb_get_fix(&fix, con, 0);
-
-	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->next_line = fix.line_length;
-	display->can_soft_blank = 0;
-	display->inverse = 0;
-
-	display->dispsw = &fbcon_cfb8;
-}
-
 static struct fb_ops maxinefb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	maxinefb_get_fix,
-	fb_get_var:	maxinefb_get_var,
-	fb_set_var:	maxinefb_set_var,
-	fb_get_cmap:	maxinefb_get_cmap,
-	fb_set_cmap:	maxinefb_set_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_setcolreg:	maxinefb_setcolreg,	
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,		
 };
 
 int __init maxinefb_init(void)
 {
 	volatile unsigned char *fboff;
+	unsigned long fb_start;
 	int i;
 
 	/* Validate we're on the proper machine type */
@@ -332,6 +144,8 @@
 	for (fboff = fb_start; fboff < fb_start + 0x1ffff; fboff++)
 		*fboff = 0x0;
 
+	maxinefb_fix.smem_start = fb_start;
+	
 	/* erase hardware cursor */
 	for (i = 0; i < 512; i++) {
 		maxinefb_ims332_write_register(IMS332_REG_CURSOR_RAM + i,
@@ -344,34 +158,26 @@
 		 */
 	}
 
-	/* Fill in the available video resolution */
-	maxinefb_defined.xres = 1024;
-	maxinefb_defined.yres = 768;
-	maxinefb_defined.xres_virtual = 1024;
-	maxinefb_defined.yres_virtual = 768;
-	maxinefb_defined.bits_per_pixel = 8;
-
 	/* Let there be consoles... */
 
 	strcpy(fb_info.modename, "Maxine onboard graphics 1024x768x8");
-	/* fb_info.modename: maximum of 39 characters + trailing nullbyte, KM */
 	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
 	fb_info.fbops = &maxinefb_ops;
-	fb_info.screen_base = (char *) fb_start;
+	fb_info.screen_base = (char *) maxinefb_fix.smem_start;
+	fb_info.var = maxinefb_defined;
+	fb_info.fix = maxinefb_fix;
 	fb_info.disp = &disp;
 	fb_info.currcon = -1;
-	fb_info.switch_con = &maxinefb_switch;
-	fb_info.updatevar = &maxinefb_fb_update_var;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	maxinefb_do_fb_set_var(&maxinefb_defined, 1);
 
-	maxinefb_get_var(&disp.var, -1, &fb_info);
-	maxinefb_set_disp(-1);
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+	gen_set_disp(-1, &fb_info);
 
 	if (register_framebuffer(&fb_info) < 0)
 		return 1;
-
 	return 0;
 }
 
diff -Nru a/drivers/video/neofb.c b/drivers/video/neofb.c
--- a/drivers/video/neofb.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/video/neofb.c	Sat Jun  8 22:31:35 2002
@@ -11,7 +11,9 @@
  * Public License.  See the file COPYING in the main directory of this
  * archive for more details.
  *
- *
+ * 0.3.3
+ *  - Porting over to new fbdev api. (jsimmons)
+ *  
  * 0.3.2
  *  - got rid of all floating point (dok) 
  *
@@ -66,22 +68,18 @@
 #endif
 
 #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 "neofb.h"
+#include <video/neomagic.h>
 
+#define NEOFB_VERSION "0.3.3"
 
-#define NEOFB_VERSION "0.3.2"
+struct neofb_par default_par;
 
 /* --------------------------------------------------------------------- */
 
-static int disabled   = 0;
-static int internal   = 0;
-static int external   = 0;
-static int nostretch  = 0;
+static int disabled = 0;
+static int internal = 0;
+static int external = 0;
+static int nostretch = 0;
 static int nopciburst = 0;
 
 
@@ -97,7 +95,8 @@
 MODULE_PARM(external, "i");
 MODULE_PARM_DESC(external, "Enable output on external CRT.");
 MODULE_PARM(nostretch, "i");
-MODULE_PARM_DESC(nostretch, "Disable stretching of modes smaller than LCD.");
+MODULE_PARM_DESC(nostretch,
+		 "Disable stretching of modes smaller than LCD.");
 MODULE_PARM(nopciburst, "i");
 MODULE_PARM_DESC(nopciburst, "Disable PCI burst mode.");
 
@@ -106,1579 +105,1301 @@
 
 /* --------------------------------------------------------------------- */
 
-static biosMode bios8[] = {	
-    { 320, 240, 0x40 },
-    { 300, 400, 0x42 },    
-    { 640, 400, 0x20 },
-    { 640, 480, 0x21 },
-    { 800, 600, 0x23 },
-    { 1024, 768, 0x25 },
+static biosMode bios8[] = {
+	{320, 240, 0x40},
+	{300, 400, 0x42},
+	{640, 400, 0x20},
+	{640, 480, 0x21},
+	{800, 600, 0x23},
+	{1024, 768, 0x25},
 };
 
 static biosMode bios16[] = {
-    { 320, 200, 0x2e },
-    { 320, 240, 0x41 },
-    { 300, 400, 0x43 },
-    { 640, 480, 0x31 },
-    { 800, 600, 0x34 },
-    { 1024, 768, 0x37 },
+	{320, 200, 0x2e},
+	{320, 240, 0x41},
+	{300, 400, 0x43},
+	{640, 480, 0x31},
+	{800, 600, 0x34},
+	{1024, 768, 0x37},
 };
 
 static biosMode bios24[] = {
-    { 640, 480, 0x32 },
-    { 800, 600, 0x35 },
-    { 1024, 768, 0x38 }
+	{640, 480, 0x32},
+	{800, 600, 0x35},
+	{1024, 768, 0x38}
 };
 
 #ifdef NO_32BIT_SUPPORT_YET
 /* FIXME: guessed values, wrong */
 static biosMode bios32[] = {
-    { 640, 480, 0x33 },
-    { 800, 600, 0x36 },
-    { 1024, 768, 0x39 }
-    };
+	{640, 480, 0x33},
+	{800, 600, 0x36},
+	{1024, 768, 0x39}
+};
 #endif
 
-static int neoFindMode (int xres, int yres, int depth)
+static int neoFindMode(int xres, int yres, int depth)
 {
-  int xres_s;
-  int i, size;
-  biosMode *mode;
-
-  switch (depth)
-    {
-    case 8:
-      size = sizeof(bios8) / sizeof(biosMode);
-      mode = bios8;
-      break;
-    case 16:
-      size = sizeof(bios16) / sizeof(biosMode);
-      mode = bios16;
-      break;
-    case 24:
-      size = sizeof(bios24) / sizeof(biosMode);
-      mode = bios24;
-      break;
+	int xres_s;
+	int i, size;
+	biosMode *mode;
+
+	switch (depth) {
+	case 8:
+		size = sizeof(bios8) / sizeof(biosMode);
+		mode = bios8;
+		break;
+	case 16:
+		size = sizeof(bios16) / sizeof(biosMode);
+		mode = bios16;
+		break;
+	case 24:
+		size = sizeof(bios24) / sizeof(biosMode);
+		mode = bios24;
+		break;
 #ifdef NO_32BIT_SUPPORT_YET
-    case 32:
-      size = sizeof(bios32) / sizeof(biosMode);
-      mode = bios32;
-      break;
+	case 32:
+		size = sizeof(bios32) / sizeof(biosMode);
+		mode = bios32;
+		break;
 #endif
-    default:
-      return 0;
-    }
-
-  for (i = 0; i < size; i++)
-    {
-      if (xres <= mode[i].x_res)
-	{
-	  xres_s = mode[i].x_res;
-	  for (; i < size; i++)
-	    {
-	      if (mode[i].x_res != xres_s)
-		return mode[i-1].mode;
-	      if (yres <= mode[i].y_res)
-		return mode[i].mode;
-	    }
+	default:
+		return 0;
 	}
-    }
-  return mode[size - 1].mode;
-}
 
-/* -------------------- Hardware specific routines ------------------------- */
+	for (i = 0; i < size; i++) {
+		if (xres <= mode[i].x_res) {
+			xres_s = mode[i].x_res;
+			for (; i < size; i++) {
+				if (mode[i].x_res != xres_s)
+					return mode[i - 1].mode;
+				if (yres <= mode[i].y_res)
+					return mode[i].mode;
+			}
+		}
+	}
+	return mode[size - 1].mode;
+}
 
 /*
- * Hardware Acceleration for Neo2200+
+ * neoCalcVCLK --
+ *
+ * Determine the closest clock frequency to the one requested.
  */
-static inline void neo2200_wait_idle (struct neofb_info *fb)
+#define REF_FREQ 0xe517		/* 14.31818 in 20.12 fixed point */
+#define MAX_N 127
+#define MAX_D 31
+#define MAX_F 1
+
+static void neoCalcVCLK(const struct fb_info *info,
+			struct neofb_par *par, long freq)
 {
-  int waitcycles;
+	int n, d, f;
+	int n_best = 0, d_best = 0, f_best = 0;
+	long f_best_diff = (0x7ffff << 12);	/* 20.12 */
+	long f_target = (freq << 12) / 1000;	/* 20.12 */
+
+	for (f = 0; f <= MAX_F; f++)
+		for (n = 0; n <= MAX_N; n++)
+			for (d = 0; d <= MAX_D; d++) {
+				long f_out;	/* 20.12 */
+				long f_diff;	/* 20.12 */
+
+				f_out =
+				    ((((n + 1) << 12) / ((d +
+							  1) *
+							 (1 << f))) >> 12)
+				    * REF_FREQ;
+				f_diff = abs(f_out - f_target);
+				if (f_diff < f_best_diff) {
+					f_best_diff = f_diff;
+					n_best = n;
+					d_best = d;
+					f_best = f;
+				}
+			}
+
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		/* NOT_DONE:  We are trying the full range of the 2200 clock.
+		   We should be able to try n up to 2047 */
+		par->VCLK3NumeratorLow = n_best;
+		par->VCLK3NumeratorHigh = (f_best << 7);
+	} else
+		par->VCLK3NumeratorLow = n_best | (f_best << 7);
 
-  while (fb->neo2200->bltStat & 1)
-    waitcycles++;
-}
+	par->VCLK3Denominator = d_best;
 
-static inline void neo2200_wait_fifo (struct neofb_info *fb,
-                                      int requested_fifo_space)
-{
-  //  ndev->neo.waitfifo_calls++;
-  //  ndev->neo.waitfifo_sum += requested_fifo_space;
+#ifdef NEOFB_DEBUG
+	printk("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
+	       f_target >> 12,
+	       par->VCLK3NumeratorLow,
+	       par->VCLK3NumeratorHigh,
+	       par->VCLK3Denominator, f_best_diff >> 12);
+#endif
+}
 
-  /* FIXME: does not work
-  if (neo_fifo_space < requested_fifo_space)
-    {
-      neo_fifo_waitcycles++;
+/*
+ * vgaHWInit --
+ *      Handle the initialization, etc. of a screen.
+ *      Return FALSE on failure.
+ */
 
-      while (1)
-        {
-          neo_fifo_space = (neo2200->bltStat >> 8);
-          if (neo_fifo_space >= requested_fifo_space)
-            break;
-        }
-    }
-  else
-    {
-      neo_fifo_cache_hits++;
-    }
+static int vgaHWInit(const struct fb_var_screeninfo *var,
+		     const struct fb_info *info,
+		     struct neofb_par *par, struct xtimings *timings)
+{
+	par->MiscOutReg = 0x23;
+
+	if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
+		par->MiscOutReg |= 0x40;
+
+	if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
+		par->MiscOutReg |= 0x80;
+
+	/*
+	 * Time Sequencer
+	 */
+	par->Sequencer[0] = 0x00;
+	par->Sequencer[1] = 0x01;
+	par->Sequencer[2] = 0x0F;
+	par->Sequencer[3] = 0x00;	/* Font select */
+	par->Sequencer[4] = 0x0E;	/* Misc */
+
+	/*
+	 * CRTC Controller
+	 */
+	par->CRTC[0] = (timings->HTotal >> 3) - 5;
+	par->CRTC[1] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[2] = (timings->HDisplay >> 3) - 1;
+	par->CRTC[3] = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
+	par->CRTC[4] = (timings->HSyncStart >> 3);
+	par->CRTC[5] = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
+	    | (((timings->HSyncEnd >> 3)) & 0x1F);
+	par->CRTC[6] = (timings->VTotal - 2) & 0xFF;
+	par->CRTC[7] = (((timings->VTotal - 2) & 0x100) >> 8)
+	    | (((timings->VDisplay - 1) & 0x100) >> 7)
+	    | ((timings->VSyncStart & 0x100) >> 6)
+	    | (((timings->VDisplay - 1) & 0x100) >> 5)
+	    | 0x10 | (((timings->VTotal - 2) & 0x200) >> 4)
+	    | (((timings->VDisplay - 1) & 0x200) >> 3)
+	    | ((timings->VSyncStart & 0x200) >> 2);
+	par->CRTC[8] = 0x00;
+	par->CRTC[9] = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
+
+	if (timings->dblscan)
+		par->CRTC[9] |= 0x80;
+
+	par->CRTC[10] = 0x00;
+	par->CRTC[11] = 0x00;
+	par->CRTC[12] = 0x00;
+	par->CRTC[13] = 0x00;
+	par->CRTC[14] = 0x00;
+	par->CRTC[15] = 0x00;
+	par->CRTC[16] = timings->VSyncStart & 0xFF;
+	par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
+	par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
+	par->CRTC[19] = var->xres_virtual >> 4;
+	par->CRTC[20] = 0x00;
+	par->CRTC[21] = (timings->VDisplay - 1) & 0xFF;
+	par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
+	par->CRTC[23] = 0xC3;
+	par->CRTC[24] = 0xFF;
+
+	/*
+	 * are these unnecessary?
+	 * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+	 * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
+	 */
+
+	/*
+	 * Graphics Display Controller
+	 */
+	par->Graphics[0] = 0x00;
+	par->Graphics[1] = 0x00;
+	par->Graphics[2] = 0x00;
+	par->Graphics[3] = 0x00;
+	par->Graphics[4] = 0x00;
+	par->Graphics[5] = 0x40;
+	par->Graphics[6] = 0x05;	/* only map 64k VGA memory !!!! */
+	par->Graphics[7] = 0x0F;
+	par->Graphics[8] = 0xFF;
+
+
+	par->Attribute[0] = 0x00;	/* standard colormap translation */
+	par->Attribute[1] = 0x01;
+	par->Attribute[2] = 0x02;
+	par->Attribute[3] = 0x03;
+	par->Attribute[4] = 0x04;
+	par->Attribute[5] = 0x05;
+	par->Attribute[6] = 0x06;
+	par->Attribute[7] = 0x07;
+	par->Attribute[8] = 0x08;
+	par->Attribute[9] = 0x09;
+	par->Attribute[10] = 0x0A;
+	par->Attribute[11] = 0x0B;
+	par->Attribute[12] = 0x0C;
+	par->Attribute[13] = 0x0D;
+	par->Attribute[14] = 0x0E;
+	par->Attribute[15] = 0x0F;
+	par->Attribute[16] = 0x41;
+	par->Attribute[17] = 0xFF;
+	par->Attribute[18] = 0x0F;
+	par->Attribute[19] = 0x00;
+	par->Attribute[20] = 0x00;
+
+	return 0;
+}
+
+static void vgaHWLock(void)
+{
+	/* Protect CRTC[0-7] */
+	VGAwCR(0x11, VGArCR(0x11) | 0x80);
+}
+
+static void vgaHWUnlock(void)
+{
+	/* Unprotect CRTC[0-7] */
+	VGAwCR(0x11, VGArCR(0x11) & ~0x80);
+}
+
+static void neoLock(void)
+{
+	VGAwGR(0x09, 0x00);
+	vgaHWLock();
+}
 
-  neo_fifo_space -= requested_fifo_space;
-  */
+static void neoUnlock(void)
+{
+	vgaHWUnlock();
+	VGAwGR(0x09, 0x26);
+}
 
-  neo2200_wait_idle (fb);
+/*
+ * vgaHWSeqReset
+ *      perform a sequencer reset.
+ */
+void vgaHWSeqReset(int start)
+{
+	if (start)
+		VGAwSEQ(0x00, 0x01);	/* Synchronous Reset */
+	else
+		VGAwSEQ(0x00, 0x03);	/* End Reset */
 }
 
-static inline void neo2200_accel_init (struct neofb_info        *fb,
-				       struct fb_var_screeninfo *var)
+void vgaHWProtect(int on)
 {
-  Neo2200 *neo2200 = fb->neo2200;
-  u32 bltMod, pitch;
+	unsigned char tmp;
 
-  neo2200_wait_idle (fb);
+	if (on) {
+		/*
+		 * Turn off screen and disable sequencer.
+		 */
+		tmp = VGArSEQ(0x01);
 
-  switch (var->bits_per_pixel)
-    {
-    case 8:
-      bltMod = NEO_MODE1_DEPTH8;
-      pitch  = var->xres_virtual;
-      break;
-    case 15:
-    case 16:
-      bltMod = NEO_MODE1_DEPTH16;
-      pitch  = var->xres_virtual * 2;
-      break;
-    default:
-      printk( KERN_ERR "neofb: neo2200_accel_init: unexpected bits per pixel!\n" );
-      return;
-    }
+		vgaHWSeqReset(1);	/* start synchronous reset */
+		VGAwSEQ(0x01, tmp | 0x20);	/* disable the display */
 
-  neo2200->bltStat = bltMod << 16;
-  neo2200->pitch   = (pitch << 16) | pitch;
-}
+		VGAenablePalette();
+	} else {
+		/*
+		 * Reenable sequencer, then turn on screen.
+		 */
 
-static void neo2200_accel_setup (struct display *p)
-{
-  struct neofb_info        *fb  = (struct neofb_info *)p->fb_info;
-  struct fb_var_screeninfo *var = &p->fb_info->var;
+		tmp = VGArSEQ(0x01);
 
-  fb->dispsw->setup(p);
+		VGAwSEQ(0x01, tmp & ~0x20);	/* reenable display */
+		vgaHWSeqReset(0);	/* clear synchronousreset */
 
-  neo2200_accel_init (fb, var);
+		VGAdisablePalette();
+	}
 }
 
-static void
-neo2200_accel_bmove (struct display *p, int sy, int sx, int dy, int dx,
-		     int height, int width)
+static void vgaHWRestore(const struct fb_info *info,
+			 const struct neofb_par *par)
 {
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
-  struct fb_var_screeninfo *var = &p->fb_info->var;
-  Neo2200 *neo2200 = fb->neo2200;
-  u_long src, dst;
-  int bpp, pitch, inc_y;
-  u_int fh, fw;
-
-  /* setting blitting direction does not work, so this case is unaccelerated */
-  if (sx != dx)
-    {
-      neo2200_wait_idle (fb);
-      fb->dispsw->bmove(p, sy, sx, dy, dx, height, width);
-      return;
-    }
-
-  bpp    = (var->bits_per_pixel+7) / 8;
-  pitch  = var->xres_virtual * bpp;
-
-  fw     = fontwidth(p);
-  sx    *= fw * bpp;
-  dx    *= fw * bpp;
-  width *= fw;
-
-  fh     = fontheight(p);
-  sy    *= fh;
-  dy    *= fh;
-
-  if (sy > dy)
-    inc_y = fh;
-  else
-    {
-      inc_y  = -fh;
-      sy    += (height - 1) * fh;
-      dy    += (height - 1) * fh;
-    }
-
-  neo2200_wait_fifo (fb, 1);
-
-  /* set blt control */
-  neo2200->bltCntl = NEO_BC3_FIFO_EN      |
-                     NEO_BC3_SKIP_MAPPING |  0x0c0000;
-
-  /* looks silly, but setting the blitting direction did not work */
-  while (height--)
-    {
-      src = sx + sy * pitch;
-      dst = dx + dy * pitch;
-
-      neo2200_wait_fifo (fb, 3);
-
-      neo2200->srcStart = src;
-      neo2200->dstStart = dst;
-      neo2200->xyExt = (fh << 16) | (width & 0xffff);
-
-      sy += inc_y;
-      dy += inc_y;
-    }
-}
+	int i;
 
-static void
-neo2200_accel_clear (struct vc_data *conp, struct display *p, int sy, int sx,
-		     int height, int width)
-{
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
-  struct fb_var_screeninfo *var = &p->fb_info->var;
-  Neo2200 *neo2200 = fb->neo2200;
-  u_long dst;
-  u_int fw, fh;
-  u32 bgx = attr_bgcol_ec(p, conp);
-
-  fw = fontwidth(p);
-  fh = fontheight(p);
-
-  dst    = sx * fw + sy * var->xres_virtual * fh;
-  width  = width * fw;
-  height = height * fh;
-
-  neo2200_wait_fifo (fb, 4);
-
-  /* set blt control */
-  neo2200->bltCntl  = NEO_BC3_FIFO_EN      |
-                      NEO_BC0_SRC_IS_FG    |
-                      NEO_BC3_SKIP_MAPPING |  0x0c0000;
-
-  switch (var->bits_per_pixel)
-    {
-    case 8:
-      neo2200->fgColor = bgx;
-      break;
-    case 16:
-      neo2200->fgColor = ((u16 *)(p->fb_info)->pseudo_palette)[bgx];
-      break;
-    }
+	VGAwMISC(par->MiscOutReg);
 
-  neo2200->dstStart = dst * ((var->bits_per_pixel+7) / 8);
+	for (i = 1; i < 5; i++)
+		VGAwSEQ(i, par->Sequencer[i]);
 
-  neo2200->xyExt    = (height << 16) | (width & 0xffff);
-}
+	/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
+	VGAwCR(17, par->CRTC[17] & ~0x80);
 
-static void
-neo2200_accel_putc (struct vc_data *conp, struct display *p, int c,
-		    int yy, int xx)
-{
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	for (i = 0; i < 25; i++)
+		VGAwCR(i, par->CRTC[i]);
 
-  neo2200_wait_idle (fb);
-  fb->dispsw->putc(conp, p, c, yy, xx);
-}
+	for (i = 0; i < 9; i++)
+		VGAwGR(i, par->Graphics[i]);
 
-static void
-neo2200_accel_putcs (struct vc_data *conp, struct display *p,
-		     const unsigned short *s, int count, int yy, int xx)
-{
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	VGAenablePalette();
 
-  neo2200_wait_idle (fb);
-  fb->dispsw->putcs(conp, p, s, count, yy, xx);
-}
+	for (i = 0; i < 21; i++)
+		VGAwATTR(i, par->Attribute[i]);
 
-static void neo2200_accel_revc (struct display *p, int xx, int yy)
-{
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
-	
-  neo2200_wait_idle (fb);
-  fb->dispsw->revc (p, xx, yy);
+	VGAdisablePalette();
 }
 
-static void
-neo2200_accel_clear_margins (struct vc_data *conp, struct display *p,
-			     int bottom_only)
+
+/* -------------------- Hardware specific routines ------------------------- */
+
+/*
+ * Hardware Acceleration for Neo2200+
+ */
+static inline void neo2200_wait_idle(struct neofb_par *par)
 {
-  struct neofb_info *fb = (struct neofb_info *)p->fb_info;
+	int waitcycles;
 
-  fb->dispsw->clear_margins (conp, p, bottom_only);
+	while (par->neo2200->bltStat & 1)
+		waitcycles++;
 }
 
-static struct display_switch fbcon_neo2200_accel = {
-  setup:		neo2200_accel_setup,
-  bmove:		neo2200_accel_bmove,
-  clear:		neo2200_accel_clear,
-  putc:			neo2200_accel_putc,
-  putcs:		neo2200_accel_putcs,
-  revc:			neo2200_accel_revc,
-  clear_margins:	neo2200_accel_clear_margins,
-  fontwidthmask:	FONTWIDTH(8)|FONTWIDTH(16)
-};
+static inline void neo2200_wait_fifo(struct neofb_par *par,
+				     int requested_fifo_space)
+{
+	//  ndev->neo.waitfifo_calls++;
+	//  ndev->neo.waitfifo_sum += requested_fifo_space;
+
+	/* FIXME: does not work
+	   if (neo_fifo_space < requested_fifo_space)
+	   {
+	   neo_fifo_waitcycles++;
+
+	   while (1)
+	   {
+	   neo_fifo_space = (neo2200->bltStat >> 8);
+	   if (neo_fifo_space >= requested_fifo_space)
+	   break;
+	   }
+	   }
+	   else
+	   {
+	   neo_fifo_cache_hits++;
+	   }
+
+	   neo_fifo_space -= requested_fifo_space;
+	 */
+
+	neo2200_wait_idle(par);
+}
+
+static inline void neo2200_accel_init(struct fb_info *fb,
+				      struct fb_var_screeninfo *var)
+{
+	struct neofb_par *par = (struct neofb_par *) fb->par;
+	Neo2200 *neo2200 = par->neo2200;
+	u32 bltMod, pitch;
+
+	neo2200_wait_idle(par);
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		bltMod = NEO_MODE1_DEPTH8;
+		pitch = var->xres_virtual;
+		break;
+	case 15:
+	case 16:
+		bltMod = NEO_MODE1_DEPTH16;
+		pitch = var->xres_virtual * 2;
+		break;
+	default:
+		printk(KERN_ERR
+		       "neofb: neo2200_accel_init: unexpected bits per pixel!\n");
+		return;
+	}
 
+	neo2200->bltStat = bltMod << 16;
+	neo2200->pitch = (pitch << 16) | pitch;
+}
 
 /* --------------------------------------------------------------------- */
 
-/*
- *    Set a single color register. Return != 0 for invalid regno.
- */
-static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			   u_int transp, struct fb_info *fb)
+static int
+neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-  struct neofb_info *info = (struct neofb_info *)fb;
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	unsigned int pixclock = var->pixclock;
+	struct xtimings timings;
+	int memlen, vramlen;
+	int mode_ok = 0;
+
+	DBG("neofb_check_var");
+
+	if (!pixclock)
+		pixclock = 10000;	/* 10ns = 100MHz */
+	timings.pixclock = 1000000000 / pixclock;
+	if (timings.pixclock < 1)
+		timings.pixclock = 1;
+
+	if (timings.pixclock > par->maxClock)
+		return -EINVAL;
+
+	timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = var->xres;
+	timings.HSyncStart = timings.HDisplay + var->right_margin;
+	timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
+	timings.HTotal = timings.HSyncEnd + var->left_margin;
+	timings.VDisplay = var->yres;
+	timings.VSyncStart = timings.VDisplay + var->lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
+	timings.VTotal = timings.VSyncEnd + var->upper_margin;
+	timings.sync = var->sync;
+
+	/* Is the mode larger than the LCD panel? */
+	if ((var->xres > par->NeoPanelWidth) ||
+	    (var->yres > par->NeoPanelHeight)) {
+		printk(KERN_INFO
+		       "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
+		       var->xres, var->yres, par->NeoPanelWidth,
+		       par->NeoPanelHeight);
+		return -EINVAL;
+	}
 
-  if (regno >= NR_PALETTE)
-    return -EINVAL;
+	/* Is the mode one of the acceptable sizes? */
+	switch (var->xres) {
+	case 1280:
+		if (var->yres == 1024)
+			mode_ok = 1;
+		break;
+	case 1024:
+		if (var->yres == 768)
+			mode_ok = 1;
+		break;
+	case 800:
+		if (var->yres == 600)
+			mode_ok = 1;
+		break;
+	case 640:
+		if (var->yres == 480)
+			mode_ok = 1;
+		break;
+	}
 
-  info->palette[regno].red    = red;
-  info->palette[regno].green  = green;
-  info->palette[regno].blue   = blue;
-  info->palette[regno].transp = transp;
-
-  switch (fb->var.bits_per_pixel)
-    {
-#ifdef FBCON_HAS_CFB8
-    case 8:
-      outb(regno, 0x3c8);
-
-      outb(red   >> 10, 0x3c9);
-      outb(green >> 10, 0x3c9);
-      outb(blue  >> 10, 0x3c9);
-      break;
-#endif
+	if (!mode_ok) {
+		printk(KERN_INFO
+		       "Mode (%dx%d) won't display properly on LCD\n",
+		       var->xres, var->yres);
+		return -EINVAL;
+	}
 
-#ifdef FBCON_HAS_CFB16
-    case 16:
-      if (regno < 16)
-	((u16 *)fb->pseudo_palette)[regno] = ((red   & 0xf800)      ) |
-	                                     ((green & 0xfc00) >>  5) |
-                                             ((blue  & 0xf800) >> 11);
-      break;
-#endif
+	var->red.msb_right = 0;
+	var->green.msb_right = 0;
+	var->blue.msb_right = 0;
+
+	switch (var->bits_per_pixel) {
+	case 8:		/* PSEUDOCOLOUR, 256 */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 0;
+		var->red.length = 8;
+		var->green.offset = 0;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
+
+	case 16:		/* DIRECTCOLOUR, 64k */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 11;
+		var->red.length = 5;
+		var->green.offset = 5;
+		var->green.length = 6;
+		var->blue.offset = 0;
+		var->blue.length = 5;
+		break;
+
+	case 24:		/* TRUECOLOUR, 16m */
+		var->transp.offset = 0;
+		var->transp.length = 0;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		break;
 
-#ifdef FBCON_HAS_CFB24
-    case 24:
-      if (regno < 16)
-	((u32 *)fb->pseudo_palette)[regno] = ((red   & 0xff00) << 8) |
-                                             ((green & 0xff00)     ) |
-	                                     ((blue  & 0xff00) >> 8);
-      break;
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:		/* TRUECOLOUR, 16m */
+		var->transp.offset = 24;
+		var->transp.length = 8;
+		var->red.offset = 16;
+		var->red.length = 8;
+		var->green.offset = 8;
+		var->green.length = 8;
+		var->blue.offset = 0;
+		var->blue.length = 8;
+		break;
 #endif
+	default:
+		printk(KERN_WARNING "neofb: no support for %dbpp\n",
+		       var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	vramlen = info->fix.smem_len;
+	if (vramlen > 4 * 1024 * 1024)
+		vramlen = 4 * 1024 * 1024;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+
+	memlen =
+	    var->xres_virtual * var->bits_per_pixel * var->yres_virtual /
+	    8;
+	if (memlen > vramlen) {
+		var->yres_virtual =
+		    vramlen * 8 / (var->xres_virtual *
+				   var->bits_per_pixel);
+		memlen =
+		    var->xres_virtual * var->bits_per_pixel *
+		    var->yres_virtual / 8;
+	}
 
+	/* we must round yres/xres down, we already rounded y/xres_virtual up
+	   if it was possible. We should return -EINVAL, but I disagree */
+	if (var->yres_virtual < var->yres)
+		var->yres = var->yres_virtual;
+	if (var->xres_virtual < var->xres)
+		var->xres = var->xres_virtual;
+	if (var->xoffset + var->xres > var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres;
+	if (var->yoffset + var->yres > var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres;
+
+	if (var->bits_per_pixel >= 24 || !par->neo2200)
+		var->accel_flags &= ~FB_ACCELF_TEXT;
+	return 0;
+}
+
+static int neofb_set_par(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	struct xtimings timings;
+	unsigned char temp;
+	int i, clock_hi = 0;
+	int lcd_stretch;
+	int hoffset, voffset;
+
+	DBG("neofb_set_par");
+
+	neoUnlock();
+
+	vgaHWProtect(1);	/* Blank the screen */
+
+	timings.dblscan = info->var.vmode & FB_VMODE_DOUBLE;
+	timings.interlaced = info->var.vmode & FB_VMODE_INTERLACED;
+	timings.HDisplay = info->var.xres;
+	timings.HSyncStart = timings.HDisplay + info->var.right_margin;
+	timings.HSyncEnd = timings.HSyncStart + info->var.hsync_len;
+	timings.HTotal = timings.HSyncEnd + info->var.left_margin;
+	timings.VDisplay = info->var.yres;
+	timings.VSyncStart = timings.VDisplay + info->var.lower_margin;
+	timings.VSyncEnd = timings.VSyncStart + info->var.vsync_len;
+	timings.VTotal = timings.VSyncEnd + info->var.upper_margin;
+	timings.sync = info->var.sync;
+	timings.pixclock = PICOS2KHZ(info->var.pixclock);
+
+	if (timings.pixclock < 1)
+		timings.pixclock = 1;
+
+	/*
+	 * This will allocate the datastructure and initialize all of the
+	 * generic VGA registers.
+	 */
+
+	if (vgaHWInit(&info->var, info, par, &timings))
+		return -EINVAL;
+
+	/*
+	 * The default value assigned by vgaHW.c is 0x41, but this does
+	 * not work for NeoMagic.
+	 */
+	par->Attribute[16] = 0x01;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		par->CRTC[0x13] = info->var.xres_virtual >> 3;
+		par->ExtCRTOffset = info->var.xres_virtual >> 11;
+		par->ExtColorModeSelect = 0x11;
+		break;
+	case 16:
+		par->CRTC[0x13] = info->var.xres_virtual >> 2;
+		par->ExtCRTOffset = info->var.xres_virtual >> 10;
+		par->ExtColorModeSelect = 0x13;
+		break;
+	case 24:
+		par->CRTC[0x13] = (info->var.xres_virtual * 3) >> 3;
+		par->ExtCRTOffset = (info->var.xres_virtual * 3) >> 11;
+		par->ExtColorModeSelect = 0x14;
+		break;
 #ifdef NO_32BIT_SUPPORT_YET
-#ifdef FBCON_HAS_CFB32
-    case 32:
-      if (regno < 16)
-	((u32 *)fb->pseudo_palette)[regno] = ((transp & 0xff00) << 16) |
-	                                     ((red    & 0xff00) <<  8) |
-                                             ((green  & 0xff00)      ) |
-	                                     ((blue   & 0xff00) >>  8);
-      break;
-#endif
+	case 32:		/* FIXME: guessed values */
+		par->CRTC[0x13] = info->var.xres_virtual >> 1;
+		par->ExtCRTOffset = info->var.xres_virtual >> 9;
+		par->ExtColorModeSelect = 0x15;
+		break;
 #endif
+	default:
+		break;
+	}
 
-    default:
-      return 1;
-    }
-
-  return 0;
-}
+	par->ExtCRTDispAddr = 0x10;
 
-static void vgaHWLock (void)
-{
-  /* Protect CRTC[0-7] */
-  VGAwCR (0x11, VGArCR (0x11) | 0x80);
-}
+	/* Vertical Extension */
+	par->VerticalExt = (((timings.VTotal - 2) & 0x400) >> 10)
+	    | (((timings.VDisplay - 1) & 0x400) >> 9)
+	    | (((timings.VSyncStart) & 0x400) >> 8)
+	    | (((timings.VSyncStart) & 0x400) >> 7);
+
+	/* Fast write bursts on unless disabled. */
+	if (par->pci_burst)
+		par->SysIfaceCntl1 = 0x30;
+	else
+		par->SysIfaceCntl1 = 0x00;
+
+	par->SysIfaceCntl2 = 0xc0;	/* VESA Bios sets this to 0x80! */
+
+	/* Enable any user specified display devices. */
+	par->PanelDispCntlReg1 = 0x00;
+	if (par->internal_display)
+		par->PanelDispCntlReg1 |= 0x02;
+	if (par->external_display)
+		par->PanelDispCntlReg1 |= 0x01;
+
+	/* If the user did not specify any display devices, then... */
+	if (par->PanelDispCntlReg1 == 0x00) {
+		/* Default to internal (i.e., LCD) only. */
+		par->PanelDispCntlReg1 |= 0x02;
+	}
 
-static void vgaHWUnlock (void)
-{
-  /* Unprotect CRTC[0-7] */
-  VGAwCR (0x11, VGArCR (0x11) & ~0x80);
-}
+	/* If we are using a fixed mode, then tell the chip we are. */
+	switch (info->var.xres) {
+	case 1280:
+		par->PanelDispCntlReg1 |= 0x60;
+		break;
+	case 1024:
+		par->PanelDispCntlReg1 |= 0x40;
+		break;
+	case 800:
+		par->PanelDispCntlReg1 |= 0x20;
+		break;
+	case 640:
+	default:
+		break;
+	}
 
-static void neoLock (void)
-{
-  VGAwGR (0x09, 0x00);
-  vgaHWLock();
-}
+	/* Setup shadow register locking. */
+	switch (par->PanelDispCntlReg1 & 0x03) {
+	case 0x01:		/* External CRT only mode: */
+		par->GeneralLockReg = 0x00;
+		/* We need to program the VCLK for external display only mode. */
+		par->ProgramVCLK = 1;
+		break;
+	case 0x02:		/* Internal LCD only mode: */
+	case 0x03:		/* Simultaneous internal/external (LCD/CRT) mode: */
+		par->GeneralLockReg = 0x01;
+		/* Don't program the VCLK when using the LCD. */
+		par->ProgramVCLK = 0;
+		break;
+	}
 
-static void neoUnlock (void)
-{
-  vgaHWUnlock();
-  VGAwGR (0x09, 0x26);
-}
+	/*
+	 * If the screen is to be stretched, turn on stretching for the
+	 * various modes.
+	 *
+	 * OPTION_LCD_STRETCH means stretching should be turned off!
+	 */
+	par->PanelDispCntlReg2 = 0x00;
+	par->PanelDispCntlReg3 = 0x00;
+
+	if (par->lcd_stretch && (par->PanelDispCntlReg1 == 0x02) &&	/* LCD only */
+	    (info->var.xres != par->NeoPanelWidth)) {
+		switch (info->var.xres) {
+		case 320:	/* Needs testing.  KEM -- 24 May 98 */
+		case 400:	/* Needs testing.  KEM -- 24 May 98 */
+		case 640:
+		case 800:
+		case 1024:
+			lcd_stretch = 1;
+			par->PanelDispCntlReg2 |= 0xC6;
+			break;
+		default:
+			lcd_stretch = 0;
+			/* No stretching in these modes. */
+		}
+	} else
+		lcd_stretch = 0;
+
+	/*
+	 * If the screen is to be centerd, turn on the centering for the
+	 * various modes.
+	 */
+	par->PanelVertCenterReg1 = 0x00;
+	par->PanelVertCenterReg2 = 0x00;
+	par->PanelVertCenterReg3 = 0x00;
+	par->PanelVertCenterReg4 = 0x00;
+	par->PanelVertCenterReg5 = 0x00;
+	par->PanelHorizCenterReg1 = 0x00;
+	par->PanelHorizCenterReg2 = 0x00;
+	par->PanelHorizCenterReg3 = 0x00;
+	par->PanelHorizCenterReg4 = 0x00;
+	par->PanelHorizCenterReg5 = 0x00;
+
+
+	if (par->PanelDispCntlReg1 & 0x02) {
+		if (info->var.xres == par->NeoPanelWidth) {
+			/*
+			 * No centering required when the requested display width
+			 * equals the panel width.
+			 */
+		} else {
+			par->PanelDispCntlReg2 |= 0x01;
+			par->PanelDispCntlReg3 |= 0x10;
+
+			/* Calculate the horizontal and vertical offsets. */
+			if (!lcd_stretch) {
+				hoffset =
+				    ((par->NeoPanelWidth -
+				      info->var.xres) >> 4) - 1;
+				voffset =
+				    ((par->NeoPanelHeight -
+				      info->var.yres) >> 1) - 2;
+			} else {
+				/* Stretched modes cannot be centered. */
+				hoffset = 0;
+				voffset = 0;
+			}
+
+			switch (info->var.xres) {
+			case 320:	/* Needs testing.  KEM -- 24 May 98 */
+				par->PanelHorizCenterReg3 = hoffset;
+				par->PanelVertCenterReg2 = voffset;
+				break;
+			case 400:	/* Needs testing.  KEM -- 24 May 98 */
+				par->PanelHorizCenterReg4 = hoffset;
+				par->PanelVertCenterReg1 = voffset;
+				break;
+			case 640:
+				par->PanelHorizCenterReg1 = hoffset;
+				par->PanelVertCenterReg3 = voffset;
+				break;
+			case 800:
+				par->PanelHorizCenterReg2 = hoffset;
+				par->PanelVertCenterReg4 = voffset;
+				break;
+			case 1024:
+				par->PanelHorizCenterReg5 = hoffset;
+				par->PanelVertCenterReg5 = voffset;
+				break;
+			case 1280:
+			default:
+				/* No centering in these modes. */
+				break;
+			}
+		}
+	}
 
-/*
- * vgaHWSeqReset
- *      perform a sequencer reset.
- */
-void
-vgaHWSeqReset(int start)
-{
-  if (start)
-    VGAwSEQ (0x00, 0x01);		/* Synchronous Reset */
-  else
-    VGAwSEQ (0x00, 0x03);		/* End Reset */
-}
+	par->biosMode =
+	    neoFindMode(info->var.xres, info->var.yres,
+			info->var.bits_per_pixel);
+
+	/*
+	 * Calculate the VCLK that most closely matches the requested dot
+	 * clock.
+	 */
+	neoCalcVCLK(info, par, timings.pixclock);
+
+	/* Since we program the clocks ourselves, always use VCLK3. */
+	par->MiscOutReg |= 0x0C;
+
+	/* linear colormap for non palettized modes */
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		/* PseudoColor, 256 */
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
+	case 16:
+		/* DirectColor, 64k */
+		info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+
+		for (i = 0; i < 64; i++) {
+			outb(i, 0x3c8);
+
+			outb(i << 1, 0x3c9);
+			outb(i, 0x3c9);
+			outb(i << 1, 0x3c9);
+		}
+		break;
+	case 24:
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:
+#endif
+		/* TrueColor, 16m */
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
 
-void
-vgaHWProtect(int on)
-{
-  unsigned char tmp;
-  
-  if (on)
-    {
-      /*
-       * Turn off screen and disable sequencer.
-       */
-      tmp = VGArSEQ (0x01);
+		for (i = 0; i < 256; i++) {
+			outb(i, 0x3c8);
 
-      vgaHWSeqReset (1);			/* start synchronous reset */
-      VGAwSEQ (0x01, tmp | 0x20);	/* disable the display */
+			outb(i, 0x3c9);
+			outb(i, 0x3c9);
+			outb(i, 0x3c9);
+		}
+		break;
+	}
 
-      VGAenablePalette();
-    }
-  else
-    {
-      /*
-       * Reenable sequencer, then turn on screen.
-       */
-  
-      tmp = VGArSEQ (0x01);
+	/* alread unlocked above */
+	/* BOGUS  VGAwGR (0x09, 0x26); */
 
-      VGAwSEQ (0x01, tmp & ~0x20);	/* reenable display */
-      vgaHWSeqReset (0);		/* clear synchronousreset */
+	/* don't know what this is, but it's 0 from bootup anyway */
+	VGAwGR(0x15, 0x00);
 
-      VGAdisablePalette();
-    }
-}
+	/* was set to 0x01 by my bios in text and vesa modes */
+	VGAwGR(0x0A, par->GeneralLockReg);
 
-static void vgaHWRestore (const struct neofb_info *info,
-			  const struct neofb_par  *par)
-{
-  int i;
+	/*
+	 * The color mode needs to be set before calling vgaHWRestore
+	 * to ensure the DAC is initialized properly.
+	 *
+	 * NOTE: Make sure we don't change bits make sure we don't change
+	 * any reserved bits.
+	 */
+	temp = VGArGR(0x90);
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		temp &= 0xF0;	/* Save bits 7:4 */
+		temp |= (par->ExtColorModeSelect & ~0xF0);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+	case FB_ACCEL_NEOMAGIC_NM2097:
+	case FB_ACCEL_NEOMAGIC_NM2160:
+	case FB_ACCEL_NEOMAGIC_NM2200:
+	case FB_ACCEL_NEOMAGIC_NM2230:
+	case FB_ACCEL_NEOMAGIC_NM2360:
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		temp &= 0x70;	/* Save bits 6:4 */
+		temp |= (par->ExtColorModeSelect & ~0x70);
+		break;
+	}
 
-  VGAwMISC (par->MiscOutReg);
+	VGAwGR(0x90, temp);
 
-  for (i = 1; i < 5; i++)
-    VGAwSEQ (i, par->Sequencer[i]);
-  
-  /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or CRTC[17] */
-  VGAwCR (17, par->CRTC[17] & ~0x80);
+	/*
+	 * In some rare cases a lockup might occur if we don't delay
+	 * here. (Reported by Miles Lane)
+	 */
+	//mdelay(200);
+
+	/*
+	 * Disable horizontal and vertical graphics and text expansions so
+	 * that vgaHWRestore works properly.
+	 */
+	temp = VGArGR(0x25);
+	temp &= 0x39;
+	VGAwGR(0x25, temp);
+
+	/*
+	 * Sleep for 200ms to make sure that the two operations above have
+	 * had time to take effect.
+	 */
+	mdelay(200);
+
+	/*
+	 * This function handles restoring the generic VGA registers.  */
+	vgaHWRestore(info, par);
+
+
+	VGAwGR(0x0E, par->ExtCRTDispAddr);
+	VGAwGR(0x0F, par->ExtCRTOffset);
+	temp = VGArGR(0x10);
+	temp &= 0x0F;		/* Save bits 3:0 */
+	temp |= (par->SysIfaceCntl1 & ~0x0F);	/* VESA Bios sets bit 1! */
+	VGAwGR(0x10, temp);
+
+	VGAwGR(0x11, par->SysIfaceCntl2);
+	VGAwGR(0x15, 0 /*par->SingleAddrPage */ );
+	VGAwGR(0x16, 0 /*par->DualAddrPage */ );
+
+	temp = VGArGR(0x20);
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		temp &= 0xFC;	/* Save bits 7:2 */
+		temp |= (par->PanelDispCntlReg1 & ~0xFC);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+	case FB_ACCEL_NEOMAGIC_NM2097:
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		temp &= 0xDC;	/* Save bits 7:6,4:2 */
+		temp |= (par->PanelDispCntlReg1 & ~0xDC);
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+	case FB_ACCEL_NEOMAGIC_NM2230:
+	case FB_ACCEL_NEOMAGIC_NM2360:
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		temp &= 0x98;	/* Save bits 7,4:3 */
+		temp |= (par->PanelDispCntlReg1 & ~0x98);
+		break;
+	}
+	VGAwGR(0x20, temp);
 
-  for (i = 0; i < 25; i++)
-    VGAwCR (i, par->CRTC[i]);
+	temp = VGArGR(0x25);
+	temp &= 0x38;		/* Save bits 5:3 */
+	temp |= (par->PanelDispCntlReg2 & ~0x38);
+	VGAwGR(0x25, temp);
+
+	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+		temp = VGArGR(0x30);
+		temp &= 0xEF;	/* Save bits 7:5 and bits 3:0 */
+		temp |= (par->PanelDispCntlReg3 & ~0xEF);
+		VGAwGR(0x30, temp);
+	}
 
-  for (i = 0; i < 9; i++)
-    VGAwGR (i, par->Graphics[i]);
+	VGAwGR(0x28, par->PanelVertCenterReg1);
+	VGAwGR(0x29, par->PanelVertCenterReg2);
+	VGAwGR(0x2a, par->PanelVertCenterReg3);
+
+	if (info->fix.accel != FB_ACCEL_NEOMAGIC_NM2070) {
+		VGAwGR(0x32, par->PanelVertCenterReg4);
+		VGAwGR(0x33, par->PanelHorizCenterReg1);
+		VGAwGR(0x34, par->PanelHorizCenterReg2);
+		VGAwGR(0x35, par->PanelHorizCenterReg3);
+	}
 
-  VGAenablePalette();
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2160)
+		VGAwGR(0x36, par->PanelHorizCenterReg4);
 
-  for (i = 0; i < 21; i++)
-    VGAwATTR (i, par->Attribute[i]);
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		VGAwGR(0x36, par->PanelHorizCenterReg4);
+		VGAwGR(0x37, par->PanelVertCenterReg5);
+		VGAwGR(0x38, par->PanelHorizCenterReg5);
 
-  VGAdisablePalette();
-}
+		clock_hi = 1;
+	}
 
-static void neofb_set_par (struct neofb_info       *info,
-			   const struct neofb_par  *par)
-{
-  unsigned char temp;
-  int i;
-  int clock_hi = 0;
-    
-  DBG("neofb_set_par");
+	/* Program VCLK3 if needed. */
+	if (par->ProgramVCLK && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
+				 || (VGArGR(0x9F) != par->VCLK3Denominator)
+				 || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
+						  != (par->
+						      VCLK3NumeratorHigh &
+						      ~0x0F))))) {
+		VGAwGR(0x9B, par->VCLK3NumeratorLow);
+		if (clock_hi) {
+			temp = VGArGR(0x8F);
+			temp &= 0x0F;	/* Save bits 3:0 */
+			temp |= (par->VCLK3NumeratorHigh & ~0x0F);
+			VGAwGR(0x8F, temp);
+		}
+		VGAwGR(0x9F, par->VCLK3Denominator);
+	}
 
-  neoUnlock();
+	if (par->biosMode)
+		VGAwCR(0x23, par->biosMode);
 
-  vgaHWProtect (1);		/* Blank the screen */
+	VGAwGR(0x93, 0xc0);	/* Gives 5x faster framebuffer writes !!! */
 
-  /* linear colormap for non palettized modes */
-  switch (par->depth)
-    {
-    case 8:
-      break;
-    case 16:
-      for (i=0; i<64; i++)
-	{
-	  outb(i, 0x3c8);
-	  
-	  outb(i << 1, 0x3c9);
-	  outb(i, 0x3c9);
-	  outb(i << 1, 0x3c9);
+	/* Program vertical extension register */
+	if (info->fix.accel == FB_ACCEL_NEOMAGIC_NM2200 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2230 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2360 ||
+	    info->fix.accel == FB_ACCEL_NEOMAGIC_NM2380) {
+		VGAwCR(0x70, par->VerticalExt);
 	}
-      break;
-    case 24:
-#ifdef NO_32BIT_SUPPORT_YET
-    case 32:
-#endif
-      for (i=0; i<256; i++)
-	{
-	  outb(i, 0x3c8);
-	  
-	  outb(i, 0x3c9);
-	  outb(i, 0x3c9);
-	  outb(i, 0x3c9);
-	}
-      break;
-    }
-    
-  /* alread unlocked above */
-  /* BOGUS  VGAwGR (0x09, 0x26);*/
-    
-  /* don't know what this is, but it's 0 from bootup anyway */
-  VGAwGR (0x15, 0x00);
-
-  /* was set to 0x01 by my bios in text and vesa modes */
-  VGAwGR (0x0A, par->GeneralLockReg);
-
-  /*
-   * The color mode needs to be set before calling vgaHWRestore
-   * to ensure the DAC is initialized properly.
-   *
-   * NOTE: Make sure we don't change bits make sure we don't change
-   * any reserved bits.
-   */
-  temp = VGArGR(0x90);
-  switch (info->accel)
-    {
-    case FB_ACCEL_NEOMAGIC_NM2070:
-      temp &= 0xF0; /* Save bits 7:4 */
-      temp |= (par->ExtColorModeSelect & ~0xF0);
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2090:
-    case FB_ACCEL_NEOMAGIC_NM2093:
-    case FB_ACCEL_NEOMAGIC_NM2097:
-    case FB_ACCEL_NEOMAGIC_NM2160:
-    case FB_ACCEL_NEOMAGIC_NM2200:
-    case FB_ACCEL_NEOMAGIC_NM2230:
-    case FB_ACCEL_NEOMAGIC_NM2360:
-    case FB_ACCEL_NEOMAGIC_NM2380:
-      temp &= 0x70; /* Save bits 6:4 */
-      temp |= (par->ExtColorModeSelect & ~0x70);
-      break;
-    }
-
-  VGAwGR(0x90,temp);
-
-  /*
-   * In some rare cases a lockup might occur if we don't delay
-   * here. (Reported by Miles Lane)
-   */
-  //mdelay(200);
-
-  /*
-   * Disable horizontal and vertical graphics and text expansions so
-   * that vgaHWRestore works properly.
-   */
-  temp = VGArGR(0x25);
-  temp &= 0x39;
-  VGAwGR (0x25, temp);
-
-  /*
-   * Sleep for 200ms to make sure that the two operations above have
-   * had time to take effect.
-   */
-  mdelay(200);
-
-  /*
-   * This function handles restoring the generic VGA registers.  */
-  vgaHWRestore (info, par);
-
-
-  VGAwGR(0x0E, par->ExtCRTDispAddr);
-  VGAwGR(0x0F, par->ExtCRTOffset);
-  temp = VGArGR(0x10);
-  temp &= 0x0F; /* Save bits 3:0 */
-  temp |= (par->SysIfaceCntl1 & ~0x0F); /* VESA Bios sets bit 1! */
-  VGAwGR(0x10, temp);
-
-  VGAwGR(0x11, par->SysIfaceCntl2);
-  VGAwGR(0x15, 0 /*par->SingleAddrPage*/);
-  VGAwGR(0x16, 0 /*par->DualAddrPage*/);
-
-  temp = VGArGR(0x20);
-  switch (info->accel)
-    {
-    case FB_ACCEL_NEOMAGIC_NM2070:
-      temp &= 0xFC; /* Save bits 7:2 */
-      temp |= (par->PanelDispCntlReg1 & ~0xFC);
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2090:
-    case FB_ACCEL_NEOMAGIC_NM2093:
-    case FB_ACCEL_NEOMAGIC_NM2097:
-    case FB_ACCEL_NEOMAGIC_NM2160:
-      temp &= 0xDC; /* Save bits 7:6,4:2 */
-      temp |= (par->PanelDispCntlReg1 & ~0xDC);
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2200:
-    case FB_ACCEL_NEOMAGIC_NM2230:
-    case FB_ACCEL_NEOMAGIC_NM2360:
-    case FB_ACCEL_NEOMAGIC_NM2380:
-      temp &= 0x98; /* Save bits 7,4:3 */
-      temp |= (par->PanelDispCntlReg1 & ~0x98);
-      break;
-    }
-  VGAwGR(0x20, temp);
-
-  temp = VGArGR(0x25);
-  temp &= 0x38; /* Save bits 5:3 */
-  temp |= (par->PanelDispCntlReg2 & ~0x38);
-  VGAwGR(0x25, temp);
-
-  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
-    {
-      temp = VGArGR(0x30);
-      temp &= 0xEF; /* Save bits 7:5 and bits 3:0 */
-      temp |= (par->PanelDispCntlReg3 & ~0xEF);
-      VGAwGR(0x30, temp);
-    }
-
-  VGAwGR(0x28, par->PanelVertCenterReg1);
-  VGAwGR(0x29, par->PanelVertCenterReg2);
-  VGAwGR(0x2a, par->PanelVertCenterReg3);
-
-  if (info->accel != FB_ACCEL_NEOMAGIC_NM2070)
-    {
-      VGAwGR(0x32, par->PanelVertCenterReg4);
-      VGAwGR(0x33, par->PanelHorizCenterReg1);
-      VGAwGR(0x34, par->PanelHorizCenterReg2);
-      VGAwGR(0x35, par->PanelHorizCenterReg3);
-    }
-
-  if (info->accel == FB_ACCEL_NEOMAGIC_NM2160)
-    VGAwGR(0x36, par->PanelHorizCenterReg4);
-
-  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
-    {
-      VGAwGR(0x36, par->PanelHorizCenterReg4);
-      VGAwGR(0x37, par->PanelVertCenterReg5);
-      VGAwGR(0x38, par->PanelHorizCenterReg5);
-
-      clock_hi = 1;
-    }
-
-  /* Program VCLK3 if needed. */
-  if (par->ProgramVCLK
-      && ((VGArGR(0x9B) != par->VCLK3NumeratorLow)
-	  || (VGArGR(0x9F) !=  par->VCLK3Denominator)
-	  || (clock_hi && ((VGArGR(0x8F) & ~0x0f)
-			   != (par->VCLK3NumeratorHigh & ~0x0F)))))
-    {
-      VGAwGR(0x9B, par->VCLK3NumeratorLow);
-      if (clock_hi)
-	{
-	  temp = VGArGR(0x8F);
-	  temp &= 0x0F; /* Save bits 3:0 */
-	  temp |= (par->VCLK3NumeratorHigh & ~0x0F);
-	  VGAwGR(0x8F, temp);
-	}
-      VGAwGR(0x9F, par->VCLK3Denominator);
-    }
-
-  if (par->biosMode)
-    VGAwCR(0x23, par->biosMode);
-    
-  VGAwGR (0x93, 0xc0); /* Gives 5x faster framebuffer writes !!! */
-
-  /* Program vertical extension register */
-  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
-    {
-      VGAwCR(0x70, par->VerticalExt);
-    }
-
-
-  vgaHWProtect (0);		/* Turn on screen */
-
-  /* Calling this also locks offset registers required in update_start */
-  neoLock();
-}
-
-static void neofb_update_start (struct neofb_info *info, struct fb_var_screeninfo *var)
-{
-  int oldExtCRTDispAddr;
-  int Base; 
-
-  DBG("neofb_update_start");
-
-  Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
-  Base *= (var->bits_per_pixel + 7) / 8;
-
-  neoUnlock();
-
-  /*
-   * These are the generic starting address registers.
-   */
-  VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
-  VGAwCR(0x0D, (Base & 0x00FF));
-
-  /*
-   * Make sure we don't clobber some other bits that might already
-   * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
-   * be needed.
-   */
-  oldExtCRTDispAddr = VGArGR(0x0E);
-  VGAwGR(0x0E,(((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
 
-  neoLock();
-}
 
-/*
- * neoCalcVCLK --
- *
- * Determine the closest clock frequency to the one requested.
- */
-#define REF_FREQ 0xe517  /* 14.31818 in 20.12 fixed point */
-#define MAX_N 127
-#define MAX_D 31
-#define MAX_F 1
+	vgaHWProtect(0);	/* Turn on screen */
 
-static void neoCalcVCLK (const struct neofb_info *info, struct neofb_par *par, long freq)
-{
-  int n, d, f;
-  int n_best = 0, d_best = 0, f_best = 0;
-  long f_best_diff = (0x7ffff << 12); /* 20.12 */
-  long f_target = (freq << 12) / 1000; /* 20.12 */
-
-  for (f = 0; f <= MAX_F; f++)
-    for (n = 0; n <= MAX_N; n++)
-      for (d = 0; d <= MAX_D; d++)
-	{
-          long f_out;  /* 20.12 */
-          long f_diff; /* 20.12 */
-
-	  f_out = ((((n+1) << 12)  /  ((d+1)*(1<<f))) >> 12)  *  REF_FREQ;
-	  f_diff = abs(f_out-f_target);
-	  if (f_diff < f_best_diff)
-	    {
-	      f_best_diff = f_diff;
-	      n_best = n;
-	      d_best = d;
-	      f_best = f;
-	    }
-	}
-
-  if (info->accel == FB_ACCEL_NEOMAGIC_NM2200 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2230 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2360 ||
-      info->accel == FB_ACCEL_NEOMAGIC_NM2380)
-    {
-      /* NOT_DONE:  We are trying the full range of the 2200 clock.
-	 We should be able to try n up to 2047 */
-      par->VCLK3NumeratorLow  = n_best;
-      par->VCLK3NumeratorHigh = (f_best << 7);
-    }
-  else
-    par->VCLK3NumeratorLow  = n_best | (f_best << 7);
+	/* Calling this also locks offset registers required in update_start */
+	neoLock();
 
-  par->VCLK3Denominator = d_best;
+	info->fix.line_length =
+	    info->var.xres_virtual * (info->var.bits_per_pixel >> 3);
 
-#ifdef NEOFB_DEBUG
-  printk ("neoVCLK: f:%d NumLow=%d NumHi=%d Den=%d Df=%d\n",
-	  f_target >> 12,
-	  par->VCLK3NumeratorLow,
-	  par->VCLK3NumeratorHigh,
-	  par->VCLK3Denominator,
-	  f_best_diff >> 12);
-#endif
+	if (info->var.accel_flags & FB_ACCELF_TEXT)
+		neo2200_accel_init(info, &info->var);
+	return 0;
 }
 
-/*
- * vgaHWInit --
- *      Handle the initialization, etc. of a screen.
- *      Return FALSE on failure.
- */
-
-static int vgaHWInit (const struct fb_var_screeninfo *var,
-		      const struct neofb_info        *info,
-		      struct neofb_par               *par,
-		      struct xtimings                *timings)
-{
-  par->MiscOutReg = 0x23;
-
-  if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
-    par->MiscOutReg |= 0x40;
-
-  if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
-    par->MiscOutReg |= 0x80;
-    
-  /*
-   * Time Sequencer
-   */
-  par->Sequencer[0] = 0x00;
-  par->Sequencer[1] = 0x01;
-  par->Sequencer[2] = 0x0F;
-  par->Sequencer[3] = 0x00;                             /* Font select */
-  par->Sequencer[4] = 0x0E;                             /* Misc */
-
-  /*
-   * CRTC Controller
-   */
-  par->CRTC[0]  = (timings->HTotal >> 3) - 5;
-  par->CRTC[1]  = (timings->HDisplay >> 3) - 1;
-  par->CRTC[2]  = (timings->HDisplay >> 3) - 1;
-  par->CRTC[3]  = (((timings->HTotal >> 3) - 1) & 0x1F) | 0x80;
-  par->CRTC[4]  = (timings->HSyncStart >> 3);
-  par->CRTC[5]  = ((((timings->HTotal >> 3) - 1) & 0x20) << 2)
-    | (((timings->HSyncEnd >> 3)) & 0x1F);
-  par->CRTC[6]  = (timings->VTotal - 2) & 0xFF;
-  par->CRTC[7]  = (((timings->VTotal - 2) & 0x100) >> 8)
-    | (((timings->VDisplay - 1) & 0x100) >> 7)
-    | ((timings->VSyncStart & 0x100) >> 6)
-    | (((timings->VDisplay - 1) & 0x100) >> 5)
-    | 0x10
-    | (((timings->VTotal - 2) & 0x200)   >> 4)
-    | (((timings->VDisplay - 1) & 0x200) >> 3)
-    | ((timings->VSyncStart & 0x200) >> 2);
-  par->CRTC[8]  = 0x00;
-  par->CRTC[9]  = (((timings->VDisplay - 1) & 0x200) >> 4) | 0x40;
-
-  if (timings->dblscan)
-    par->CRTC[9] |= 0x80;
-
-  par->CRTC[10] = 0x00;
-  par->CRTC[11] = 0x00;
-  par->CRTC[12] = 0x00;
-  par->CRTC[13] = 0x00;
-  par->CRTC[14] = 0x00;
-  par->CRTC[15] = 0x00;
-  par->CRTC[16] = timings->VSyncStart & 0xFF;
-  par->CRTC[17] = (timings->VSyncEnd & 0x0F) | 0x20;
-  par->CRTC[18] = (timings->VDisplay - 1) & 0xFF;
-  par->CRTC[19] = var->xres_virtual >> 4;
-  par->CRTC[20] = 0x00;
-  par->CRTC[21] = (timings->VDisplay - 1) & 0xFF; 
-  par->CRTC[22] = (timings->VTotal - 1) & 0xFF;
-  par->CRTC[23] = 0xC3;
-  par->CRTC[24] = 0xFF;
-
-  /*
-   * are these unnecessary?
-   * vgaHWHBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
-   * vgaHWVBlankKGA(mode, regp, 0, KGA_FIX_OVERSCAN | KGA_ENABLE_ON_ZERO);
-   */
-
-  /*
-   * Graphics Display Controller
-   */
-  par->Graphics[0] = 0x00;
-  par->Graphics[1] = 0x00;
-  par->Graphics[2] = 0x00;
-  par->Graphics[3] = 0x00;
-  par->Graphics[4] = 0x00;
-  par->Graphics[5] = 0x40;
-  par->Graphics[6] = 0x05;   /* only map 64k VGA memory !!!! */
-  par->Graphics[7] = 0x0F;
-  par->Graphics[8] = 0xFF;
-  
-
-  par->Attribute[0]  = 0x00; /* standard colormap translation */
-  par->Attribute[1]  = 0x01;
-  par->Attribute[2]  = 0x02;
-  par->Attribute[3]  = 0x03;
-  par->Attribute[4]  = 0x04;
-  par->Attribute[5]  = 0x05;
-  par->Attribute[6]  = 0x06;
-  par->Attribute[7]  = 0x07;
-  par->Attribute[8]  = 0x08;
-  par->Attribute[9]  = 0x09;
-  par->Attribute[10] = 0x0A;
-  par->Attribute[11] = 0x0B;
-  par->Attribute[12] = 0x0C;
-  par->Attribute[13] = 0x0D;
-  par->Attribute[14] = 0x0E;
-  par->Attribute[15] = 0x0F;
-  par->Attribute[16] = 0x41;
-  par->Attribute[17] = 0xFF;
-  par->Attribute[18] = 0x0F;
-  par->Attribute[19] = 0x00;
-  par->Attribute[20] = 0x00;
-
-  return 0;
-}
-
-static int neofb_decode_var (struct fb_var_screeninfo        *var,
-                             const struct neofb_info         *info,
-                             struct neofb_par                *par)
-{
-  struct xtimings timings;
-  int lcd_stretch;
-  int hoffset, voffset;
-  int memlen, vramlen;
-  int mode_ok = 0;
-  unsigned int pixclock = var->pixclock;
-
-  DBG("neofb_decode_var");
-
-  if (!pixclock) pixclock = 10000;	/* 10ns = 100MHz */
-  timings.pixclock = 1000000000 / pixclock;
-  if (timings.pixclock < 1) timings.pixclock = 1;
-  timings.dblscan = var->vmode & FB_VMODE_DOUBLE;
-  timings.interlaced = var->vmode & FB_VMODE_INTERLACED;
-  timings.HDisplay = var->xres;
-  timings.HSyncStart = timings.HDisplay + var->right_margin;
-  timings.HSyncEnd = timings.HSyncStart + var->hsync_len;
-  timings.HTotal = timings.HSyncEnd + var->left_margin;
-  timings.VDisplay = var->yres;
-  timings.VSyncStart = timings.VDisplay + var->lower_margin;
-  timings.VSyncEnd = timings.VSyncStart + var->vsync_len;
-  timings.VTotal = timings.VSyncEnd + var->upper_margin;
-  timings.sync = var->sync;
-
-  if (timings.pixclock > info->maxClock)
-    return -EINVAL;
-
-  /* Is the mode larger than the LCD panel? */
-  if ((var->xres > info->NeoPanelWidth) ||
-      (var->yres > info->NeoPanelHeight))
-    {
-      printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel (%dx%d)\n",
-	      var->xres,
-	      var->yres,
-	      info->NeoPanelWidth,
-	      info->NeoPanelHeight);
-      return -EINVAL;
-    }
-
-  /* Is the mode one of the acceptable sizes? */
-  switch (var->xres)
-    {
-    case 1280:
-      if (var->yres == 1024)
-	mode_ok = 1;
-      break;
-    case 1024:
-      if (var->yres == 768)
-	mode_ok = 1;
-      break;
-    case  800:
-      if (var->yres == 600)
-	mode_ok = 1;
-      break;
-    case  640:
-      if (var->yres == 480)
-	mode_ok = 1;
-      break;
-    }
-
-  if (!mode_ok)
-    {
-      printk (KERN_INFO "Mode (%dx%d) won't display properly on LCD\n",
-	      var->xres, var->yres);
-      return -EINVAL;
-    }
-
-
-  switch (var->bits_per_pixel)
-    {
-#ifdef FBCON_HAS_CFB8
-    case 8:
-      break;
-#endif
-
-#ifdef FBCON_HAS_CFB16
-    case 16:
-      break;
-#endif
-
-#ifdef FBCON_HAS_CFB24
-    case 24:
-      break;
-#endif
-
-#ifdef NO_32BIT_SUPPORT_YET
-# ifdef FBCON_HAS_CFB32
-    case 32:
-      break;
-# endif
-#endif
-
-    default:
-      return -EINVAL;
-    }
-
-  par->depth = var->bits_per_pixel;
-
-  vramlen = info->video.len;
-  if (vramlen > 4*1024*1024)
-    vramlen = 4*1024*1024;
-
-  if (var->yres_virtual < var->yres)
-    var->yres_virtual = var->yres;
-  if (var->xres_virtual < var->xres)
-    var->xres_virtual = var->xres;
-
-  memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
-  if (memlen > vramlen)
-    {
-      var->yres_virtual = vramlen * 8 / (var->xres_virtual * var->bits_per_pixel);
-      memlen = var->xres_virtual * var->bits_per_pixel * var->yres_virtual / 8;
-    }
-
-  /* we must round yres/xres down, we already rounded y/xres_virtual up
-     if it was possible. We should return -EINVAL, but I disagree */
-  if (var->yres_virtual < var->yres)
-    var->yres = var->yres_virtual;
-  if (var->xres_virtual < var->xres)
-    var->xres = var->xres_virtual;
-  if (var->xoffset + var->xres > var->xres_virtual)
-    var->xoffset = var->xres_virtual - var->xres;
-  if (var->yoffset + var->yres > var->yres_virtual)
-    var->yoffset = var->yres_virtual - var->yres;
-
-
-  /*
-   * This will allocate the datastructure and initialize all of the
-   * generic VGA registers.
-   */
-
-  if (vgaHWInit (var, info, par, &timings))
-    return -EINVAL;
-
-  /*
-   * The default value assigned by vgaHW.c is 0x41, but this does
-   * not work for NeoMagic.
-   */
-  par->Attribute[16] = 0x01;
-
-  switch (var->bits_per_pixel)
-    {
-    case  8:
-      par->CRTC[0x13]   = var->xres_virtual >> 3;
-      par->ExtCRTOffset = var->xres_virtual >> 11;
-      par->ExtColorModeSelect = 0x11;
-      break;
-    case 16:
-      par->CRTC[0x13]   = var->xres_virtual >> 2;
-      par->ExtCRTOffset = var->xres_virtual >> 10;
-      par->ExtColorModeSelect = 0x13;
-      break;
-    case 24:
-      par->CRTC[0x13]   = (var->xres_virtual * 3) >> 3;
-      par->ExtCRTOffset = (var->xres_virtual * 3) >> 11;
-      par->ExtColorModeSelect = 0x14;
-      break;
-#ifdef NO_32BIT_SUPPORT_YET
-    case 32: /* FIXME: guessed values */
-      par->CRTC[0x13]   = var->xres_virtual >> 1;
-      par->ExtCRTOffset = var->xres_virtual >> 9;
-      par->ExtColorModeSelect = 0x15;
-      break;
-#endif
-    default:
-      break;
-    }
-	
-  par->ExtCRTDispAddr = 0x10;
-
-  /* Vertical Extension */
-  par->VerticalExt = (((timings.VTotal -2) & 0x400) >> 10 )
-    | (((timings.VDisplay -1) & 0x400) >> 9 )
-    | (((timings.VSyncStart) & 0x400) >> 8 )
-    | (((timings.VSyncStart) & 0x400) >> 7 );
-
-  /* Fast write bursts on unless disabled. */
-  if (info->pci_burst)
-    par->SysIfaceCntl1 = 0x30; 
-  else
-    par->SysIfaceCntl1 = 0x00; 
-
-  par->SysIfaceCntl2 = 0xc0; /* VESA Bios sets this to 0x80! */
-
-  /* Enable any user specified display devices. */
-  par->PanelDispCntlReg1 = 0x00;
-  if (info->internal_display)
-    par->PanelDispCntlReg1 |= 0x02;
-  if (info->external_display)
-    par->PanelDispCntlReg1 |= 0x01;
-
-  /* If the user did not specify any display devices, then... */
-  if (par->PanelDispCntlReg1 == 0x00) {
-    /* Default to internal (i.e., LCD) only. */
-    par->PanelDispCntlReg1 |= 0x02;
-  }
-
-  /* If we are using a fixed mode, then tell the chip we are. */
-  switch (var->xres)
-    {
-    case 1280:
-      par->PanelDispCntlReg1 |= 0x60;
-      break;
-    case 1024:
-      par->PanelDispCntlReg1 |= 0x40;
-      break;
-    case 800:
-      par->PanelDispCntlReg1 |= 0x20;
-      break;
-    case 640:
-    default:
-      break;
-    }
-  
-  /* Setup shadow register locking. */
-  switch (par->PanelDispCntlReg1 & 0x03)
-    {
-    case 0x01: /* External CRT only mode: */
-      par->GeneralLockReg = 0x00;
-      /* We need to program the VCLK for external display only mode. */
-      par->ProgramVCLK = 1;
-      break;
-    case 0x02: /* Internal LCD only mode: */
-    case 0x03: /* Simultaneous internal/external (LCD/CRT) mode: */
-      par->GeneralLockReg = 0x01;
-      /* Don't program the VCLK when using the LCD. */
-      par->ProgramVCLK = 0;
-      break;
-    }
-
-  /*
-   * If the screen is to be stretched, turn on stretching for the
-   * various modes.
-   *
-   * OPTION_LCD_STRETCH means stretching should be turned off!
-   */
-  par->PanelDispCntlReg2 = 0x00;
-  par->PanelDispCntlReg3 = 0x00;
-
-  if (info->lcd_stretch &&
-      (par->PanelDispCntlReg1 == 0x02) &&  /* LCD only */
-      (var->xres != info->NeoPanelWidth))
-    {
-      switch (var->xres)
-	{
-	case  320: /* Needs testing.  KEM -- 24 May 98 */
-	case  400: /* Needs testing.  KEM -- 24 May 98 */
-	case  640:
-	case  800:
-	case 1024:
-	  lcd_stretch = 1;
-	  par->PanelDispCntlReg2 |= 0xC6;
-	  break;
-	default:
-	  lcd_stretch = 0;
-	  /* No stretching in these modes. */
-	}
-    }
-  else
-    lcd_stretch = 0;
-
-  /*
-   * If the screen is to be centerd, turn on the centering for the
-   * various modes.
-   */
-  par->PanelVertCenterReg1  = 0x00;
-  par->PanelVertCenterReg2  = 0x00;
-  par->PanelVertCenterReg3  = 0x00;
-  par->PanelVertCenterReg4  = 0x00;
-  par->PanelVertCenterReg5  = 0x00;
-  par->PanelHorizCenterReg1 = 0x00;
-  par->PanelHorizCenterReg2 = 0x00;
-  par->PanelHorizCenterReg3 = 0x00;
-  par->PanelHorizCenterReg4 = 0x00;
-  par->PanelHorizCenterReg5 = 0x00;
-
-
-  if (par->PanelDispCntlReg1 & 0x02)
-    {
-      if (var->xres == info->NeoPanelWidth)
-	{
-	  /*
-	   * No centering required when the requested display width
-	   * equals the panel width.
-	   */
-	}
-      else
-	{
-	  par->PanelDispCntlReg2 |= 0x01;
-	  par->PanelDispCntlReg3 |= 0x10;
-
-	  /* Calculate the horizontal and vertical offsets. */
-	  if (!lcd_stretch)
-	    {
-	      hoffset = ((info->NeoPanelWidth - var->xres) >> 4) - 1;
-	      voffset = ((info->NeoPanelHeight - var->yres) >> 1) - 2;
-	    }
-	  else
-	    {
-	      /* Stretched modes cannot be centered. */
-	      hoffset = 0;
-	      voffset = 0;
-	    }
-
-	  switch (var->xres)
-	    {
-	    case  320: /* Needs testing.  KEM -- 24 May 98 */
-	      par->PanelHorizCenterReg3 = hoffset;
-	      par->PanelVertCenterReg2  = voffset;
-	      break;
-	    case  400: /* Needs testing.  KEM -- 24 May 98 */
-	      par->PanelHorizCenterReg4 = hoffset;
-	      par->PanelVertCenterReg1  = voffset;
-	      break;
-	    case  640:
-	      par->PanelHorizCenterReg1 = hoffset;
-	      par->PanelVertCenterReg3  = voffset;
-	      break;
-	    case  800:
-	      par->PanelHorizCenterReg2 = hoffset;
-	      par->PanelVertCenterReg4  = voffset;
-	      break;
-	    case 1024:
-	      par->PanelHorizCenterReg5 = hoffset;
-	      par->PanelVertCenterReg5  = voffset;
-	      break;
-	    case 1280:
-	    default:
-	      /* No centering in these modes. */
-	      break;
-	    }
-	}
-    }
-
-  par->biosMode = neoFindMode (var->xres, var->yres, var->bits_per_pixel);
-    
-  /*
-   * Calculate the VCLK that most closely matches the requested dot
-   * clock.
-   */
-  neoCalcVCLK (info, par, timings.pixclock);
-
-  /* Since we program the clocks ourselves, always use VCLK3. */
-  par->MiscOutReg |= 0x0C;
-
-  return 0;
-}
-
-static int neofb_set_var (struct fb_var_screeninfo *var, int con,
-                          struct fb_info *fb)
-{
-  struct neofb_info *info = (struct neofb_info *)fb;
-  struct display *display;
-  struct neofb_par par;
-  int err, chgvar = 0;
-
-  DBG("neofb_set_var");
-
-  err = neofb_decode_var (var, info, &par);
-  if (err)
-    return err;
-
-  if (var->activate & FB_ACTIVATE_TEST)
-    return 0;
-
-  if (con < 0)
-    {
-      display = fb->disp;
-      chgvar = 0;
-    }
-  else
-    {
-      display = fb_display + con;
-
-      if (fb->var.xres != var->xres)
-	chgvar = 1;
-      if (fb->var.yres != var->yres)
-	chgvar = 1;
-      if (fb->var.xres_virtual != var->xres_virtual)
-	chgvar = 1;
-      if (fb->var.yres_virtual != var->yres_virtual)
-	chgvar = 1;
-      if (fb->var.bits_per_pixel != var->bits_per_pixel)
-	chgvar = 1;
-    }
-
-  if (!info->neo2200)
-    var->accel_flags &= ~FB_ACCELF_TEXT;
-
-  var->red.msb_right	= 0;
-  var->green.msb_right	= 0;
-  var->blue.msb_right	= 0;
-
-  switch (var->bits_per_pixel)
-    {
-#ifdef FBCON_HAS_CFB8
-    case 8:	/* PSEUDOCOLOUR, 256 */
-      var->transp.offset   = 0;
-      var->transp.length   = 0;
-      var->red.offset      = 0;
-      var->red.length      = 8;
-      var->green.offset	   = 0;
-      var->green.length	   = 8;
-      var->blue.offset	   = 0;
-      var->blue.length	   = 8;
-      
-      fb->fix.visual       = FB_VISUAL_PSEUDOCOLOR;
-      info->dispsw         = &fbcon_cfb8;
-      display->dispsw_data = NULL;
-      display->next_line   = var->xres_virtual;
-      break;
-#endif
+static void neofb_update_start(struct fb_info *info,
+			       struct fb_var_screeninfo *var)
+{
+	int oldExtCRTDispAddr;
+	int Base;
 
-#ifdef FBCON_HAS_CFB16
-    case 16: /* DIRECTCOLOUR, 64k */
-      var->transp.offset   = 0;
-      var->transp.length   = 0;
-      var->red.offset      = 11;
-      var->red.length      = 5;
-      var->green.offset    = 5;
-      var->green.length    = 6;
-      var->blue.offset     = 0;
-      var->blue.length     = 5;
-
-      fb->fix.visual       = FB_VISUAL_DIRECTCOLOR;
-      info->dispsw         = &fbcon_cfb16;
-      display->dispsw_data = fb->pseudo_palette;
-      display->next_line   = var->xres_virtual * 2;
-      break;
-#endif
+	DBG("neofb_update_start");
 
-#ifdef FBCON_HAS_CFB24
-    case 24: /* TRUECOLOUR, 16m */
-      var->transp.offset   = 0;
-      var->transp.length   = 0;
-      var->red.offset      = 16;
-      var->red.length      = 8;
-      var->green.offset    = 8;
-      var->green.length    = 8;
-      var->blue.offset     = 0;
-      var->blue.length     = 8;
-
-      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
-      info->dispsw         = &fbcon_cfb24;
-      display->dispsw_data = fb->pseudo_palette;
-      display->next_line   = var->xres_virtual * 3;
+	Base = (var->yoffset * var->xres_virtual + var->xoffset) >> 2;
+	Base *= (var->bits_per_pixel + 7) / 8;
 
-      var->accel_flags    &= ~FB_ACCELF_TEXT;
-      break;
-#endif
+	neoUnlock();
 
-#ifdef NO_32BIT_SUPPORT_YET
-# ifdef FBCON_HAS_CFB32
-    case 32: /* TRUECOLOUR, 16m */
-      var->transp.offset   = 24;
-      var->transp.length   = 8;
-      var->red.offset      = 16;
-      var->red.length      = 8;
-      var->green.offset    = 8;
-      var->green.length    = 8;
-      var->blue.offset     = 0;
-      var->blue.length     = 8;
-
-      fb->fix.visual       = FB_VISUAL_TRUECOLOR;
-      info->dispsw         = &fbcon_cfb32;
-      display->dispsw_data = fb->pseudo_palette;
-      display->next_line   = var->xres_virtual * 4;
-
-      var->accel_flags    &= ~FB_ACCELF_TEXT;
-      break;
-# endif
-#endif
+	/*
+	 * These are the generic starting address registers.
+	 */
+	VGAwCR(0x0C, (Base & 0x00FF00) >> 8);
+	VGAwCR(0x0D, (Base & 0x00FF));
 
-    default:
-      printk (KERN_WARNING "neofb: no support for %dbpp\n", var->bits_per_pixel);
-      info->dispsw      = &fbcon_dummy;
-      var->accel_flags &= ~FB_ACCELF_TEXT;
-      break;
-    }
-
-  if (var->accel_flags & FB_ACCELF_TEXT)
-    display->dispsw = &fbcon_neo2200_accel;
-  else
-    display->dispsw = info->dispsw;
-
-  fb->fix.line_length = display->next_line;
-
-  display->line_length    = fb->fix.line_length;
-  display->visual         = fb->fix.visual;
-  display->type	          = fb->fix.type;
-  display->type_aux       = fb->fix.type_aux;
-  display->ypanstep       = fb->fix.ypanstep;
-  display->ywrapstep      = fb->fix.ywrapstep;
-  display->can_soft_blank = 1;
-  display->inverse        = 0;
-
-  fb->var = *var;
-  fb->var.activate &= ~FB_ACTIVATE_ALL;
-
-  /*
-   * Update the old var.  The fbcon drivers still use this.
-   * Once they are using cfb->fb.var, this can be dropped.
-   *					--rmk
-   */
-  display->var = fb->var;
-
-  /*
-   * If we are setting all the virtual consoles, also set the
-   * defaults used to create new consoles.
-   */
-  if (var->activate & FB_ACTIVATE_ALL)
-    fb->disp->var = fb->var;
-
-  if (chgvar && fb && fb->changevar)
-    fb->changevar (con);
-
-  if (con == info->fb.currcon)
-    {
-      if (chgvar || con < 0)
-        neofb_set_par (info, &par);
-
-      neofb_update_start (info, var);
-      fb_set_cmap (&fb->cmap, 1, fb);
-
-      if (var->accel_flags & FB_ACCELF_TEXT)
-	neo2200_accel_init (info, var);
-    }
+	/*
+	 * Make sure we don't clobber some other bits that might already
+	 * have been set. NOTE: NM2200 has a writable bit 3, but it shouldn't
+	 * be needed.
+	 */
+	oldExtCRTDispAddr = VGArGR(0x0E);
+	VGAwGR(0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
 
-  return 0;
+	neoLock();
 }
 
 /*
  *    Pan or Wrap the Display
  */
-static int neofb_pan_display (struct fb_var_screeninfo *var, int con,
-			      struct fb_info *fb)
+static int neofb_pan_display(struct fb_var_screeninfo *var, int con,
+			     struct fb_info *fb)
 {
-  struct neofb_info *info = (struct neofb_info *)fb;
-  u_int y_bottom;
+	struct fb_info *info = (struct fb_info *) fb;
+	u_int y_bottom;
 
-  y_bottom = var->yoffset;
+	y_bottom = var->yoffset;
 
-  if (!(var->vmode & FB_VMODE_YWRAP))
-    y_bottom += var->yres;
+	if (!(var->vmode & FB_VMODE_YWRAP))
+		y_bottom += var->yres;
 
-  if (var->xoffset > (var->xres_virtual - var->xres))
-    return -EINVAL;
-  if (y_bottom > fb->var.yres_virtual)
-    return -EINVAL;
+	if (var->xoffset > (var->xres_virtual - var->xres))
+		return -EINVAL;
+	if (y_bottom > fb->var.yres_virtual)
+		return -EINVAL;
 
-  neofb_update_start (info, var);
+	neofb_update_start(info, var);
 
-  fb->var.xoffset = var->xoffset;
-  fb->var.yoffset = var->yoffset;
+	fb->var.xoffset = var->xoffset;
+	fb->var.yoffset = var->yoffset;
 
-  if (var->vmode & FB_VMODE_YWRAP)
-    fb->var.vmode |= FB_VMODE_YWRAP;
-  else
-    fb->var.vmode &= ~FB_VMODE_YWRAP;
+	if (var->vmode & FB_VMODE_YWRAP)
+		fb->var.vmode |= FB_VMODE_YWRAP;
+	else
+		fb->var.vmode &= ~FB_VMODE_YWRAP;
 
-  return 0;
+	return 0;
 }
 
+static int neofb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int transp, struct fb_info *fb)
+{
+	if (regno >= NR_PALETTE)
+		return -EINVAL;
+
+	switch (fb->var.bits_per_pixel) {
+	case 8:
+		outb(regno, 0x3c8);
+
+		outb(red >> 10, 0x3c9);
+		outb(green >> 10, 0x3c9);
+		outb(blue >> 10, 0x3c9);
+		break;
+	case 16:
+		if (regno < 16)
+			((u16 *) fb->pseudo_palette)[regno] =
+			    ((red & 0xf800)) | ((green & 0xfc00) >> 5) |
+			    ((blue & 0xf800) >> 11);
+		break;
+	case 24:
+		if (regno < 16)
+			((u32 *) fb->pseudo_palette)[regno] =
+			    ((red & 0xff00) << 8) | ((green & 0xff00)) |
+			    ((blue & 0xff00) >> 8);
+		break;
+#ifdef NO_32BIT_SUPPORT_YET
+	case 32:
+		if (regno < 16)
+			((u32 *) fb->pseudo_palette)[regno] =
+			    ((transp & 0xff00) << 16) | ((red & 0xff00) <<
+							 8) | ((green &
+								0xff00)) |
+			    ((blue & 0xff00) >> 8);
+		break;
+#endif
+	default:
+		return 1;
+	}
+	return 0;
+}
 
 /*
- *    Update the `var' structure (called by fbcon.c)
- *
- *    This call looks only at yoffset and the FB_VMODE_YWRAP flag in `var'.
- *    Since it's called by a kernel driver, no range checking is done.
+ *    (Un)Blank the display.
  */
-static int neofb_updatevar (int con, struct fb_info *fb)
+static int neofb_blank(int blank, struct fb_info *fb)
 {
-  struct neofb_info *info = (struct neofb_info *)fb;
-
-  neofb_update_start (info, &fb_display[con].var);
+	//  struct fb_info *info = (struct fb_info *)fb;
 
-  return 0;
+	/*
+	 *  Blank the screen if blank_mode != 0, else unblank. If
+	 *  blank == NULL then the caller blanks by setting the CLUT
+	 *  (Color Look Up Table) to all black. Return 0 if blanking
+	 *  succeeded, != 0 if un-/blanking failed due to e.g. a
+	 *  video mode which doesn't support it. Implements VESA
+	 *  suspend and powerdown modes on hardware that supports
+	 *  disabling hsync/vsync:
+	 *    blank_mode == 2: suspend vsync
+	 *    blank_mode == 3: suspend hsync
+	 *    blank_mode == 4: powerdown
+	 *
+	 *  wms...Enable VESA DMPS compatible powerdown mode
+	 *  run "setterm -powersave powerdown" to take advantage
+	 */
+
+	switch (blank) {
+	case 4:		/* powerdown - both sync lines down */
+		break;
+	case 3:		/* hsync off */
+		break;
+	case 2:		/* vsync off */
+		break;
+	case 1:		/* just software blanking of screen */
+		break;
+	default:		/* case 0, or anything else: unblank */
+		break;
+	}
+	return 0;
 }
 
-static int neofb_switch (int con, struct fb_info *fb)
+static void
+neo2200fb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
 {
-  struct neofb_info *info = (struct neofb_info *)fb;
-  struct display *disp;
-  struct fb_cmap *cmap;
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	u_long dst, rop;
+
+	dst = rect->dx + rect->dy * info->var.xres_virtual;
+	rop = rect->rop ? 0x060000 : 0x0c0000;
+
+	neo2200_wait_fifo(par, 4);
+
+	/* set blt control */
+	par->neo2200->bltCntl = NEO_BC3_FIFO_EN |
+	    NEO_BC0_SRC_IS_FG | NEO_BC3_SKIP_MAPPING |
+	    //               NEO_BC3_DST_XY_ADDR  |
+	    //               NEO_BC3_SRC_XY_ADDR  |
+	    rop;
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		par->neo2200->fgColor = rect->color;
+		break;
+	case 16:
+		par->neo2200->fgColor =
+		    ((u16 *) (info->pseudo_palette))[rect->color];
+		break;
+	}
+
+	par->neo2200->dstStart =
+	    dst * ((info->var.bits_per_pixel + 7) / 8);
+	par->neo2200->xyExt =
+	    (rect->height << 16) | (rect->width & 0xffff);
+}
 
-  if (info->fb.currcon >= 0)
-    {
-      disp = fb_display + info->fb.currcon;
+static void
+neo2200fb_copyarea(struct fb_info *info, struct fb_copyarea *area)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	u_long src, dst, bltCntl;
 
-      /*
-       * Save the old colormap and video mode.
-       */
-      disp->var = fb->var;
-      if (disp->cmap.len)
-	fb_copy_cmap(&fb->cmap, &disp->cmap, 0);
-    }
+	bltCntl = NEO_BC3_FIFO_EN | NEO_BC3_SKIP_MAPPING | 0x0C0000;
 
-  info->fb.currcon = con;
-  disp = fb_display + con;
+	if (area->sy < area->dy) {
+		area->sy += (area->height - 1);
+		area->dy += (area->height - 1);
 
-  /*
-   * Install the new colormap and change the video mode.  By default,
-   * fbcon sets all the colormaps and video modes to the default
-   * values at bootup.
-   *
-   * Really, we want to set the colourmap size depending on the
-   * depth of the new video mode.  For now, we leave it at its
-   * default 256 entry.
-   */
-  if (disp->cmap.len)
-    cmap = &disp->cmap;
-  else
-    cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+		bltCntl |= NEO_BC0_DST_Y_DEC | NEO_BC0_SRC_Y_DEC;
+	}
 
-  fb_copy_cmap(cmap, &fb->cmap, 0);
+	if (area->sx < area->dx) {
+		area->sx += (area->width - 1);
+		area->dx += (area->width - 1);
 
-  disp->var.activate = FB_ACTIVATE_NOW;
-  neofb_set_var(&disp->var, con, fb);
+		bltCntl |= NEO_BC0_X_DEC;
+	}
 
-  return 0;
+	src =
+	    area->sx * (info->var.bits_per_pixel >> 3) +
+	    area->sy * info->fix.line_length;
+	dst =
+	    area->dx * (info->var.bits_per_pixel >> 3) +
+	    area->dy * info->fix.line_length;
+
+	neo2200_wait_fifo(par, 4);
+
+	/* set blt control */
+	par->neo2200->bltCntl = bltCntl;
+
+	par->neo2200->srcStart = src;
+	par->neo2200->dstStart = dst;
+	par->neo2200->xyExt =
+	    (area->height << 16) | (area->width & 0xffff);
 }
 
-/*
- *    (Un)Blank the display.
- */
-static int neofb_blank (int blank, struct fb_info *fb)
+static void
+neo2200fb_imageblit(struct fb_info *info, struct fb_image *image)
 {
-  //  struct neofb_info *info = (struct neofb_info *)fb;
+	struct neofb_par *par = (struct neofb_par *) info->par;
 
-  /*
-   *  Blank the screen if blank_mode != 0, else unblank. If
-   *  blank == NULL then the caller blanks by setting the CLUT
-   *  (Color Look Up Table) to all black. Return 0 if blanking
-   *  succeeded, != 0 if un-/blanking failed due to e.g. a
-   *  video mode which doesn't support it. Implements VESA
-   *  suspend and powerdown modes on hardware that supports
-   *  disabling hsync/vsync:
-   *    blank_mode == 2: suspend vsync
-   *    blank_mode == 3: suspend hsync
-   *    blank_mode == 4: powerdown
-   *
-   *  wms...Enable VESA DMPS compatible powerdown mode
-   *  run "setterm -powersave powerdown" to take advantage
-   */
-     
-  switch (blank)
-    {
-    case 4:	/* powerdown - both sync lines down */
-      break;	
-    case 3:	/* hsync off */
-      break;	
-    case 2:	/* vsync off */
-      break;	
-    case 1:	/* just software blanking of screen */
-      break;
-    default: /* case 0, or anything else: unblank */
-      break;
-    }
-   return 0; 	
+	neo2200_wait_idle(par);
+
+	switch (info->var.bits_per_pixel) {
+	case 8:
+		par->neo2200->fgColor = image->fg_color;
+		par->neo2200->bgColor = image->bg_color;
+		break;
+	case 16:
+		par->neo2200->fgColor =
+		    ((u16 *) (info->pseudo_palette))[image->fg_color];
+		par->neo2200->bgColor =
+		    ((u16 *) (info->pseudo_palette))[image->bg_color];
+		break;
+	}
+
+	par->neo2200->bltCntl = NEO_BC0_SYS_TO_VID |
+	    NEO_BC0_SRC_MONO | NEO_BC3_SKIP_MAPPING |
+	    //                      NEO_BC3_DST_XY_ADDR |
+	    0x0c0000;
+
+	par->neo2200->srcStart = 0;
+//      par->neo2200->dstStart = (image->dy << 16) | (image->dx & 0xffff);
+	par->neo2200->dstStart =
+	    ((image->dx & 0xffff) * (info->var.bits_per_pixel >> 3) +
+	     image->dy * info->fix.line_length);
+	par->neo2200->xyExt =
+	    (image->height << 16) | (image->width & 0xffff);
+
+	memcpy(par->mmio_vbase + 0x100000, image->data,
+	       (image->width * image->height) >> 3);
 }
 
 static struct fb_ops neofb_ops = {
-  owner:          THIS_MODULE,
-  fb_set_var:     neofb_set_var,
-  fb_set_cmap:    gen_set_cmap,
-  fb_setcolreg:	  neofb_setcolreg,	
-  fb_pan_display: neofb_pan_display,
-  fb_blank:	  neofb_blank,	
-  fb_get_fix:     gen_get_fix,
-  fb_get_var:     gen_get_var,
-  fb_get_cmap:    gen_get_cmap,
+	owner:		THIS_MODULE,
+	fb_check_var:	neofb_check_var,
+	fb_set_par:	neofb_set_par,
+	fb_set_var:	gen_set_var,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_setcolreg:	neofb_setcolreg,
+	fb_pan_display:	neofb_pan_display,
+	fb_blank:	neofb_blank,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 /* --------------------------------------------------------------------- */
@@ -1687,9 +1408,9 @@
 	accel_flags:	FB_ACCELF_TEXT,
 	xres:		640,
 	yres:		480,
-	xres_virtual:   640,
-	yres_virtual:   30000,
-	bits_per_pixel: 8,
+	xres_virtual:	640,
+	yres_virtual:	30000,
+	bits_per_pixel:	8,
 	pixclock:	39722,
 	left_margin:	48,
 	right_margin:	16,
@@ -1697,7 +1418,6 @@
 	lower_margin:	10,
 	hsync_len:	96,
 	vsync_len:	2,
-	sync:		0,
 	vmode:		FB_VMODE_NONINTERLACED
 };
 
@@ -1705,9 +1425,9 @@
 	accel_flags:	FB_ACCELF_TEXT,
 	xres:		800,
 	yres:		600,
-	xres_virtual:   800,
-	yres_virtual:   30000,
-	bits_per_pixel: 8,
+	xres_virtual:	800,
+	yres_virtual:	30000,
+	bits_per_pixel:	8,
 	pixclock:	25000,
 	left_margin:	88,
 	right_margin:	40,
@@ -1723,9 +1443,9 @@
 	accel_flags:	FB_ACCELF_TEXT,
 	xres:		1024,
 	yres:		768,
-	xres_virtual:   1024,
-	yres_virtual:   30000,
-	bits_per_pixel: 8,
+	xres_virtual:	1024,
+	yres_virtual:	30000,
+	bits_per_pixel:	8,
 	pixclock:	15385,
 	left_margin:	160,
 	right_margin:	24,
@@ -1742,9 +1462,9 @@
 	accel_flags:	FB_ACCELF_TEXT,
 	xres:		1280,
 	yres:		1024,
-	xres_virtual:   1280,
-	yres_virtual:   30000,
-	bits_per_pixel: 8,
+	xres_virtual:	1280,
+	yres_virtual:	30000,
+	bits_per_pixel:	8,
 	pixclock:	9260,
 	left_margin:	248,
 	right_margin:	48,
@@ -1759,530 +1479,536 @@
 
 static struct fb_var_screeninfo *neofb_var = NULL;
 
-
-static int __devinit neo_map_mmio (struct neofb_info *info)
+static int __devinit neo_map_mmio(struct fb_info *info,
+				  struct pci_dev *dev)
 {
-  DBG("neo_map_mmio");
+	struct neofb_par *par = (struct neofb_par *) info->par;
 
-  info->mmio.pbase = pci_resource_start (info->pcidev, 1);
-  info->mmio.len   = MMIO_SIZE;
+	DBG("neo_map_mmio");
 
-  if (!request_mem_region (info->mmio.pbase, MMIO_SIZE, "memory mapped I/O"))
-    {
-      printk ("neofb: memory mapped IO in use\n");
-      return -EBUSY;
-    }
+	info->fix.mmio_start = pci_resource_start(dev, 1);
+	info->fix.mmio_len = MMIO_SIZE;
 
-  info->mmio.vbase = ioremap (info->mmio.pbase, MMIO_SIZE);
-  if (!info->mmio.vbase)
-    {
-      printk ("neofb: unable to map memory mapped IO\n");
-      release_mem_region (info->mmio.pbase, info->mmio.len);
-      return -ENOMEM;
-    }
-  else
-    printk (KERN_INFO "neofb: mapped io at %p\n", info->mmio.vbase);
+	if (!request_mem_region
+	    (info->fix.mmio_start, MMIO_SIZE, "memory mapped I/O")) {
+		printk("neofb: memory mapped IO in use\n");
+		return -EBUSY;
+	}
 
-  info->fb.fix.mmio_start = info->mmio.pbase;
-  info->fb.fix.mmio_len   = info->mmio.len;
+	par->mmio_vbase = ioremap(info->fix.mmio_start, MMIO_SIZE);
+	if (!par->mmio_vbase) {
+		printk("neofb: unable to map memory mapped IO\n");
+		release_mem_region(info->fix.mmio_start,
+				   info->fix.mmio_len);
+		return -ENOMEM;
+	} else
+		printk(KERN_INFO "neofb: mapped io at %p\n",
+		       par->mmio_vbase);
+	return 0;
+}
+
+static void __devinit neo_unmap_mmio(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
+
+	DBG("neo_unmap_mmio");
+
+	if (par->mmio_vbase) {
+		iounmap(par->mmio_vbase);
+		par->mmio_vbase = NULL;
 
-  return 0;
+		release_mem_region(info->fix.mmio_start,
+				   info->fix.mmio_len);
+	}
 }
 
-static void __devinit neo_unmap_mmio (struct neofb_info *info)
+static int __devinit neo_map_video(struct fb_info *info,
+				   struct pci_dev *dev, int video_len)
 {
-  DBG("neo_unmap_mmio");
+	struct neofb_par *par = (struct neofb_par *) info->par;
 
-  if (info->mmio.vbase)
-    {
-      iounmap (info->mmio.vbase);
-      info->mmio.vbase = NULL;
+	DBG("neo_map_video");
 
-      release_mem_region (info->mmio.pbase, info->mmio.len);
-    }
-}
+	info->fix.smem_start = pci_resource_start(dev, 0);
+	info->fix.smem_len = video_len;
 
-static int __devinit neo_map_video (struct neofb_info *info, int video_len)
-{
-  DBG("neo_map_video");
+	if (!request_mem_region
+	    (info->fix.smem_start, info->fix.smem_len, "frame buffer")) {
+		printk("neofb: frame buffer in use\n");
+		return -EBUSY;
+	}
 
-  info->video.pbase = pci_resource_start (info->pcidev, 0);
-  info->video.len   = video_len;
+	info->screen_base =
+	    ioremap(info->fix.smem_start, info->fix.smem_len);
+	if (!info->screen_base) {
+		printk("neofb: unable to map screen memory\n");
+		release_mem_region(info->fix.smem_start,
+				   info->fix.smem_len);
+		return -ENOMEM;
+	} else
+		printk(KERN_INFO "neofb: mapped framebuffer at %p\n",
+		       info->screen_base);
 
-  if (!request_mem_region (info->video.pbase, info->video.len, "frame buffer"))
-    {
-      printk ("neofb: frame buffer in use\n");
-      return -EBUSY;
-    }
+#ifdef CONFIG_MTRR
+	par->mtrr =
+	    mtrr_add(info->fix.smem_start, pci_resource_len(dev, 0),
+		     MTRR_TYPE_WRCOMB, 1);
+#endif
+
+	/* Clear framebuffer, it's all white in memory after boot */
+	memset(info->screen_base, 0, info->fix.smem_len);
+	return 0;
+}
 
-  info->video.vbase = ioremap (info->video.pbase, info->video.len);
-  if (!info->video.vbase)
-    {
-      printk ("neofb: unable to map screen memory\n");
-      release_mem_region (info->video.pbase, info->video.len);
-      return -ENOMEM;
-    }
-  else
-    printk (KERN_INFO "neofb: mapped framebuffer at %p\n", info->video.vbase);
+static void __devinit neo_unmap_video(struct fb_info *info)
+{
+	struct neofb_par *par = (struct neofb_par *) info->par;
 
-  info->fb.fix.smem_start = info->video.pbase;
-  info->fb.fix.smem_len   = info->video.len;
-  info->fb.screen_base    = info->video.vbase;
+	DBG("neo_unmap_video");
 
+	if (info->screen_base) {
 #ifdef CONFIG_MTRR
-  info->video.mtrr = mtrr_add (info->video.pbase, pci_resource_len (info->pcidev, 0), MTRR_TYPE_WRCOMB, 1);
+		mtrr_del(par->mtrr, info->fix.smem_start,
+			 info->fix.smem_len);
 #endif
 
-  /* Clear framebuffer, it's all white in memory after boot */
-  memset (info->video.vbase, 0, info->video.len);
+		iounmap(info->screen_base);
+		info->screen_base = NULL;
 
-  return 0;
+		release_mem_region(info->fix.smem_start,
+				   info->fix.smem_len);
+	}
 }
 
-static void __devinit neo_unmap_video (struct neofb_info *info)
+static int __devinit neo_init_hw(struct fb_info *info)
 {
-  DBG("neo_unmap_video");
+	struct neofb_par *par = (struct neofb_par *) info->par;
+	int videoRam = 896;
+	int maxClock = 65000;
+	int CursorMem = 1024;
+	int CursorOff = 0x100;
+	int linearSize = 1024;
+	int maxWidth = 1024;
+	int maxHeight = 1024;
+	unsigned char type, display;
+	int w;
 
-  if (info->video.vbase)
-    {
-#ifdef CONFIG_MTRR
-      mtrr_del (info->video.mtrr, info->video.pbase, info->video.len);
-#endif
+	DBG("neo_init_hw");
 
-      iounmap (info->video.vbase);
-      info->video.vbase = NULL;
-      info->fb.screen_base = NULL;
-
-      release_mem_region (info->video.pbase, info->video.len);
-    }
-}
-
-static int __devinit neo_init_hw (struct neofb_info *info)
-{
-  int videoRam = 896;
-  int maxClock = 65000;
-  int CursorMem = 1024;
-  int CursorOff = 0x100;
-  int linearSize = 1024;
-  int maxWidth = 1024;
-  int maxHeight = 1024;
-  unsigned char type, display;
-  int w;
-    
-  DBG("neo_init_hw");
-
-  neoUnlock();
+	neoUnlock();
 
 #if 0
-  printk (KERN_DEBUG "--- Neo extended register dump ---\n");
-  for (w=0; w<0x85; w++)
-    printk (KERN_DEBUG "CR %p: %p\n", (void*)w, (void*)VGArCR (w));
-  for (w=0; w<0xC7; w++)
-    printk (KERN_DEBUG "GR %p: %p\n", (void*)w, (void*)VGArGR (w));
-#endif
-
-  /* Determine the panel type */
-  VGAwGR(0x09,0x26);
-  type = VGArGR(0x21);
-  display = VGArGR(0x20);
-    
-  /* Determine panel width -- used in NeoValidMode. */
-  w = VGArGR(0x20);
-  VGAwGR(0x09,0x00);
-  switch ((w & 0x18) >> 3)
-    {
-    case 0x00:
-      info->NeoPanelWidth  = 640;
-      info->NeoPanelHeight = 480;
-      neofb_var = &neofb_var640x480x8;
-      break;
-    case 0x01:
-      info->NeoPanelWidth  = 800;
-      info->NeoPanelHeight = 600;
-      neofb_var = &neofb_var800x600x8;
-      break;
-    case 0x02:
-      info->NeoPanelWidth  = 1024;
-      info->NeoPanelHeight = 768;
-      neofb_var = &neofb_var1024x768x8;
-      break;
-    case 0x03:
-      /* 1280x1024 panel support needs to be added */
+	printk(KERN_DEBUG "--- Neo extended register dump ---\n");
+	for (w = 0; w < 0x85; w++)
+		printk(KERN_DEBUG "CR %p: %p\n", (void *) w,
+		       (void *) VGArCR(w));
+	for (w = 0; w < 0xC7; w++)
+		printk(KERN_DEBUG "GR %p: %p\n", (void *) w,
+		       (void *) VGArGR(w));
+#endif
+
+	/* Determine the panel type */
+	VGAwGR(0x09, 0x26);
+	type = VGArGR(0x21);
+	display = VGArGR(0x20);
+
+	/* Determine panel width -- used in NeoValidMode. */
+	w = VGArGR(0x20);
+	VGAwGR(0x09, 0x00);
+	switch ((w & 0x18) >> 3) {
+	case 0x00:
+		par->NeoPanelWidth = 640;
+		par->NeoPanelHeight = 480;
+		neofb_var = &neofb_var640x480x8;
+		break;
+	case 0x01:
+		par->NeoPanelWidth = 800;
+		par->NeoPanelHeight = 600;
+		neofb_var = &neofb_var800x600x8;
+		break;
+	case 0x02:
+		par->NeoPanelWidth = 1024;
+		par->NeoPanelHeight = 768;
+		neofb_var = &neofb_var1024x768x8;
+		break;
+	case 0x03:
+		/* 1280x1024 panel support needs to be added */
 #ifdef NOT_DONE
-      info->NeoPanelWidth  = 1280;
-      info->NeoPanelHeight = 1024;
-      neofb_var = &neofb_var1280x1024x8;
-      break;
+		par->NeoPanelWidth = 1280;
+		par->NeoPanelHeight = 1024;
+		neofb_var = &neofb_var1280x1024x8;
+		break;
 #else
-      printk (KERN_ERR "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
-      return -1;
+		printk(KERN_ERR
+		       "neofb: Only 640x480, 800x600 and 1024x768 panels are currently supported\n");
+		return -1;
 #endif
-    default:
-      info->NeoPanelWidth  = 640;
-      info->NeoPanelHeight = 480;
-      neofb_var = &neofb_var640x480x8;
-      break;
-    }
-
-  printk (KERN_INFO "Panel is a %dx%d %s %s display\n",
-	  info->NeoPanelWidth,
-	  info->NeoPanelHeight,
-	  (type & 0x02) ? "color" : "monochrome",
-	  (type & 0x10) ? "TFT" : "dual scan");
-
-  switch (info->accel)
-    {
-    case FB_ACCEL_NEOMAGIC_NM2070:
-      videoRam   = 896;
-      maxClock   = 65000;
-      CursorMem  = 2048;
-      CursorOff  = 0x100;
-      linearSize = 1024;
-      maxWidth   = 1024;
-      maxHeight  = 1024;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2090:
-    case FB_ACCEL_NEOMAGIC_NM2093:
-      videoRam   = 1152;
-      maxClock   = 80000;
-      CursorMem  = 2048;
-      CursorOff  = 0x100;
-      linearSize = 2048;
-      maxWidth   = 1024;
-      maxHeight  = 1024;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2097:
-      videoRam   = 1152;
-      maxClock   = 80000;
-      CursorMem  = 1024;
-      CursorOff  = 0x100;
-      linearSize = 2048;
-      maxWidth   = 1024;
-      maxHeight  = 1024;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2160:
-      videoRam   = 2048;
-      maxClock   = 90000;
-      CursorMem  = 1024;
-      CursorOff  = 0x100;
-      linearSize = 2048;
-      maxWidth   = 1024;
-      maxHeight  = 1024;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2200:
-      videoRam   = 2560;
-      maxClock   = 110000;
-      CursorMem  = 1024;
-      CursorOff  = 0x1000;
-      linearSize = 4096;
-      maxWidth   = 1280;
-      maxHeight  = 1024;  /* ???? */
-
-      info->neo2200 = (Neo2200*) info->mmio.vbase;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2230:
-      videoRam   = 3008;
-      maxClock   = 110000;
-      CursorMem  = 1024;
-      CursorOff  = 0x1000;
-      linearSize = 4096;
-      maxWidth   = 1280;
-      maxHeight  = 1024;  /* ???? */
-
-      info->neo2200 = (Neo2200*) info->mmio.vbase;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2360:
-      videoRam   = 4096;
-      maxClock   = 110000;
-      CursorMem  = 1024;
-      CursorOff  = 0x1000;
-      linearSize = 4096;
-      maxWidth   = 1280;
-      maxHeight  = 1024;  /* ???? */
-
-      info->neo2200 = (Neo2200*) info->mmio.vbase;
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2380:
-      videoRam   = 6144;
-      maxClock   = 110000;
-      CursorMem  = 1024;
-      CursorOff  = 0x1000;
-      linearSize = 8192;
-      maxWidth   = 1280;
-      maxHeight  = 1024;  /* ???? */
-
-      info->neo2200 = (Neo2200*) info->mmio.vbase;
-      break;
-    }
-
-  info->maxClock = maxClock;
-
-  return videoRam * 1024;
-}
-
-
-static struct neofb_info * __devinit neo_alloc_fb_info (struct pci_dev *dev,
-							const struct pci_device_id *id)
-{
-  struct neofb_info *info;
-
-  info = kmalloc (sizeof(struct neofb_info) + sizeof(struct display) +
-		  sizeof(u32) * 16, GFP_KERNEL);
-
-  if (!info)
-    return NULL;
-
-  memset (info, 0, sizeof(struct neofb_info) + sizeof(struct display));
-
-  info->fb.currcon = -1;
-  info->pcidev  = dev;
-  info->accel   = id->driver_data;
-
-  info->pci_burst   = !nopciburst;
-  info->lcd_stretch = !nostretch;
-
-  if (!internal && !external)
-    {
-      info->internal_display = 1;
-      info->external_display = 0;
-    }
-  else
-    {
-      info->internal_display = internal;
-      info->external_display = external;
-    }
-
-  switch (info->accel)
-    {
-    case FB_ACCEL_NEOMAGIC_NM2070:
-      sprintf (info->fb.fix.id, "MagicGraph 128");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2090:
-      sprintf (info->fb.fix.id, "MagicGraph 128V");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2093:
-      sprintf (info->fb.fix.id, "MagicGraph 128ZV");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2097:
-      sprintf (info->fb.fix.id, "MagicGraph 128ZV+");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2160:
-      sprintf (info->fb.fix.id, "MagicGraph 128XD");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2200:
-      sprintf (info->fb.fix.id, "MagicGraph 256AV");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2230:
-      sprintf (info->fb.fix.id, "MagicGraph 256AV+");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2360:
-      sprintf (info->fb.fix.id, "MagicGraph 256ZX");
-      break;
-    case FB_ACCEL_NEOMAGIC_NM2380:
-      sprintf (info->fb.fix.id, "MagicGraph 256XL+");
-      break;
-    }
-
-  info->fb.fix.type	   = FB_TYPE_PACKED_PIXELS;
-  info->fb.fix.type_aux	   = 0;
-  info->fb.fix.xpanstep	   = 0;
-  info->fb.fix.ypanstep	   = 4;
-  info->fb.fix.ywrapstep   = 0;
-  info->fb.fix.accel       = id->driver_data;
-
-  info->fb.var.nonstd      = 0;
-  info->fb.var.activate    = FB_ACTIVATE_NOW;
-  info->fb.var.height      = -1;
-  info->fb.var.width       = -1;
-  info->fb.var.accel_flags = 0;
-
-  strcpy (info->fb.modename, info->fb.fix.id);
-
-  info->fb.fbops          = &neofb_ops;
-  info->fb.changevar      = NULL;
-  info->fb.switch_con     = neofb_switch;
-  info->fb.updatevar      = neofb_updatevar;
-  info->fb.flags          = FBINFO_FLAG_DEFAULT;
-  info->fb.disp           = (struct display *)(info + 1);
-  info->fb.pseudo_palette = (void *)(info->fb.disp + 1);
-
-  fb_alloc_cmap (&info->fb.cmap, NR_PALETTE, 0);
-
-  return info;
-}
-
-static void __devinit neo_free_fb_info (struct neofb_info *info)
-{
-  if (info)
-    {
-      /*
-       * Free the colourmap
-       */
-      fb_alloc_cmap (&info->fb.cmap, 0, 0);
+	default:
+		par->NeoPanelWidth = 640;
+		par->NeoPanelHeight = 480;
+		neofb_var = &neofb_var640x480x8;
+		break;
+	}
+
+	printk(KERN_INFO "Panel is a %dx%d %s %s display\n",
+	       par->NeoPanelWidth,
+	       par->NeoPanelHeight,
+	       (type & 0x02) ? "color" : "monochrome",
+	       (type & 0x10) ? "TFT" : "dual scan");
+
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		videoRam = 896;
+		maxClock = 65000;
+		CursorMem = 2048;
+		CursorOff = 0x100;
+		linearSize = 1024;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+	case FB_ACCEL_NEOMAGIC_NM2093:
+		videoRam = 1152;
+		maxClock = 80000;
+		CursorMem = 2048;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2097:
+		videoRam = 1152;
+		maxClock = 80000;
+		CursorMem = 1024;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		videoRam = 2048;
+		maxClock = 90000;
+		CursorMem = 1024;
+		CursorOff = 0x100;
+		linearSize = 2048;
+		maxWidth = 1024;
+		maxHeight = 1024;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+		videoRam = 2560;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2230:
+		videoRam = 3008;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2360:
+		videoRam = 4096;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 4096;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 *) par->mmio_vbase;
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		videoRam = 6144;
+		maxClock = 110000;
+		CursorMem = 1024;
+		CursorOff = 0x1000;
+		linearSize = 8192;
+		maxWidth = 1280;
+		maxHeight = 1024;	/* ???? */
+
+		par->neo2200 = (Neo2200 *) par->mmio_vbase;
+		break;
+	}
+
+	par->maxClock = maxClock;
 
-      kfree (info);
-    }
+	return videoRam * 1024;
+}
+
+
+static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const struct
+						   pci_device_id *id)
+{
+	struct fb_info *info;
+	struct neofb_par *par;
+
+	info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
+		       sizeof(u32) * 16, GFP_KERNEL);
+
+	if (!info)
+		return NULL;
+
+	memset(info, 0, sizeof(struct fb_info) + sizeof(struct display));
+
+	par = &default_par;
+	memset(par, 0, sizeof(struct neofb_par));
+
+	info->currcon = -1;
+	info->fix.accel = id->driver_data;
+
+	par->pci_burst = !nopciburst;
+	par->lcd_stretch = !nostretch;
+
+	if (!internal && !external) {
+		par->internal_display = 1;
+		par->external_display = 0;
+	} else {
+		par->internal_display = internal;
+		par->external_display = external;
+	}
+
+	switch (info->fix.accel) {
+	case FB_ACCEL_NEOMAGIC_NM2070:
+		sprintf(info->fix.id, "MagicGraph 128");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2090:
+		sprintf(info->fix.id, "MagicGraph 128V");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2093:
+		sprintf(info->fix.id, "MagicGraph 128ZV");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2097:
+		sprintf(info->fix.id, "MagicGraph 128ZV+");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2160:
+		sprintf(info->fix.id, "MagicGraph 128XD");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2200:
+		sprintf(info->fix.id, "MagicGraph 256AV");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2230:
+		sprintf(info->fix.id, "MagicGraph 256AV+");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2360:
+		sprintf(info->fix.id, "MagicGraph 256ZX");
+		break;
+	case FB_ACCEL_NEOMAGIC_NM2380:
+		sprintf(info->fix.id, "MagicGraph 256XL+");
+		break;
+	}
+
+	info->fix.type = FB_TYPE_PACKED_PIXELS;
+	info->fix.type_aux = 0;
+	info->fix.xpanstep = 0;
+	info->fix.ypanstep = 4;
+	info->fix.ywrapstep = 0;
+	info->fix.accel = id->driver_data;
+
+	info->var.nonstd = 0;
+	info->var.activate = FB_ACTIVATE_NOW;
+	info->var.height = -1;
+	info->var.width = -1;
+	info->var.accel_flags = 0;
+
+	strcpy(info->modename, info->fix.id);
+
+	info->fbops = &neofb_ops;
+	info->changevar = NULL;
+	info->switch_con = gen_switch;
+	info->updatevar = gen_update_var;
+	info->flags = FBINFO_FLAG_DEFAULT;
+	info->par = par;
+	info->disp = (struct display *) (info + 1);
+	info->pseudo_palette = (void *) (info->disp + 1);
+
+	fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
+
+	return info;
+}
+
+static void __devinit neo_free_fb_info(struct fb_info *info)
+{
+	if (info) {
+		/*
+		 * Free the colourmap
+		 */
+		fb_alloc_cmap(&info->cmap, 0, 0);
+
+		kfree(info);
+	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static int __devinit neofb_probe (struct pci_dev* dev, const struct pci_device_id* id)
+static int __devinit neofb_probe(struct pci_dev *dev,
+				 const struct pci_device_id *id)
 {
-  struct neofb_info *info;
-  u_int h_sync, v_sync;
-  int err;
-  int video_len;
-
-  DBG("neofb_probe");
-
-  err = pci_enable_device (dev);
-  if (err)
-    return err;
-
-  err = -ENOMEM;
-  info = neo_alloc_fb_info (dev, id);
-  if (!info)
-    goto failed;
-
-  err = neo_map_mmio (info);
-  if (err)
-    goto failed;
-
-  video_len = neo_init_hw (info);
-  if (video_len < 0)
-    {
-      err = video_len;
-      goto failed;
-    }
-
-  err = neo_map_video (info, video_len);
-  if (err)
-    goto failed;
-
-  neofb_set_var (neofb_var, -1, &info->fb);
-
-  /*
-   * Calculate the hsync and vsync frequencies.  Note that
-   * we split the 1e12 constant up so that we can preserve
-   * the precision and fit the results into 32-bit registers.
-   *  (1953125000 * 512 = 1e12)
-   */
-  h_sync = 1953125000 / info->fb.var.pixclock;
-  h_sync = h_sync * 512 / (info->fb.var.xres + info->fb.var.left_margin +
-			   info->fb.var.right_margin + info->fb.var.hsync_len);
-  v_sync = h_sync / (info->fb.var.yres + info->fb.var.upper_margin +
-		     info->fb.var.lower_margin + info->fb.var.vsync_len);
-
-  printk(KERN_INFO "neofb v" NEOFB_VERSION ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
-	 info->fb.fix.smem_len >> 10,
-	 info->fb.var.xres, info->fb.var.yres,
-	 h_sync / 1000, h_sync % 1000, v_sync);
-
-
-  err = register_framebuffer (&info->fb);
-  if (err < 0)
-    goto failed;
-
-  printk (KERN_INFO "fb%d: %s frame buffer device\n",
-	  GET_FB_IDX(info->fb.node), info->fb.modename);
-
-  /*
-   * Our driver data
-   */
-  dev->driver_data = info;
-
-  return 0;
-
-failed:
-  neo_unmap_video (info);
-  neo_unmap_mmio (info);
-  neo_free_fb_info (info);
-
-  return err;
-}
-
-static void __devexit neofb_remove (struct pci_dev *dev)
-{
-  struct neofb_info *info = (struct neofb_info *)dev->driver_data;
-
-  DBG("neofb_remove");
-
-  if (info)
-    {
-      /*
-       * If unregister_framebuffer fails, then
-       * we will be leaving hooks that could cause
-       * oopsen laying around.
-       */
-      if (unregister_framebuffer (&info->fb))
-	printk (KERN_WARNING "neofb: danger danger!  Oopsen imminent!\n");
-
-      neo_unmap_video (info);
-      neo_unmap_mmio (info);
-      neo_free_fb_info (info);
-
-      /*
-       * Ensure that the driver data is no longer
-       * valid.
-       */
-      dev->driver_data = NULL;
-    }
+	struct fb_info *info;
+	u_int h_sync, v_sync;
+	int err;
+	int video_len;
+
+	DBG("neofb_probe");
+
+	err = pci_enable_device(dev);
+	if (err)
+		return err;
+
+	err = -ENOMEM;
+	info = neo_alloc_fb_info(dev, id);
+	if (!info)
+		goto failed;
+
+	err = neo_map_mmio(info, dev);
+	if (err)
+		goto failed;
+
+	video_len = neo_init_hw(info);
+	if (video_len < 0) {
+		err = video_len;
+		goto failed;
+	}
+
+	err = neo_map_video(info, dev, video_len);
+	if (err)
+		goto failed;
+
+	gen_set_var(neofb_var, -1, info);
+
+	/*
+	 * Calculate the hsync and vsync frequencies.  Note that
+	 * we split the 1e12 constant up so that we can preserve
+	 * the precision and fit the results into 32-bit registers.
+	 *  (1953125000 * 512 = 1e12)
+	 */
+	h_sync = 1953125000 / info->var.pixclock;
+	h_sync =
+	    h_sync * 512 / (info->var.xres + info->var.left_margin +
+			    info->var.right_margin + info->var.hsync_len);
+	v_sync =
+	    h_sync / (info->var.yres + info->var.upper_margin +
+		      info->var.lower_margin + info->var.vsync_len);
+
+	printk(KERN_INFO "neofb v" NEOFB_VERSION
+	       ": %dkB VRAM, using %dx%d, %d.%03dkHz, %dHz\n",
+	       info->fix.smem_len >> 10, info->var.xres,
+	       info->var.yres, h_sync / 1000, h_sync % 1000, v_sync);
+
+
+	err = register_framebuffer(info);
+	if (err < 0)
+		goto failed;
+
+	printk(KERN_INFO "fb%d: %s frame buffer device\n",
+	       GET_FB_IDX(info->node), info->modename);
+
+	/*
+	 * Our driver data
+	 */
+	dev->driver_data = info;
+
+	return 0;
+
+      failed:
+	neo_unmap_video(info);
+	neo_unmap_mmio(info);
+	neo_free_fb_info(info);
+
+	return err;
+}
+
+static void __devexit neofb_remove(struct pci_dev *dev)
+{
+	struct fb_info *info = (struct fb_info *) dev->driver_data;
+
+	DBG("neofb_remove");
+
+	if (info) {
+		/*
+		 * If unregister_framebuffer fails, then
+		 * we will be leaving hooks that could cause
+		 * oopsen laying around.
+		 */
+		if (unregister_framebuffer(info))
+			printk(KERN_WARNING
+			       "neofb: danger danger!  Oopsen imminent!\n");
+
+		neo_unmap_video(info);
+		neo_unmap_mmio(info);
+		neo_free_fb_info(info);
+
+		/*
+		 * Ensure that the driver data is no longer
+		 * valid.
+		 */
+		dev->driver_data = NULL;
+	}
 }
 
 static struct pci_device_id neofb_devices[] __devinitdata = {
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2070,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2070},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2090,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2090},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2093,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2093},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2097,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2097},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2160,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2160},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2200,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2200},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2230,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2230},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2360,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2360},
 
-  {PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
-   PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
+	{PCI_VENDOR_ID_NEOMAGIC, PCI_CHIP_NM2380,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, FB_ACCEL_NEOMAGIC_NM2380},
 
-  {0, 0, 0, 0, 0, 0, 0}
+	{0, 0, 0, 0, 0, 0, 0}
 };
 
 MODULE_DEVICE_TABLE(pci, neofb_devices);
 
 static struct pci_driver neofb_driver = {
-  name:      "neofb",
-  id_table:  neofb_devices,
-  probe:     neofb_probe,
-  remove:    __devexit_p(neofb_remove)
+	name:		"neofb",
+	id_table:	neofb_devices,
+	probe:		neofb_probe,
+	remove:		__devexit_p(neofb_remove)
 };
 
 /* **************************** init-time only **************************** */
 
-static void __init neo_init (void)
+static void __init neo_init(void)
 {
-  DBG("neo_init");
-  pci_register_driver (&neofb_driver);
+	DBG("neo_init");
+	pci_register_driver(&neofb_driver);
 }
 
 /* **************************** exit-time only **************************** */
 
-static void __exit neo_done (void)
+static void __exit neo_done(void)
 {
-  DBG("neo_done");
-  pci_unregister_driver (&neofb_driver);
+	DBG("neo_done");
+	pci_unregister_driver(&neofb_driver);
 }
 
 
@@ -2290,51 +2016,50 @@
 
 /* ************************* init in-kernel code ************************** */
 
-int __init neofb_setup (char *options)
+int __init neofb_setup(char *options)
 {
-  char *this_opt;
+	char *this_opt;
 
-  DBG("neofb_setup");
+	DBG("neofb_setup");
 
-  if (!options || !*options)
-    return 0;
+	if (!options || !*options)
+		return 0;
 
-  while ((this_opt = strsep(&options,",")) != NULL)
-    {
-      if (!*this_opt) continue;
-
-      if (!strncmp(this_opt, "disabled", 8))
-	disabled = 1;
-      if (!strncmp(this_opt, "internal", 8))
-	internal = 1;
-      if (!strncmp(this_opt, "external", 8))
-	external = 1;
-      if (!strncmp(this_opt, "nostretch", 9))
-	nostretch = 1;
-      if (!strncmp(this_opt, "nopciburst", 10))
-	nopciburst = 1;
-    }
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+
+		if (!strncmp(this_opt, "disabled", 8))
+			disabled = 1;
+		if (!strncmp(this_opt, "internal", 8))
+			internal = 1;
+		if (!strncmp(this_opt, "external", 8))
+			external = 1;
+		if (!strncmp(this_opt, "nostretch", 9))
+			nostretch = 1;
+		if (!strncmp(this_opt, "nopciburst", 10))
+			nopciburst = 1;
+	}
 
-  return 0;
+	return 0;
 }
 
-static int __init initialized = 0;
+static int __initdata initialized = 0;
 
 int __init neofb_init(void)
 {
-  DBG("neofb_init");
+	DBG("neofb_init");
 
-  if (disabled)
-    return -ENXIO;
+	if (disabled)
+		return -ENXIO;
 
-  if (!initialized)
-    {
-      initialized = 1;
-      neo_init();
-    }
+	if (!initialized) {
+		initialized = 1;
+		neo_init();
+	}
 
-  /* never return failure, user can hotplug card later... */
-  return 0;
+	/* never return failure, user can hotplug card later... */
+	return 0;
 }
 
 #else
@@ -2343,17 +2068,17 @@
 
 int __init init_module(void)
 {
-  DBG("init_module");
+	DBG("init_module");
 
-  if (disabled)
-    return -ENXIO;
+	if (disabled)
+		return -ENXIO;
 
-  neo_init();
+	neo_init();
 
-  /* never return failure; user can hotplug card later... */
-  return 0;
+	/* never return failure; user can hotplug card later... */
+	return 0;
 }
 
-#endif	/* MODULE */
+#endif				/* MODULE */
 
 module_exit(neo_done);
diff -Nru a/drivers/video/neofb.h b/drivers/video/neofb.h
--- a/drivers/video/neofb.h	Sat Jun  8 22:31:49 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,291 +0,0 @@
-/*
- * linux/drivers/video/neofb.h -- NeoMagic Framebuffer Driver
- *
- * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
- *
- * 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.
- */
-
-
-#ifdef NEOFB_DEBUG
-# define DBG(x)		printk (KERN_DEBUG "neofb: %s\n", (x));
-#else
-# define DBG(x)
-#endif
-
-
-#define PCI_CHIP_NM2070 0x0001
-#define PCI_CHIP_NM2090 0x0002
-#define PCI_CHIP_NM2093 0x0003
-#define PCI_CHIP_NM2097 0x0083
-#define PCI_CHIP_NM2160 0x0004
-#define PCI_CHIP_NM2200 0x0005
-#define PCI_CHIP_NM2230 0x0025
-#define PCI_CHIP_NM2360 0x0006
-#define PCI_CHIP_NM2380 0x0016
-
-
-struct xtimings {
-  unsigned int pixclock;
-  unsigned int HDisplay;
-  unsigned int HSyncStart;
-  unsigned int HSyncEnd;
-  unsigned int HTotal;
-  unsigned int VDisplay;
-  unsigned int VSyncStart;
-  unsigned int VSyncEnd;
-  unsigned int VTotal;
-  unsigned int sync;
-  int	       dblscan;
-  int	       interlaced;
-};
-
-
-/* --------------------------------------------------------------------- */
-
-typedef volatile struct {
-  __u32 bltStat;
-  __u32 bltCntl;
-  __u32 xpColor;
-  __u32 fgColor;
-  __u32 bgColor;
-  __u32 pitch;
-  __u32 clipLT;
-  __u32 clipRB;
-  __u32 srcBitOffset;
-  __u32 srcStart;
-  __u32 reserved0;
-  __u32 dstStart;
-  __u32 xyExt;
-
-  __u32 reserved1[19];
-
-  __u32 pageCntl;
-  __u32 pageBase;
-  __u32 postBase;
-  __u32 postPtr;
-  __u32 dataPtr;
-} Neo2200;
-
-#define NR_PALETTE	256
-
-#define MMIO_SIZE 0x200000
-
-#define NEO_EXT_CR_MAX 0x85
-#define NEO_EXT_GR_MAX 0xC7
-
-struct neofb_par {
-
-  int depth;
-
-  unsigned char MiscOutReg;     /* Misc */
-  unsigned char CRTC[25];       /* Crtc Controller */
-  unsigned char Sequencer[5];   /* Video Sequencer */
-  unsigned char Graphics[9];    /* Video Graphics */
-  unsigned char Attribute[21];  /* Video Atribute */
-
-  unsigned char GeneralLockReg;
-  unsigned char ExtCRTDispAddr;
-  unsigned char ExtCRTOffset;
-  unsigned char SysIfaceCntl1;
-  unsigned char SysIfaceCntl2;
-  unsigned char ExtColorModeSelect;
-  unsigned char biosMode;
-
-  unsigned char PanelDispCntlReg1;
-  unsigned char PanelDispCntlReg2;
-  unsigned char PanelDispCntlReg3;
-  unsigned char PanelVertCenterReg1;
-  unsigned char PanelVertCenterReg2;
-  unsigned char PanelVertCenterReg3;
-  unsigned char PanelVertCenterReg4;
-  unsigned char PanelVertCenterReg5;
-  unsigned char PanelHorizCenterReg1;
-  unsigned char PanelHorizCenterReg2;
-  unsigned char PanelHorizCenterReg3;
-  unsigned char PanelHorizCenterReg4;
-  unsigned char PanelHorizCenterReg5;
-
-  int           ProgramVCLK;
-  unsigned char VCLK3NumeratorLow;
-  unsigned char VCLK3NumeratorHigh;
-  unsigned char VCLK3Denominator;
-  unsigned char VerticalExt;
-};
-
-struct neofb_info {
-
-  struct fb_info  fb;
-  struct display_switch	*dispsw;
-
-  struct pci_dev *pcidev;
-  int   accel;
-  char *name;
-
-  struct {
-    u8    *vbase;
-    u32    pbase;
-    u32    len;
-#ifdef CONFIG_MTRR
-    int    mtrr;
-#endif
-  } video;
-
-  struct {
-    u8    *vbase;
-    u32    pbase;
-    u32    len;
-  } mmio;
-
-  Neo2200 *neo2200;
-
-  /* Panels size */
-  int NeoPanelWidth;
-  int NeoPanelHeight;
-
-  int maxClock;
-
-  int pci_burst;
-  int lcd_stretch;
-  int internal_display;
-  int external_display;
-
-  struct {
-    u16 red, green, blue, transp;
-  } palette[NR_PALETTE];
-};
-
-
-typedef struct {
-    int x_res;
-    int y_res;
-    int mode;
-} biosMode;
-
-
-/* vga IO functions */
-static inline u8 VGArCR (u8 index)
-{
-  outb (index, 0x3d4);
-  return inb (0x3d5);
-}
-
-static inline void VGAwCR (u8 index, u8 val)
-{
-  outb (index, 0x3d4);
-  outb (val, 0x3d5);
-}
-
-static inline u8 VGArGR (u8 index)
-{
-  outb (index, 0x3ce);
-  return inb (0x3cf);
-}
-
-static inline void VGAwGR (u8 index, u8 val)
-{
-  outb (index, 0x3ce);
-  outb (val, 0x3cf);
-}
-
-static inline u8 VGArSEQ (u8 index)
-{
-  outb (index, 0x3c4);
-  return inb (0x3c5);
-}
-
-static inline void VGAwSEQ (u8 index, u8 val)
-{
-  outb (index, 0x3c4);
-  outb (val, 0x3c5);
-}
-
-
-static int paletteEnabled = 0;
-
-static inline void VGAenablePalette (void)
-{
-  u8 tmp;
-
-  tmp = inb (0x3da);
-  outb (0x00, 0x3c0);
-  paletteEnabled = 1;
-}
-
-static inline void VGAdisablePalette (void)
-{
-  u8 tmp;
-
-  tmp = inb (0x3da);
-  outb (0x20, 0x3c0);
-  paletteEnabled = 0;
-}
-
-static inline void VGAwATTR (u8 index, u8 value)
-{
-  u8 tmp;
-
-  if (paletteEnabled)
-    index &= ~0x20;
-  else
-    index |= 0x20;
-
-  tmp = inb (0x3da);
-  outb (index, 0x3c0);
-  outb (value, 0x3c0);
-}
-
-static inline void VGAwMISC (u8 value)
-{
-  outb (value, 0x3c2);
-}
-
-
-#define NEO_BS0_BLT_BUSY        0x00000001
-#define NEO_BS0_FIFO_AVAIL      0x00000002
-#define NEO_BS0_FIFO_PEND       0x00000004
-
-#define NEO_BC0_DST_Y_DEC       0x00000001
-#define NEO_BC0_X_DEC           0x00000002
-#define NEO_BC0_SRC_TRANS       0x00000004
-#define NEO_BC0_SRC_IS_FG       0x00000008
-#define NEO_BC0_SRC_Y_DEC       0x00000010
-#define NEO_BC0_FILL_PAT        0x00000020
-#define NEO_BC0_SRC_MONO        0x00000040
-#define NEO_BC0_SYS_TO_VID      0x00000080
-
-#define NEO_BC1_DEPTH8          0x00000100
-#define NEO_BC1_DEPTH16         0x00000200
-#define NEO_BC1_X_320           0x00000400
-#define NEO_BC1_X_640           0x00000800
-#define NEO_BC1_X_800           0x00000c00
-#define NEO_BC1_X_1024          0x00001000
-#define NEO_BC1_X_1152          0x00001400
-#define NEO_BC1_X_1280          0x00001800
-#define NEO_BC1_X_1600          0x00001c00
-#define NEO_BC1_DST_TRANS       0x00002000
-#define NEO_BC1_MSTR_BLT        0x00004000
-#define NEO_BC1_FILTER_Z        0x00008000
-
-#define NEO_BC2_WR_TR_DST       0x00800000
-
-#define NEO_BC3_SRC_XY_ADDR     0x01000000
-#define NEO_BC3_DST_XY_ADDR     0x02000000
-#define NEO_BC3_CLIP_ON         0x04000000
-#define NEO_BC3_FIFO_EN         0x08000000
-#define NEO_BC3_BLT_ON_ADDR     0x10000000
-#define NEO_BC3_SKIP_MAPPING    0x80000000
-
-#define NEO_MODE1_DEPTH8        0x0100
-#define NEO_MODE1_DEPTH16       0x0200
-#define NEO_MODE1_DEPTH24       0x0300
-#define NEO_MODE1_X_320         0x0400
-#define NEO_MODE1_X_640         0x0800
-#define NEO_MODE1_X_800         0x0c00
-#define NEO_MODE1_X_1024        0x1000
-#define NEO_MODE1_X_1152        0x1400
-#define NEO_MODE1_X_1280        0x1800
-#define NEO_MODE1_X_1600        0x1c00
-#define NEO_MODE1_BLT_ON_ADDR   0x2000
diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
--- a/drivers/video/pm2fb.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/video/pm2fb.c	Sat Jun  8 22:31:52 2002
@@ -1,10 +1,19 @@
 /*
  * Permedia2 framebuffer driver.
- * Copyright (c) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
  * Copyright (c) 1999 Jakub Jelinek (jakub@redhat.com)
  * Based on linux/drivers/video/skeletonfb.c by Geert Uytterhoeven.
  * --------------------------------------------------------------------------
- * $Id: pm2fb.c,v 1.163 1999/02/21 14:06:49 illo Exp $
+ * $Id: pm2fb.c,v 1.213 2000/09/19 01:03:19 illo Exp $
+ * --------------------------------------------------------------------------
+ * History:
+ *  1999/05/09 added Jim Hague's 'var' kernel option (thanks Jim!)
+ *  2002/04/23 Jim Hague <jim.hague@acm.org>
+ *	* Integrated Illo's last changes, No changelist available.
+ *	  Major items: acceleration support, hardware cursor code
+ *	  (not yet enabled).
+ *	* Fixed -vsync, added lowhsync/lowvsync overrides for use with
+ *	  XFree GLINT driver.
  * --------------------------------------------------------------------------
  * TODO multiple boards support
  * --------------------------------------------------------------------------
@@ -67,6 +76,9 @@
 #define DPRINTK(a,b...)
 #endif 
 
+#define PICOS2KHZ(a) (1000000000UL/(a))
+#define KHZ2PICOS(a) (1000000000UL/(a))
+
 /*
  * The _DEFINITIVE_ memory mapping/unmapping functions.
  * This is due to the fact that they're changing soooo often...
@@ -78,9 +90,15 @@
  * The _DEFINITIVE_ memory i/o barrier functions.
  * This is due to the fact that they're changing soooo often...
  */
+#ifdef __mc68000__
+#define DEFW()
+#define DEFR()
+#define DEFRW()	
+#else
 #define DEFW()		wmb()
 #define DEFR()		rmb()
 #define DEFRW()		mb()
+#endif
 
 #ifndef MIN
 #define MIN(a,b) ((a)<(b)?(a):(b))
@@ -90,6 +108,10 @@
 #define MAX(a,b) ((a)>(b)?(a):(b))
 #endif
 
+#define VIDEO_MASK	0x00011e7f	/* r/w values for VIDEO_CONTROL */
+
+#define PM2FF_ACCEL		(1L<<0)
+
 struct pm2fb_par {
 	u32 pixclock;		/* pixclock in KHz */
 	u32 width;		/* width of virtual screen */
@@ -106,12 +128,17 @@
 	u32 base;		/* screen base (xoffset+yoffset) */
 	u32 depth;		/* screen depth (8, 16, 24 or 32) */
 	u32 video;		/* video control (hsync,vsync) */
+	u32 flags;		/* internal flags (PM2FF_xxxx) */
 };
 
 #define OPTF_OLD_MEM		(1L<<0)
 #define OPTF_YPAN		(1L<<1)
 #define OPTF_VIRTUAL		(1L<<2)
 #define OPTF_USER		(1L<<3)
+#define OPTF_USER_VAR		(1L<<4)
+#define	OPTF_LOW_HSYNC		(1L<<5)
+#define	OPTF_LOW_VSYNC		(1L<<6)
+
 static struct {
 	char font[40];
 	u32 flags;
@@ -126,70 +153,76 @@
 
 static char curblink __initdata = 1;
 
-static struct {
+static struct fb_var_screeninfo user_var __initdata={0,};
+
+#define DEFAULT_USER_MODE	0
+
+static const struct {
 	char name[16];
 	struct pm2fb_par par;
 } user_mode[] __initdata = {
 	{"640x480-60",
-		{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121}},
+		{25174,640,480,4,28,40,199,9,11,45,524,80,0,8,121,PM2FF_ACCEL}},
 	{"640x480-72",
-		{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121}},
+		{31199,640,480,6,16,48,207,8,10,39,518,80,0,8,121,PM2FF_ACCEL}},
 	{"640x480-75",
-		{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121}},
+		{31499,640,480,4,20,50,209,0,3,20,499,80,0,8,121,PM2FF_ACCEL}},
 	{"640x480-90",
-		{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121}},
+		{39909,640,480,8,18,48,207,24,38,53,532,80,0,8,121,PM2FF_ACCEL}},
 	{"640x480-100",
-		{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121}},
+		{44899,640,480,8,40,52,211,21,33,51,530,80,0,8,121,PM2FF_ACCEL}},
 	{"800x600-56",
-		{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41}},
+		{35999,800,600,6,24,56,255,0,2,25,624,100,0,8,41,PM2FF_ACCEL}},
 	{"800x600-60",
-		{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41}},
+		{40000,800,600,10,42,64,263,0,4,28,627,100,0,8,41,PM2FF_ACCEL}},
 	{"800x600-70",
-		{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105}},
+		{44899,800,600,6,42,52,251,8,20,36,635,100,0,8,105,PM2FF_ACCEL}},
 	{"800x600-72",
-		{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41}},
+		{50000,800,600,14,44,60,259,36,42,66,665,100,0,8,41,PM2FF_ACCEL}},
 	{"800x600-75",
-		{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41}},
+		{49497,800,600,4,24,64,263,0,3,25,624,100,0,8,41,PM2FF_ACCEL}},
 	{"800x600-90",
-		{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41}},
+		{56637,800,600,2,18,48,247,7,18,35,634,100,0,8,41,PM2FF_ACCEL}},
 	{"800x600-100",
-		{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41}},
+		{67499,800,600,0,16,70,269,6,10,25,624,100,0,8,41,PM2FF_ACCEL}},
 	{"1024x768-60",
-		{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121}},
+		{64998,1024,768,6,40,80,335,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
 	{"1024x768-70",
-		{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121}},
+		{74996,1024,768,6,40,76,331,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
 	{"1024x768-72",
-		{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121}},
+		{74996,1024,768,6,40,66,321,2,8,38,805,128,0,8,121,PM2FF_ACCEL}},
 	{"1024x768-75",
-		{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41}},
+		{78932,1024,768,4,28,72,327,0,3,32,799,128,0,8,41,PM2FF_ACCEL}},
 	{"1024x768-90",
-		{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121}},
+		{100000,1024,768,0,24,72,327,20,35,77,844,128,0,8,121,PM2FF_ACCEL}},
 	{"1024x768-100",
-		{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121}},
+		{109998,1024,768,0,22,92,347,0,7,24,791,128,0,8,121,PM2FF_ACCEL}},
 	{"1024x768-illo",
-		{120322,1024,768,12,48,120,375,3,7,32,799,128,0,8,41}},
+		{120336,1024,768,12,48,120,375,3,7,32,799,128,0,8,41,PM2FF_ACCEL}},
 	{"1152x864-60",
-		{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41}},
+		{80000,1152,864,16,44,76,363,5,10,52,915,144,0,8,41,PM2FF_ACCEL}},
 	{"1152x864-70",
-		{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41}},
+		{100000,1152,864,10,48,90,377,12,23,81,944,144,0,8,41,PM2FF_ACCEL}},
 	{"1152x864-75",
-		{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41}},
+		{109998,1152,864,6,42,78,365,44,52,138,1001,144,0,8,41,PM2FF_ACCEL}},
 	{"1152x864-80",
-		{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41}},
+		{109998,1152,864,4,32,72,359,29,36,94,957,144,0,8,41,PM2FF_ACCEL}},
+        {"1152x900-66-sun",
+                {92940,1152,900,16,80,176,751,1,5,37,936,288,0,16,121,PM2FF_ACCEL}},
 	{"1280x1024-60",
-		{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41}},
+		{107991,1280,1024,12,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL}},
 	{"1280x1024-70",
-		{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41}},
+		{125992,1280,1024,20,48,102,421,0,5,42,1065,160,0,8,41,PM2FF_ACCEL}},
 	{"1280x1024-74",
-		{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41}},
+		{134989,1280,1024,8,44,108,427,0,29,40,1063,160,0,8,41,PM2FF_ACCEL}},
 	{"1280x1024-75",
-		{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41}},
+		{134989,1280,1024,4,40,102,421,0,3,42,1065,160,0,8,41,PM2FF_ACCEL}},
 	{"1600x1200-60",
-		{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121}},
+		{155981,1600,1200,8,48,112,511,9,17,70,1269,200,0,8,121,PM2FF_ACCEL}},
 	{"1600x1200-66",
-		{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121}},
+		{171998,1600,1200,10,44,120,519,2,5,53,1252,200,0,8,121,PM2FF_ACCEL}},
 	{"1600x1200-76",
-		{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121}},
+		{197980,1600,1200,10,44,120,519,2,7,50,1249,200,0,8,121,PM2FF_ACCEL}},
 	{"\0", },
 };
 
@@ -225,7 +258,7 @@
 	struct fb_info_gen gen;
 	int board;			/* Permedia2 board index (see
 					   board_table[] below) */
-	pm2type_t type;
+	pm2type_t type;			/* Permedia2 board type */
 	struct {
 		unsigned long  fb_base;	/* physical framebuffer memory base */
 		u32 fb_size;		/* framebuffer memory size */
@@ -248,6 +281,7 @@
 	} board_par;
 	struct pm2fb_par current_par;	/* displayed screen */
 	int current_par_valid;
+	int is_blank;
 	u32 memclock;			/* memclock (set by the per-board
 					   		init routine) */
 	struct display disp;
@@ -360,9 +394,6 @@
 static int pm2fb_getcolreg(unsigned regno,
 			unsigned* red, unsigned* green, unsigned* blue,
 				unsigned* transp, struct fb_info* info);
-static int pm2fb_setcolreg(unsigned regno,
-			unsigned red, unsigned green, unsigned blue,
-				unsigned transp, struct fb_info* info);
 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info);
 static int pm2fb_pan_display(const struct fb_var_screeninfo* var,
 					struct fb_info_gen* info);
@@ -376,15 +407,20 @@
 	pm2fb_blank, pm2fb_set_disp
 };
 
+
+static int pm2fb_setcolreg(unsigned regno,
+			unsigned red, unsigned green, unsigned blue,
+				unsigned transp, struct fb_info* info);
+
 static struct fb_ops pm2fb_ops={
 	owner:		THIS_MODULE,
 	fb_get_fix:	fbgen_get_fix,
 	fb_get_var:	fbgen_get_var,
 	fb_set_var:	fbgen_set_var,
 	fb_get_cmap:	fbgen_get_cmap,
-	fb_set_cmap:	gen_set_cmap,
-	fb_setcolreg:	pm2fb_setcolreg,
+	fb_set_cmap:	fbgen_set_cmap,
 	fb_pan_display:	fbgen_pan_display,
+	fb_setcolreg:	pm2fb_setcolreg,
 	fb_blank:	fbgen_blank,
 };
 
@@ -394,12 +430,12 @@
 
 inline static u32 RD32(unsigned char* base, s32 off) {
 
-	return readl(base+off);
+	return fb_readl(base+off);
 }
 
 inline static void WR32(unsigned char* base, s32 off, u32 v) {
 
-	writel(v, base+off);
+	fb_writel(v, base+off);
 }
 
 inline static u32 pm2_RD(struct pm2fb_info* p, s32 off) {
@@ -520,7 +556,7 @@
 }
 
 static void pm2_mnp(u32 clk, unsigned char* mm, unsigned char* nn,
-		unsigned char* pp) {
+		    unsigned char* pp) {
 	unsigned char m;
 	unsigned char n;
 	unsigned char p;
@@ -608,7 +644,7 @@
 	switch (info->type) {
 	case PM2_TYPE_PERMEDIA2:
 		pm2_mnp(clk, &m, &n, &p);
-		WAIT_FIFO(info, 10);
+		WAIT_FIFO(info, 8);
 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A3, 0);
 		DEFW();
 		pm2_RDAC_WR(info, PM2I_RD_PIXEL_CLOCK_A1, m);
@@ -618,13 +654,16 @@
 		DEFW();
 		pm2_RDAC_RD(info, PM2I_RD_PIXEL_CLOCK_STATUS);
 		DEFR();
-		for (i=256; i &&
-		     !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED); i--);
+		for (i=256;
+		     i && !(pm2_RD(info, PM2R_RD_INDEXED_DATA)&PM2F_PLL_LOCKED);
+		     i--)
+		    ;
 		break;
 	case PM2_TYPE_PERMEDIA2V:
 		pm2v_mnp(clk/2, &m, &n, &p);
 		WAIT_FIFO(info, 8);
-		pm2_WR(info, PM2VR_RD_INDEX_HIGH, PM2VI_RD_CLK0_PRESCALE >> 8);
+		pm2_WR(info, PM2VR_RD_INDEX_HIGH,
+		       PM2VI_RD_CLK0_PRESCALE >> 8);
 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_PRESCALE, m);
 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_FEEDBACK, n);
 		pm2v_RDAC_WR(info, PM2VI_RD_CLK0_POSTSCALE, p);
@@ -662,7 +701,7 @@
 
 static void set_aperture(struct pm2fb_info* i, struct pm2fb_par* p) {
 
-	WAIT_FIFO(i, 2);
+	WAIT_FIFO(i, 4);
 #ifdef __LITTLE_ENDIAN
 	pm2_WR(i, PM2R_APERTURE_ONE, 0);
 	pm2_WR(i, PM2R_APERTURE_TWO, 0);
@@ -685,13 +724,113 @@
 #endif
 }
 
+static void set_video(struct pm2fb_info* i, u32 video) {
+	u32 tmp;
+	u32 vsync;
+
+	vsync=video;
+	
+	/*
+	 * The hardware cursor needs +vsync to recognise vert retrace.
+	 * We may not be using the hardware cursor, but the X Glint
+	 * driver may well. So always set +hsync/+vsync and then set
+	 * the RAMDAC to invert the sync if necessary.
+	 */
+	vsync&=~(PM2F_HSYNC_MASK|PM2F_VSYNC_MASK);
+	vsync|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+
+	WAIT_FIFO(i, 5);
+	pm2_WR(i, PM2R_VIDEO_CONTROL, vsync);
+
+	switch (i->type) {
+		case PM2_TYPE_PERMEDIA2:
+			tmp = PM2F_RD_PALETTE_WIDTH_8;
+			if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
+				tmp |= 4; /* invert hsync */
+			if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
+				tmp |= 8; /* invert vsync */
+			pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
+			break;
+		case PM2_TYPE_PERMEDIA2V:
+			tmp = 0;
+			if ((video & PM2F_HSYNC_MASK) == PM2F_HSYNC_ACT_LOW)
+				tmp |= 1; /* invert hsync */
+			if ((video & PM2F_VSYNC_MASK) == PM2F_VSYNC_ACT_LOW)
+				tmp |= 4; /* invert vsync */
+			pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
+			pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
+			break;
+	}
+}
+
+static void get_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
+	u32 clrmode;
+	u32 readpx;
+	u32 misc;
+
+	memset(p, 0, sizeof(struct pm2fb_par));
+	p->base=pm2_RD(i, PM2R_SCREEN_BASE);
+	p->video=pm2_RD(i, PM2R_VIDEO_CONTROL) & VIDEO_MASK;
+	switch (i->type) {
+		case PM2_TYPE_PERMEDIA2:
+			misc=pm2_RDAC_RD(i, PM2I_RD_MISC_CONTROL);
+			if ( misc & 4 )
+				/* Hsync is actually low */
+				p->video |= PM2F_HSYNC_ACT_LOW;
+			if ( misc & 8 )
+				/* Vsync is actually low */
+				p->video |= PM2F_VSYNC_ACT_LOW;
+			break;
+		case PM2_TYPE_PERMEDIA2V:
+			misc=pm2_RDAC_RD(i, PM2VI_RD_SYNC_CONTROL);
+			if ( misc & 1 )
+				/* Hsync is actually low */
+				p->video |= PM2F_HSYNC_ACT_LOW;
+			if ( misc & 4 )
+				/* Vsync is actually low */
+				p->video |= PM2F_VSYNC_ACT_LOW;
+			break;
+	}
+	p->width=pm2_RD(i, PM2R_SCREEN_SIZE) & 0xffff;
+	p->height=pm2_RD(i, PM2R_SCREEN_SIZE) >> 16;
+	p->htotal=pm2_RD(i, PM2R_H_TOTAL);
+	p->hsstart=pm2_RD(i, PM2R_HS_START);
+	p->hsend=pm2_RD(i, PM2R_HS_END);
+	p->hbend=pm2_RD(i, PM2R_HB_END);
+	p->vtotal=pm2_RD(i, PM2R_V_TOTAL);
+	p->vsstart=pm2_RD(i, PM2R_VS_START);
+	p->vsend=pm2_RD(i, PM2R_VS_END);
+	p->vbend=pm2_RD(i, PM2R_VB_END);
+	p->stride=pm2_RD(i, PM2R_SCREEN_STRIDE);
+	clrmode=pm2_RDAC_RD(i, PM2I_RD_COLOR_MODE);
+	readpx=pm2_RD(i, PM2R_FB_READ_PIXEL);
+	if (clrmode & PM2F_RD_GUI_ACTIVE) {
+		clrmode &= ~(PM2F_RD_COLOR_MODE_RGB|PM2F_RD_GUI_ACTIVE);
+		if (clrmode==0 && readpx==0)
+			p->depth=8;
+		else if (clrmode==(PM2F_RD_TRUECOLOR|0x06) && readpx==1)
+			p->depth=16;
+		else if (clrmode==(PM2F_RD_TRUECOLOR|0x08) && readpx==2)
+			p->depth=32;
+		else if (clrmode==(PM2F_RD_TRUECOLOR|0x09) && readpx==4)
+			p->depth=24;
+	}
+	/*
+	 * Somehow I have to manage this unretrievable fields.
+	 * To say the truth, 'flags' field ought to be somewhere else.
+	 */
+	if (i->current_par_valid) {
+		p->pixclock=i->current_par.pixclock;
+		p->flags=i->current_par.flags;
+	}
+}
+	
 static void set_screen(struct pm2fb_info* i, struct pm2fb_par* p) {
-	u32 clrmode=0;
+	u32 clrmode=PM2F_RD_COLOR_MODE_RGB;
 	u32 txtmap=0;
 	u32 pixsize=0;
 	u32 clrformat=0;
 	u32 xres;
-	u32 video, tmp;
 
 	if (i->type == PM2_TYPE_PERMEDIA2V) {
 		WAIT_FIFO(i, 1);
@@ -700,7 +839,7 @@
 	xres=(p->width+31)&~31;
 	set_aperture(i, p);
 	DEFRW();
-	WAIT_FIFO(i, 27);
+	WAIT_FIFO(i, 19);
 	pm2_RDAC_WR(i, PM2I_RD_COLOR_KEY_CONTROL, p->depth==8?0:
 						PM2F_COLOR_KEY_TEST_OFF);
 	switch (p->depth) {
@@ -710,28 +849,29 @@
 			break;
 		case 16:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 1);
-			clrmode=PM2F_RD_TRUECOLOR|0x06;
+			clrmode|=PM2F_RD_TRUECOLOR|0x06;
 			txtmap=PM2F_TEXTEL_SIZE_16;
 			pixsize=1;
 			clrformat=0x70;
 			break;
 		case 32:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 2);
-			clrmode=PM2F_RD_TRUECOLOR|0x08;
+			clrmode|=PM2F_RD_TRUECOLOR|0x08;
 			txtmap=PM2F_TEXTEL_SIZE_32;
 			pixsize=2;
 			clrformat=0x20;
 			break;
 		case 24:
 			pm2_WR(i, PM2R_FB_READ_PIXEL, 4);
-			clrmode=PM2F_RD_TRUECOLOR|0x09;
+			clrmode|=PM2F_RD_TRUECOLOR|0x09;
+#ifndef PM2FB_BE_APERTURE
+			clrmode&=~PM2F_RD_COLOR_MODE_RGB;
+#endif
 			txtmap=PM2F_TEXTEL_SIZE_24;
 			pixsize=4;
 			clrformat=0x20;
 			break;
 	}
-	pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
-	pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
 	pm2_WR(i, PM2R_FB_WRITE_MODE, PM2F_FB_WRITE_ENABLE);
 	pm2_WR(i, PM2R_FB_READ_MODE, partprod(xres));
 	pm2_WR(i, PM2R_LB_READ_MODE, partprod(xres));
@@ -747,36 +887,34 @@
 	pm2_WR(i, PM2R_VB_END, p->vbend);
 	pm2_WR(i, PM2R_SCREEN_STRIDE, p->stride);
 	DEFW();
+	pm2_WR(i, PM2R_WINDOW_ORIGIN, 0);
+	pm2_WR(i, PM2R_SCREEN_SIZE, (p->height<<16)|p->width);
+	pm2_WR(i, PM2R_SCISSOR_MODE, PM2F_SCREEN_SCISSOR_ENABLE);
+	DEFW();
 	pm2_WR(i, PM2R_SCREEN_BASE, p->base);
-	/* HW cursor needs /VSYNC for recognizing vert retrace */
-	video=p->video & ~(PM2F_HSYNC_ACT_LOW|PM2F_VSYNC_ACT_LOW);
-	video|=PM2F_HSYNC_ACT_HIGH|PM2F_VSYNC_ACT_HIGH;
+	DEFW();
+	set_video(i, p->video);
+	WAIT_FIFO(i, 4);
 	switch (i->type) {
-	case PM2_TYPE_PERMEDIA2:
-		tmp = PM2F_RD_PALETTE_WIDTH_8;
-		pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
-						   PM2F_RD_GUI_ACTIVE|clrmode);
-		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
-			tmp |= 4; /* invert hsync */
-		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
-			tmp |= 8; /* invert vsync */
-		pm2_RDAC_WR(i, PM2I_RD_MISC_CONTROL, tmp);
-		break;
-	case PM2_TYPE_PERMEDIA2V:
-		tmp = 0;
-		pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
-		pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
-		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
-			tmp |= 1; /* invert hsync */
-		if ((p->video & PM2F_HSYNC_ACT_LOW) == PM2F_HSYNC_ACT_LOW)
-			tmp |= 4; /* invert vsync */
-		pm2v_RDAC_WR(i, PM2VI_RD_SYNC_CONTROL, tmp);
-		pm2v_RDAC_WR(i, PM2VI_RD_MISC_CONTROL, 1);
-		break;
+		case PM2_TYPE_PERMEDIA2:
+			pm2_RDAC_WR(i, PM2I_RD_COLOR_MODE, PM2F_RD_COLOR_MODE_RGB|
+					PM2F_RD_GUI_ACTIVE|clrmode);
+			break;
+		case PM2_TYPE_PERMEDIA2V:
+			pm2v_RDAC_WR(i, PM2VI_RD_PIXEL_SIZE, pixsize);
+			pm2v_RDAC_WR(i, PM2VI_RD_COLOR_FORMAT, clrformat);
+			break;
 	}
-	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
 	pm2_set_pixclock(i, p->pixclock);
-};
+}
+
+static int screen_is_valid(struct pm2fb_info* i) {
+	struct pm2fb_par actual;
+
+	get_screen(i, &actual);
+	return i->current_par_valid &&
+		!memcmp(&actual, &i->current_par, sizeof(struct pm2fb_par));
+}
 
 /*
  * copy with packed pixels (8/16bpp only).
@@ -788,11 +926,10 @@
 
 	if (!w || !h)
 		return;
-	WAIT_FIFO(i, 7);
+	WAIT_FIFO(i, 6);
 	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
 				PM2F_CONFIG_FB_PACKED_DATA|
 				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
-	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
 	pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
 						((xsrc-x)&0xfff));
 	offset=(x&0x3)-(xsrc&0x3);
@@ -816,10 +953,9 @@
 
 	if (!w || !h)
 		return;
-	WAIT_FIFO(i, 6);
+	WAIT_FIFO(i, 5);
 	pm2_WR(i, PM2R_CONFIG,	PM2F_CONFIG_FB_WRITE_ENABLE|
-				PM2F_CONFIG_FB_READ_SOURCE_ENABLE);
-	pm2_WR(i, PM2R_FB_PIXEL_OFFSET, 0);
+				(copy?PM2F_CONFIG_FB_READ_SOURCE_ENABLE:0));
 	if (copy)
 		pm2_WR(i, PM2R_FB_SOURCE_DELTA,	((ysrc-y)&0xfff)<<16|
 							((xsrc-x)&0xfff));
@@ -839,37 +975,24 @@
  * Begin of generic initialization functions
  ***************************************************************************/
 
-static void pm2fb_reset(struct pm2fb_info* p) {
+static void reset_units(struct pm2fb_info* p) {
 
-	if (p->type == PM2_TYPE_PERMEDIA2V)
-		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
-	pm2_WR(p, PM2R_RESET_STATUS, 0);
-	DEFRW();
-	while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
-	DEFRW();
-#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
-	DPRINTK("FIFO disconnect enabled\n");
-	pm2_WR(p, PM2R_FIFO_DISCON, 1);
-	DEFRW();
-#endif
-	if (board_table[p->board].init)
-		board_table[p->board].init(p);
-	WAIT_FIFO(p, 48);
+	WAIT_FIFO(p, 52);
 	pm2_WR(p, PM2R_CHIP_CONFIG, pm2_RD(p, PM2R_CHIP_CONFIG)&
 					~(PM2F_VGA_ENABLE|PM2F_VGA_FIXED));
 	pm2_WR(p, PM2R_BYPASS_WRITE_MASK, ~(0L));
 	pm2_WR(p, PM2R_FRAMEBUFFER_WRITE_MASK, ~(0L));
 	pm2_WR(p, PM2R_FIFO_CONTROL, 0);
-	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
 	pm2_WR(p, PM2R_APERTURE_ONE, 0);
 	pm2_WR(p, PM2R_APERTURE_TWO, 0);
+	pm2_WR(p, PM2R_RASTERIZER_MODE, 0);
+	pm2_WR(p, PM2R_DELTA_MODE, PM2F_DELTA_ORDER_RGB);
 	pm2_WR(p, PM2R_LB_READ_FORMAT, 0);
 	pm2_WR(p, PM2R_LB_WRITE_FORMAT, 0); 
 	pm2_WR(p, PM2R_LB_READ_MODE, 0);
 	pm2_WR(p, PM2R_LB_SOURCE_OFFSET, 0);
 	pm2_WR(p, PM2R_FB_SOURCE_OFFSET, 0);
 	pm2_WR(p, PM2R_FB_PIXEL_OFFSET, 0);
-	pm2_WR(p, PM2R_WINDOW_ORIGIN, 0);
 	pm2_WR(p, PM2R_FB_WINDOW_BASE, 0);
 	pm2_WR(p, PM2R_LB_WINDOW_BASE, 0);
 	pm2_WR(p, PM2R_FB_SOFT_WRITE_MASK, ~(0L));
@@ -890,6 +1013,7 @@
 	pm2_WR(p, PM2R_LOGICAL_OP_MODE, 0);
 	pm2_WR(p, PM2R_STATISTICS_MODE, 0);
 	pm2_WR(p, PM2R_SCISSOR_MODE, 0);
+	pm2_WR(p, PM2R_FILTER_MODE, PM2F_SYNCHRONIZATION);
 	switch (p->type) {
 	case PM2_TYPE_PERMEDIA2:
 		pm2_RDAC_WR(p, PM2I_RD_MODE_CONTROL, 0); /* no overlay */
@@ -905,12 +1029,30 @@
 	pm2_RDAC_WR(p, PM2I_RD_RED_KEY, 0);
 	pm2_RDAC_WR(p, PM2I_RD_GREEN_KEY, 0);
 	pm2_RDAC_WR(p, PM2I_RD_BLUE_KEY, 0);
+}
+
+static void pm2fb_reset(struct pm2fb_info* p) {
+
+	if (p->type == PM2_TYPE_PERMEDIA2V)
+		pm2_WR(p, PM2VR_RD_INDEX_HIGH, 0);
+	pm2_WR(p, PM2R_RESET_STATUS, 0);
+	DEFRW();
+	while (pm2_RD(p, PM2R_RESET_STATUS)&PM2F_BEING_RESET);
+	DEFRW();
+#ifdef CONFIG_FB_PM2_FIFO_DISCONNECT
+	DPRINTK("FIFO disconnect enabled\n");
+	pm2_WR(p, PM2R_FIFO_DISCON, 1);
+	DEFRW();
+#endif
+	if (board_table[p->board].init)
+		board_table[p->board].init(p);
+	reset_units(p);
 	clear_palette(p);
 	if (p->memclock)
 		pm2_set_memclock(p, p->memclock);
 }
 
-static int __init pm2fb_conf(struct pm2fb_info* p){
+static int __init pm2fb_conf(struct pm2fb_info* p) {
 
 	for (p->board=0; board_table[p->board].detect &&
 			!(board_table[p->board].detect(p)); p->board++);
@@ -921,9 +1063,9 @@
 	DPRINTK("found board: %s\n", board_table[p->board].name);
 
 	p->regions.p_fb=p->regions.fb_base;
-	if (!request_mem_region(p->regions.p_fb, p->regions.fb_size,
-		    		"pm2fb")) {
-		printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n");
+	if (!request_mem_region((unsigned long )p->regions.p_fb,
+					p->regions.fb_size, "pm2fb")) {
+		printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort.\n");
 		return 0;
 	}
 	p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size);
@@ -933,8 +1075,9 @@
 #else
 	p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE;
 #endif
-	if (!request_mem_region(p->regions.p_regs, PM2_REGS_SIZE, "pm2fb")) {
-		printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n");
+	if (!request_mem_region((unsigned long )p->regions.p_regs,
+						PM2_REGS_SIZE, "pm2fb")) {
+		printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort.\n");
 		UNMAP(p->regions.v_fb, p->regions.fb_size);
 		return 0;
 	}
@@ -994,7 +1137,7 @@
 
 	if (!cvppc_PCI_init(&p->board_par.cvppc))
 		return 0;
-	p->type = PM2_TYPE_PERMEDIA2;
+	p->type=PM2_TYPE_PERMEDIA2;
 	p->regions.fb_base=CVPPC_FB_APERTURE_ONE;
 	p->regions.fb_size=CVPPC_FB_SIZE;
 	p->regions.rg_base=CVPPC_REGS_REGION;
@@ -1024,10 +1167,13 @@
 	char *name;
 	pm2type_t type;
 } pm2pci_cards[] __initdata = {
-{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020, "Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
-{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2, "3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
-{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V, "3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
-{ 0, 0 }
+	{ PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TVP4020,
+		"Texas Instruments TVP4020", PM2_TYPE_PERMEDIA2 },
+	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2,
+		"3dLabs Permedia 2", PM2_TYPE_PERMEDIA2 },
+	{ PCI_VENDOR_ID_3DLABS, PCI_DEVICE_ID_3DLABS_PERMEDIA2V,
+		"3dLabs Permedia 2v", PM2_TYPE_PERMEDIA2V },
+	{ 0, 0 }
 };
 
 static int __init pm2pci_detect(struct pm2fb_info* p) {
@@ -1072,19 +1218,24 @@
 	p->regions.fb_base= pci->dev->resource[1].start;
 	pcp = pci->dev->sysdata;
 	/* If the user has not asked for a particular mode, lets guess */
-	if (pcp->prom_node && !(pm2fb_options.flags & OPTF_USER)) {
+	if (pcp->prom_node &&
+	    !(pm2fb_options.flags & (OPTF_USER|OPTF_USER_VAR))) {
 		char timing[256], *q, *r;
 		unsigned long w, h;
 		int i;
 		prom_getstring(pcp->prom_node, "timing-numbers", timing, 256);
-		/* FIXME: Find out what the actual pixclock is and other values as well */
+		/* FIXME: Find out what the actual pixclock is
+		 * and other values as well */
 		if (timing[0]) {
 			w = simple_strtoul(timing, &q, 0);
 			h = 0;
 			if (q == timing) w = 0;
 			if (w) {
 				for (i = 0; i < 3; i++) {
-					for (r = q; *r && (*r < '0' || *r > '9'); r++);
+					for (r = q;
+					     *r && (*r < '0' || *r > '9');
+					     r++)
+						;
 					simple_strtoul(r, &q, 0);
 					if (r == q) break;
 				}
@@ -1101,7 +1252,9 @@
 					  (w != user_mode[i].par.width ||
 					   h != user_mode[i].par.height); i++);
 				if (user_mode[i].name[0])
-					memcpy(&p->current_par, &user_mode[i].par, sizeof(user_mode[i].par));
+					memcpy(&p->current_par,
+					       &user_mode[i].par,
+					       sizeof(user_mode[i].par));
 			}
 		}
 	}
@@ -1159,7 +1312,6 @@
  * Console hw acceleration
  ***************************************************************************/
 
-
 static int pm2fb_blank(int blank_mode, struct fb_info_gen* info) {
 	struct pm2fb_info* i=(struct pm2fb_info* )info;
 	u32 video;
@@ -1168,6 +1320,7 @@
 		return 1;
 	video=i->current_par.video;
 	if (blank_mode>0) {
+		i->is_blank=1;
 		switch (blank_mode-1) {
 			case VESA_NO_BLANKING:		/* FIXME */
 				video=video&~(PM2F_VIDEO_ENABLE);
@@ -1187,8 +1340,9 @@
 				break;
 		}
 	}
-	WAIT_FIFO(i, 1);
-	pm2_WR(i, PM2R_VIDEO_CONTROL, video);
+	else
+		i->is_blank=0;
+	set_video(i, video);
 	return 0;
 }
 
@@ -1321,7 +1475,7 @@
 	u32 sx;
 	u32 sy;
 
-	c = ((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c=((u16 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 	c|=c<<16;
 	sx=conp->vc_cols*fontwidth(p);
 	sy=conp->vc_rows*fontheight(p);
@@ -1374,26 +1528,15 @@
 static void pm2fb_clear_margins24(struct vc_data* conp, struct display* p,
 							int bottom_only) {
 	struct pm2fb_info* i=(struct pm2fb_info* )p->fb_info;
-	u32 c;
 	u32 sx;
 	u32 sy;
 
-	c=attr_bgcol_ec(p, conp);
-	if (		i->palette[c].red==i->palette[c].green &&
-			i->palette[c].green==i->palette[c].blue) {
-		c=((u32 *)p->dispsw_data)[c];
-		c|=(c&0xff0000)<<8;
-		sx=conp->vc_cols*fontwidth(p);
-		sy=conp->vc_rows*fontheight(p);
-		if (!bottom_only)
+	sx=conp->vc_cols*fontwidth(p);
+	sy=conp->vc_rows*fontheight(p);
+	if (!bottom_only)
 		pm2fb_block_op(i, 0, 0, 0, sx, 0, (p->var.xres-sx),
-							p->var.yres_virtual, c);
-		pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy,
-						sx, p->var.yres-sy, c);
-	}
-	else
-		fbcon_cfb24_clear_margins(conp, p, bottom_only);
-
+			       p->var.yres_virtual, 0L);
+	pm2fb_block_op(i, 0, 0, 0, 0, p->var.yoffset+sy, sx, p->var.yres-sy, 0L);
 }
 
 static struct display_switch pm2_cfb24 = {
@@ -1430,7 +1573,7 @@
 	u32 sx;
 	u32 sy;
 
-	c = ((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+	c=((u32 *)p->dispsw_data)[attr_bgcol_ec(p, conp)];
 	sx=conp->vc_cols*fontwidth(p);
 	sy=conp->vc_rows*fontheight(p);
 	if (!bottom_only)
@@ -1466,17 +1609,14 @@
 	struct pm2fb_par* p=(struct pm2fb_par* )par;
 
 	strcpy(fix->id, permedia2_name);
-	fix->smem_start=i->regions.p_fb;
+	fix->smem_start=(unsigned long )i->regions.p_fb;
 	fix->smem_len=i->regions.fb_size;
-	fix->mmio_start=i->regions.p_regs;
+	fix->mmio_start=(unsigned long )i->regions.p_regs;
 	fix->mmio_len=PM2_REGS_SIZE;
 	fix->accel=FB_ACCEL_3DLABS_PERMEDIA2;
 	fix->type=FB_TYPE_PACKED_PIXELS;
 	fix->visual=p->depth==8?FB_VISUAL_PSEUDOCOLOR:FB_VISUAL_TRUECOLOR;
-	if (i->current_par_valid)
-		fix->line_length=i->current_par.width*(i->current_par.depth/8);
-	else
-		fix->line_length=0;
+	fix->line_length=p->width*p->depth/8;
 	fix->xpanstep=p->depth==24?8:64/p->depth;
 	fix->ypanstep=1;
 	fix->ywrapstep=0;
@@ -1525,11 +1665,13 @@
 	int data64;
 
 	memset(&p, 0, sizeof(struct pm2fb_par));
+	if (var->accel_flags & FB_ACCELF_TEXT)
+		p.flags |= PM2FF_ACCEL;
 	p.width=(var->xres_virtual+7)&~7;
 	p.height=var->yres_virtual;
 	p.depth=(var->bits_per_pixel+7)&~7;
 	p.depth=p.depth>32?32:p.depth;
-	data64=p.depth>8 || i->type == PM2_TYPE_PERMEDIA2V;
+	data64=p.depth>8 || i->type==PM2_TYPE_PERMEDIA2V;
 	xres=(var->xres+31)&~31;
 	if (p.width<xres+var->xoffset)
 		p.width=xres+var->xoffset;
@@ -1578,12 +1720,22 @@
 	p.base=to3264(var->yoffset*xres+var->xoffset, p.depth, 1);
 	if (data64)
 		p.video|=PM2F_DATA_64_ENABLE;
-	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-		p.video|=PM2F_HSYNC_ACT_HIGH;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT) {
+		if (pm2fb_options.flags & OPTF_LOW_HSYNC) {
+			DPRINTK("ignoring +hsync, using -hsync.\n");
+			p.video|=PM2F_HSYNC_ACT_LOW;
+		} else
+			p.video|=PM2F_HSYNC_ACT_HIGH;
+	}
 	else
 		p.video|=PM2F_HSYNC_ACT_LOW;
-	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-		p.video|=PM2F_VSYNC_ACT_HIGH;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT) {
+		if (pm2fb_options.flags & OPTF_LOW_VSYNC) {
+			DPRINTK("ignoring +vsync, using -vsync.\n");
+			p.video|=PM2F_VSYNC_ACT_LOW;
+		} else
+			p.video|=PM2F_VSYNC_ACT_HIGH;
+	}
 	else
 		p.video|=PM2F_VSYNC_ACT_LOW;
 	if ((var->vmode & FB_VMODE_MASK)==FB_VMODE_INTERLACED) {
@@ -1611,110 +1763,115 @@
 }
 #endif
 
-static int pm2fb_encode_var(struct fb_var_screeninfo* var,
-				const void* par, struct fb_info_gen* info) {
-	struct pm2fb_par* p=(struct pm2fb_par* )par;
-	struct fb_var_screeninfo v;
+static void pm2fb_par2var(struct fb_var_screeninfo* v,
+					const struct pm2fb_par* p) {
 	u32 base;
 
-	memset(&v, 0, sizeof(struct fb_var_screeninfo));
-	v.xres_virtual=p->width;
-	v.yres_virtual=p->height;
-	v.xres=(p->htotal+1)-p->hbend;
-	v.yres=(p->vtotal+1)-p->vbend;
-	v.right_margin=p->hsstart;
-	v.hsync_len=p->hsend-p->hsstart;
-	v.left_margin=p->hbend-p->hsend;
-	v.lower_margin=p->vsstart+1;
-	v.vsync_len=p->vsend-v.lower_margin+1;
-	v.upper_margin=p->vbend-v.lower_margin-v.vsync_len;
-	v.bits_per_pixel=p->depth;
+	memset(v, 0, sizeof(struct fb_var_screeninfo));
+	if (p->flags & PM2FF_ACCEL)
+		v->accel_flags |= FB_ACCELF_TEXT;
+	v->xres_virtual=p->width;
+	v->yres_virtual=p->height;
+	v->xres=(p->htotal+1)-p->hbend;
+	v->yres=(p->vtotal+1)-p->vbend;
+	v->right_margin=p->hsstart;
+	v->hsync_len=p->hsend-p->hsstart;
+	v->left_margin=p->hbend-p->hsend;
+	v->lower_margin=p->vsstart+1;
+	v->vsync_len=p->vsend-v->lower_margin+1;
+	v->upper_margin=p->vbend-v->lower_margin-v->vsync_len;
+	v->bits_per_pixel=p->depth;
 	if (p->video & PM2F_DATA_64_ENABLE) {
-		v.xres=v.xres<<1;
-		v.right_margin=v.right_margin<<1;
-		v.hsync_len=v.hsync_len<<1;
-		v.left_margin=v.left_margin<<1;
+		v->xres=v->xres<<1;
+		v->right_margin=v->right_margin<<1;
+		v->hsync_len=v->hsync_len<<1;
+		v->left_margin=v->left_margin<<1;
 	}
 	switch (p->depth) {
 		case 8:
-			v.red.length=v.green.length=v.blue.length=8;
-			v.xres=v.xres<<2;
-			v.right_margin=v.right_margin<<2;
-			v.hsync_len=v.hsync_len<<2;
-			v.left_margin=v.left_margin<<2;
+			v->red.length=v->green.length=v->blue.length=8;
+			v->xres=v->xres<<2;
+			v->right_margin=v->right_margin<<2;
+			v->hsync_len=v->hsync_len<<2;
+			v->left_margin=v->left_margin<<2;
 			break;
 		case 16:
-			v.red.offset=11;
-			v.red.length=5;
-			v.green.offset=5;
-			v.green.length=6;
-			v.blue.length=5;
-			v.xres=v.xres<<1;
-			v.right_margin=v.right_margin<<1;
-			v.hsync_len=v.hsync_len<<1;
-			v.left_margin=v.left_margin<<1;
+			v->red.offset=11;
+			v->red.length=5;
+			v->green.offset=5;
+			v->green.length=6;
+			v->blue.length=5;
+			v->xres=v->xres<<1;
+			v->right_margin=v->right_margin<<1;
+			v->hsync_len=v->hsync_len<<1;
+			v->left_margin=v->left_margin<<1;
 			break;
 		case 32:
-			v.transp.offset=24;
-			v.red.offset=16;
-			v.green.offset=8;
-			v.red.length=v.green.length=v.blue.length=
-							v.transp.length=8;
+			v->transp.offset=24;
+			v->red.offset=16;
+			v->green.offset=8;
+			v->red.length=v->green.length=v->blue.length=
+							v->transp.length=8;
 			break;
 		case 24:
-			v.blue.offset=16;
-			v.green.offset=8;
-			v.red.length=v.green.length=v.blue.length=8;
-			v.xres=(v.xres<<2)/3;
-			v.right_margin=(v.right_margin<<2)/3;
-			v.hsync_len=(v.hsync_len<<2)/3;
-			v.left_margin=(v.left_margin<<2)/3;
+			v->blue.offset=16;
+			v->green.offset=8;
+			v->red.length=v->green.length=v->blue.length=8;
+			v->xres=(v->xres<<2)/3;
+			v->right_margin=(v->right_margin<<2)/3;
+			v->hsync_len=(v->hsync_len<<2)/3;
+			v->left_margin=(v->left_margin<<2)/3;
 			break;
 	}
 	base=from3264(p->base, p->depth, 1);
-	v.xoffset=base%v.xres;
-	v.yoffset=base/v.xres;
-	v.height=v.width=-1;
-	v.pixclock=KHZ2PICOS(p->pixclock);
+	v->xoffset=base%v->xres;
+	v->yoffset=base/v->xres;
+	v->height=v->width=-1;
+	v->pixclock=KHZ2PICOS(p->pixclock);
 	if ((p->video & PM2F_HSYNC_MASK)==PM2F_HSYNC_ACT_HIGH)
-		v.sync|=FB_SYNC_HOR_HIGH_ACT;
+		v->sync|=FB_SYNC_HOR_HIGH_ACT;
 	if ((p->video & PM2F_VSYNC_MASK)==PM2F_VSYNC_ACT_HIGH)
-		v.sync|=FB_SYNC_VERT_HIGH_ACT;
+		v->sync|=FB_SYNC_VERT_HIGH_ACT;
 	if (p->video & PM2F_LINE_DOUBLE)
-		v.vmode=FB_VMODE_DOUBLE;
-	*var=v;
+		v->vmode=FB_VMODE_DOUBLE;
+}
+
+
+static int pm2fb_encode_var(struct fb_var_screeninfo* var,
+				const void* par, struct fb_info_gen* info) {
+
+	pm2fb_par2var(var, (struct pm2fb_par* )par);
 	return 0;
 }
 
 static void set_user_mode(struct pm2fb_info* i) {
 
+	memcpy(&i->current_par, &pm2fb_options.user_mode,
+	       sizeof(i->current_par));
 	if (pm2fb_options.flags & OPTF_YPAN) {
-		int h = i->current_par.height;
 		i->current_par.height=i->regions.fb_size/
 			(i->current_par.width*i->current_par.depth/8);
 		i->current_par.height=MIN(i->current_par.height,2047);
-		i->current_par.height=MAX(i->current_par.height,h);
+		i->current_par.height=MAX(i->current_par.height,
+					  pm2fb_options.user_mode.height);
 	}
 }
 
 static void pm2fb_get_par(void* par, struct fb_info_gen* info) {
 	struct pm2fb_info* i=(struct pm2fb_info* )info;
-	
+
 	if (!i->current_par_valid) {
 		set_user_mode(i);
-		pm2fb_reset(i);
-		set_screen(i, &i->current_par);
-		i->current_par_valid=1;
+		pm2fb_set_par(&i->current_par, info);
 	}
-	*((struct pm2fb_par* )par)=i->current_par;
+	get_screen(i, (struct pm2fb_par* )par);
 }
 
 static void pm2fb_set_par(const void* par, struct fb_info_gen* info) {
 	struct pm2fb_info* i=(struct pm2fb_info* )info;
-	struct pm2fb_par* p;
+	struct pm2fb_par* p=(struct pm2fb_par* )par;
 
-	p=(struct pm2fb_par* )par;
-	if (i->current_par_valid) {
+	if (screen_is_valid(i)) {
 		i->current_par.base=p->base;
 		if (!memcmp(p, &i->current_par, sizeof(struct pm2fb_par))) {
 			WAIT_FIFO(i, 1);
@@ -1722,12 +1879,16 @@
 			return;
 		}
 	}
+
+	wait_pm2(i);
+	reset_units(i);
 	set_screen(i, p);
 	i->current_par=*p;
 	i->current_par_valid=1;
 #ifdef PM2FB_HW_CURSOR	
 	if (i->cursor) {
-		pm2v_set_cursor_color(i, cursor_color_map, cursor_color_map, cursor_color_map);
+		pm2v_set_cursor_color(i, cursor_color_map,
+				cursor_color_map, cursor_color_map);
 		pm2v_set_cursor_shape(i);
 	}
 #endif
@@ -1801,35 +1962,51 @@
 }
 
 static void pm2fb_set_disp(const void* par, struct display* disp,
-						   struct fb_info_gen* info) {
+						struct fb_info_gen* info) {
 	struct pm2fb_info* i=(struct pm2fb_info* )info;
+	struct pm2fb_par* p=(struct pm2fb_par* )par;
 	unsigned long flags;
-	unsigned long depth;
 
 	save_flags(flags);
 	cli();
-	i->gen.info.screen_base = i->regions.v_fb;
-	switch (depth=((struct pm2fb_par* )par)->depth) {
+#ifdef __alpha__
+	disp->screen_base=i->regions.v_fb + dense_mem(i->regions.v_fb);
+#else
+	disp->screen_base=i->regions.v_fb;
+#endif
+	switch (p->depth) {
 #ifdef FBCON_HAS_CFB8
 		case 8:
-			disp->dispsw=&pm2_cfb8;
+			if (p->flags & PM2FF_ACCEL)
+				disp->dispsw=&pm2_cfb8;
+			else
+				disp->dispsw=&fbcon_cfb8;
 			break;
 #endif
 #ifdef FBCON_HAS_CFB16
 		case 16:
-			disp->dispsw=&pm2_cfb16;
+			if (p->flags & PM2FF_ACCEL)
+				disp->dispsw=&pm2_cfb16;
+			else
+				disp->dispsw=&fbcon_cfb16;
 			disp->dispsw_data=i->cmap.cmap16;
 			break;
 #endif
 #ifdef FBCON_HAS_CFB24
 		case 24:
-			disp->dispsw=&pm2_cfb24;
+			if (p->flags & PM2FF_ACCEL)
+				disp->dispsw=&pm2_cfb24;
+			else
+				disp->dispsw=&fbcon_cfb24;
 			disp->dispsw_data=i->cmap.cmap24;
 			break;
 #endif
 #ifdef FBCON_HAS_CFB32
 		case 32:
-			disp->dispsw=&pm2_cfb32;
+			if (p->flags & PM2FF_ACCEL)
+				disp->dispsw=&pm2_cfb32;
+			else
+				disp->dispsw=&fbcon_cfb32;
 			disp->dispsw_data=i->cmap.cmap32;
 			break;
 #endif
@@ -2050,46 +2227,62 @@
 
 #ifdef MODULE
 static void pm2fb_cleanup(void) {
-	struct pm2fb_info* i = &fb_info;
+	struct pm2fb_info* i=&fb_info;
 
-	unregister_framebuffer((struct fb_info *)i);
+	unregister_framebuffer((struct fb_info* )info);
 	pm2fb_reset(i);
-
-	UNMAP(i->regions.v_fb, i->regions.fb_size);
-	release_mem_region(i->regions.p_fb, i->regions.fb_size);
-
-	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
-	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
-
+	
+ 	UNMAP(i->regions.v_fb, i->regions.fb_size);
+ 	release_mem_region(i->regions.p_fb, i->regions.fb_size);
+ 
+ 	UNMAP(i->regions.v_regs, PM2_REGS_SIZE);
+ 	release_mem_region(i->regions.p_regs, PM2_REGS_SIZE);
+	
 	if (board_table[i->board].cleanup)
 		board_table[i->board].cleanup(i);
 }
 #endif /* MODULE */
 
-int __init pm2fb_init(void){
+int __init pm2fb_init(void) {
 
 	MOD_INC_USE_COUNT;
 	memset(&fb_info, 0, sizeof(fb_info));
-	memcpy(&fb_info.current_par, &pm2fb_options.user_mode, sizeof(fb_info.current_par));
+
 	if (!pm2fb_conf(&fb_info)) {
 		MOD_DEC_USE_COUNT;
 		return -ENXIO;
 	}
+
+        /* Pick up user_var settings if set. */
+	if ((pm2fb_options.flags & OPTF_USER_VAR) &&
+	    pm2fb_decode_var(&user_var, &pm2fb_options.user_mode,
+			     &fb_info.gen)<0) {
+		printk("pm2fb: user supplied var: mode is bad.\n");
+		memcpy(&pm2fb_options.user_mode,
+		       &user_mode[DEFAULT_USER_MODE].par,
+		       sizeof(struct pm2fb_par));
+	}
+	memcpy(&fb_info.current_par, &pm2fb_options.user_mode,
+					sizeof(fb_info.current_par));
+
 	pm2fb_reset(&fb_info);
 	fb_info.disp.scrollmode=SCROLL_YNOMOVE;
 	fb_info.gen.parsize=sizeof(struct pm2fb_par);
 	fb_info.gen.fbhw=&pm2fb_hwswitch;
 	strcpy(fb_info.gen.info.modename, permedia2_name);
+	fb_info.gen.info.node = NODEV;
 	fb_info.gen.info.flags=FBINFO_FLAG_DEFAULT;
 	fb_info.gen.info.fbops=&pm2fb_ops;
 	fb_info.gen.info.disp=&fb_info.disp;
 	strcpy(fb_info.gen.info.fontname, pm2fb_options.font);
 	fb_info.gen.info.switch_con=&fbgen_switch;
 	fb_info.gen.info.updatevar=&fbgen_update_var;
+
 	fbgen_get_var(&fb_info.disp.var, -1, &fb_info.gen.info);
 	fbgen_do_set_var(&fb_info.disp.var, 1, &fb_info.gen);
 	fbgen_set_disp(-1, &fb_info.gen);
-	do_install_cmap(0, &fb_info.gen.info);
+	fbgen_install_cmap(0, &fb_info.gen);
+
 	if (register_framebuffer(&fb_info.gen.info)<0) {
 		printk(KERN_ERR "pm2fb: unable to register.\n");
 		MOD_DEC_USE_COUNT;
@@ -2103,7 +2296,7 @@
 	return 0;
 }
 
-static void __init pm2fb_mode_setup(char* options){
+static void __init pm2fb_mode_setup(char* options) {
 	int i;
 
 	for (i=0; user_mode[i].name[0] &&
@@ -2111,17 +2304,77 @@
 	if (user_mode[i].name[0]) {
 		memcpy(&pm2fb_options.user_mode, &user_mode[i].par,
 					sizeof(pm2fb_options.user_mode));
-		pm2fb_options.flags |= OPTF_USER;
+		pm2fb_options.flags|=OPTF_USER;
 	}
 }
 
-static void __init pm2fb_font_setup(char* options){
+static void __init pm2fb_font_setup(char* options) {
 
 	strncpy(pm2fb_options.font, options, sizeof(pm2fb_options.font));
 	pm2fb_options.font[sizeof(pm2fb_options.font)-1]='\0';
 }
 
-int __init pm2fb_setup(char* options){
+static void __init pm2fb_var_setup(char* options) {
+	char* next;
+
+	pm2fb_par2var(&user_var, &pm2fb_options.user_mode);
+
+	while (options) {
+		if ((next=strchr(options, ';')))
+			*(next++)='\0';
+		if (!strncmp(options, "bpp:", 4))
+			user_var.bits_per_pixel=
+				simple_strtoul(options+4, NULL, 0);
+		else if (!strncmp(options, "xres:", 5))
+			user_var.xres=simple_strtoul(options+5, NULL, 0);
+		else if (!strncmp(options, "yres:", 5))
+			user_var.yres=simple_strtoul(options+5, NULL, 0);
+		else if (!strncmp(options, "vxres:", 6))
+			user_var.xres_virtual=
+				simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "vyres:", 6))
+			user_var.yres_virtual=
+				simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "left:", 5))
+			user_var.left_margin=
+				simple_strtoul(options+5, NULL, 0);
+		else if (!strncmp(options, "right:", 6))
+			user_var.right_margin=
+				simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "lower:", 6))
+			user_var.lower_margin=
+				simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "upper:", 6))
+			user_var.upper_margin=
+				simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "hslen:", 6))
+			user_var.hsync_len=simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "vslen:", 6))
+			user_var.vsync_len=simple_strtoul(options+6, NULL, 0);
+		else if (!strncmp(options, "pixclock:", 9))
+			user_var.pixclock=simple_strtoul(options+9, NULL, 0);
+		else if (!strcmp(options, "+hsync"))
+			user_var.sync|=FB_SYNC_HOR_HIGH_ACT;
+		else if (!strcmp(options, "-hsync"))
+			user_var.sync&=~FB_SYNC_HOR_HIGH_ACT;
+		else if (!strcmp(options, "+vsync"))
+			user_var.sync|=FB_SYNC_VERT_HIGH_ACT;
+		else if (!strcmp(options, "-vsync"))
+			user_var.sync&=~FB_SYNC_VERT_HIGH_ACT;
+		else if (!strcmp(options, "+double"))
+			user_var.vmode|=FB_VMODE_DOUBLE;
+		else if (!strcmp(options, "-double"))
+			user_var.vmode&=~FB_VMODE_DOUBLE;
+		else if (!strcmp(options, "+accel"))
+			user_var.accel_flags|=FB_ACCELF_TEXT;
+		else if (!strcmp(options, "-accel"))
+			user_var.accel_flags&=~FB_ACCELF_TEXT;
+		options=next;
+	}
+	pm2fb_options.flags|=OPTF_USER_VAR;
+}
+
+int __init pm2fb_setup(char* options) {
 	char* next;
 
 	while (options) {
@@ -2131,16 +2384,23 @@
 			pm2fb_font_setup(options+5);
 		else if (!strncmp(options, "mode:", 5))
 			pm2fb_mode_setup(options+5);
+		else if (!strncmp(options, "var:", 4))
+			pm2fb_var_setup(options+4);
 		else if (!strcmp(options, "ypan"))
 			pm2fb_options.flags |= OPTF_YPAN;
 		else if (!strcmp(options, "oldmem"))
 			pm2fb_options.flags |= OPTF_OLD_MEM;
 		else if (!strcmp(options, "virtual"))
 			pm2fb_options.flags |= OPTF_VIRTUAL;
+		else if (!strcmp(options, "lowhsync"))
+			pm2fb_options.flags |= OPTF_LOW_HSYNC;
+		else if (!strcmp(options, "lowvsync"))
+			pm2fb_options.flags |= OPTF_LOW_VSYNC;
 		else if (!strcmp(options, "noblink"))
-			curblink = 0;
+			curblink=0;
 		options=next;
 	}
+	user_var.activate=FB_ACTIVATE_NOW;
 	return 0;
 }
 
@@ -2156,9 +2416,10 @@
 
 MODULE_PARM(mode, "s");
 
-int __init init_module(void) {
+int init_module(void) {
 
-	if (mode) pm2fb_mode_setup(mode);
+	if (mode)
+		pm2fb_mode_setup(mode);
 	return pm2fb_init();
 }
 
diff -Nru a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
--- a/drivers/video/pmag-ba-fb.c	Sat Jun  8 22:31:52 2002
+++ b/drivers/video/pmag-ba-fb.c	Sat Jun  8 22:31:52 2002
@@ -37,12 +37,6 @@
 #include "pmag-ba-fb.h"
 
 #include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
 
 struct pmag_ba_ramdac_regs {
 	unsigned char addr_low;
@@ -54,316 +48,119 @@
 	unsigned char cmap;
 };
 
-struct pmag_ba_my_fb_info {
-	struct fb_info info;
-	struct pmag_ba_ramdac_regs *bt459_regs;
-	unsigned long pmagba_fb_start;
-	unsigned long pmagba_fb_size;
-	unsigned long pmagba_fb_line_length;
-};
-
-static struct display disp;
 /*
  * Max 3 TURBOchannel slots -> max 3 PMAG-BA :)
  */
-static struct pmag_ba_my_fb_info pmagba_fb_info[3];
+static struct fb_info pmagba_fb_info[3];
+static struct display pmagba_disp[3];
 
 static struct fb_var_screeninfo pmagbafb_defined = {
-	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
-	0, 0,			/* virtual -> visible no offset */
-	0,			/* depth -> load bits_per_pixel */
-	0,			/* greyscale ? */
-	{0, 0, 0},		/* R */
-	{0, 0, 0},		/* G */
-	{0, 0, 0},		/* B */
-	{0, 0, 0},		/* transparency */
-	0,			/* standard pixel format */
-	FB_ACTIVATE_NOW,
-	274, 195,		/* 14" monitor */
-	FB_ACCEL_NONE,
-	0L, 0L, 0L, 0L, 0L,
-	0L, 0L, 0,		/* No sync info */
-	FB_VMODE_NONINTERLACED,
-	{0, 0, 0, 0, 0, 0}
-};
-
-struct pmagbafb_par {
-};
-
-struct pmagbafb_par current_par;
-
-static void pmagbafb_encode_var(struct fb_var_screeninfo *var,
-				struct pmagbafb_par *par)
-{
-	int i = 0;
-	var->xres = 1024;
-	var->yres = 864;
-	var->xres_virtual = 1024;
-	var->yres_virtual = 864;
-	var->xoffset = 0;
-	var->yoffset = 0;
-	var->bits_per_pixel = 8;
-	var->grayscale = 0;
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	var->transp.msb_right = 0;
-	var->nonstd = 0;
-	var->activate = 1;
-	var->height = -1;
-	var->width = -1;
-	var->vmode = FB_VMODE_NONINTERLACED;
-	var->pixclock = 0;
-	var->sync = 0;
-	var->left_margin = 0;
-	var->right_margin = 0;
-	var->upper_margin = 0;
-	var->lower_margin = 0;
-	var->hsync_len = 0;
-	var->vsync_len = 0;
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-}
-
-static void pmagbafb_get_par(struct pmagbafb_par *par)
-{
-	*par = current_par;
-}
-
-static int pmagba_fb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
-
-static int pmagba_do_fb_set_var(struct fb_var_screeninfo *var,
-				int isactive)
-{
-	struct pmagbafb_par par;
-
-	pmagbafb_get_par(&par);
-	pmagbafb_encode_var(var, &par);
-	return 0;
+	xres:		1024,
+	yres:		864,
+	xres_virtual:	1024,
+	yres_virtual:	864,
+	bits_per_pixel:	8,
+	activate:	FB_ACTIVATE_NOW, 
+	height:		274,	
+	width:		195,
+	accel:		FB_ACCEL_NONE,
+	vmode:		FB_VMODE_NONINTERLACED,
+}
+
+static struct fb_fix_screeninfo pmagbafb_fix = {
+	id:		"PMAG-BA",
+	smem_len:	(1024 * 864),
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	line_length:	1024,
 }
 
 /*
  * Turn hardware cursor off
  */
-void pmagbafb_erase_cursor(struct pmag_ba_my_fb_info *info)
-{
-	info->bt459_regs->addr_low = 0;
-	info->bt459_regs->addr_hi = 3;
-	info->bt459_regs->data = 0;
-}
-
-/*
- * Write to a Bt459 color map register
- */
-void pmag_ba_bt459_write_colormap(struct pmag_ba_my_fb_info *info,
-				  int reg, __u8 red, __u8 green, __u8 blue)
-{
-	info->bt459_regs->addr_low = (__u8) reg;
-	info->bt459_regs->addr_hi = 0;
-	info->bt459_regs->cmap = red;
-	info->bt459_regs->cmap = green;
-	info->bt459_regs->cmap = blue;
-}
-
-/*
- * Get the palette
- */
-
-static int pmagbafb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
+void pmagbafb_erase_cursor(struct pmag_ba_ramdac_regs *bt459_regs)
 {
-	unsigned int i;
-	unsigned int length;
-
-	if (((cmap->start) + (cmap->len)) >= 256) {
-		length = 256 - (cmap->start);
-	} else {
-		length = cmap->len;
-	}
-	for (i = 0; i < length; i++) {
-		/*
-		 * TODO
-		 */
-	}
-	return 0;
+	bt459_regs->addr_low = 0;
+	bt459_regs->addr_hi = 3;
+	bt459_regs->data = 0;
 }
 
 /*
  * Set the palette. 
  */
-static int pmagbafb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
+static int pmagbafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                              unsigned blue, unsigned transp,
+                              struct fb_info *info)
 {
-	unsigned int i;
-	__u8 cmap_red, cmap_green, cmap_blue;
-	unsigned int length;
-
-	if (((cmap->start) + (cmap->len)) >= 256)
-		length = 256 - (cmap->start);
-	else
-		length = cmap->len;
-
-	for (i = 0; i < length; i++) {
-		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
-		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
-		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
-
-		pmag_ba_bt459_write_colormap((struct pmag_ba_my_fb_info *)
-					     info, cmap->start + i,
-					     cmap_red, cmap_green,
-					     cmap_blue);
-	}
-	return 0;
-}
+	struct pmag_ba_ramdac_regs *bt459_regs = (struct pmag_ba_ramdac_regs *) info->par; 
 
-static int pmagbafb_get_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	struct pmagbafb_par par;
-	if (con == -1) {
-		pmagbafb_get_par(&par);
-		pmagbafb_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
-	return 0;
-}
-
-
-static int pmagbafb_set_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	int err;
-
-	if ((err = pmagba_do_fb_set_var(var, 1)))
-		return err;
-	return 0;
-}
-
-static void pmagbafb_encode_fix(struct fb_fix_screeninfo *fix,
-				struct pmagbafb_par *par,
-				struct pmag_ba_my_fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "PMAG-BA");
-
-	fix->smem_start = info->pmagba_fb_start;
-	fix->smem_len = info->pmagba_fb_size;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = info->pmagba_fb_line_length;
-}
-
-static int pmagbafb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			    struct fb_info *info)
-{
-	struct pmagbafb_par par;
-
-	pmagbafb_get_par(&par);
-	pmagbafb_encode_fix(fix, &par, (struct pmag_ba_my_fb_info *) info);
-
-	return 0;
-}
+	if (regno >= info->cmap.len)
+		return 1;
 
-static int pmagbafb_switch(int con, struct fb_info *info)
-{
-	pmagba_do_fb_set_var(&fb_display[con].var, 1);
-	info->currcon = con;
+	red   >>= 8;	/* The cmap fields are 16 bits    */
+	green >>= 8;	/* wide, but the harware colormap */
+	blue  >>= 8;	/* registers are only 8 bits wide */
+
+	bt459_regs->addr_low = (__u8) regno;
+	bt459_regs->addr_hi = 0;
+	bt459_regs->cmap = red;
+	bt459_regs->cmap = green;
+	bt459_regs->cmap = blue;
 	return 0;
 }
 
-static void pmagbafb_set_disp(int con, struct pmag_ba_my_fb_info *info)
-{
-	struct fb_fix_screeninfo fix;
-	struct display *display;
-
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	pmagbafb_get_fix(&fix, con, (struct fb_info *) info);
-
-	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->next_line = fix.line_length;
-	display->can_soft_blank = 0;
-	display->inverse = 0;
-
-	display->dispsw = &fbcon_cfb8;
-}
-
 static struct fb_ops pmagbafb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	pmagbafb_get_fix,
-	fb_get_var:	pmagbafb_get_var,
-	fb_set_var:	pmagbafb_set_var,
-	fb_get_cmap:	pmagbafb_get_cmap,
-	fb_set_cmap:	pmagbafb_set_cmap,
-};
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_setcolreg:	pmagbafb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
+}
 
 int __init pmagbafb_init_one(int slot)
 {
 	unsigned long base_addr = get_tc_base_addr(slot);
-	struct pmag_ba_my_fb_info *ip =
-	    (struct pmag_ba_my_fb_info *) &pmagba_fb_info[slot];
+	struct fb_info *info = &pmagba_fb_info[slot]; 
+	struct display *disp = &pmagba_disp[slot];
 
 	printk("PMAG-BA framebuffer in slot %d\n", slot);
-
 	/*
 	 * Framebuffer display memory base address and friends
 	 */
-	ip->bt459_regs =
-	    (struct pmag_ba_ramdac_regs *) (base_addr +
-					    PMAG_BA_BT459_OFFSET);
-	ip->pmagba_fb_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
-	ip->pmagba_fb_size = 1024 * 864;
-	ip->pmagba_fb_line_length = 1024;
+	pmagbafb_fix.smem_start = base_addr + PMAG_BA_ONBOARD_FBMEM_OFFSET;
+	info->par = (base_addr + PMAG_BA_BT459_OFFSET);
 
 	/*
 	 * Configure the Bt459 RAM DAC
 	 */
-	pmagbafb_erase_cursor(ip);
-
-	/*
-	 *      Fill in the available video resolution
-	 */
-
-	pmagbafb_defined.xres = 1024;
-	pmagbafb_defined.yres = 864;
-	pmagbafb_defined.xres_virtual = 1024;
-	pmagbafb_defined.yres_virtual = 864;
-	pmagbafb_defined.bits_per_pixel = 8;
+	pmagbafb_erase_cursor((struct pmag_ba_ramdac_regs *) info->par);
 
 	/*
 	 *      Let there be consoles..
 	 */
-	strcpy(ip->info.modename, "PMAG-BA");
-	ip->info.changevar = NULL;
-	ip->info.node = NODEV;
-	ip->info.fbops = &pmagbafb_ops;
-	ip->info.screen_base = ip->pmagba_fb_start;
-	ip->info.disp = &disp;
-	ip->info.currcon = -1;
-	ip->info.switch_con = &pmagbafb_switch;
-	ip->info.updatevar = &pmagba_fb_update_var;
-	ip->info.flags = FBINFO_FLAG_DEFAULT;
-
-	pmagba_do_fb_set_var(&pmagbafb_defined, 1);
-	pmagbafb_get_var(&disp.var, -1, (struct fb_info *) ip);
-	pmagbafb_set_disp(-1, ip);
+	strcpy(info->modename, pmagbafb_fix.id);
+	info->changevar = NULL;
+	info->node = NODEV;
+	info->fbops = &pmagbafb_ops;
+	info->var = pmagbafb_defined;
+	info->fix = pmagbafb_fix; 
+	info->screen_base = pmagbafb_fix.smem_start;
+	info->disp = &disp;
+	info->currcon = -1;
+	info->switch_con = gen_switch;
+	info->updatevar = gen_update_var;
+	info->flags = FBINFO_FLAG_DEFAULT;
+
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+	gen_set_disp(-1, info);
 	
-	if (register_framebuffer((struct fb_info *) ip) < 0)
+	if (register_framebuffer(info) < 0)
 		return 1;
-
 	return 0;
 }
 
diff -Nru a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
--- a/drivers/video/pmagb-b-fb.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/video/pmagb-b-fb.c	Sat Jun  8 22:31:35 2002
@@ -40,12 +40,6 @@
 #include "pmagb-b-fb.h"
 
 #include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-
-#define arraysize(x)    (sizeof(x)/sizeof(*(x)))
 
 struct pmagb_b_ramdac_regs {
 	unsigned char addr_low;
@@ -57,317 +51,119 @@
 	unsigned char cmap;
 };
 
-struct pmagb_b_my_fb_info {
-	struct fb_info info;
-	struct pmagb_b_ramdac_regs *bt459_regs;
-	unsigned long pmagbb_fb_start;
-	unsigned long pmagbb_fb_size;
-	unsigned long pmagbb_fb_line_length;
-};
-
-static struct display disp;
 /*
  * Max 3 TURBOchannel slots -> max 3 PMAGB-B :)
  */
-static struct pmagb_b_my_fb_info pmagbb_fb_info[3];
+static struct fb_info pmagbb_fb_info[3];
+static struct display pmagbb_disp[3];
 
 static struct fb_var_screeninfo pmagbbfb_defined = {
-	0, 0, 0, 0,		/* W,H, W, H (virtual) load xres,xres_virtual */
-	0, 0,			/* virtual -> visible no offset */
-	0,			/* depth -> load bits_per_pixel */
-	0,			/* greyscale ? */
-	{0, 0, 0},		/* R */
-	{0, 0, 0},		/* G */
-	{0, 0, 0},		/* B */
-	{0, 0, 0},		/* transparency */
-	0,			/* standard pixel format */
-	FB_ACTIVATE_NOW,
-	274, 195,		/* 14" monitor */
-	FB_ACCEL_NONE,
-	0L, 0L, 0L, 0L, 0L,
-	0L, 0L, 0,		/* No sync info */
-	FB_VMODE_NONINTERLACED,
-	{0, 0, 0, 0, 0, 0}
-};
-
-struct pmagbbfb_par {
+	xres:		1280,
+	yres:		1024,
+	xres_virtual:	1280,
+	yres_virtual:	1024,
+	bits_per_pixel:	8,
+	activate:	FB_ACTIVATE_NOW,
+	height:		274,
+	width:		195,
+	accel_flags:	FB_ACCEL_NONE,
+	vmode:		FB_VMODE_NONINTERLACED,
 };
 
-struct pmagbbfb_par current_par;
-
-static void pmagbbfb_encode_var(struct fb_var_screeninfo *var,
-				struct pmagbbfb_par *par)
-{
-	int i = 0;
-	var->xres = 1280;
-	var->yres = 1024;
-	var->xres_virtual = 1280;
-	var->yres_virtual = 1024;
-	var->xoffset = 0;
-	var->yoffset = 0;
-	var->bits_per_pixel = 8;
-	var->grayscale = 0;
-	var->transp.offset = 0;
-	var->transp.length = 0;
-	var->transp.msb_right = 0;
-	var->nonstd = 0;
-	var->activate = 1;
-	var->height = -1;
-	var->width = -1;
-	var->vmode = FB_VMODE_NONINTERLACED;
-	var->pixclock = 0;
-	var->sync = 0;
-	var->left_margin = 0;
-	var->right_margin = 0;
-	var->upper_margin = 0;
-	var->lower_margin = 0;
-	var->hsync_len = 0;
-	var->vsync_len = 0;
-	for (i = 0; i < arraysize(var->reserved); i++)
-		var->reserved[i] = 0;
-}
-
-static void pmagbbfb_get_par(struct pmagbbfb_par *par)
-{
-	*par = current_par;
-}
-
-static int pmagbb_fb_update_var(int con, struct fb_info *info)
-{
-	return 0;
-}
-
-static int pmagbb_do_fb_set_var(struct fb_var_screeninfo *var,
-				int isactive)
-{
-	struct pmagbbfb_par par;
-
-	pmagbbfb_get_par(&par);
-	pmagbbfb_encode_var(var, &par);
-	return 0;
+static struct fb_fix_screeninfo pmagbafb_fix = {
+	id:		"PMAGB-BA",
+	smem_len:	(1280 * 1024),
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR,
+	line_length:	1280,
 }
 
 /*
  * Turn hardware cursor off
  */
-void pmagbbfb_erase_cursor(struct pmagb_b_my_fb_info *info)
+void pmagbbfb_erase_cursor(struct pmagb_b_ramdac_regs *bt459_regs)
 {
-	info->bt459_regs->addr_low = 0;
-	info->bt459_regs->addr_hi = 3;
-	info->bt459_regs->data = 0;
-}
-
-/*
- * Write to a Bt459 color map register
- */
-void pmagb_b_bt459_write_colormap(struct pmagb_b_my_fb_info *info,
-				  int reg, __u8 red, __u8 green, __u8 blue)
-{
-	info->bt459_regs->addr_low = (__u8) reg;
-	info->bt459_regs->addr_hi = 0;
-	info->bt459_regs->cmap = red;
-	info->bt459_regs->cmap = green;
-	info->bt459_regs->cmap = blue;
-}
-
-/*
- * Get the palette
- */
-
-static int pmagbbfb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
-{
-	unsigned int i;
-	unsigned int length;
-
-	if (((cmap->start) + (cmap->len)) >= 256) {
-		length = 256 - (cmap->start);
-	} else {
-		length = cmap->len;
-	}
-	for (i = 0; i < length; i++) {
-		/*
-		 * TODO
-		 */
-	}
-	return 0;
+	bt459_regs->addr_low = 0;
+	bt459_regs->addr_hi = 3;
+	bt459_regs->data = 0;
 }
 
 /*
  * Set the palette. 
  */
-static int pmagbbfb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
-			     struct fb_info *info)
-{
-	unsigned int i;
-	__u8 cmap_red, cmap_green, cmap_blue;
-	unsigned int length;
-
-	if (((cmap->start) + (cmap->len)) >= 256)
-		length = 256 - (cmap->start);
-	else
-		length = cmap->len;
-
-	for (i = 0; i < length; i++) {
-		cmap_red = ((cmap->red[i]) >> 8);	/* The cmap fields are 16 bits    */
-		cmap_green = ((cmap->green[i]) >> 8);	/* wide, but the harware colormap */
-		cmap_blue = ((cmap->blue[i]) >> 8);	/* registers are only 8 bits wide */
-
-		pmagb_b_bt459_write_colormap((struct pmagb_b_my_fb_info *)
-					     info, cmap->start + i,
-					     cmap_red, cmap_green,
-					     cmap_blue);
-	}
-	return 0;
-}
-
-static int pmagbbfb_get_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	struct pmagbbfb_par par;
-	if (con == -1) {
-		pmagbbfb_get_par(&par);
-		pmagbbfb_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
-	return 0;
-}
-
-
-static int pmagbbfb_set_var(struct fb_var_screeninfo *var, int con,
-			    struct fb_info *info)
-{
-	int err;
-
-	if ((err = pmagbb_do_fb_set_var(var, 1)))
-		return err;
-	return 0;
-}
-
-static void pmagbbfb_encode_fix(struct fb_fix_screeninfo *fix,
-				struct pmagbbfb_par *par,
-				struct pmagb_b_my_fb_info *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, "PMAGB-BA");
-
-	fix->smem_start = info->pmagbb_fb_start;
-	fix->smem_len = info->pmagbb_fb_size;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-	fix->xpanstep = 0;
-	fix->ypanstep = 0;
-	fix->ywrapstep = 0;
-	fix->line_length = info->pmagbb_fb_line_length;
-}
-
-static int pmagbbfb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			    struct fb_info *info)
-{
-	struct pmagbbfb_par par;
-
-	pmagbbfb_get_par(&par);
-	pmagbbfb_encode_fix(fix, &par, (struct pmagb_b_my_fb_info *) info);
-
-	return 0;
-}
+static int pmagbbfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+                              unsigned blue, unsigned transp,
+                              struct fb_info *info)
+{
+	struct pmagb_b_ramdac_regs *bt459_regs = (struct pmagb_b_ramdac_regs *) info->par;
+	
+	if (regno >= info->cmap.len)
+		return 1;
 
-static int pmagbbfb_switch(int con, struct fb_info *info)
-{
-	pmagbb_do_fb_set_var(&fb_display[con].var, 1);
-	info->currcon = con;
+	red   >>= 8;	/* The cmap fields are 16 bits    */
+	green >>= 8;	/* wide, but the harware colormap */
+	blue  >>= 8;	/* registers are only 8 bits wide */
+
+	bt459_regs->addr_low = (__u8) regno;
+	bt459_regs->addr_hi = 0;
+	bt459_regs->cmap = red;
+	bt459_regs->cmap = green;
+	bt459_regs->cmap = blue;
 	return 0;
 }
 
-static void pmagbbfb_set_disp(int con, struct pmagb_b_my_fb_info *info)
-{
-	struct fb_fix_screeninfo fix;
-	struct display *display;
-
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
-
-	pmagbbfb_get_fix(&fix, con, (struct fb_info *) info);
-
-	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->next_line = fix.line_length;
-	display->can_soft_blank = 0;
-	display->inverse = 0;
-
-	display->dispsw = &fbcon_cfb8;
-}
-
 static struct fb_ops pmagbbfb_ops = {
 	owner:		THIS_MODULE,
-	fb_get_fix:	pmagbbfb_get_fix,
-	fb_get_var:	pmagbbfb_get_var,
-	fb_set_var:	pmagbbfb_set_var,
-	fb_get_cmap:	pmagbbfb_get_cmap,
-	fb_set_cmap:	pmagbbfb_set_cmap,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_setcolreg:	pmagbbfb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
 int __init pmagbbfb_init_one(int slot)
 {
 	unsigned long base_addr = get_tc_base_addr(slot);
-	struct pmagb_b_my_fb_info *ip =
-	    (struct pmagb_b_my_fb_info *) &pmagbb_fb_info[slot];
+	struct fb_info *info = &pmagbb_fb_info[slot];
+	struct display *disp = &pmagbb_disp[slot];
 
 	printk("PMAGB-BA framebuffer in slot %d\n", slot);
-
 	/*
 	 * Framebuffer display memory base address and friends
 	 */
-	ip->bt459_regs =
-	    (struct pmagb_b_ramdac_regs *) (base_addr +
-					    PMAGB_B_BT459_OFFSET);
-	ip->pmagbb_fb_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
-	ip->pmagbb_fb_size = 1280 * 1024;
-	ip->pmagbb_fb_line_length = 1280;
-
+	pmagbbfb_fix.smem_start = base_addr + PMAGB_B_ONBOARD_FBMEM_OFFSET;
+	info->par = (base_addr + PMAGB_B_BT459_OFFSET); 
+	
 	/*
 	 * Configure the Bt459 RAM DAC
 	 */
-	pmagbbfb_erase_cursor(ip);
-
-	/*
-	 *      Fill in the available video resolution
-	 */
-
-	pmagbbfb_defined.xres = 1280;
-	pmagbbfb_defined.yres = 1024;
-	pmagbbfb_defined.xres_virtual = 1280;
-	pmagbbfb_defined.yres_virtual = 1024;
-	pmagbbfb_defined.bits_per_pixel = 8;
+	pmagbbfb_erase_cursor((struct pmagb_b_ramdac_regs *) info->par);
 
 	/*
 	 *      Let there be consoles..
 	 */
-	strcpy(ip->info.modename, "PMAGB-BA");
-	ip->info.changevar = NULL;
-	ip->info.node = NODEV;
-	ip->info.fbops = &pmagbbfb_ops;
-	ip->info.screen_base = (char *) ip->pmagbb_fb_start;
-	fix->smem_len = info->pmagbb_fb_size;
-	ip->info.disp = &disp;
-	ip->info.currcon = -1;
-	ip->info.switch_con = &pmagbbfb_switch;
-	ip->info.updatevar = &pmagbb_fb_update_var;
-	ip->info.flags = FBINFO_FLAG_DEFAULT;
-
-	pmagbb_do_fb_set_var(&pmagbbfb_defined, 1);
-	pmagbbfb_get_var(&disp.var, -1, (struct fb_info *) ip);
-	pmagbbfb_set_disp(-1, ip);
+	strcpy(info->modename, pmagbbfb_fix.id);
+	info->changevar = NULL;
+	info->node = NODEV;
+	info->fbops = &pmagbbfb_ops;
+	info->var = pmagbbfb_defined;
+	info->fix = pmagbbfb_fix;
+	info->screen_base = pmagbbfb_fix.smem_start; 
+	info->disp = &disp;
+	info->currcon = -1;
+	info->switch_con = gen_switch;
+	info->updatevar = gen_update_var;
+	info->flags = FBINFO_FLAG_DEFAULT;
 
-	if (register_framebuffer((struct fb_info *) ip) < 0)
-		return 1;
+	fb_alloc_cmap(&fb_info.cmap, 256, 0);
+	gen_set_disp(-1, info);
 
+	if (register_framebuffer(info) < 0)
+		return 1;
 	return 0;
 }
 
diff -Nru a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
--- a/drivers/video/skeletonfb.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/skeletonfb.c	Sat Jun  8 22:31:36 2002
@@ -298,7 +298,7 @@
  *      Returns negative errno on error, or zero on success.
  *
  */
-static int xxxfb_pan_display(struct fb_var_screeninfo *var,
+static int xxxfb_pan_display(struct fb_var_screeninfo *var, int con,
 			     const struct fb_info *info)
 {
     /* ... */
diff -Nru a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
--- a/drivers/video/tdfxfb.c	Sat Jun  8 22:31:36 2002
+++ b/drivers/video/tdfxfb.c	Sat Jun  8 22:31:36 2002
@@ -18,12 +18,12 @@
  * Voodoo3 support was contributed Harold Oga. Lots of additions
  * (proper acceleration, 24 bpp, hardware cursor) and bug fixes by Attila
  * Kesmarki. Thanks guys!
- * 
+ *
  * Voodoo1 and Voodoo2 support aren't relevant to this driver as they
  * behave very differently from the Voodoo3/4/5. For anyone wanting to
  * use frame buffer on the Voodoo1/2, see the sstfb driver (which is
  * located at http://www.sourceforge.net/projects/sstfb).
- *
+ * 
  * While I _am_ grateful to 3Dfx for releasing the specs for Banshee,
  * I do wish the next version is a bit more complete. Without the XF86
  * patches I couldn't have gotten even this far... for instance, the
@@ -76,374 +76,205 @@
 #include <linux/timer.h>
 #include <linux/spinlock.h>
 
-#include <linux/kd.h>
-#include <linux/console.h>
-#include <linux/selection.h>
-#include <linux/vt_kern.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#endif
-
 #include <video/tdfx.h>
 #include <video/fbcon.h>
 
 #ifndef PCI_DEVICE_ID_3DFX_VOODOO5
-#define PCI_DEVICE_ID_3DFX_VOODOO5	0x0009
+#define PCI_DEVICE_ID_3DFX_VOODOO5      0x0009
 #endif
 
-#define TDFXF_HSYNC_ACT_HIGH	0x01
-#define TDFXF_HSYNC_ACT_LOW	0x02
-#define TDFXF_VSYNC_ACT_HIGH	0x04
-#define TDFXF_VSYNC_ACT_LOW	0x08
-#define TDFXF_LINE_DOUBLE	0x10
-#define TDFXF_VIDEO_ENABLE	0x20
-
-#define TDFXF_HSYNC_MASK	0x03
-#define TDFXF_VSYNC_MASK	0x0c
-
-//#define TDFXFB_DEBUG 
+#undef TDFXFB_DEBUG 
 #ifdef TDFXFB_DEBUG
 #define DPRINTK(a,b...) printk(KERN_DEBUG "fb: %s: " a, __FUNCTION__ , ## b)
 #else
 #define DPRINTK(a,b...)
-#endif
+#endif 
 
 #define BANSHEE_MAX_PIXCLOCK 270000.0
 #define VOODOO3_MAX_PIXCLOCK 300000.0
 #define VOODOO5_MAX_PIXCLOCK 350000.0
 
-struct tdfxfb_par {
-	u32 pixclock;
-
-	u32 baseline;
+static struct fb_fix_screeninfo tdfx_fix __initdata = {
+	id:		"3Dfx",
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_PSEUDOCOLOR, 
+	ypanstep:	1,
+	ywrapstep:	1, 
+	accel:		FB_ACCEL_3DFX_BANSHEE
+};
 
-	u32 width;
-	u32 height;
-	u32 width_virt;
-	u32 height_virt;
-	u32 lpitch;		/* line pitch, in bytes */
-	u32 ppitch;		/* pixel pitch, in bits */
-	u32 bpp;
-
-	u32 hdispend;
-	u32 hsyncsta;
-	u32 hsyncend;
-	u32 htotal;
-
-	u32 vdispend;
-	u32 vsyncsta;
-	u32 vsyncend;
-	u32 vtotal;
-
-	u32 video;
-	u32 accel_flags;
-	u32 cmap_len;
+static struct fb_var_screeninfo tdfx_var __initdata = {
+	/* "640x480, 8 bpp @ 60 Hz */
+	xres:		640,
+	yres:		480,
+	xres_virtual:	640,
+	yres_virtual:	1024,
+	bits_per_pixel:	8,
+	red:		{0, 8, 0},
+	blue:		{0, 8, 0},
+	green:		{0, 8, 0},
+	activate:	FB_ACTIVATE_NOW,
+	height:		-1,
+	width:		-1,
+	accel_flags:	FB_ACCELF_TEXT,
+	pixclock:	39722,
+	left_margin:	40,
+	right_margin:	24,
+	upper_margin:	32,
+	lower_margin:	11,
+	hsync_len:	96,
+	vsync_len:	2,
+	vmode:		FB_VMODE_NONINTERLACED
 };
 
-struct fb_info_tdfx {
-	struct fb_info fb_info;
+/*
+ * PCI driver prototypes
+ */
+static int tdfxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id);
+static void tdfxfb_remove(struct pci_dev *pdev);
 
-	u16 dev;
-	u32 max_pixclock;
+static struct pci_device_id tdfxfb_id_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
+	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
+	  0xff0000, 0 },
+	{ 0, }
+};
 
-	unsigned long regbase_phys;
-	void *regbase_virt;
-	unsigned long regbase_size;
-	unsigned long bufbase_phys;
-	void *bufbase_virt;
-	unsigned long bufbase_size;
-	unsigned long iobase;
-
-	struct {
-		unsigned red, green, blue, pad;
-	} palette[256];
-	struct tdfxfb_par default_par;
-	struct tdfxfb_par current_par;
-	struct display disp;
-#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32)
-	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;
-#endif
-	struct {
-		int type;
-		int state;
-		int w, u, d;
-		int x, y, redraw;
-		unsigned long enable, disable;
-		unsigned long cursorimage;
-		struct timer_list timer;
-	} cursor;
-
-	spinlock_t DAClock;
-#ifdef CONFIG_MTRR
-	int mtrr_idx;
-#endif
+static struct pci_driver tdfxfb_driver = {
+	name:		"tdfxfb",
+	id_table:	tdfxfb_id_table,
+	probe:		tdfxfb_probe,
+	remove:		tdfxfb_remove,
 };
 
+MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
+
 /*
  *  Frame buffer device API
  */
-static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
-			  int con, struct fb_info *fb);
-static int tdfxfb_get_var(struct fb_var_screeninfo *var,
-			  int con, struct fb_info *fb);
-static int tdfxfb_set_var(struct fb_var_screeninfo *var,
-			  int con, struct fb_info *fb);
-static int tdfxfb_setcolreg(u_int regno,
-			    u_int red,
-			    u_int green,
-			    u_int blue, u_int transp, struct fb_info *fb);
-static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
-			      int con, struct fb_info *fb);
-static int tdfxfb_get_cmap(struct fb_cmap *cmap,
-			   int kspc, int con, struct fb_info *info);
-static int tdfxfb_set_cmap(struct fb_cmap *cmap,
-			   int kspc, int con, struct fb_info *info);
+int tdfxfb_init(void);
+void tdfxfb_setup(char *options, int *ints); 
 
-/*
- *  Interface to the low level console driver
- */
-static int tdfxfb_switch_con(int con, struct fb_info *fb);
-static int tdfxfb_updatevar(int con, struct fb_info *fb);
-static int tdfxfb_blank(int blank, struct fb_info *fb);
+static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); 
+static int tdfxfb_set_par(struct fb_info *info); 
+static int tdfxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 
+			    u_int transp, struct fb_info *info); 
+static int tdfxfb_blank(int blank, struct fb_info *info); 
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info);
+static void tdfxfb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+static void tdfxfb_copyarea(struct fb_info *info, struct fb_copyarea *area);  
+static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *image); 
 
-/*
- *  Internal routines
- */
-static void tdfxfb_set_par(const struct tdfxfb_par *par,
-			   struct fb_info_tdfx *info);
-static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
-			     struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info);
-static int tdfxfb_encode_var(struct fb_var_screeninfo *var,
-			     const struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info);
-static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix,
-			     const struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info);
-static void tdfxfb_set_dispsw(struct display *disp,
-			      struct fb_info_tdfx *info,
-			      int bpp, int accel);
-static int tdfxfb_getcolreg(u_int regno,
-			    u_int * red,
-			    u_int * green,
-			    u_int * blue,
-			    u_int * transp, struct fb_info *fb);
-
-static void tdfxfb_hwcursor_init(void);
-static void tdfxfb_createcursorshape(struct display *p);
-static void tdfxfb_createcursor(struct display *p);
+static struct fb_ops tdfxfb_ops = {
+	owner:		THIS_MODULE,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
+	fb_check_var:	tdfxfb_check_var,
+	fb_set_par:	tdfxfb_set_par,
+	fb_setcolreg:	tdfxfb_setcolreg,
+	fb_blank:	tdfxfb_blank,
+	fb_pan_display:	tdfxfb_pan_display,
+	fb_fillrect:	tdfxfb_fillrect,
+	fb_copyarea:	tdfxfb_copyarea,
+	fb_imageblit:	tdfxfb_imageblit,
+};
 
 /*
  * do_xxx: Hardware-specific functions
  */
-static void do_pan_var(struct fb_var_screeninfo *var,
-		       struct fb_info_tdfx *i);
-static void do_flashcursor(unsigned long ptr);
-static void do_bitblt(u32 curx, u32 cury, u32 dstx, u32 dsty,
-		      u32 width, u32 height, u32 stride, u32 bpp);
-static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
-			u32 color, u32 stride, u32 bpp, u32 rop);
-static void do_putc(u32 fgx, u32 bgx, struct display *p,
-		    int c, int yy, int xx);
-static void do_putcs(u32 fgx, u32 bgx, struct display *p,
-		     const unsigned short *s, int count, int yy, int xx);
 static u32 do_calc_pll(int freq, int *freq_out);
-static void do_write_regs(struct banshee_reg *reg);
-static unsigned long do_lfb_size(void);
-
-/*
- *  Interface used by the world
- */
-int tdfxfb_init(void);
-void tdfxfb_setup(char *options, int *ints);
+static void  do_write_regs(struct banshee_reg *reg);
+static unsigned long do_lfb_size(unsigned short);
 
 /*
- * PCI driver prototypes
+ * Driver data 
  */
-static int tdfxfb_probe(struct pci_dev *pdev,
-			const struct pci_device_id *id);
-static void tdfxfb_remove(struct pci_dev *pdev);
-
-static struct fb_ops tdfxfb_ops = {
-	owner:THIS_MODULE,
-	fb_get_fix:tdfxfb_get_fix,
-	fb_get_var:tdfxfb_get_var,
-	fb_set_var:tdfxfb_set_var,
-	fb_get_cmap:tdfxfb_get_cmap,
-	fb_set_cmap:tdfxfb_set_cmap,
-	fb_setcolreg:tdfxfb_setcolreg,
-	fb_pan_display:tdfxfb_pan_display,
-	fb_blank:tdfxfb_blank,
-};
-
-static struct pci_device_id tdfxfb_id_table[] __devinitdata = {
-	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE,
-	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	 0xff0000, 0},
-	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3,
-	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	 0xff0000, 0},
-	{PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO5,
-	 PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
-	 0xff0000, 0},
-	{0,}
-};
-
-static struct pci_driver tdfxfb_driver = {
-	name:"tdfxfb",
-	id_table:tdfxfb_id_table,
-	probe:tdfxfb_probe,
-	remove:__devexit_p(tdfxfb_remove),
-};
-
-MODULE_DEVICE_TABLE(pci, tdfxfb_id_table);
+static struct tdfx_par default_par;
 
-struct mode {
-	char *name;
-	struct fb_var_screeninfo var;
-} mode;
-
-/* 2.3.x kernels have a fb mode database, so supply only one backup default */
-struct mode default_mode[] = {
-	{"640x480-8@60",	/* @ 60 Hz */
-	 {
-	  640, 480, 640, 1024, 0, 0, 8, 0,
-	  {0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
-	  0, FB_ACTIVATE_NOW, -1, -1, FB_ACCELF_TEXT,
-	  39722, 40, 24, 32, 11, 96, 2,
-	  0, FB_VMODE_NONINTERLACED}
-	 }
-};
-
-static struct fb_info_tdfx fb_info;
-
-static int noaccel = 0;
-static int nopan = 0;
-static int nowrap = 1;		// not implemented (yet)
-static int inverse = 0;
-#ifdef CONFIG_MTRR
-static int nomtrr = 0;
-#endif
-static int nohwcursor = 0;
-static char __initdata fontname[40] = { 0 };
+static int  nopan   = 0;
+static int  nowrap  = 1;      // not implemented (yet)
+static int  inverse = 0;
 static char *mode_option __initdata = NULL;
 
 /* ------------------------------------------------------------------------- 
  *                      Hardware-specific funcions
  * ------------------------------------------------------------------------- */
 
-#ifdef VGA_REG_IO
-static inline u8 vga_inb(u32 reg)
-{
-	return inb(reg);
-}
-static inline u16 vga_inw(u32 reg)
-{
-	return inw(reg);
-}
-static inline u16 vga_inl(u32 reg)
-{
-	return inl(reg);
-}
-
-static inline void vga_outb(u32 reg, u8 val)
-{
-	outb(val, reg);
-}
-static inline void vga_outw(u32 reg, u16 val)
-{
-	outw(val, reg);
-}
-static inline void vga_outl(u32 reg, u32 val)
-{
-	outl(val, reg);
-}
+#ifdef VGA_REG_IO 
+static inline  u8 vga_inb(u32 reg) { return inb(reg); }
+static inline u16 vga_inw(u32 reg) { return inw(reg); }
+static inline u16 vga_inl(u32 reg) { return inl(reg); }
+
+static inline void vga_outb(u32 reg,  u8 val) { outb(val, reg); }
+static inline void vga_outw(u32 reg, u16 val) { outw(val, reg); }
+static inline void vga_outl(u32 reg, u32 val) { outl(val, reg); }
 #else
-static inline u8 vga_inb(u32 reg)
-{
-	return inb(fb_info.iobase + reg - 0x300);
+static inline  u8 vga_inb(u32 reg) { 
+	return inb(default_par.iobase + reg - 0x300); 
 }
-static inline u16 vga_inw(u32 reg)
-{
-	return inw(fb_info.iobase + reg - 0x300);
+static inline u16 vga_inw(u32 reg) { 
+	return inw(default_par.iobase + reg - 0x300); 
 }
-static inline u16 vga_inl(u32 reg)
-{
-	return inl(fb_info.iobase + reg - 0x300);
+static inline u16 vga_inl(u32 reg) { 
+	return inl(default_par.iobase + reg - 0x300); 
 }
-
-static inline void vga_outb(u32 reg, u8 val)
-{
-	outb(val, fb_info.iobase + reg - 0x300);
+static inline void vga_outb(u32 reg,  u8 val) { 
+	outb(val, default_par.iobase + reg - 0x300); 
 }
-static inline void vga_outw(u32 reg, u16 val)
-{
-	outw(val, fb_info.iobase + reg - 0x300);
+static inline void vga_outw(u32 reg, u16 val) { 
+	outw(val, default_par.iobase + reg - 0x300); 
 }
-static inline void vga_outl(u32 reg, u32 val)
-{
-	outl(val, fb_info.iobase + reg - 0x300);
+static inline void vga_outl(u32 reg, u32 val) { 
+	outl(val, default_par.iobase + reg - 0x300); 
 }
 #endif
 
-static inline void gra_outb(u32 idx, u8 val)
-{
-	vga_outb(GRA_I, idx);
-	vga_outb(GRA_D, val);
+static inline void gra_outb(u32 idx, u8 val) {
+	vga_outb(GRA_I, idx); vga_outb(GRA_D, val);
 }
 
-static inline u8 gra_inb(u32 idx)
-{
-	vga_outb(GRA_I, idx);
-	return vga_inb(GRA_D);
+static inline u8 gra_inb(u32 idx) {
+	vga_outb(GRA_I, idx); return vga_inb(GRA_D);
 }
 
-static inline void seq_outb(u32 idx, u8 val)
-{
-	vga_outb(SEQ_I, idx);
-	vga_outb(SEQ_D, val);
+static inline void seq_outb(u32 idx, u8 val) {
+	vga_outb(SEQ_I, idx); vga_outb(SEQ_D, val);
 }
 
-static inline u8 seq_inb(u32 idx)
-{
-	vga_outb(SEQ_I, idx);
-	return vga_inb(SEQ_D);
+static inline u8 seq_inb(u32 idx) {
+	vga_outb(SEQ_I, idx); return vga_inb(SEQ_D);
 }
 
-static inline void crt_outb(u32 idx, u8 val)
-{
-	vga_outb(CRT_I, idx);
-	vga_outb(CRT_D, val);
+static inline void crt_outb(u32 idx, u8 val) {
+	vga_outb(CRT_I, idx); vga_outb(CRT_D, val);
 }
 
-static inline u8 crt_inb(u32 idx)
-{
-	vga_outb(CRT_I, idx);
-	return vga_inb(CRT_D);
+static inline u8 crt_inb(u32 idx) {
+	vga_outb(CRT_I, idx); return vga_inb(CRT_D);
 }
 
-static inline void att_outb(u32 idx, u8 val)
+static inline void att_outb(u32 idx, u8 val) 
 {
 	unsigned char tmp;
+	
 	tmp = vga_inb(IS1_R);
 	vga_outb(ATT_IW, idx);
 	vga_outb(ATT_IW, val);
 }
 
-static inline u8 att_inb(u32 idx)
+static inline u8 att_inb(u32 idx) 
 {
 	unsigned char tmp;
+
 	tmp = vga_inb(IS1_R);
 	vga_outb(ATT_IW, idx);
 	return vga_inb(ATT_IW);
@@ -452,6 +283,7 @@
 static inline void vga_disable_video(void)
 {
 	unsigned char s;
+
 	s = seq_inb(0x01) | 0x20;
 	seq_outb(0x00, 0x01);
 	seq_outb(0x01, s);
@@ -461,6 +293,7 @@
 static inline void vga_enable_video(void)
 {
 	unsigned char s;
+
 	s = seq_inb(0x01) & 0xdf;
 	seq_outb(0x00, 0x01);
 	seq_outb(0x01, s);
@@ -479,21 +312,21 @@
 	vga_outb(ATT_IW, 0x20);
 }
 
-static inline u32 tdfx_inl(unsigned int reg)
+static inline u32 tdfx_inl(unsigned int reg) 
 {
-	return readl(fb_info.regbase_virt + reg);
+	return readl(default_par.regbase_virt + reg);
 }
 
 static inline void tdfx_outl(unsigned int reg, u32 val)
 {
-	writel(val, fb_info.regbase_virt + reg);
+	writel(val, default_par.regbase_virt + reg);
 }
 
 static inline void banshee_make_room(int size)
 {
-	while ((tdfx_inl(STATUS) & 0x1f) < size);
+	while((tdfx_inl(STATUS) & 0x1f) < size);
 }
-
+ 
 static inline void banshee_wait_idle(void)
 {
 	int i = 0;
@@ -501,10 +334,9 @@
 	banshee_make_room(1);
 	tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
 
-	while (1) {
+	while(1) {
 		i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
-		if (i == 3)
-			break;
+		if(i == 3) break;
 	}
 }
 
@@ -512,249 +344,17 @@
  * Set the color of a palette entry in 8bpp mode 
  */
 static inline void do_setpalentry(unsigned regno, u32 c)
-{
+{  
 	banshee_make_room(2);
 	tdfx_outl(DACADDR, regno);
 	tdfx_outl(DACDATA, c);
 }
 
-/* 
- * Set the starting position of the visible screen to var->yoffset 
- */
-static void do_pan_var(struct fb_var_screeninfo *var,
-		       struct fb_info_tdfx *i)
-{
-	u32 addr;
-	addr = var->yoffset * i->current_par.lpitch;
-	banshee_make_room(1);
-	tdfx_outl(VIDDESKSTART, addr);
-}
-
-/*
- * Invert the hardware cursor image (timerfunc)  
- */
-static void do_flashcursor(unsigned long ptr)
-{
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) ptr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&i->DAClock, flags);
-	banshee_make_room(1);
-	tdfx_outl(VIDPROCCFG,
-		  tdfx_inl(VIDPROCCFG) ^ VIDCFG_HWCURSOR_ENABLE);
-	i->cursor.timer.expires = jiffies + HZ / 2;
-	add_timer(&i->cursor.timer);
-	spin_unlock_irqrestore(&i->DAClock, flags);
-}
-
-/*
- * FillRect 2D command (solidfill or invert (via ROP_XOR))   
- */
-static void do_fillrect(u32 x, u32 y, u32 w, u32 h,
-			u32 color, u32 stride, u32 bpp, u32 rop)
-{
-
-	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
-
-	banshee_make_room(5);
-	tdfx_outl(DSTFORMAT, fmt);
-	tdfx_outl(COLORFORE, color);
-	tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (rop << 24));
-	tdfx_outl(DSTSIZE, w | (h << 16));
-	tdfx_outl(LAUNCH_2D, x | (y << 16));
-	banshee_wait_idle();
-}
-
-/*
- * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) 
- */
-
-static void do_bitblt(u32 curx,
-		      u32 cury,
-		      u32 dstx,
-		      u32 dsty, u32 width, u32 height, u32 stride, u32 bpp)
-{
-
-	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
-	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
-
-	if (curx <= dstx) {
-		//-X 
-		blitcmd |= BIT(14);
-		curx += width - 1;
-		dstx += width - 1;
-	}
-	if (cury <= dsty) {
-		//-Y  
-		blitcmd |= BIT(15);
-		cury += height - 1;
-		dsty += height - 1;
-	}
-
-	banshee_make_room(6);
-
-	tdfx_outl(SRCFORMAT, fmt);
-	tdfx_outl(DSTFORMAT, fmt);
-	tdfx_outl(COMMAND_2D, blitcmd);
-	tdfx_outl(DSTSIZE, width | (height << 16));
-	tdfx_outl(DSTXY, dstx | (dsty << 16));
-	tdfx_outl(LAUNCH_2D, curx | (cury << 16));
-	banshee_wait_idle();
-}
-
-static void do_putc(u32 fgx, u32 bgx,
-		    struct display *p, int c, int yy, int xx)
-{
-	int i;
-	int stride = fb_info.current_par.lpitch;
-	u32 bpp = fb_info.current_par.bpp;
-	int fw = (fontwidth(p) + 7) >> 3;
-	u8 *chardata =
-	    p->fontdata + (c & p->charmask) * fontheight(p) * fw;
-	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
-
-	xx *= fontwidth(p);
-	yy *= fontheight(p);
-
-	banshee_make_room(8 + ((fontheight(p) * fw + 3) >> 2));
-	tdfx_outl(COLORFORE, fgx);
-	tdfx_outl(COLORBACK, bgx);
-	tdfx_outl(SRCXY, 0);
-	tdfx_outl(DSTXY, xx | (yy << 16));
-	tdfx_outl(COMMAND_2D,
-		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
-	tdfx_outl(SRCFORMAT, 0x400000);
-	tdfx_outl(DSTFORMAT, fmt);
-	tdfx_outl(DSTSIZE, fontwidth(p) | (fontheight(p) << 16));
-	i = fontheight(p);
-	switch (fw) {
-	case 1:
-		while (i >= 4) {
-			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-			chardata += 4;
-			i -= 4;
-		}
-		switch (i) {
-		case 0:
-			break;
-		case 1:
-			tdfx_outl(LAUNCH_2D, *chardata);
-			break;
-		case 2:
-			tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
-			break;
-		case 3:
-			tdfx_outl(LAUNCH_2D,
-				  *(u16 *) chardata | ((chardata[3]) <<
-						       24));
-			break;
-		}
-		break;
-	case 2:
-		while (i >= 2) {
-			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-			chardata += 4;
-			i -= 2;
-		}
-		if (i)
-			tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
-		break;
-	default:
-		// Is there a font with width more that 16 pixels ?
-		for (i = fontheight(p); i > 0; i--) {
-			tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-			chardata += 4;
-		}
-		break;
-	}
-	banshee_wait_idle();
-}
-
-static void do_putcs(u32 fgx, u32 bgx,
-		     struct display *p,
-		     const unsigned short *s, int count, int yy, int xx)
-{
-	int i;
-	int stride = fb_info.current_par.lpitch;
-	u32 bpp = fb_info.current_par.bpp;
-	int fw = (fontwidth(p) + 7) >> 3;
-	int w = fontwidth(p);
-	int h = fontheight(p);
-	int regsneed = 1 + ((h * fw + 3) >> 2);
-	u32 fmt = stride | ((bpp + ((bpp == 8) ? 0 : 8)) << 13);
-
-	xx *= w;
-	yy = (yy * h) << 16;
-	banshee_make_room(8);
-
-	tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
-	tdfx_outl(COLORFORE, fgx);
-	tdfx_outl(COLORBACK, bgx);
-	tdfx_outl(SRCFORMAT, 0x400000);
-	tdfx_outl(DSTFORMAT, fmt);
-	tdfx_outl(DSTSIZE, w | (h << 16));
-	tdfx_outl(SRCXY, 0);
-	tdfx_outl(COMMAND_2D,
-		  COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
-
-	while (count--) {
-		u8 *chardata =
-		    p->fontdata + (scr_readw(s++) & p->charmask) * h * fw;
-
-		banshee_make_room(regsneed);
-		tdfx_outl(DSTXY, xx | yy);
-		xx += w;
-
-		i = h;
-		switch (fw) {
-		case 1:
-			while (i >= 4) {
-				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-				chardata += 4;
-				i -= 4;
-			}
-			switch (i) {
-			case 0:
-				break;
-			case 1:
-				tdfx_outl(LAUNCH_2D, *chardata);
-				break;
-			case 2:
-				tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
-				break;
-			case 3:
-				tdfx_outl(LAUNCH_2D,
-					  *(u16 *) chardata |
-					  ((chardata[3]) << 24));
-				break;
-			}
-			break;
-		case 2:
-			while (i >= 2) {
-				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-				chardata += 4;
-				i -= 2;
-			}
-			if (i)
-				tdfx_outl(LAUNCH_2D, *(u16 *) chardata);
-			break;
-		default:
-			// Is there a font with width more that 16 pixels ?
-			for (; i > 0; i--) {
-				tdfx_outl(LAUNCH_2D, *(u32 *) chardata);
-				chardata += 4;
-			}
-			break;
-		}
-	}
-	banshee_wait_idle();
-}
-
-static u32 do_calc_pll(int freq, int *freq_out)
+static u32 do_calc_pll(int freq, int* freq_out) 
 {
 	int m, n, k, best_m, best_n, best_k, f_cur, best_error;
 	int fref = 14318;
-
+  
 	/* this really could be done with more intelligence --
 	   255*63*4 = 64260 iterations is silly */
 	best_error = freq;
@@ -762,10 +362,9 @@
 	for (n = 1; n < 256; n++) {
 		for (m = 1; m < 64; m++) {
 			for (k = 0; k < 4; k++) {
-				f_cur =
-				    fref * (n + 2) / (m + 2) / (1 << k);
+				f_cur = fref*(n + 2)/(m + 2)/(1 << k);
 				if (abs(f_cur - freq) < best_error) {
-					best_error = abs(f_cur - freq);
+					best_error = abs(f_cur-freq);
 					best_n = n;
 					best_m = m;
 					best_k = k;
@@ -776,12 +375,11 @@
 	n = best_n;
 	m = best_m;
 	k = best_k;
-	*freq_out = fref * (n + 2) / (m + 2) / (1 << k);
-
+	*freq_out = fref*(n + 2)/(m + 2)/(1 << k);
 	return (n << 8) | (m << 2) | k;
 }
 
-static void do_write_regs(struct banshee_reg *reg)
+static void do_write_regs(struct banshee_reg* reg) 
 {
 	int i;
 
@@ -789,16 +387,16 @@
 
 	tdfx_outl(MISCINIT1, tdfx_inl(MISCINIT1) | 0x01);
 
-	crt_outb(0x11, crt_inb(0x11) & 0x7f);	/* CRT unprotect */
+	crt_outb(0x11, crt_inb(0x11) & 0x7f); /* CRT unprotect */
 
 	banshee_make_room(3);
-	tdfx_outl(VGAINIT1, reg->vgainit1 & 0x001FFFFF);
-	tdfx_outl(VIDPROCCFG, reg->vidcfg & ~0x00000001);
+	tdfx_outl(VGAINIT1,	reg->vgainit1 &  0x001FFFFF);
+	tdfx_outl(VIDPROCCFG,	reg->vidcfg   & ~0x00000001);
 #if 0
 	tdfx_outl(PLLCTRL1, reg->mempll);
 	tdfx_outl(PLLCTRL2, reg->gfxpll);
 #endif
-	tdfx_outl(PLLCTRL0, reg->vidpll);
+	tdfx_outl(PLLCTRL0,	reg->vidpll);
 
 	vga_outb(MISC_W, reg->misc[0x00] | 0x01);
 
@@ -821,56 +419,49 @@
 	vga_enable_video();
 
 	banshee_make_room(11);
-	tdfx_outl(VGAINIT0, reg->vgainit0);
-	tdfx_outl(DACMODE, reg->dacmode);
+	tdfx_outl(VGAINIT0,      reg->vgainit0);
+	tdfx_outl(DACMODE,       reg->dacmode);
 	tdfx_outl(VIDDESKSTRIDE, reg->stride);
-	if (nohwcursor) {
-		tdfx_outl(HWCURPATADDR, 0);
-	} else {
-		tdfx_outl(HWCURPATADDR, reg->curspataddr);
-		tdfx_outl(HWCURC0, reg->cursc0);
-		tdfx_outl(HWCURC1, reg->cursc1);
-		tdfx_outl(HWCURLOC, reg->cursloc);
-	}
-
-	tdfx_outl(VIDSCREENSIZE, reg->screensize);
-	tdfx_outl(VIDDESKSTART, reg->startaddr);
-	tdfx_outl(VIDPROCCFG, reg->vidcfg);
-	tdfx_outl(VGAINIT1, reg->vgainit1);
-	tdfx_outl(MISCINIT0, reg->miscinit0);
+	tdfx_outl(HWCURPATADDR,  0);
+   
+	tdfx_outl(VIDSCREENSIZE,reg->screensize);
+	tdfx_outl(VIDDESKSTART,	reg->startaddr);
+	tdfx_outl(VIDPROCCFG,	reg->vidcfg);
+	tdfx_outl(VGAINIT1,	reg->vgainit1);  
+	tdfx_outl(MISCINIT0,	reg->miscinit0);	
 
 	banshee_make_room(8);
-	tdfx_outl(SRCBASE, reg->srcbase);
-	tdfx_outl(DSTBASE, reg->dstbase);
+	tdfx_outl(SRCBASE,         reg->srcbase);
+	tdfx_outl(DSTBASE,         reg->dstbase);
 	tdfx_outl(COMMANDEXTRA_2D, 0);
-	tdfx_outl(CLIP0MIN, 0);
-	tdfx_outl(CLIP0MAX, 0x0fff0fff);
-	tdfx_outl(CLIP1MIN, 0);
-	tdfx_outl(CLIP1MAX, 0x0fff0fff);
-	tdfx_outl(SRCXY, 0);
+	tdfx_outl(CLIP0MIN,        0);
+	tdfx_outl(CLIP0MAX,        0x0fff0fff);
+	tdfx_outl(CLIP1MIN,        0);
+	tdfx_outl(CLIP1MAX,        0x0fff0fff);
+	tdfx_outl(SRCXY,	   0);
 
 	banshee_wait_idle();
 }
 
-static unsigned long do_lfb_size(void)
+static unsigned long do_lfb_size(unsigned short dev_id) 
 {
 	u32 draminit0 = 0;
 	u32 draminit1 = 0;
 	u32 miscinit1 = 0;
-	u32 lfbsize = 0;
-	int sgram_p = 0;
+	u32 lfbsize   = 0;
+	int sgram_p   = 0;
 
-	draminit0 = tdfx_inl(DRAMINIT0);
+	draminit0 = tdfx_inl(DRAMINIT0);  
 	draminit1 = tdfx_inl(DRAMINIT1);
-
-	if ((fb_info.dev == PCI_DEVICE_ID_3DFX_BANSHEE) ||
-	    (fb_info.dev == PCI_DEVICE_ID_3DFX_VOODOO3)) {
+ 
+	if ((dev_id == PCI_DEVICE_ID_3DFX_BANSHEE) ||
+	    (dev_id == PCI_DEVICE_ID_3DFX_VOODOO3)) {             	 
 		sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1;
-
-		lfbsize = sgram_p ?
-		    (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
-		     ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 *
-		     1024) : 16 * 1024 * 1024;
+  
+	lfbsize = sgram_p ?
+		(((draminit0 & DRAMINIT0_SGRAM_NUM)  ? 2 : 1) * 
+		((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
+		16 * 1024 * 1024;
 	} else {
 		/* Voodoo4/5 */
 		u32 chips, psize, banks;
@@ -880,316 +471,164 @@
 		banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4;
 		lfbsize = chips * psize * banks;
 		lfbsize <<= 20;
-	}
-
+	}                 
 	/* disable block writes for SDRAM (why?) */
 	miscinit1 = tdfx_inl(MISCINIT1);
 	miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS;
 	miscinit1 |= MISCINIT1_CLUT_INV;
 
-	banshee_make_room(1);
+	banshee_make_room(1); 
 	tdfx_outl(MISCINIT1, miscinit1);
-
 	return lfbsize;
 }
 
-/* ------------------------------------------------------------------------- 
- *              Hardware independent part, interface to the world
- * ------------------------------------------------------------------------- */
+/* ------------------------------------------------------------------------- */
 
-#define tdfx_cfb24_putc  tdfx_cfb32_putc
-#define tdfx_cfb24_putcs tdfx_cfb32_putcs
-#define tdfx_cfb24_clear tdfx_cfb32_clear
-
-static void tdfx_cfbX_clear_margins(struct vc_data *conp,
-				    struct display *p, int bottom_only)
-{
-	unsigned int cw = fontwidth(p);
-	unsigned int ch = fontheight(p);
-	unsigned int rw = p->var.xres % cw;	// it be in a non-standard mode or not?
-	unsigned int bh = p->var.yres % ch;
-	unsigned int rs = p->var.xres - rw;
-	unsigned int bs = p->var.yres - bh;
-
-	if (!bottom_only && rw) {
-		do_fillrect(p->var.xoffset + rs, 0,
-			    rw, p->var.yres_virtual, 0,
-			    fb_info.current_par.lpitch,
-			    fb_info.current_par.bpp, TDFX_ROP_COPY);
-	}
-
-	if (bh) {
-		do_fillrect(p->var.xoffset, p->var.yoffset + bs,
-			    rs, bh, 0,
-			    fb_info.current_par.lpitch,
-			    fb_info.current_par.bpp, TDFX_ROP_COPY);
-	}
-}
-static void tdfx_cfbX_bmove(struct display *p,
-			    int sy,
-			    int sx, int dy, int dx, int height, int width)
-{
-	do_bitblt(fontwidth(p) * sx,
-		  fontheight(p) * sy,
-		  fontwidth(p) * dx,
-		  fontheight(p) * dy,
-		  fontwidth(p) * width,
-		  fontheight(p) * height,
-		  fb_info.current_par.lpitch, fb_info.current_par.bpp);
-}
-static void tdfx_cfb8_putc(struct vc_data *conp,
-			   struct display *p, int c, int yy, int xx)
-{
-	u32 fgx, bgx;
-	fgx = attr_fgcol(p, c);
-	bgx = attr_bgcol(p, c);
-	do_putc(fgx, bgx, p, c, yy, xx);
-}
-
-static void tdfx_cfb16_putc(struct vc_data *conp,
-			    struct display *p, int c, int yy, int xx)
-{
-	u32 fgx, bgx;
-	fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
-	bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
-	do_putc(fgx, bgx, p, c, yy, xx);
-}
-
-static void tdfx_cfb32_putc(struct vc_data *conp,
-			    struct display *p, int c, int yy, int xx)
-{
-	u32 fgx, bgx;
-	fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
-	bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-	do_putc(fgx, bgx, p, c, yy, xx);
-}
-static void tdfx_cfb8_putcs(struct vc_data *conp,
-			    struct display *p,
-			    const unsigned short *s, int count, int yy,
-			    int xx)
-{
-	u16 c = scr_readw(s);
-	u32 fgx = attr_fgcol(p, c);
-	u32 bgx = attr_bgcol(p, c);
-	do_putcs(fgx, bgx, p, s, count, yy, xx);
-}
-static void tdfx_cfb16_putcs(struct vc_data *conp,
-			     struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx)
-{
-	u16 c = scr_readw(s);
-	u32 fgx = ((u16 *) p->dispsw_data)[attr_fgcol(p, c)];
-	u32 bgx = ((u16 *) p->dispsw_data)[attr_bgcol(p, c)];
-	do_putcs(fgx, bgx, p, s, count, yy, xx);
-}
-static void tdfx_cfb32_putcs(struct vc_data *conp,
-			     struct display *p,
-			     const unsigned short *s, int count, int yy,
-			     int xx)
-{
-	u16 c = scr_readw(s);
-	u32 fgx = ((u32 *) p->dispsw_data)[attr_fgcol(p, c)];
-	u32 bgx = ((u32 *) p->dispsw_data)[attr_bgcol(p, c)];
-	do_putcs(fgx, bgx, p, s, count, yy, xx);
-}
-
-static void tdfx_cfb8_clear(struct vc_data *conp,
-			    struct display *p,
-			    int sy, int sx, int height, int width)
-{
-	u32 bg;
-
-	bg = attr_bgcol_ec(p, conp);
-	do_fillrect(fontwidth(p) * sx,
-		    fontheight(p) * sy,
-		    fontwidth(p) * width,
-		    fontheight(p) * height,
-		    bg,
-		    fb_info.current_par.lpitch,
-		    fb_info.current_par.bpp, TDFX_ROP_COPY);
-}
-
-static void tdfx_cfb16_clear(struct vc_data *conp,
-			     struct display *p,
-			     int sy, int sx, int height, int width)
-{
-	u32 bg;
-
-	bg = ((u16 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-	do_fillrect(fontwidth(p) * sx,
-		    fontheight(p) * sy,
-		    fontwidth(p) * width,
-		    fontheight(p) * height,
-		    bg,
-		    fb_info.current_par.lpitch,
-		    fb_info.current_par.bpp, TDFX_ROP_COPY);
-}
-
-static void tdfx_cfb32_clear(struct vc_data *conp,
-			     struct display *p,
-			     int sy, int sx, int height, int width)
-{
-	u32 bg;
-
-	bg = ((u32 *) p->dispsw_data)[attr_bgcol_ec(p, conp)];
-	do_fillrect(fontwidth(p) * sx,
-		    fontheight(p) * sy,
-		    fontwidth(p) * width,
-		    fontheight(p) * height,
-		    bg,
-		    fb_info.current_par.lpitch,
-		    fb_info.current_par.bpp, TDFX_ROP_COPY);
-}
-static void tdfx_cfbX_revc(struct display *p, int xx, int yy)
-{
-	int bpp = fb_info.current_par.bpp;
-
-	do_fillrect(xx * fontwidth(p), yy * fontheight(p),
-		    fontwidth(p), fontheight(p),
-		    (bpp == 8) ? 0x0f : 0xffffffff,
-		    fb_info.current_par.lpitch, bpp, TDFX_ROP_XOR);
-
-}
-static void tdfx_cfbX_cursor(struct display *p, int mode, int x, int y)
-{
-	unsigned long flags;
-	int tip;
-	struct fb_info_tdfx *info = (struct fb_info_tdfx *) p->fb_info;
-
-	tip = p->conp->vc_cursor_type & CUR_HWMASK;
-	if (mode == CM_ERASE) {
-		if (info->cursor.state != CM_ERASE) {
-			spin_lock_irqsave(&info->DAClock, flags);
-			info->cursor.state = CM_ERASE;
-			del_timer(&(info->cursor.timer));
-			tdfx_outl(VIDPROCCFG, info->cursor.disable);
-			spin_unlock_irqrestore(&info->DAClock, flags);
-		}
-		return;
+static int tdfxfb_check_var(struct fb_var_screeninfo *var,struct fb_info *info) 
+{
+	struct tdfx_par *par = (struct tdfx_par *) info->par; 
+	u32 lpitch;
+
+	if (var->bits_per_pixel != 8  && var->bits_per_pixel != 16 &&
+	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
+		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
+		return -EINVAL;
 	}
-	if ((p->conp->vc_cursor_type & CUR_HWMASK) != info->cursor.type)
-		tdfxfb_createcursor(p);
-	x *= fontwidth(p);
-	y *= fontheight(p);
-	y -= p->var.yoffset;
-	spin_lock_irqsave(&info->DAClock, flags);
-	if ((x != info->cursor.x) ||
-	    (y != info->cursor.y) || (info->cursor.redraw)) {
-		info->cursor.x = x;
-		info->cursor.y = y;
-		info->cursor.redraw = 0;
-		x += 63;
-		y += 63;
-		banshee_make_room(2);
-		tdfx_outl(VIDPROCCFG, info->cursor.disable);
-		tdfx_outl(HWCURLOC, (y << 16) + x);
-		/* fix cursor color - XFree86 forgets to restore it properly */
-		tdfx_outl(HWCURC0, 0);
-		tdfx_outl(HWCURC1, 0xffffff);
+
+	if (var->xres != var->xres_virtual) {
+		DPRINTK("virtual x resolution != physical x resolution not supported\n");
+		return -EINVAL;
 	}
-	info->cursor.state = CM_DRAW;
-	mod_timer(&info->cursor.timer, jiffies + HZ / 2);
-	banshee_make_room(1);
-	tdfx_outl(VIDPROCCFG, info->cursor.enable);
-	spin_unlock_irqrestore(&info->DAClock, flags);
-	return;
-}
-
-#ifdef FBCON_HAS_CFB8
-static struct display_switch fbcon_banshee8 = {
-	setup:fbcon_cfb8_setup,
-	bmove:tdfx_cfbX_bmove,
-	clear:tdfx_cfb8_clear,
-	putc:tdfx_cfb8_putc,
-	putcs:tdfx_cfb8_putcs,
-	revc:tdfx_cfbX_revc,
-	cursor:tdfx_cfbX_cursor,
-	clear_margins:tdfx_cfbX_clear_margins,
-	fontwidthmask:FONTWIDTHRANGE(8, 12)
-};
-#endif
-#ifdef FBCON_HAS_CFB16
-static struct display_switch fbcon_banshee16 = {
-	setup:fbcon_cfb16_setup,
-	bmove:tdfx_cfbX_bmove,
-	clear:tdfx_cfb16_clear,
-	putc:tdfx_cfb16_putc,
-	putcs:tdfx_cfb16_putcs,
-	revc:tdfx_cfbX_revc,
-	cursor:tdfx_cfbX_cursor,
-	clear_margins:tdfx_cfbX_clear_margins,
-	fontwidthmask:FONTWIDTHRANGE(8, 12)
-};
-#endif
-#ifdef FBCON_HAS_CFB24
-static struct display_switch fbcon_banshee24 = {
-	setup:fbcon_cfb24_setup,
-	bmove:tdfx_cfbX_bmove,
-	clear:tdfx_cfb24_clear,
-	putc:tdfx_cfb24_putc,
-	putcs:tdfx_cfb24_putcs,
-	revc:tdfx_cfbX_revc,
-	cursor:tdfx_cfbX_cursor,
-	clear_margins:tdfx_cfbX_clear_margins,
-	fontwidthmask:FONTWIDTHRANGE(8, 12)
-};
-#endif
-#ifdef FBCON_HAS_CFB32
-static struct display_switch fbcon_banshee32 = {
-	setup:fbcon_cfb32_setup,
-	bmove:tdfx_cfbX_bmove,
-	clear:tdfx_cfb32_clear,
-	putc:tdfx_cfb32_putc,
-	putcs:tdfx_cfb32_putcs,
-	revc:tdfx_cfbX_revc,
-	cursor:tdfx_cfbX_cursor,
-	clear_margins:tdfx_cfbX_clear_margins,
-	fontwidthmask:FONTWIDTHRANGE(8, 12)
-};
-#endif
 
-/* ------------------------------------------------------------------------- */
+	if (var->yres > var->yres_virtual) {
+		DPRINTK("virtual y resolution < physical y resolution not possible\n");
+		return -EINVAL;
+	}
+
+	if (var->xoffset) {
+		DPRINTK("xoffset not supported\n");
+		return -EINVAL;
+	}
+
+	/* fixme: does Voodoo3 support interlace? Banshee doesn't */
+	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+		DPRINTK("interlace not supported\n");
+		return -EINVAL;
+	}
+
+	var->xres = (var->xres + 15) & ~15; /* could sometimes be 8 */
+	lpitch = var->xres * ((var->bits_per_pixel + 7)>>3);
+  
+	if (var->xres < 320 || var->xres > 2048) {
+		DPRINTK("width not supported: %u\n", var->xres);
+		return -EINVAL;
+	}
+  
+	if (var->yres < 200 || var->yres > 2048) {
+		DPRINTK("height not supported: %u\n", var->yres);
+		return -EINVAL;
+	}
+  
+	if (lpitch * var->yres_virtual > info->fix.smem_len) {
+		DPRINTK("no memory for screen (%ux%ux%u)\n",
+		var->xres, var->yres_virtual, var->bits_per_pixel);
+		return -EINVAL;
+	}
+  
+	if (PICOS2KHZ(var->pixclock) > par->max_pixclock) {
+		DPRINTK("pixclock too high (%ldKHz)\n",PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	switch(var->bits_per_pixel) {
+		case 8:
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+		case 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;
+			break;
+		case 24:
+			var->red.offset=16;
+			var->green.offset=8;
+			var->blue.offset=0;
+			var->red.length = var->green.length = var->blue.length = 8;
+		case 32:
+			var->red.offset   = 16;
+			var->green.offset = 8;
+			var->blue.offset  = 0;
+			var->red.length = var->green.length = var->blue.length = 8;
+			break;
+	}
+	var->height = var->width = -1;
+  
+	var->accel_flags = FB_ACCELF_TEXT;
+	
+	DPRINTK("Checking graphics mode at %dx%d depth %d\n",  var->xres, var->yres, var->bits_per_pixel);
+	return 0;
+}
 
-static void tdfxfb_set_par(const struct tdfxfb_par *par,
-			   struct fb_info_tdfx *info)
+static int tdfxfb_set_par(struct fb_info *info)
 {
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
-	struct banshee_reg reg;
-	u32 cpp;
+	struct tdfx_par *par = (struct tdfx_par *) info->par;	
+	u32 hdispend, hsyncsta, hsyncend, htotal;
 	u32 hd, hs, he, ht, hbs, hbe;
 	u32 vd, vs, ve, vt, vbs, vbe;
-	u32 wd;
-	int fout;
-	int freq;
-
+	struct banshee_reg reg;
+	int fout, freq;
+	u32 wd, cpp;
+  
+	info->cmap.len = (info->var.bits_per_pixel == 8) ? 256 : 16;
+	par->baseline  = 0;
+ 
 	memset(&reg, 0, sizeof(reg));
+	cpp = (info->var.bits_per_pixel + 7)/8;
+ 
+	reg.vidcfg = VIDCFG_VIDPROC_ENABLE | VIDCFG_DESK_ENABLE | VIDCFG_CURS_X11 | ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) | (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
 
-	cpp = (par->bpp + 7) / 8;
+	/* PLL settings */
+	freq = PICOS2KHZ(info->var.pixclock);
+
+	reg.dacmode = 0;
+	reg.vidcfg  &= ~VIDCFG_2X;
 
-	wd = (par->hdispend >> 3) - 1;
+	hdispend = info->var.xres;
+	hsyncsta = hdispend + info->var.right_margin;
+	hsyncend = hsyncsta + info->var.hsync_len;
+	htotal   = hsyncend + info->var.left_margin;	
 
-	hd = (par->hdispend >> 3) - 1;
-	hs = (par->hsyncsta >> 3) - 1;
-	he = (par->hsyncend >> 3) - 1;
-	ht = (par->htotal >> 3) - 1;
+	if (freq > par->max_pixclock/2) {
+		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
+		reg.dacmode |= DACMODE_2X;
+		reg.vidcfg  |= VIDCFG_2X;
+		hdispend >>= 1;
+		hsyncsta >>= 1;
+		hsyncend >>= 1;
+		htotal   >>= 1;
+	}
+  
+	hd  = wd = (hdispend >> 3) - 1;
+	hs  = (hsyncsta >> 3) - 1;
+	he  = (hsyncend >> 3) - 1;
+	ht  = (htotal >> 3) - 1;
 	hbs = hd;
 	hbe = ht;
 
-	vd = par->vdispend - 1;
-	vs = par->vsyncsta - 1;
-	ve = par->vsyncend - 1;
-	vt = par->vtotal - 2;
-	vbs = vd;
-	vbe = vt;
-
+	vbs = vd = info->var.yres - 1;
+	vs  = vd + info->var.lower_margin;
+	ve  = vs + info->var.vsync_len;
+	vbe = vt = ve + info->var.upper_margin - 1;
+  
 	/* this is all pretty standard VGA register stuffing */
-	reg.misc[0x00] =
-	    0x0f |
-	    (par->hdispend < 400 ? 0xa0 :
-	     par->hdispend < 480 ? 0x60 :
-	     par->hdispend < 768 ? 0xe0 : 0x20);
-
+	reg.misc[0x00] = 0x0f | 
+			(info->var.xres < 400 ? 0xa0 :
+			 info->var.xres < 480 ? 0x60 :
+			 info->var.xres < 768 ? 0xe0 : 0x20);
+     
 	reg.gra[0x00] = 0x00;
 	reg.gra[0x01] = 0x00;
 	reg.gra[0x02] = 0x00;
@@ -1223,7 +662,7 @@
 	reg.att[0x14] = 0x00;
 
 	reg.seq[0x00] = 0x03;
-	reg.seq[0x01] = 0x01;	/* fixme: clkdiv2? */
+	reg.seq[0x01] = 0x01; /* fixme: clkdiv2? */
 	reg.seq[0x02] = 0x0f;
 	reg.seq[0x03] = 0x00;
 	reg.seq[0x04] = 0x0e;
@@ -1233,18 +672,17 @@
 	reg.crt[0x02] = hbs;
 	reg.crt[0x03] = 0x80 | (hbe & 0x1f);
 	reg.crt[0x04] = hs;
-	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f);
+	reg.crt[0x05] = ((hbe & 0x20) << 2) | (he & 0x1f); 
 	reg.crt[0x06] = vt;
-	reg.crt[0x07] =
-	    ((vs & 0x200) >> 2) |
-	    ((vd & 0x200) >> 3) |
-	    ((vt & 0x200) >> 4) |
-	    0x10 |
-	    ((vbs & 0x100) >> 5) |
-	    ((vs & 0x100) >> 6) |
-	    ((vd & 0x100) >> 7) | ((vt & 0x100) >> 8);
+	reg.crt[0x07] = ((vs & 0x200) >> 2) |
+			((vd & 0x200) >> 3) |
+			((vt & 0x200) >> 4) | 0x10 |
+			((vbs & 0x100) >> 5) |
+			((vs  & 0x100) >> 6) |
+			((vd  & 0x100) >> 7) |
+			((vt  & 0x100) >> 8);
 	reg.crt[0x08] = 0x00;
-	reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4);
+	reg.crt[0x09] = 0x40 | ((vbs & 0x200) >> 4); 
 	reg.crt[0x0a] = 0x00;
 	reg.crt[0x0b] = 0x00;
 	reg.crt[0x0c] = 0x00;
@@ -1252,63 +690,53 @@
 	reg.crt[0x0e] = 0x00;
 	reg.crt[0x0f] = 0x00;
 	reg.crt[0x10] = vs;
-	reg.crt[0x11] = (ve & 0x0f) | 0x20;
+	reg.crt[0x11] = (ve & 0x0f) | 0x20; 
 	reg.crt[0x12] = vd;
 	reg.crt[0x13] = wd;
 	reg.crt[0x14] = 0x00;
 	reg.crt[0x15] = vbs;
-	reg.crt[0x16] = vbe + 1;
+	reg.crt[0x16] = vbe + 1; 
 	reg.crt[0x17] = 0xc3;
 	reg.crt[0x18] = 0xff;
-
+ 
 	/* Banshee's nonvga stuff */
-	reg.ext[0x00] = (((ht & 0x100) >> 8) |
-			 ((hd & 0x100) >> 6) |
-			 ((hbs & 0x100) >> 4) |
-			 ((hbe & 0x40) >> 1) |
-			 ((hs & 0x100) >> 2) | ((he & 0x20) << 2));
-	reg.ext[0x01] = (((vt & 0x400) >> 10) |
-			 ((vd & 0x400) >> 8) |
-			 ((vbs & 0x400) >> 6) | ((vbe & 0x400) >> 4));
-
-	reg.vgainit0 =
-	    VGAINIT0_8BIT_DAC |
-	    VGAINIT0_EXT_ENABLE |
-	    VGAINIT0_WAKEUP_3C3 |
-	    VGAINIT0_ALT_READBACK | VGAINIT0_EXTSHIFTOUT;
+	reg.ext[0x00] = (((ht  & 0x100) >> 8) | 
+			((hd  & 0x100) >> 6) |
+			((hbs & 0x100) >> 4) |
+			((hbe &  0x40) >> 1) |
+			((hs  & 0x100) >> 2) |
+			((he  &  0x20) << 2)); 
+	reg.ext[0x01] = (((vt  & 0x400) >> 10) |
+			((vd  & 0x400) >>  8) | 
+			((vbs & 0x400) >>  6) |
+			((vbe & 0x400) >>  4));
+
+	reg.vgainit0 = 	VGAINIT0_8BIT_DAC     |
+			VGAINIT0_EXT_ENABLE   |
+			VGAINIT0_WAKEUP_3C3   |
+			VGAINIT0_ALT_READBACK |
+			VGAINIT0_EXTSHIFTOUT;
 	reg.vgainit1 = tdfx_inl(VGAINIT1) & 0x1fffff;
 
-	reg.vidcfg =
-	    VIDCFG_VIDPROC_ENABLE |
-	    VIDCFG_DESK_ENABLE |
-	    VIDCFG_CURS_X11 |
-	    ((cpp - 1) << VIDCFG_PIXFMT_SHIFT) |
-	    (cpp != 1 ? VIDCFG_CLUT_BYPASS : 0);
-
-	fb_info.cursor.enable = reg.vidcfg | VIDCFG_HWCURSOR_ENABLE;
-	fb_info.cursor.disable = reg.vidcfg;
-
-	reg.stride = par->width * cpp;
-	reg.cursloc = 0;
-
-	reg.cursc0 = 0;
-	reg.cursc1 = 0xffffff;
-
-	reg.curspataddr = fb_info.cursor.cursorimage;
-
+	reg.cursloc   = 0;
+   
+	reg.cursc0    = 0; 
+	reg.cursc1    = 0xffffff;
+   
+	reg.stride    = info->var.xres * cpp;
 	reg.startaddr = par->baseline * reg.stride;
-	reg.srcbase = reg.startaddr;
-	reg.dstbase = reg.startaddr;
+	reg.srcbase   = reg.startaddr;
+	reg.dstbase   = reg.startaddr;
 
 	/* PLL settings */
-	freq = par->pixclock;
+	freq = PICOS2KHZ(info->var.pixclock);
 
 	reg.dacmode &= ~DACMODE_2X;
-	reg.vidcfg &= ~VIDCFG_2X;
-	if (freq > i->max_pixclock / 2) {
-		freq = freq > i->max_pixclock ? i->max_pixclock : freq;
+	reg.vidcfg  &= ~VIDCFG_2X;
+	if (freq > par->max_pixclock/2) {
+		freq = freq > par->max_pixclock ? par->max_pixclock : freq;
 		reg.dacmode |= DACMODE_2X;
-		reg.vidcfg |= VIDCFG_2X;
+		reg.vidcfg  |= VIDCFG_2X;
 	}
 	reg.vidpll = do_calc_pll(freq, &fout);
 #if 0
@@ -1316,648 +744,418 @@
 	reg.gfxpll = do_calc_pll(..., &fout);
 #endif
 
-	reg.screensize = par->width | (par->height << 12);
+	reg.screensize = info->var.xres | (info->var.yres << 12);
 	reg.vidcfg &= ~VIDCFG_HALF_MODE;
-
 	reg.miscinit0 = tdfx_inl(MISCINIT0);
 
 #if defined(__BIG_ENDIAN)
-	switch (par->bpp) {
-	case 8:
-		reg.miscinit0 &= ~(1 << 30);
-		reg.miscinit0 &= ~(1 << 31);
-		break;
-	case 16:
-		reg.miscinit0 |= (1 << 30);
-		reg.miscinit0 |= (1 << 31);
-		break;
-	case 24:
-	case 32:
-		reg.miscinit0 |= (1 << 30);
-		reg.miscinit0 &= ~(1 << 31);
-		break;
+	switch (info->var.bits_per_pixel) {
+		case 8:
+			reg.miscinit0 &= ~(1 << 30);
+			reg.miscinit0 &= ~(1 << 31);
+			break;
+		case 16:
+			reg.miscinit0 |= (1 << 30);
+			reg.miscinit0 |= (1 << 31);
+			break;
+		case 24:
+		case 32:
+			reg.miscinit0 |= (1 << 30);
+			reg.miscinit0 &= ~(1 << 31);
+			break;
 	}
-#endif
-
+#endif             
 	do_write_regs(&reg);
 
-	i->current_par = *par;
-
+	/* Now change fb_fix_screeninfo according to changes in par */
+	info->fix.line_length = info->var.xres * ((info->var.bits_per_pixel + 7)>>3);
+	info->fix.visual = (info->var.bits_per_pixel == 8) 
+				? FB_VISUAL_PSEUDOCOLOR
+				: FB_VISUAL_TRUECOLOR;
+	DPRINTK("Graphics mode is now set at %dx%d depth %d\n", info->var.xres, info->var.yres, info->var.bits_per_pixel);
+	return 0;	
 }
 
-static int tdfxfb_decode_var(const struct fb_var_screeninfo *var,
-			     struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info)
+static int tdfxfb_setcolreg(unsigned regno, unsigned red, unsigned green,  
+			    unsigned blue,unsigned transp,struct fb_info *info) 
 {
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
-
-	if (var->bits_per_pixel != 8 &&
-	    var->bits_per_pixel != 16 &&
-	    var->bits_per_pixel != 24 && var->bits_per_pixel != 32) {
-		DPRINTK("depth not supported: %u\n", var->bits_per_pixel);
-		return -EINVAL;
-	}
-
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-		DPRINTK("interlace not supported\n");
-		return -EINVAL;
-	}
-
-	if (var->xoffset) {
-		DPRINTK("xoffset not supported\n");
-		return -EINVAL;
-	}
-
-	if (var->xres != var->xres_virtual) {
-		DPRINTK
-		    ("virtual x resolution != physical x resolution not supported\n");
-		return -EINVAL;
-	}
-
-	if (var->yres > var->yres_virtual) {
-		DPRINTK
-		    ("virtual y resolution < physical y resolution not possible\n");
-		return -EINVAL;
-	}
-
-	/* fixme: does Voodoo3 support interlace? Banshee doesn't */
-	if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
-		DPRINTK("interlace not supported\n");
-		return -EINVAL;
-	}
-
-	memset(par, 0, sizeof(struct tdfxfb_par));
-
-	switch (i->dev) {
-	case PCI_DEVICE_ID_3DFX_BANSHEE:
-	case PCI_DEVICE_ID_3DFX_VOODOO3:
-	case PCI_DEVICE_ID_3DFX_VOODOO5:
-		par->width = (var->xres + 15) & ~15;	/* could sometimes be 8 */
-		par->width_virt = par->width;
-		par->height = var->yres;
-		par->height_virt = var->yres_virtual;
-		par->bpp = var->bits_per_pixel;
-		par->ppitch = var->bits_per_pixel;
-		par->lpitch = par->width * ((par->ppitch + 7) >> 3);
-		par->cmap_len = (par->bpp == 8) ? 256 : 16;
-
-		par->baseline = 0;
-
-		if (par->width < 320 || par->width > 2048) {
-			DPRINTK("width not supported: %u\n", par->width);
-			return -EINVAL;
-		}
-		if (par->height < 200 || par->height > 2048) {
-			DPRINTK("height not supported: %u\n", par->height);
-			return -EINVAL;
-		}
-		if (par->lpitch * par->height_virt > i->bufbase_size) {
-			DPRINTK("no memory for screen (%ux%ux%u)\n",
-				par->width, par->height_virt, par->bpp);
-			return -EINVAL;
-		}
-		par->pixclock = PICOS2KHZ(var->pixclock);
-		if (par->pixclock > i->max_pixclock) {
-			DPRINTK("pixclock too high (%uKHz)\n",
-				par->pixclock);
-			return -EINVAL;
-		}
-
-		par->hdispend = var->xres;
-		par->hsyncsta = par->hdispend + var->right_margin;
-		par->hsyncend = par->hsyncsta + var->hsync_len;
-		par->htotal = par->hsyncend + var->left_margin;
-
-		par->vdispend = var->yres;
-		par->vsyncsta = par->vdispend + var->lower_margin;
-		par->vsyncend = par->vsyncsta + var->vsync_len;
-		par->vtotal = par->vsyncend + var->upper_margin;
-
-		if (var->sync & FB_SYNC_HOR_HIGH_ACT)
-			par->video |= TDFXF_HSYNC_ACT_HIGH;
-		else
-			par->video |= TDFXF_HSYNC_ACT_LOW;
-		if (var->sync & FB_SYNC_VERT_HIGH_ACT)
-			par->video |= TDFXF_VSYNC_ACT_HIGH;
-		else
-			par->video |= TDFXF_VSYNC_ACT_LOW;
-		if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
-			par->video |= TDFXF_LINE_DOUBLE;
-		if (var->activate == FB_ACTIVATE_NOW)
-			par->video |= TDFXF_VIDEO_ENABLE;
-	}
-
-	if (var->accel_flags & FB_ACCELF_TEXT)
-		par->accel_flags = FB_ACCELF_TEXT;
-	else
-		par->accel_flags = 0;
-
-	return 0;
-}
-
-static int tdfxfb_encode_var(struct fb_var_screeninfo *var,
-			     const struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info)
-{
-	struct fb_var_screeninfo v;
-
-	memset(&v, 0, sizeof(struct fb_var_screeninfo));
-	v.xres_virtual = par->width_virt;
-	v.yres_virtual = par->height_virt;
-	v.xres = par->width;
-	v.yres = par->height;
-	v.right_margin = par->hsyncsta - par->hdispend;
-	v.hsync_len = par->hsyncend - par->hsyncsta;
-	v.left_margin = par->htotal - par->hsyncend;
-	v.lower_margin = par->vsyncsta - par->vdispend;
-	v.vsync_len = par->vsyncend - par->vsyncsta;
-	v.upper_margin = par->vtotal - par->vsyncend;
-	v.bits_per_pixel = par->bpp;
-	switch (par->bpp) {
-	case 8:
-		v.red.length = v.green.length = v.blue.length = 8;
-		break;
-	case 16:
-		v.red.offset = 11;
-		v.red.length = 5;
-		v.green.offset = 5;
-		v.green.length = 6;
-		v.blue.offset = 0;
-		v.blue.length = 5;
-		break;
-	case 24:
-		v.red.offset = 16;
-		v.green.offset = 8;
-		v.blue.offset = 0;
-		v.red.length = v.green.length = v.blue.length = 8;
-	case 32:
-		v.red.offset = 16;
-		v.green.offset = 8;
-		v.blue.offset = 0;
-		v.red.length = v.green.length = v.blue.length = 8;
-		break;
-	}
-	v.height = v.width = -1;
-	v.pixclock = KHZ2PICOS(par->pixclock);
-	if ((par->video & TDFXF_HSYNC_MASK) == TDFXF_HSYNC_ACT_HIGH)
-		v.sync |= FB_SYNC_HOR_HIGH_ACT;
-	if ((par->video & TDFXF_VSYNC_MASK) == TDFXF_VSYNC_ACT_HIGH)
-		v.sync |= FB_SYNC_VERT_HIGH_ACT;
-	if (par->video & TDFXF_LINE_DOUBLE)
-		v.vmode = FB_VMODE_DOUBLE;
-	*var = v;
-	return 0;
-}
-
-static int tdfxfb_encode_fix(struct fb_fix_screeninfo *fix,
-			     const struct tdfxfb_par *par,
-			     const struct fb_info_tdfx *info)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-
-	switch (info->dev) {
-	case PCI_DEVICE_ID_3DFX_BANSHEE:
-		strcpy(fix->id, "3Dfx Banshee");
-		break;
-	case PCI_DEVICE_ID_3DFX_VOODOO3:
-		strcpy(fix->id, "3Dfx Voodoo3");
-		break;
-	case PCI_DEVICE_ID_3DFX_VOODOO5:
-		strcpy(fix->id, "3Dfx Voodoo5");
-		break;
-	default:
-		return -EINVAL;
+	u32 rgbcol;
+   
+	if (regno >= info->cmap.len) return 1;
+   
+	switch (info->fix.visual) {
+		case FB_VISUAL_PSEUDOCOLOR:
+			rgbcol =(((u32)red   & 0xff00) << 8) |
+				(((u32)green & 0xff00) << 0) |
+				(((u32)blue  & 0xff00) >> 8);
+			do_setpalentry(regno, rgbcol);
+			break;
+		/* Truecolor has no hardware color palettes. */
+		case FB_VISUAL_TRUECOLOR:
+			rgbcol = (red << info->var.red.offset) |
+				 (green << info->var.green.offset) |
+				 (blue << info->var.blue.offset) |
+				 (transp << info->var.transp.offset);
+			if (info->var.bits_per_pixel <= 16)
+				((u16*)(info->pseudo_palette))[regno] = rgbcol;
+			else
+				((u32*)(info->pseudo_palette))[regno] = rgbcol;
+			break;
+		default:
+			DPRINTK("bad depth %u\n", info->var.bits_per_pixel);
+			break;
 	}
-
-	fix->smem_start = info->bufbase_phys;
-	fix->smem_len = info->bufbase_size;
-	fix->mmio_start = info->regbase_phys;
-	fix->mmio_len = info->regbase_size;
-	fix->accel = FB_ACCEL_3DFX_BANSHEE;
-	fix->type = FB_TYPE_PACKED_PIXELS;
-	fix->type_aux = 0;
-	fix->line_length = par->lpitch;
-	fix->visual = (par->bpp == 8)
-	    ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_DIRECTCOLOR;
-
-	fix->xpanstep = 0;
-	fix->ypanstep = nopan ? 0 : 1;
-	fix->ywrapstep = nowrap ? 0 : 1;
-
 	return 0;
 }
 
-static int tdfxfb_get_fix(struct fb_fix_screeninfo *fix,
-			  int con, struct fb_info *fb)
-{
-	const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
-	struct tdfxfb_par par;
-
-	if (con == -1)
-		par = info->default_par;
-	else
-		tdfxfb_decode_var(&fb_display[con].var, &par, info);
-	tdfxfb_encode_fix(fix, &par, info);
-	return 0;
-}
-
-static int tdfxfb_get_var(struct fb_var_screeninfo *var,
-			  int con, struct fb_info *fb)
-{
-	const struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
-
-	if (con == -1)
-		tdfxfb_encode_var(var, &info->default_par, info);
-	else
-		*var = fb_display[con].var;
-	return 0;
-}
+/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
+static int tdfxfb_blank(int blank, struct fb_info *info)
+{ 
+	u32 dacmode, state = 0, vgablank = 0;
 
-static void tdfxfb_set_dispsw(struct display *disp,
-			      struct fb_info_tdfx *info,
-			      int bpp, int accel)
-{
+	dacmode = tdfx_inl(DACMODE);
 
-	if (disp->dispsw && disp->conp)
-		fb_con.con_cursor(disp->conp, CM_ERASE);
-	switch (bpp) {
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		disp->dispsw = noaccel ? &fbcon_cfb8 : &fbcon_banshee8;
-		if (nohwcursor)
-			fbcon_banshee8.cursor = NULL;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		disp->dispsw = noaccel ? &fbcon_cfb16 : &fbcon_banshee16;
-		disp->dispsw_data = info->fbcon_cmap.cfb16;
-		if (nohwcursor)
-			fbcon_banshee16.cursor = NULL;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	case 24:
-		disp->dispsw = noaccel ? &fbcon_cfb24 : &fbcon_banshee24;
-		disp->dispsw_data = info->fbcon_cmap.cfb24;
-		if (nohwcursor)
-			fbcon_banshee24.cursor = NULL;
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		disp->dispsw = noaccel ? &fbcon_cfb32 : &fbcon_banshee32;
-		disp->dispsw_data = info->fbcon_cmap.cfb32;
-		if (nohwcursor)
-			fbcon_banshee32.cursor = NULL;
-		break;
-#endif
-	default:
-		disp->dispsw = &fbcon_dummy;
+	switch (blank) {
+		case 0: /* Screen: On; HSync: On, VSync: On */    
+			state    = 0;
+			vgablank = 0;
+			break;
+		case 1: /* Screen: Off; HSync: On, VSync: On */
+			state    = 0;
+			vgablank = 1;
+			break;
+		case 2: /* Screen: Off; HSync: On, VSync: Off */
+			state    = BIT(3);
+			vgablank = 1;
+			break;
+		case 3: /* Screen: Off; HSync: Off, VSync: On */
+			state    = BIT(1);
+			vgablank = 1;
+			break;
+		case 4: /* Screen: Off; HSync: Off, VSync: Off */
+			state    = BIT(1) | BIT(3);
+			vgablank = 1;
+			break;
 	}
 
-}
-
-static int tdfxfb_set_var(struct fb_var_screeninfo *var,
-			  int con, struct fb_info *fb)
-{
-	struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
-	struct tdfxfb_par par;
-	struct display *display;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp, oldaccel, accel,
-	    err;
-	int activate = var->activate;
-	int j, k;
-
-	if (con >= 0)
-		display = &fb_display[con];
+	dacmode &= ~(BIT(1) | BIT(3));
+	dacmode |= state;
+	banshee_make_room(1); 
+	tdfx_outl(DACMODE, dacmode);
+	if (vgablank) 
+		vga_disable_video();
 	else
-		display = fb->disp;	/* used during initialization */
-
-	if ((err = tdfxfb_decode_var(var, &par, info)))
-		return err;
-
-	tdfxfb_encode_var(var, &par, 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;
-		if (con < 0 ||
-		    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;
-
-			tdfxfb_encode_fix(&fix, &par, info);
-			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->next_line = fix.line_length;
-			display->can_soft_blank = 1;
-			display->inverse = inverse;
-			accel = var->accel_flags & FB_ACCELF_TEXT;
-			tdfxfb_set_dispsw(display, info, par.bpp, accel);
-
-			if (nopan)
-				display->scrollmode = SCROLL_YREDRAW;
-
-			if (info->fb_info.changevar)
-				(*info->fb_info.changevar) (con);
-		}
-		if (var->bits_per_pixel == 8)
-			for (j = 0; j < 16; j++) {
-				k = color_table[j];
-				fb_info.palette[j].red = default_red[k];
-				fb_info.palette[j].green = default_grn[k];
-				fb_info.palette[j].blue = default_blu[k];
-			}
-
-		del_timer(&(info->cursor.timer));
-		fb_info.cursor.state = CM_ERASE;
-		if (!info->fb_info.display_fg ||
-		    info->fb_info.display_fg->vc_num == con || con < 0)
-			tdfxfb_set_par(&par, info);
-		if (!nohwcursor)
-			if (display && display->conp)
-				tdfxfb_createcursor(display);
-		info->cursor.redraw = 1;
-		if (oldbpp != var->bits_per_pixel || con < 0) {
-			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-				return err;
-			do_install_cmap(con, &(info->fb_info));
-		}
-	}
-
+		vga_enable_video();
 	return 0;
 }
 
-static int tdfxfb_pan_display(struct fb_var_screeninfo *var,
-			      int con, struct fb_info *fb)
+/*   
+ * Set the starting position of the visible screen to var->yoffset
+ */   
+static int tdfxfb_pan_display(struct fb_var_screeninfo *var, int con,
+			      struct fb_info *info) 
 {
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
+	u32 addr;  	
 
-	if (nopan)
-		return -EINVAL;
-	if (var->xoffset)
+	if (nopan || var->xoffset || (var->yoffset > var->yres_virtual))
 		return -EINVAL;
-	if (var->yoffset > var->yres_virtual)
+	if ((var->yoffset + var->yres > var->yres_virtual && nowrap))
 		return -EINVAL;
-	if (nowrap && (var->yoffset + var->yres > var->yres_virtual))
-		return -EINVAL;
-
-	if (con == fb->currcon)
-		do_pan_var(var, i);
 
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
+	addr = var->yoffset * info->fix.line_length;
+	banshee_make_room(1);
+	tdfx_outl(VIDDESKSTART, addr);
+   
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset; 
 	return 0;
 }
 
-static int tdfxfb_get_cmap(struct fb_cmap *cmap,
-			   int kspc, int con, struct fb_info *fb)
+/*
+ * FillRect 2D command (solidfill or invert (via ROP_XOR))   
+ */
+static void tdfxfb_fillrect(struct fb_info *info, struct fb_fillrect *rect) 
 {
+	u32 bpp = info->var.bits_per_pixel;
+	u32 stride = info->fix.line_length;
+	u32 fmt= stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	int tdfx_rop;
+   	
+	if (rect->rop == ROP_COPY) 
+		tdfx_rop = TDFX_ROP_COPY;
+	else 			 
+		tdfx_rop = TDFX_ROP_XOR;
 
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
-	struct display *d = (con < 0) ? fb->disp : fb_display + con;
+	banshee_make_room(5);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(COLORFORE, rect->color);
+	tdfx_outl(COMMAND_2D, COMMAND_2D_FILLRECT | (tdfx_rop << 24));
+	tdfx_outl(DSTSIZE,    rect->width | (rect->height << 16));
+	tdfx_outl(LAUNCH_2D,  rect->dx | (rect->dy << 16));
+	banshee_wait_idle();
+}
 
-	if (con == fb->currcon) {
-		/* current console? */
-		return fb_get_cmap(cmap, kspc, tdfxfb_getcolreg, fb);
-	} else if (d->cmap.len) {
-		/* non default colormap? */
-		fb_copy_cmap(&d->cmap, cmap, kspc ? 0 : 2);
-	} else {
-		fb_copy_cmap(fb_default_cmap(i->current_par.cmap_len),
-			     cmap, kspc ? 0 : 2);
+/*
+ * Screen-to-Screen BitBlt 2D command (for the bmove fb op.) 
+ */
+static void tdfxfb_copyarea(struct fb_info *info, struct fb_copyarea *area)  
+{
+	u32 bpp = info->var.bits_per_pixel;
+	u32 stride = info->fix.line_length;
+	u32 blitcmd = COMMAND_2D_S2S_BITBLT | (TDFX_ROP_COPY << 24);
+	u32 fmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+   
+	if (area->sx <= area->dx) {
+		//-X 
+		blitcmd |= BIT(14);
+		area->sx += area->width - 1;
+		area->dx += area->width - 1;
 	}
-	return 0;
+	if (area->sy <= area->dy) {
+		//-Y  
+		blitcmd |= BIT(15);
+		area->sy += area->height - 1;
+		area->dy += area->height - 1;
+	}
+   
+	banshee_make_room(6);
+
+	tdfx_outl(SRCFORMAT, fmt);
+	tdfx_outl(DSTFORMAT, fmt);
+	tdfx_outl(COMMAND_2D, blitcmd); 
+	tdfx_outl(DSTSIZE,   area->width | (area->height << 16));
+	tdfx_outl(DSTXY,     area->dx | (area->dy << 16));
+	tdfx_outl(LAUNCH_2D, area->sx | (area->sy << 16)); 
+	banshee_wait_idle();
 }
 
-static int tdfxfb_set_cmap(struct fb_cmap *cmap,
-			   int kspc, int con, struct fb_info *fb)
+static void tdfxfb_imageblit(struct fb_info *info, struct fb_image *pixmap) 
 {
-	struct display *d = (con < 0) ? fb->disp : fb_display + con;
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
-
-	int cmap_len = (i->current_par.bpp == 8) ? 256 : 16;
-	if (d->cmap.len != cmap_len) {
-		int err;
-		if ((err = fb_alloc_cmap(&d->cmap, cmap_len, 0)))
-			return err;
-	}
-	if (con == fb->currcon) {
-		/* current console? */
-		return fb_set_cmap(cmap, kspc, fb);
+	int size = pixmap->height*((pixmap->width*pixmap->depth + 7)>>3);
+	int i, stride = info->fix.line_length;
+	u32 bpp = info->var.bits_per_pixel;
+	u32 dstfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13); 
+	u8 *chardata = (u8 *) pixmap->data;
+	u32 srcfmt;
+
+	if (pixmap->depth == 1) {
+		banshee_make_room(8 + ((size + 3) >> 2));
+		tdfx_outl(COLORFORE, pixmap->fg_color);
+		tdfx_outl(COLORBACK, pixmap->bg_color);
+		srcfmt = 0x400000;
 	} else {
-		fb_copy_cmap(cmap, &d->cmap, kspc ? 0 : 1);
+		banshee_make_room(6 + ((size + 3) >> 2));
+		srcfmt = stride | ((bpp+((bpp==8) ? 0 : 8)) << 13) | 0x400000;
+	}	
+
+	tdfx_outl(SRCXY,     0);
+	tdfx_outl(DSTXY,     pixmap->dx | (pixmap->dy << 16));
+	tdfx_outl(COMMAND_2D, COMMAND_2D_H2S_BITBLT | (TDFX_ROP_COPY << 24));
+	tdfx_outl(SRCFORMAT, srcfmt);
+	tdfx_outl(DSTFORMAT, dstfmt);
+	tdfx_outl(DSTSIZE,   pixmap->width | (pixmap->height << 16));
+
+	/* Send four bytes at a time of data */	
+	for (i = (size >> 2) ; i > 0; i--) { 
+		tdfx_outl(LAUNCH_2D,*(u32*)chardata);
+		chardata += 4; 
+	}	
+
+	/* Send the leftovers now */	
+	i = size%4;	
+	switch (i) {
+		case 0: break;
+		case 1:  tdfx_outl(LAUNCH_2D,*chardata); break;
+		case 2:  tdfx_outl(LAUNCH_2D,*(u16*)chardata); break;
+		case 3:  tdfx_outl(LAUNCH_2D,*(u16*)chardata | ((chardata[3]) << 24)); break;
 	}
-	return 0;
+	banshee_wait_idle();
 }
 
 /**
- * 	tdfxfb_probe - Device Initializiation
- * 	
- * 	@pdev:	PCI Device to initialize
- * 	@id:	PCI Device ID
+ *      tdfxfb_probe - Device Initializiation
+ *
+ *      @pdev:  PCI Device to initialize
+ *      @id:    PCI Device ID
  *
- * 	Initializes and allocates resources for PCI device @pdev.
+ *      Initializes and allocates resources for PCI device @pdev.
  *
  */
 static int __devinit tdfxfb_probe(struct pci_dev *pdev,
-				  const struct pci_device_id *id)
+                                  const struct pci_device_id *id)
 {
-	struct fb_var_screeninfo var;
-	char *name = NULL;
+	struct fb_info *info;
+	int size, err;
 
-	fb_info.dev = pdev->device;
+	if ((err = pci_enable_device(pdev))) {
+		printk(KERN_WARNING "tdfxfb: Can't enable pdev: %d\n", err);
+		return err;
+	}
 
+	info = kmalloc(sizeof(struct fb_info) + sizeof(struct display) +
+			sizeof(u32) * 16, GFP_KERNEL);
+
+	if (!info)	return -ENXIO;
+		
+	memset(info, 0, sizeof(info) + sizeof(struct display) + sizeof(u32) * 16);
+     
+	/* Configure the default fb_fix_screeninfo first */
 	switch (pdev->device) {
-	case PCI_DEVICE_ID_3DFX_BANSHEE:
-		fb_info.max_pixclock = BANSHEE_MAX_PIXCLOCK;
-		name = "Banshee";
-		break;
-	case PCI_DEVICE_ID_3DFX_VOODOO3:
-		fb_info.max_pixclock = VOODOO3_MAX_PIXCLOCK;
-		name = "Voodoo3";
-		break;
-	case PCI_DEVICE_ID_3DFX_VOODOO5:
-		fb_info.max_pixclock = VOODOO5_MAX_PIXCLOCK;
-		name = "Voodoo5";
-		break;
-	}
-
-	fb_info.regbase_phys = pci_resource_start(pdev, 0);
-	fb_info.regbase_size = 1 << 24;
-	fb_info.regbase_virt =
-	    ioremap_nocache(fb_info.regbase_phys, 1 << 24);
-
-	if (!fb_info.regbase_virt) {
-		printk(KERN_WARNING "fb: Can't remap %s register area.\n",
-		       name);
-		return -ENXIO;
+		case PCI_DEVICE_ID_3DFX_BANSHEE:	
+			strcat(tdfx_fix.id, " Banshee");
+			default_par.max_pixclock = BANSHEE_MAX_PIXCLOCK;
+			break;
+		case PCI_DEVICE_ID_3DFX_VOODOO3:
+			strcat(tdfx_fix.id, " Voodoo3");
+			default_par.max_pixclock = VOODOO3_MAX_PIXCLOCK;
+			break;
+		case PCI_DEVICE_ID_3DFX_VOODOO5:
+			strcat(tdfx_fix.id, " Voodoo5");
+			default_par.max_pixclock = VOODOO5_MAX_PIXCLOCK;
+			break;
 	}
 
-	fb_info.bufbase_phys = pci_resource_start(pdev, 1);
-
-	if (!(fb_info.bufbase_size = do_lfb_size())) {
-		iounmap(fb_info.regbase_virt);
-		printk(KERN_WARNING "fb: Can't count %s memory.\n", name);
+	tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
+	tdfx_fix.mmio_len = 1 << 24;
+	default_par.regbase_virt = ioremap_nocache(tdfx_fix.mmio_start, 1<<24);
+	if (!default_par.regbase_virt) {
+		printk("fb: Can't remap %s register area.\n", tdfx_fix.id);
 		return -ENXIO;
 	}
+    
+	if (!request_mem_region(pci_resource_start(pdev, 0),
+	    pci_resource_len(pdev, 0), "tdfx regbase")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve regbase\n");
+		iounmap(default_par.regbase_virt);
+		return -ENXIO;
+	} 
 
-	fb_info.bufbase_virt = ioremap_nocache(fb_info.bufbase_phys,
-					       fb_info.bufbase_size);
-
-	if (!fb_info.regbase_virt) {
-		printk(KERN_WARNING "fb: Can't remap %s framebuffer.\n",
-		       name);
-		iounmap(fb_info.regbase_virt);
+	tdfx_fix.smem_start = pci_resource_start(pdev, 1);
+	if (!(tdfx_fix.smem_len = do_lfb_size(pdev->device))) {
+		iounmap(default_par.regbase_virt);
+		printk("fb: Can't count %s memory.\n", tdfx_fix.id);
 		return -ENXIO;
 	}
 
-	fb_info.iobase = pci_resource_start(pdev, 2);
-
-	printk("fb: %s memory = %ldK\n", name, fb_info.bufbase_size >> 10);
+	if (!request_mem_region(pci_resource_start(pdev, 1),
+	     pci_resource_len(pdev, 1), "tdfx smem")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve smem\n");
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		iounmap(default_par.regbase_virt);
+		return -ENXIO;
+	}
 
-#ifdef CONFIG_MTRR
-	if (!nomtrr) {
-		fb_info.mtrr_idx = mtrr_add(fb_info.bufbase_phys,
-					    fb_info.bufbase_size,
-					    MTRR_TYPE_WRCOMB, 1);
-		printk(KERN_INFO "fb: MTRR's turned on\n");
+	info->screen_base = ioremap_nocache(tdfx_fix.smem_start, 
+	tdfx_fix.smem_len);
+	if (!info->screen_base) {
+		printk("fb: Can't remap %s framebuffer.\n", tdfx_fix.id);
+		iounmap(default_par.regbase_virt);
+		return -ENXIO;
 	}
-#endif
 
-	/* clear framebuffer memory */
-	memset_io(fb_info.bufbase_virt, 0, fb_info.bufbase_size);
-	fb_info.fb_info.currcon = -1;
+	default_par.iobase = pci_resource_start(pdev, 2);
+    
+	if (!request_region(pci_resource_start(pdev, 2),
+	    pci_resource_len(pdev, 2), "tdfx iobase")) {
+		printk(KERN_WARNING "tdfxfb: Can't reserve iobase\n");
+		release_mem_region(pci_resource_start(pdev, 1),
+				   pci_resource_len(pdev, 1));
+		release_mem_region(pci_resource_start(pdev, 0),
+				   pci_resource_len(pdev, 0));
+		iounmap(default_par.regbase_virt);
+		iounmap(info->screen_base);
+		return -ENXIO;
+	}
 
-	if (!nohwcursor)
-		tdfxfb_hwcursor_init();
+	printk("fb: %s memory = %dK\n", tdfx_fix.id, tdfx_fix.smem_len >> 10);
 
-	init_timer(&fb_info.cursor.timer);
-	fb_info.cursor.timer.function = do_flashcursor;
-	fb_info.cursor.timer.data = (unsigned long) (&fb_info);
-	fb_info.cursor.state = CM_ERASE;
-	spin_lock_init(&fb_info.DAClock);
-
-	strcpy(fb_info.fb_info.modename, "3Dfx ");
-	strcat(fb_info.fb_info.modename, name);
-	fb_info.fb_info.changevar = NULL;
-	fb_info.fb_info.node = NODEV;
-	fb_info.fb_info.fbops = &tdfxfb_ops;
-	fb_info.fb_info.disp = &fb_info.disp;
-	fb_info.fb_info.currcon = -1;
-	strcpy(fb_info.fb_info.fontname, fontname);
-	fb_info.fb_info.switch_con = &tdfxfb_switch_con;
-	fb_info.fb_info.updatevar = &tdfxfb_updatevar;
-	fb_info.fb_info.flags = FBINFO_FLAG_DEFAULT;
-
-	memset(&var, 0, sizeof(var));
-
-	if (!mode_option || !fb_find_mode(&var, &fb_info.fb_info,
-					  mode_option, NULL, 0, NULL, 8))
-		var = default_mode[0].var;
-
-	noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
-	    (var.accel_flags |= FB_ACCELF_TEXT);
-
-	if (tdfxfb_decode_var(&var, &fb_info.default_par, &fb_info)) {
-		/* 
-		 * ugh -- can't use the mode from the mode db. (or command
-		 * line), so try the default
-		 */
-
-		printk(KERN_NOTICE
-		       "tdfxfb: can't decode the supplied video mode, using default\n");
-
-		var = default_mode[0].var;
-
-		noaccel ? (var.accel_flags &= ~FB_ACCELF_TEXT) :
-		    (var.accel_flags |= FB_ACCELF_TEXT);
-
-		if (tdfxfb_decode_var
-		    (&var, &fb_info.default_par, &fb_info)) {
-			/* this is getting really bad!... */
-			printk(KERN_WARNING
-			       "tdfxfb: can't decode default video mode\n");
-			return -ENXIO;
-		}
-	}
+	/* clear framebuffer memory */
+	memset_io(info->screen_base, 0, tdfx_fix.smem_len);
+	
+	tdfx_fix.ypanstep	= nopan ? 0 : 1;
+	tdfx_fix.ywrapstep	= nowrap ? 0 : 1;
+   
+	info->node		= NODEV;
+	info->fbops		= &tdfxfb_ops;
+	info->fix		= tdfx_fix; 	
+	info->par		= &default_par;
+	info->disp		= (struct display *)(info + 1);	
+	info->pseudo_palette	= (void *)(info->disp + 1); 
+	info->flags		= FBINFO_FLAG_DEFAULT;
+
+	/* The below feilds will go away !!!! */
+	strcpy(info->modename, info->fix.id);
+	info->currcon		= -1;
+	info->switch_con	= gen_switch;			 
+	info->updatevar		= gen_update_var;
+
+	if (!mode_option)
+		mode_option = "640x480@60";
+	 
+	err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8); 
+	if (!err || err == 4)
+		info->var = tdfx_var;
 
-	fb_info.fb_info.screen_base = fb_info.bufbase_virt;
-	fb_info.disp.var = var;
+	size = (info->var.bits_per_pixel == 8) ? 256 : 16;
+	fb_alloc_cmap(&info->cmap, size, 0);  
 
-	if (tdfxfb_set_var(&var, -1, &fb_info.fb_info)) {
-		printk(KERN_WARNING
-		       "tdfxfb: can't set default video mode\n");
-		return -ENXIO;
-	}
+	gen_set_var(&info->var, -1, info);
 
-	if (register_framebuffer(&fb_info.fb_info) < 0) {
-		printk(KERN_WARNING
-		       "tdfxfb: can't register framebuffer\n");
+	if (register_framebuffer(info) < 0) {
+		printk("tdfxfb: can't register framebuffer\n");
 		return -ENXIO;
 	}
-
-	printk(KERN_INFO "fb%d: %s frame buffer device\n",
-	       GET_FB_IDX(fb_info.fb_info.node), fb_info.fb_info.modename);
-
-	return 0;
+	/*
+	 * Our driver data
+	 */
+	pdev->driver_data = info;
+	return 0; 
 }
 
 /**
- *	tdfxfb_remove - Device removal
+ *      tdfxfb_remove - Device removal
  *
- * 	@pdev:	PCI Device to cleanup
+ *      @pdev:  PCI Device to cleanup
  *
- *	Releases all resources allocated during the course of the driver's
- *	lifetime for the PCI device @pdev.
+ *      Releases all resources allocated during the course of the driver's
+ *      lifetime for the PCI device @pdev.
  *
  */
 static void __devexit tdfxfb_remove(struct pci_dev *pdev)
 {
-	unregister_framebuffer(&fb_info.fb_info);
-	del_timer_sync(&fb_info.cursor.timer);
+	struct fb_info *info = (struct fb_info *)pdev->driver_data;
+	struct tdfx_par *par = (struct tdfx_par *) info->par;
 
-#ifdef CONFIG_MTRR
-	if (!nomtrr) {
-		mtrr_del(fb_info.mtrr_idx, fb_info.bufbase_phys,
-			 fb_info.bufbase_size);
-		printk("fb: MTRR's turned off\n");
-	}
-#endif
-
-	iounmap(fb_info.regbase_virt);
-	iounmap(fb_info.bufbase_virt);
+	unregister_framebuffer(info);
+	iounmap(par->regbase_virt);
+	iounmap(info->screen_base);
+
+	/* Clean up after reserved regions */
+	release_region(pci_resource_start(pdev, 2),
+		       pci_resource_len(pdev, 2));
+	release_mem_region(pci_resource_start(pdev, 1),
+			   pci_resource_len(pdev, 1));
+	release_mem_region(pci_resource_start(pdev, 0),
+			   pci_resource_len(pdev, 0));
 }
 
 int __init tdfxfb_init(void)
 {
-	return pci_module_init(&tdfxfb_driver);
+        return pci_module_init(&tdfxfb_driver);
 }
 
 static void __exit tdfxfb_exit(void)
 {
-	pci_unregister_driver(&tdfxfb_driver);
+        pci_unregister_driver(&tdfxfb_driver);
 }
 
 MODULE_AUTHOR("Hannu Mallat <hmallat@cc.hut.fi>");
 MODULE_DESCRIPTION("3Dfx framebuffer device driver");
 MODULE_LICENSE("GPL");
-
-
+MODULE_PARM(noaccel, "i");
+MODULE_PARM_DESC(noaccel, "Disable hardware acceleration (1 = disabled), enabled by default.");
+ 
 #ifdef MODULE
 module_init(tdfxfb_init);
 #endif
@@ -1966,300 +1164,26 @@
 
 #ifndef MODULE
 void tdfxfb_setup(char *options, int *ints)
-{
-	char *this_opt;
+{ 
+	char* this_opt;
 
 	if (!options || !*options)
 		return;
 
-	while ((this_opt = strsep(&options, ",")) != NULL) {
+	while ((this_opt = strsep(&options, ",")) != NULL) {	
 		if (!*this_opt)
 			continue;
 		if (!strcmp(this_opt, "inverse")) {
 			inverse = 1;
 			fb_invert_cmaps();
-		} else if (!strcmp(this_opt, "noaccel")) {
-			noaccel = nopan = nowrap = nohwcursor = 1;
-		} else if (!strcmp(this_opt, "nopan")) {
+		} else if(!strcmp(this_opt, "nopan")) {
 			nopan = 1;
-		} else if (!strcmp(this_opt, "nowrap")) {
+		} else if(!strcmp(this_opt, "nowrap")) {
 			nowrap = 1;
-		} else if (!strcmp(this_opt, "nohwcursor")) {
-			nohwcursor = 1;
-#ifdef CONFIG_MTRR
-		} else if (!strcmp(this_opt, "nomtrr")) {
-			nomtrr = 1;
-#endif
-		} else if (!strncmp(this_opt, "font:", 5)) {
-			strncpy(fontname, this_opt + 5, 40);
 		} else {
 			mode_option = this_opt;
 		}
-	}
-}
-#endif
-
-static int tdfxfb_switch_con(int con, struct fb_info *fb)
-{
-	struct fb_info_tdfx *info = (struct fb_info_tdfx *) fb;
-	struct tdfxfb_par par;
-	int old_con = fb->currcon;
-	int set_par = 1;
-
-	/* Do we have to save the colormap? */
-	if (fb->currcon >= 0)
-		if (fb_display[fb->currcon].cmap.len)
-			fb_get_cmap(&fb_display[fb->currcon].cmap, 1,
-				    tdfxfb_getcolreg, fb);
-
-	fb->currcon = con;
-	fb_display[fb->currcon].var.activate = FB_ACTIVATE_NOW;
-	tdfxfb_decode_var(&fb_display[con].var, &par, info);
-	if (old_con >= 0 && vt_cons[old_con]->vc_mode != KD_GRAPHICS) {
-		/* check if we have to change video registers */
-		struct tdfxfb_par old_par;
-		tdfxfb_decode_var(&fb_display[old_con].var, &old_par,
-				  info);
-		if (!memcmp(&par, &old_par, sizeof(par)))
-			set_par = 0;	/* avoid flicker */
-	}
-	if (set_par)
-		tdfxfb_set_par(&par, info);
-
-	if (fb_display[con].dispsw && fb_display[con].conp)
-		fb_con.con_cursor(fb_display[con].conp, CM_ERASE);
-
-	del_timer(&(info->cursor.timer));
-	fb_info.cursor.state = CM_ERASE;
-
-	if (!nohwcursor)
-		if (fb_display[con].conp)
-			tdfxfb_createcursor(&fb_display[con]);
-
-	info->cursor.redraw = 1;
-
-	tdfxfb_set_dispsw(&fb_display[con],
-			  info, par.bpp, par.accel_flags & FB_ACCELF_TEXT);
-
-	do_install_cmap(con, fb);
-	tdfxfb_updatevar(con, fb);
-
-	return 1;
-}
-
-/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
-static int tdfxfb_blank(int blank, struct fb_info *fb)
-{
-	u32 dacmode, state = 0, vgablank = 0;
-
-	dacmode = tdfx_inl(DACMODE);
-
-	switch (blank) {
-	case 0:		/* Screen: On; HSync: On, VSync: On */
-		state = 0;
-		vgablank = 0;
-		break;
-	case 1:		/* Screen: Off; HSync: On, VSync: On */
-		state = 0;
-		vgablank = 1;
-		break;
-	case 2:		/* Screen: Off; HSync: On, VSync: Off */
-		state = BIT(3);
-		vgablank = 1;
-		break;
-	case 3:		/* Screen: Off; HSync: Off, VSync: On */
-		state = BIT(1);
-		vgablank = 1;
-		break;
-	case 4:		/* Screen: Off; HSync: Off, VSync: Off */
-		state = BIT(1) | BIT(3);
-		vgablank = 1;
-		break;
-	}
-
-	dacmode &= ~(BIT(1) | BIT(3));
-	dacmode |= state;
-	banshee_make_room(1);
-	tdfx_outl(DACMODE, dacmode);
-	if (vgablank)
-		vga_disable_video();
-	else
-		vga_enable_video();
-	return 0;
-}
-
-static int tdfxfb_updatevar(int con, struct fb_info *fb)
-{
-
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
-	if ((con == fb->currcon) && (!nopan))
-		do_pan_var(&fb_display[con].var, i);
-	return 0;
-}
-
-static int tdfxfb_getcolreg(unsigned regno,
-			    unsigned *red,
-			    unsigned *green,
-			    unsigned *blue,
-			    unsigned *transp, struct fb_info *fb)
-{
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) fb;
-
-	if (regno > i->current_par.cmap_len)
-		return 1;
-
-	*red = i->palette[regno].red;
-	*green = i->palette[regno].green;
-	*blue = i->palette[regno].blue;
-	*transp = 0;
-
-	return 0;
+	} 
 }
-
-static int tdfxfb_setcolreg(unsigned regno,
-			    unsigned red,
-			    unsigned green,
-			    unsigned blue,
-			    unsigned transp, struct fb_info *info)
-{
-	struct fb_info_tdfx *i = (struct fb_info_tdfx *) info;
-#ifdef FBCON_HAS_CFB8
-	u32 rgbcol;
-#endif
-	if (regno >= i->current_par.cmap_len)
-		return 1;
-
-	i->palette[regno].red = red;
-	i->palette[regno].green = green;
-	i->palette[regno].blue = blue;
-
-	switch (i->current_par.bpp) {
-#ifdef FBCON_HAS_CFB8
-	case 8:
-		rgbcol = (((u32) red & 0xff00) << 8) |
-		    (((u32) green & 0xff00) << 0) |
-		    (((u32) blue & 0xff00) >> 8);
-		do_setpalentry(regno, rgbcol);
-		break;
-#endif
-#ifdef FBCON_HAS_CFB16
-	case 16:
-		i->fbcon_cmap.cfb16[regno] =
-		    (((u32) red & 0xf800) >> 0) |
-		    (((u32) green & 0xfc00) >> 5) |
-		    (((u32) blue & 0xf800) >> 11);
-		break;
-#endif
-#ifdef FBCON_HAS_CFB24
-	case 24:
-		i->fbcon_cmap.cfb24[regno] =
-		    (((u32) red & 0xff00) << 8) |
-		    (((u32) green & 0xff00) << 0) |
-		    (((u32) blue & 0xff00) >> 8);
-		break;
-#endif
-#ifdef FBCON_HAS_CFB32
-	case 32:
-		i->fbcon_cmap.cfb32[regno] =
-		    (((u32) red & 0xff00) << 8) |
-		    (((u32) green & 0xff00) << 0) |
-		    (((u32) blue & 0xff00) >> 8);
-		break;
-#endif
-	default:
-		DPRINTK("bad depth %u\n", i->current_par.bpp);
-		break;
-	}
-	return 0;
-}
-
-static void tdfxfb_createcursorshape(struct display *p)
-{
-	unsigned int h, cu, cd;
-
-	h = fontheight(p);
-	cd = h;
-	if (cd >= 10)
-		cd--;
-	fb_info.cursor.type = p->conp->vc_cursor_type & CUR_HWMASK;
-	switch (fb_info.cursor.type) {
-	case CUR_NONE:
-		cu = cd;
-		break;
-	case CUR_UNDERLINE:
-		cu = cd - 2;
-		break;
-	case CUR_LOWER_THIRD:
-		cu = (h * 2) / 3;
-		break;
-	case CUR_LOWER_HALF:
-		cu = h / 2;
-		break;
-	case CUR_TWO_THIRDS:
-		cu = h / 3;
-		break;
-	case CUR_BLOCK:
-	default:
-		cu = 0;
-		cd = h;
-		break;
-	}
-	fb_info.cursor.w = fontwidth(p);
-	fb_info.cursor.u = cu;
-	fb_info.cursor.d = cd;
-}
-
-static void tdfxfb_createcursor(struct display *p)
-{
-	u8 *cursorbase;
-	u32 xline;
-	unsigned int i;
-	unsigned int h, to;
-
-	tdfxfb_createcursorshape(p);
-	xline = ~((1 << (32 - fb_info.cursor.w)) - 1);
-
-#ifdef __LITTLE_ENDIAN
-	xline = swab32(xline);
 #endif
 
-	cursorbase = (u8 *) fb_info.bufbase_virt;
-	h = fb_info.cursor.cursorimage;
-
-	to = fb_info.cursor.u;
-	for (i = 0; i < to; i++) {
-		writel(0, cursorbase + h);
-		writel(0, cursorbase + h + 4);
-		writel(~0, cursorbase + h + 8);
-		writel(~0, cursorbase + h + 12);
-		h += 16;
-	}
-
-	to = fb_info.cursor.d;
-
-	for (; i < to; i++) {
-		writel(xline, cursorbase + h);
-		writel(0, cursorbase + h + 4);
-		writel(~0, cursorbase + h + 8);
-		writel(~0, cursorbase + h + 12);
-		h += 16;
-	}
-
-	for (; i < 64; i++) {
-		writel(0, cursorbase + h);
-		writel(0, cursorbase + h + 4);
-		writel(~0, cursorbase + h + 8);
-		writel(~0, cursorbase + h + 12);
-		h += 16;
-	}
-}
-
-static void tdfxfb_hwcursor_init(void)
-{
-	unsigned int start;
-	start = (fb_info.bufbase_size - 1024) & PAGE_MASK;
-	fb_info.bufbase_size = start;
-	fb_info.cursor.cursorimage = fb_info.bufbase_size;
-	printk("tdfxfb: reserving 1024 bytes for the hwcursor at %p\n",
-	       fb_info.regbase_virt + fb_info.cursor.cursorimage);
-}
diff -Nru a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
--- a/drivers/video/tx3912fb.c	Sat Jun  8 22:31:51 2002
+++ b/drivers/video/tx3912fb.c	Sat Jun  8 22:31:51 2002
@@ -1,15 +1,16 @@
 /*
- * linux/drivers/video/tx3912fb.c
+ *  drivers/video/tx3912fb.c
  *
- * Copyright (C) 1999 Harald Koerfgen
- * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
+ *  Copyright (C) 1999 Harald Koerfgen
+ *  Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
  *
  * 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.
  *
- * Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
+ *  Framebuffer for LCD controller in TMPR3912/05 and PR31700 processors
  */
+#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -20,282 +21,193 @@
 #include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/fb.h>
+#include <video/fbcon.h>
+#include <asm/io.h>
 #include <asm/bootinfo.h>
 #include <asm/uaccess.h>
-#include <video/fbcon.h>
-#include <video/fbcon-mfb.h>
-#include <video/fbcon-cfb2.h>
-#include <video/fbcon-cfb4.h>
-#include <video/fbcon-cfb8.h>
-#include "tx3912fb.h"
+#include <asm/tx3912.h>
+#include <video/tx3912.h>
 
 /*
  * Frame buffer, palette and console structures
  */
 static struct fb_info fb_info;
-static struct { u_char red, green, blue, pad; } palette[256];
-static struct display global_disp;
+static u32 cfb8[16];
+static struct display disp;
 
-/*
- * Interface used by the world
- */
-static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-				struct fb_info *info);
-static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info);
-static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info);
-static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-				struct fb_info *info);
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-			u_int transp, struct fb_info *info);
+static struct fb_fix_screeninfo tx3912fb_fix __initdata = {
+	id:		"tx3912fb",
+#ifdef CONFIG_NINO_16MB
+	smem_len:	(240 * 320),
+#else
+	smem_len:	((240 * 320)/2),
+#endif
+	type:		FB_TYPE_PACKED_PIXELS,
+	visual:		FB_VISUAL_TRUECOLOR, 
+	xpanstep:	1,
+	ypanstep:	1,
+	ywrapstep:	1,
+	accel:		FB_ACCEL_NONE,
+};
+
+static struct fb_var_screeninfo tx3912fb_var = {
+	xres:		240,
+	yres:		320,
+	xres_virtual:	240,
+	yres_virtual:	320,
+#ifdef CONFIG_NINO_16MB
+	bits_per_pixel:	8,
+	red:		{ 5, 3, 0 },	/* RGB 332 */
+	green:		{ 2, 3, 0 },
+	blue:		{ 0, 2, 0 },
+#else
+	bits_per_pixel:	4,
+#endif
+	activate:	FB_ACTIVATE_NOW,
+	width:		-1,
+	height:		-1,
+	pixclock:	20000,
+	left_margin:	64,
+	right_margin:	64,
+	upper_margin:	32,
+	lower_margin:	32,
+	hsync_len:	64,
+	vsync_len:	2,
+	vmode:		FB_VMODE_NONINTERLACED,
+};
 
 /*
- * Interface used by console driver
+ * Interface used by the world
  */
 int tx3912fb_init(void);
-static int tx3912fbcon_switch(int con, struct fb_info *info);
-static int tx3912fbcon_updatevar(int con, struct fb_info *info);
+
+static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
+			      u_int blue, u_int transp,
+			      struct fb_info *info);
 
 /*
  * Macros
  */
 #define get_line_length(xres_virtual, bpp) \
-		(u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
-
-/*
- * Internal routines
- */
-static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
-			u_int *blue, u_int *transp, struct fb_info *info);
+                (u_long) (((int) xres_virtual * (int) bpp + 7) >> 3)
 
 /*
  * Frame buffer operations structure used by console driver
  */
 static struct fb_ops tx3912fb_ops = {
-	owner: THIS_MODULE,
-	fb_get_fix: tx3912fb_get_fix,
-	fb_get_var: tx3912fb_get_var,
-	fb_set_var: tx3912fb_set_var,
-	fb_get_cmap: tx3912fb_get_cmap,
-	fb_set_cmap: gen_set_cmap,
+	owner:		THIS_MODULE,
+	fb_get_fix:	gen_get_fix,
+	fb_get_var:	gen_get_var,
+	fb_set_var:	gen_set_var,
+	fb_get_cmap:	gen_get_cmap,
+	fb_set_cmap:	gen_set_cmap,
 	fb_setcolreg:	tx3912fb_setcolreg,
+	fb_fillrect:	cfb_fillrect,
+	fb_copyarea:	cfb_copyarea,
+	fb_imageblit:	cfb_imageblit,
 };
 
-
-/*
- *  Get fixed display data
- */
-static int tx3912fb_get_fix(struct fb_fix_screeninfo *fix, int con,
-				struct fb_info *info)
-{
-	struct display *display;
-
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, TX3912FB_NAME);
-
-	if (con == -1)
-		display = &global_disp;
-	else
-		display = &fb_display[con];
-
-	fix->smem_start		= tx3912fb_vaddr;
-	fix->smem_len		= tx3912fb_size;
-	fix->type		= display->type;
-	fix->type_aux		= display->type_aux;
-	fix->xpanstep		= 0;
-	fix->ypanstep		= display->ypanstep;
-	fix->ywrapstep		= display->ywrapstep;
-	fix->visual		= display->visual;
-	fix->line_length	= display->line_length;
-	fix->accel		= FB_ACCEL_NONE;
-
-	return 0;
-}
-
-/*
- * Get user display data
- */
-static int tx3912fb_get_var(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info)
+static int tx3912fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
 {
-	if (con == -1)
-		*var = tx3912fb_info;
-	else
-		*var = fb_display[con].var;
+	/*
+	 * Memory limit
+	 */
+	line_length =
+	    get_line_length(var->xres_virtual, var->bits_per_pixel);
+	if ((line_length * var->yres_virtual) > info->fix.smem_len)
+		return -ENOMEM;
 
 	return 0;
 }
 
-/*
- *  Set user display data
- */
-static int tx3912fb_set_var(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info)
+static int tx3912fb_set_par(struct fb_info *info)
 {
-	int err, activate = var->activate;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-	u_long line_length;
-	struct display *display;
-
-	if (con == -1)
-		display = &global_disp;
-	else
-		display = &fb_display[con];
+	u_long tx3912fb_paddr = 0;
 
-	/*
-	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal
-	 * as FB_VMODE_SMOOTH_XPAN is only used internally
-	 */
-	if (var->vmode & FB_VMODE_CONUPDATE) {
-		var->xoffset = display->var.xoffset;
-		var->yoffset = display->var.yoffset;
-		var->vmode |= FB_VMODE_YWRAP;
-	}
+	/* Disable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
+	udelay(200);
 
-	/*
-	 * Make sure values are in range
-	 */
-	if (!var->xres)
-		var->xres = 1;
-	if (!var->yres)
-		var->yres = 1;
-	if (var->xres > var->xres_virtual)
-		var->xres_virtual = var->xres;
-	if (var->yres > var->yres_virtual)
-		var->yres_virtual = var->yres;
-	if (var->bits_per_pixel <= 1)
-		var->bits_per_pixel = 1;
-	else if (var->bits_per_pixel <= 2)
-		var->bits_per_pixel = 2;
-	else if (var->bits_per_pixel <= 4)
-		var->bits_per_pixel = 4;
-	else if (var->bits_per_pixel <= 8)
-		var->bits_per_pixel = 8;
-	else
-		return -EINVAL;
+	/* Set start address for DMA transfer */
+	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
 
-	/*
-	 * Memory limit
-	 */
-	line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
-	if ((line_length * var->yres_virtual) > tx3912fb_size)
-		return -ENOMEM;
+	/* Set end address for DMA transfer */
+	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
 
-	/*
-	 * This is only for color and we only support 8-bit color
-	 */
-	if (var->bits_per_pixel) {
-		/* RGB 332 */
-		var->red.offset = 5;
-		var->red.length = 3;
-		var->green.offset = 2;
-		var->green.length = 3;
-		var->blue.offset = 0;
-		var->blue.length = 2;
-		var->transp.offset = 0;
-		var->transp.length = 0;
+	/* Set the pixel depth */
+	switch (info->var.bits_per_pixel) {
+	case 1:
+		/* Monochrome */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_MONO10;
+		break;
+	case 4:
+		/* 4-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 8:
+		/* 8-bit color */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+		break;
+	case 2:
+	default:
+		/* 2-bit gray */
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		break;
 	}
-	var->red.msb_right = 0;
-	var->green.msb_right = 0;
-	var->blue.msb_right = 0;
-	var->transp.msb_right = 0;
 
-	/*
-	 * Make changes if necessary
-	 */
-	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
+	/* Enable the video clock */
+	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
+	     TX3912_CLK_CTRL);
 
-		oldxres = display->var.xres;
-		oldyres = display->var.yres;
-		oldvxres = display->var.xres_virtual;
-		oldvyres = display->var.yres_virtual;
-		oldbpp = display->var.bits_per_pixel;
-		display->var = *var;
-
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual ||
-		    oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-
-
-			switch (var->bits_per_pixel) {
-			case 1:
-				display->visual = FB_VISUAL_MONO10;
-				break;
-			case 2:
-				display->visual = FB_VISUAL_PSEUDOCOLOR;
-			case 4:
-			case 8:
-				display->visual = FB_VISUAL_TRUECOLOR;
-				break;
-			}
-
-			display->type = FB_TYPE_PACKED_PIXELS;
-			display->type_aux = 0;
-			display->ypanstep = 0;
-			display->ywrapstep = 0;
-			display->next_line =
-			display->line_length =
-				get_line_length(var->xres_virtual,
-					var->bits_per_pixel);
-			display->can_soft_blank = 0;
-			display->inverse = FB_IS_INVERSE;
-
-			switch (var->bits_per_pixel) {
-#ifdef CONFIG_FBCON_MFB
-			case 1:
-				display->dispsw = &fbcon_mfb;
-				break;
-#endif
-#ifdef CONFIG_FBCON_CFB2
-			case 2:
-				display->dispsw = &fbcon_cfb2;
-				break;
-#endif
-#ifdef CONFIG_FBCON_CFB4
-			case 4:
-				display->dispsw = &fbcon_cfb4;
-				break;
-#endif
-#ifdef CONFIG_FBCON_CFB8
-			case 8:
-				display->dispsw = &fbcon_cfb8;
-				display->dispsw_data = fbcon_cmap.cfb8;
-				break;
-#endif
-			default:
-				display->dispsw = &fbcon_dummy;
-				break;
-	    		}
-
-			if (fb_info.changevar)
-				(*fb_info.changevar)(con);
-		}
-
-		if (oldbpp != var->bits_per_pixel) {
-			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-				return err;
-			do_install_cmap(con, info);
-		}
-	}
+	/* Unfreeze video logic and enable DF toggle */
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME |
+	       TX3912_VIDEO_CTRL1_DFMODE)
+	     , TX3912_VIDEO_CTRL1);
+	udelay(200);
 
-	return 0;
+	/* Enable the video logic */
+	outl(inl(TX3912_VIDEO_CTRL1) |
+	     (TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
+
+	info->fix.line_length = get_line_length(var->xres_virtual,
+					    var->bits_per_pixel);
 }
 
 /*
- *  Get the colormap
+ * Set a single color register
  */
-static int tx3912fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			struct fb_info *info)
+static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green,
+			      u_int blue, u_int transp,
+			      struct fb_info *info)
 {
-	if (con == info->currcon)
-		return fb_get_cmap(cmap, kspc, tx3912fb_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), cmap, kspc ? 0 : 2);
+	if (regno > 255)
+		return 1;
 
+	if (regno < 16)
+		((u32 *)(info->pseudo_palette))[regno] = ((red & 0xe000) >> 8)
+		    | ((green & 0xe000) >> 11)
+		    | ((blue & 0xc000) >> 14);
 	return 0;
 }
 
@@ -304,164 +216,126 @@
  */
 int __init tx3912fb_init(void)
 {
-	/* Stop the video logic when frame completes */
-	VidCtrl1 |= ENFREEZEFRAME;
-	IntClear1 |= INT1_LCDINT;
-	while (!(IntStatus1 & INT1_LCDINT));
+	u_long tx3912fb_paddr = 0;
 
 	/* Disable the video logic */
-	VidCtrl1 &= ~(ENVID | DISPON);
+	outl(inl(TX3912_VIDEO_CTRL1) &
+	     ~(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+	     TX3912_VIDEO_CTRL1);
 	udelay(200);
 
 	/* Set start address for DMA transfer */
-	VidCtrl3 = tx3912fb_paddr &
-		(TX3912_VIDCTRL3_VIDBANK_MASK | TX3912_VIDCTRL3_VIDBASEHI_MASK);
+	outl(tx3912fb_paddr, TX3912_VIDEO_CTRL3);
 
 	/* Set end address for DMA transfer */
-	VidCtrl4 = (tx3912fb_paddr + tx3912fb_size + 1) &
-		TX3912_VIDCTRL4_VIDBASELO_MASK;
+	outl((tx3912fb_paddr + tx3912fb_fix.smem_len + 1), TX3912_VIDEO_CTRL4);
 
 	/* Set the pixel depth */
-	switch (tx3912fb_info.bits_per_pixel) {
+	switch (tx3912fb_var.bits_per_pixel) {
 	case 1:
 		/* Monochrome */
-		VidCtrl1 &= ~TX3912_VIDCTRL1_BITSEL_MASK;
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_MONO10;
 		break;
 	case 4:
 		/* 4-bit gray */
-		VidCtrl1 &= ~TX3912_VIDCTRL1_BITSEL_MASK;
-		VidCtrl1 |= TX3912_VIDCTRL1_4BIT_GRAY;
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_4BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
+		tx3912fb_fix.grayscale = 1;
 		break;
 	case 8:
 		/* 8-bit color */
-		VidCtrl1 &= ~TX3912_VIDCTRL1_BITSEL_MASK;
-		VidCtrl1 |= TX3912_VIDCTRL1_8BIT_COLOR;
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_8BIT_COLOR,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_TRUECOLOR;
 		break;
 	case 2:
 	default:
 		/* 2-bit gray */
-		VidCtrl1 &= ~TX3912_VIDCTRL1_BITSEL_MASK;
-		VidCtrl1 |= TX3912_VIDCTRL1_2BIT_GRAY;
+		outl(inl(TX3912_VIDEO_CTRL1) &
+		     ~TX3912_VIDEO_CTRL1_BITSEL_MASK, TX3912_VIDEO_CTRL1);
+		outl(inl(TX3912_VIDEO_CTRL1) |
+		     TX3912_VIDEO_CTRL1_BITSEL_2BIT_GRAY,
+		     TX3912_VIDEO_CTRL1);
+		tx3912fb_fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		tx3912fb_fix.grayscale = 1;
 		break;
 	}
 
+	/* Enable the video clock */
+	outl(inl(TX3912_CLK_CTRL) | TX3912_CLK_CTRL_ENVIDCLK,
+		TX3912_CLK_CTRL);
+
 	/* Unfreeze video logic and enable DF toggle */
-	VidCtrl1 &= ~(ENFREEZEFRAME | DFMODE);
+	outl(inl(TX3912_VIDEO_CTRL1) &
+		~(TX3912_VIDEO_CTRL1_ENFREEZEFRAME | TX3912_VIDEO_CTRL1_DFMODE),
+		TX3912_VIDEO_CTRL1);
 	udelay(200);
 
 	/* Clear the framebuffer */
-	memset((void *) tx3912fb_vaddr, 0xff, tx3912fb_size);
+	memset((void *) tx3912fb_fix.smem_start, 0xff, tx3912fb_fix.smem_len);
 	udelay(200);
 
 	/* Enable the video logic */
-	VidCtrl1 |= (DISPON | ENVID);
+	outl(inl(TX3912_VIDEO_CTRL1) |
+		(TX3912_VIDEO_CTRL1_ENVID | TX3912_VIDEO_CTRL1_DISPON),
+		TX3912_VIDEO_CTRL1);
+
+	/*
+	 * Memory limit
+	 */
+	tx3912fb_fix.line_length =
+	    get_line_length(tx3912fb_var.xres_virtual, tx3912fb_var.bits_per_pixel);
+	if ((tx3912fb_fix.line_length * tx3912fb_var.yres_virtual) > tx3912fb_fix.smem_len)
+		return -ENOMEM;
 
-	strcpy(fb_info.modename, TX3912FB_NAME);
+	strcpy(fb_info.modename, tx3912fb_fix.id);
 	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
-	fb_info.fbops = &tx3912fb_ops;
-	fb_info.screen_base = (u_char *) tx3912fb_vaddr;
-	fb_info.disp = &global_disp;
 	fb_info.currcon = -1;
-	fb_info.switch_con = &tx3912fbcon_switch;
-	fb_info.updatevar = &tx3912fbcon_updatevar;
+	fb_info.fbops = &tx3912fb_ops;
+	fb_info.var = tx3912fb_var;
+	fb_info.fix = tx3912fb_fix;
+	fb_info.pseudo_palette = pseudo_palette;
+	fb_info.disp = &disp;
+	fb_info.switch_con = gen_switch;
+	fb_info.updatevar = gen_update_var;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
 
-	tx3912fb_set_var(&tx3912fb_info, -1, &fb_info);
+	/* Clear the framebuffer */
+	memset((void *) fb_info.fix.smem_start, 0xff, fb_info.fix.smem_len);
+	udelay(200);
+
+	fb_alloc_cmap(&info->cmap, size, 0);
+	gen_set_disp(-1, &disp);	
 
 	if (register_framebuffer(&fb_info) < 0)
 		return -1;
 
-	printk (KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
-		GET_FB_IDX(fb_info.node), (u_int) (tx3912fb_size >> 10));
-
+	printk(KERN_INFO "fb%d: TX3912 frame buffer using %uKB.\n",
+	       GET_FB_IDX(fb_info.node), (u_int) (fb_info.fix.smem_len >> 10));
 	return 0;
 }
 
-/*
- * Switch the console to be the framebuffer
- */
-static int tx3912fbcon_switch(int con, struct fb_info *info)
+int __init tx3912fb_setup(char *options)
 {
-	/* Save off the color map if needed */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1,
-			tx3912fb_getcolreg, info);
+	char *this_opt;
 
-	/* Make the switch */
-	info->currcon = con;
+	if (!options || !*options)
+		return 0;
 
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	return 0;
-}
-
-/*
- * Update variable structure
- */
-static int tx3912fbcon_updatevar(int con, struct fb_info *info)
-{
-	/* Nothing */
-	return 0;
-}
-
-/*
- * Read a single color register
- */
-static int tx3912fb_getcolreg(u_int regno, u_int *red, u_int *green,
-			u_int *blue, u_int *transp, struct fb_info *info)
-{
-	if (regno > 255)
-		return 1;
-
-#if FB_IS_GREY
-	{
-		u_int grey;
-            
-		grey = regno * 255 / 15;
-
-#if FB_IS_INVERSE
-		grey ^= 255;
-#endif
-		grey |= grey << 8;
-		*red = grey;
-		*green = grey;
-		*blue = grey;
-	}
-#else
-	*red = (palette[regno].red<<8) | palette[regno].red;
-	*green = (palette[regno].green<<8) | palette[regno].green;
-	*blue = (palette[regno].blue<<8) | palette[regno].blue;
-#endif
-	*transp = 0;
-
-	return 0;
-}
-
-/*
- * Set a single color register
- */
-static int tx3912fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-				u_int transp, struct fb_info *info)
-{
-	if (regno > 255)
-		return 1;
-
-#ifdef FBCON_HAS_CFB8
-	if( regno < 16 )
-		fbcon_cmap.cfb8[regno] = ((red & 0xe000) >> 8)
-					| ((green & 0xe000) >> 11)
-					| ((blue & 0xc000) >> 14);
-#endif 
-
-	red >>= 8;
-	green >>= 8;
-	blue >>= 8;
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
-
-	return 0;
+	while ((this_opt = strsep(&options, ","))) {
+		if (!strncmp(options, "bpp:", 4))	
+			tx3912fb_var.bits_per_pixel = simple_strtoul(options+4, NULL, 0);
+	}	
 }
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/video/tx3912fb.h b/drivers/video/tx3912fb.h
--- a/drivers/video/tx3912fb.h	Sat Jun  8 22:31:35 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,128 +0,0 @@
-/*
- * linux/drivers/video/tx3912fb.h
- *
- * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
- *
- * 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.
- *
- * Includes for TMPR3912/05 and PR31700 LCD controller registers
- */
-#include <asm/tx3912.h>
-
-#define VidCtrl1        REG_AT(0x028)
-#define VidCtrl2        REG_AT(0x02C)
-#define VidCtrl3        REG_AT(0x030)
-#define VidCtrl4        REG_AT(0x034)
-#define VidCtrl5        REG_AT(0x038)
-#define VidCtrl6        REG_AT(0x03C)
-#define VidCtrl7        REG_AT(0x040)
-#define VidCtrl8        REG_AT(0x044)
-#define VidCtrl9        REG_AT(0x048)
-#define VidCtrl10       REG_AT(0x04C)
-#define VidCtrl11       REG_AT(0x050)
-#define VidCtrl12       REG_AT(0x054)
-#define VidCtrl13       REG_AT(0x058)
-#define VidCtrl14       REG_AT(0x05C)
-
-/* Video Control 1 Register */
-#define LINECNT         0xffc00000
-#define LINECNT_SHIFT   22
-#define LOADDLY         BIT(21)
-#define BAUDVAL         (BIT(20) | BIT(19) | BIT(18) | BIT(17) | BIT(16))
-#define BAUDVAL_SHIFT   16
-#define VIDDONEVAL      (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9))
-#define VIDDONEVAL_SHIFT  9
-#define ENFREEZEFRAME   BIT(8)
-#define TX3912_VIDCTRL1_BITSEL_MASK	0x000000c0
-#define TX3912_VIDCTRL1_2BIT_GRAY	0x00000040
-#define TX3912_VIDCTRL1_4BIT_GRAY	0x00000080
-#define TX3912_VIDCTRL1_8BIT_COLOR	0x000000c0
-#define BITSEL_SHIFT    6
-#define DISPSPLIT       BIT(5)
-#define DISP8           BIT(4)
-#define DFMODE          BIT(3)
-#define INVVID          BIT(2)
-#define DISPON          BIT(1)
-#define ENVID           BIT(0)
-
-/* Video Control 2 Register */
-#define VIDRATE_MASK    0xffc00000
-#define VIDRATE_SHIFT   22
-#define HORZVAL_MASK    0x001ff000
-#define HORZVAL_SHIFT   12
-#define LINEVAL_MASK    0x000001ff
-
-/* Video Control 3 Register */
-#define TX3912_VIDCTRL3_VIDBANK_MASK    0xfff00000
-#define TX3912_VIDCTRL3_VIDBASEHI_MASK  0x000ffff0
-
-/* Video Control 4 Register */
-#define TX3912_VIDCTRL4_VIDBASELO_MASK  0x000ffff0
-
-
-/*
- * Begin platform specific configurations
- */
-#if defined(CONFIG_NINO_4MB) || defined(CONFIG_NINO_8MB)
-#define FB_X_RES       240
-#define FB_Y_RES       320
-#if defined(CONFIG_FBCON_CFB4)
-#define FB_BPP         4
-#else
-#if defined(CONFIG_FBCON_CFB2)
-#define FB_BPP         2
-#else
-#define FB_BPP         1
-#endif
-#endif
-#define FB_IS_GREY     1
-#define FB_IS_INVERSE  0
-#endif
-
-#ifdef CONFIG_NINO_16MB
-#define FB_X_RES       240
-#define FB_Y_RES       320
-#define FB_BPP         8
-#define FB_IS_GREY     0
-#define FB_IS_INVERSE  0
-#endif
-
-/*
- * Define virtual resolutions if necessary
- */
-#ifndef FB_X_VIRTUAL_RES
-#define FB_X_VIRTUAL_RES FB_X_RES
-#endif
-#ifndef FB_Y_VIRTUAL_RES
-#define FB_Y_VIRTUAL_RES FB_Y_RES
-#endif
-
-/*
- * Framebuffer address and size
- */
-u_long tx3912fb_paddr = 0;
-u_long tx3912fb_vaddr = 0;
-u_long tx3912fb_size = (FB_X_RES * FB_Y_RES * FB_BPP / 8);
-
-/*
- * Framebuffer info structure
- */
-static struct fb_var_screeninfo tx3912fb_info = {
-	FB_X_RES, FB_Y_RES,
-	FB_X_VIRTUAL_RES, FB_Y_VIRTUAL_RES,
-	0, 0,
-	FB_BPP, FB_IS_GREY,
-	{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
-	0, FB_ACTIVATE_NOW,
-	-1, -1, 0, 20000,
-	64, 64, 32, 32, 64, 2,
-	0, FB_VMODE_NONINTERLACED,
-	{0,0,0,0,0,0}
-};
-
-/*
- * Framebuffer name
- */
-static char TX3912FB_NAME[16] = "tx3912fb";
diff -Nru a/drivers/video/vfb.c b/drivers/video/vfb.c
--- a/drivers/video/vfb.c	Sat Jun  8 22:31:35 2002
+++ b/drivers/video/vfb.c	Sat Jun  8 22:31:35 2002
@@ -90,7 +90,7 @@
 static int vfb_set_par(struct fb_info *info);
 static int vfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
 			 u_int transp, struct fb_info *info);
-static int vfb_pan_display(struct fb_var_screeninfo *var,
+static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
 			   struct fb_info *info);
 static int vfb_mmap(struct fb_info *info, struct file *file,
 		    struct vm_area_struct *vma);
@@ -358,7 +358,7 @@
      *  This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
      */
 
-static int vfb_pan_display(struct fb_var_screeninfo *var,
+static int vfb_pan_display(struct fb_var_screeninfo *var, int con,
 			   struct fb_info *info)
 {
 	if (var->vmode & FB_VMODE_YWRAP) {
diff -Nru a/drivers/zorro/Makefile b/drivers/zorro/Makefile
--- a/drivers/zorro/Makefile	Sat Jun  8 22:31:37 2002
+++ b/drivers/zorro/Makefile	Sat Jun  8 22:31:37 2002
@@ -7,12 +7,11 @@
 obj-$(CONFIG_ZORRO)	+= zorro.o names.o
 obj-$(CONFIG_PROC_FS)	+= proc.o
 
+host-progs 		:= gen_devlist
+
 include $(TOPDIR)/Rules.make
 
-names.o: names.c devlist.h
+names.o: devlist.h
 
 devlist.h: zorro.ids gen-devlist
 	./gen-devlist <zorro.ids
-
-gen-devlist: gen-devlist.c
-	$(HOSTCC) $(HOSTCFLAGS) -o gen-devlist gen-devlist.c
diff -Nru a/fs/binfmt_misc.c b/fs/binfmt_misc.c
--- a/fs/binfmt_misc.c	Sat Jun  8 22:31:37 2002
+++ b/fs/binfmt_misc.c	Sat Jun  8 22:31:37 2002
@@ -621,7 +621,7 @@
 
 static struct super_operations s_ops = {
 	statfs:		simple_statfs,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 	clear_inode:	bm_clear_inode,
 };
 
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Sat Jun  8 22:31:36 2002
+++ b/fs/dcache.c	Sat Jun  8 22:31:36 2002
@@ -755,6 +755,9 @@
 	}
 
 	tmp = d_alloc(NULL, &(const struct qstr) {"",0,0});
+	if (!tmp)
+		return NULL;
+
 	tmp->d_parent = tmp; /* make sure dput doesn't croak */
 	
 	spin_lock(&dcache_lock);
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Sat Jun  8 22:31:36 2002
+++ b/fs/devfs/base.c	Sat Jun  8 22:31:36 2002
@@ -2576,7 +2576,7 @@
 
 static struct super_operations devfs_sops =
 { 
-    put_inode:     force_delete,
+    drop_inode:    generic_delete_inode,
     clear_inode:   devfs_clear_inode,
     statfs:        simple_statfs,
 };
diff -Nru a/fs/driverfs/inode.c b/fs/driverfs/inode.c
--- a/fs/driverfs/inode.c	Sat Jun  8 22:31:36 2002
+++ b/fs/driverfs/inode.c	Sat Jun  8 22:31:36 2002
@@ -442,7 +442,7 @@
 
 static struct super_operations driverfs_ops = {
 	statfs:		simple_statfs,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 };
 
 static int driverfs_fill_super(struct super_block *sb, void *data, int silent)
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Sat Jun  8 22:31:36 2002
+++ b/fs/fcntl.c	Sat Jun  8 22:31:36 2002
@@ -300,11 +300,11 @@
 			unlock_kernel();
 			break;
 		case F_GETLK:
-			err = fcntl_getlk(fd, (struct flock *) arg);
+			err = fcntl_getlk(filp, (struct flock *) arg);
 			break;
 		case F_SETLK:
 		case F_SETLKW:
-			err = fcntl_setlk(fd, cmd, (struct flock *) arg);
+			err = fcntl_setlk(filp, cmd, (struct flock *) arg);
 			break;
 		case F_GETOWN:
 			/*
@@ -386,13 +386,11 @@
 
 	switch (cmd) {
 		case F_GETLK64:
-			err = fcntl_getlk64(fd, (struct flock64 *) arg);
+			err = fcntl_getlk64(filp, (struct flock64 *) arg);
 			break;
 		case F_SETLK64:
-			err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
-			break;
 		case F_SETLKW64:
-			err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
+			err = fcntl_setlk64(filp, cmd, (struct flock64 *) arg);
 			break;
 		default:
 			err = do_fcntl(fd, cmd, arg, filp);
@@ -551,7 +549,7 @@
 
 static int __init fasync_init(void)
 {
-	fasync_cache = kmem_cache_create("fasync cache",
+	fasync_cache = kmem_cache_create("fasync_cache",
 		sizeof(struct fasync_struct), 0, 0, NULL, NULL);
 	if (!fasync_cache)
 		panic("cannot create fasync slab cache");
diff -Nru a/fs/inode.c b/fs/inode.c
--- a/fs/inode.c	Sat Jun  8 22:31:37 2002
+++ b/fs/inode.c	Sat Jun  8 22:31:37 2002
@@ -390,8 +390,7 @@
 		if (atomic_read(&inode->i_count))
 			continue;
 		list_del(tmp);
-		list_del(&inode->i_hash);
-		INIT_LIST_HEAD(&inode->i_hash);
+		list_del_init(&inode->i_hash);
 		list_add(tmp, freeable);
 		inode->i_state |= I_FREEING;
 		count++;
@@ -777,11 +776,99 @@
 void remove_inode_hash(struct inode *inode)
 {
 	spin_lock(&inode_lock);
-	list_del(&inode->i_hash);
-	INIT_LIST_HEAD(&inode->i_hash);
+	list_del_init(&inode->i_hash);
 	spin_unlock(&inode_lock);
 }
 
+void generic_delete_inode(struct inode *inode)
+{
+	struct super_operations *op = inode->i_sb->s_op;
+
+	list_del_init(&inode->i_hash);
+	list_del_init(&inode->i_list);
+	inode->i_state|=I_FREEING;
+	inodes_stat.nr_inodes--;
+	spin_unlock(&inode_lock);
+
+	if (inode->i_data.nrpages)
+		truncate_inode_pages(&inode->i_data, 0);
+
+	if (op && op->delete_inode) {
+		void (*delete)(struct inode *) = op->delete_inode;
+		if (!is_bad_inode(inode))
+			DQUOT_INIT(inode);
+		/* s_op->delete_inode internally recalls clear_inode() */
+		delete(inode);
+	} else
+		clear_inode(inode);
+	if (inode->i_state != I_CLEAR)
+		BUG();
+	destroy_inode(inode);
+}
+EXPORT_SYMBOL(generic_delete_inode);
+
+static void generic_forget_inode(struct inode *inode)
+{
+	struct super_block *sb = inode->i_sb;
+
+	if (!list_empty(&inode->i_hash)) {
+		if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
+			list_del(&inode->i_list);
+			list_add(&inode->i_list, &inode_unused);
+		}
+		inodes_stat.nr_unused++;
+		spin_unlock(&inode_lock);
+		if (!sb || (sb->s_flags & MS_ACTIVE))
+			return;
+		write_inode_now(inode, 1);
+		spin_lock(&inode_lock);
+		inodes_stat.nr_unused--;
+		list_del_init(&inode->i_hash);
+	}
+	list_del_init(&inode->i_list);
+	inode->i_state|=I_FREEING;
+	inodes_stat.nr_inodes--;
+	spin_unlock(&inode_lock);
+	if (inode->i_data.nrpages)
+		truncate_inode_pages(&inode->i_data, 0);
+	clear_inode(inode);
+	destroy_inode(inode);
+}
+
+/*
+ * Normal UNIX filesystem behaviour: delete the
+ * inode when the usage count drops to zero, and
+ * i_nlink is zero.
+ */
+static void generic_drop_inode(struct inode *inode)
+{
+	if (!inode->i_nlink)
+		generic_delete_inode(inode);
+	else
+		generic_forget_inode(inode);
+}
+
+/*
+ * Called when we're dropping the last reference
+ * to an inode. 
+ *
+ * Call the FS "drop()" function, defaulting to
+ * the legacy UNIX filesystem behaviour..
+ *
+ * NOTE! NOTE! NOTE! We're called with the inode lock
+ * held, and the drop function is supposed to release
+ * the lock!
+ */
+static inline void iput_final(struct inode *inode)
+{
+	struct super_operations *op = inode->i_sb->s_op;
+	void (*drop)(struct inode *) = generic_drop_inode;
+
+	if (op && op->drop_inode)
+		drop = op->drop_inode;
+	drop(inode);
+}
+
 /**
  *	iput	- put an inode 
  *	@inode: inode to put
@@ -793,77 +880,17 @@
 void iput(struct inode *inode)
 {
 	if (inode) {
-		struct super_block *sb = inode->i_sb;
-		struct super_operations *op = NULL;
+		struct super_operations *op = inode->i_sb->s_op;
 
 		if (inode->i_state == I_CLEAR)
 			BUG();
 
-		if (sb && sb->s_op)
-			op = sb->s_op;
 		if (op && op->put_inode)
 			op->put_inode(inode);
 
-		if (!atomic_dec_and_lock(&inode->i_count, &inode_lock))
-			return;
-
-		if (!inode->i_nlink) {
-			list_del(&inode->i_hash);
-			INIT_LIST_HEAD(&inode->i_hash);
-			list_del(&inode->i_list);
-			INIT_LIST_HEAD(&inode->i_list);
-			inode->i_state|=I_FREEING;
-			inodes_stat.nr_inodes--;
-			spin_unlock(&inode_lock);
-
-			if (inode->i_data.nrpages)
-				truncate_inode_pages(&inode->i_data, 0);
-
-			if (op && op->delete_inode) {
-				void (*delete)(struct inode *) = op->delete_inode;
-				if (!is_bad_inode(inode))
-					DQUOT_INIT(inode);
-				/* s_op->delete_inode internally recalls clear_inode() */
-				delete(inode);
-			} else
-				clear_inode(inode);
-			if (inode->i_state != I_CLEAR)
-				BUG();
-		} else {
-			if (!list_empty(&inode->i_hash)) {
-				if (!(inode->i_state & (I_DIRTY|I_LOCK))) {
-					list_del(&inode->i_list);
-					list_add(&inode->i_list, &inode_unused);
-				}
-				inodes_stat.nr_unused++;
-				spin_unlock(&inode_lock);
-				if (!sb || (sb->s_flags & MS_ACTIVE))
-					return;
-				write_inode_now(inode, 1);
-				spin_lock(&inode_lock);
-				inodes_stat.nr_unused--;
-				list_del_init(&inode->i_hash);
-			}
-			list_del_init(&inode->i_list);
-			inode->i_state|=I_FREEING;
-			inodes_stat.nr_inodes--;
-			spin_unlock(&inode_lock);
-			if (inode->i_data.nrpages)
-				truncate_inode_pages(&inode->i_data, 0);
-			clear_inode(inode);
-		}
-		destroy_inode(inode);
+		if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
+			iput_final(inode);
 	}
-}
-
-void force_delete(struct inode *inode)
-{
-	/*
-	 * Kill off unused inodes ... iput() will unhash and
-	 * delete the inode if we set i_nlink to zero.
-	 */
-	if (atomic_read(&inode->i_count) == 1)
-		inode->i_nlink = 0;
 }
 
 /**
diff -Nru a/fs/jfs/file.c b/fs/jfs/file.c
--- a/fs/jfs/file.c	Sat Jun  8 22:31:37 2002
+++ b/fs/jfs/file.c	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Sat Jun  8 22:31:35 2002
+++ b/fs/jfs/inode.c	Sat Jun  8 22:31:35 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
--- a/fs/jfs/jfs_debug.c	Sat Jun  8 22:31:36 2002
+++ b/fs/jfs/jfs_debug.c	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_debug.h b/fs/jfs/jfs_debug.h
--- a/fs/jfs/jfs_debug.h	Sat Jun  8 22:31:36 2002
+++ b/fs/jfs/jfs_debug.h	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h
--- a/fs/jfs/jfs_imap.h	Sat Jun  8 22:31:36 2002
+++ b/fs/jfs/jfs_imap.h	Sat Jun  8 22:31:36 2002
@@ -153,7 +153,6 @@
 extern int diMount(struct inode *);
 extern int diUnmount(struct inode *, int);
 extern int diRead(struct inode *);
-extern void diClearExtension(struct inode *);
 extern struct inode *diReadSpecial(struct super_block *, ino_t);
 extern void diWriteSpecial(struct inode *);
 extern void diFreeSpecial(struct inode *);
diff -Nru a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
--- a/fs/jfs/jfs_incore.h	Sat Jun  8 22:31:35 2002
+++ b/fs/jfs/jfs_incore.h	Sat Jun  8 22:31:35 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
--- a/fs/jfs/jfs_lock.h	Sat Jun  8 22:31:36 2002
+++ b/fs/jfs/jfs_lock.h	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2001
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
--- a/fs/jfs/jfs_logmgr.c	Sat Jun  8 22:31:49 2002
+++ b/fs/jfs/jfs_logmgr.c	Sat Jun  8 22:31:49 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
--- a/fs/jfs/jfs_logmgr.h	Sat Jun  8 22:31:37 2002
+++ b/fs/jfs/jfs_logmgr.h	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
--- a/fs/jfs/jfs_metapage.c	Sat Jun  8 22:31:36 2002
+++ b/fs/jfs/jfs_metapage.c	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
--- a/fs/jfs/jfs_metapage.h	Sat Jun  8 22:31:49 2002
+++ b/fs/jfs/jfs_metapage.h	Sat Jun  8 22:31:49 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
--- a/fs/jfs/jfs_txnmgr.c	Sat Jun  8 22:31:35 2002
+++ b/fs/jfs/jfs_txnmgr.c	Sat Jun  8 22:31:35 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
--- a/fs/jfs/jfs_txnmgr.h	Sat Jun  8 22:31:51 2002
+++ b/fs/jfs/jfs_txnmgr.h	Sat Jun  8 22:31:51 2002
@@ -251,10 +251,17 @@
 	u8 count;		/* 1: number of pxd/xad */
 				/* (8) */
 
-	void *xdlist;		/* 4: pxd/xad list */
-	s32 rsrvd;		/* 4: */
+	/*
+	 * We need xdlistlock_t to be 64 bits (8 bytes), regardless of
+	 * whether void * is 32 or 64 bits
+	 */
+	union {
+		void *_xdlist;	/* pxd/xad list */
+		s64 pad;	/* 8: Force 64-bit xdlist size */
+	} union64;
 } xdlistlock_t;			/* (16): */
 
+#define xdlist union64._xdlist
 
 /*
  *	commit
diff -Nru a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
--- a/fs/jfs/jfs_unicode.h	Sat Jun  8 22:31:35 2002
+++ b/fs/jfs/jfs_unicode.h	Sat Jun  8 22:31:35 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/namei.c b/fs/jfs/namei.c
--- a/fs/jfs/namei.c	Sat Jun  8 22:31:51 2002
+++ b/fs/jfs/namei.c	Sat Jun  8 22:31:51 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c
--- a/fs/jfs/super.c	Sat Jun  8 22:31:37 2002
+++ b/fs/jfs/super.c	Sat Jun  8 22:31:37 2002
@@ -1,5 +1,6 @@
 /*
  *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Portions Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/jfs/symlink.c b/fs/jfs/symlink.c
--- a/fs/jfs/symlink.c	Sat Jun  8 22:31:43 2002
+++ b/fs/jfs/symlink.c	Sat Jun  8 22:31:43 2002
@@ -1,5 +1,5 @@
 /*
- *   Copyright (c) International Business Machines Corp., 2000-2002
+ *   Copyright (c) Christoph Hellwig, 2001-2002
  *
  *   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
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Sat Jun  8 22:31:37 2002
+++ b/fs/locks.c	Sat Jun  8 22:31:37 2002
@@ -1,4 +1,3 @@
-#define MSNFS	/* HACK HACK */
 /*
  *  linux/fs/locks.c
  *
@@ -126,9 +125,16 @@
 #include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
+#define IS_POSIX(fl)	(fl->fl_flags & FL_POSIX)
+#define IS_FLOCK(fl)	(fl->fl_flags & FL_FLOCK)
+#define IS_LEASE(fl)	(fl->fl_flags & FL_LEASE)
+
 int leases_enable = 1;
 int lease_break_time = 45;
 
+#define for_each_lock(inode, lockp) \
+	for (lockp = &inode->i_flock; *lockp != NULL; lockp = &(*lockp)->fl_next)
+
 LIST_HEAD(file_lock_list);
 static LIST_HEAD(blocked_list);
 
@@ -217,25 +223,41 @@
 	new->fl_u = fl->fl_u;
 }
 
+static inline int flock_translate_cmd(int cmd) {
+	if (cmd & LOCK_MAND)
+		return cmd & (LOCK_MAND | LOCK_RW);
+	switch (cmd &~ LOCK_NB) {
+	case LOCK_SH:
+		return F_RDLCK;
+	case LOCK_EX:
+		return F_WRLCK;
+	case LOCK_UN:
+		return F_UNLCK;
+	}
+	return -EINVAL;
+}
+
 /* Fill in a file_lock structure with an appropriate FLOCK lock. */
-static struct file_lock *flock_make_lock(struct file *filp, unsigned int type)
+static int flock_make_lock(struct file *filp,
+		struct file_lock **lock, unsigned int cmd)
 {
-	struct file_lock *fl = locks_alloc_lock(1);
+	struct file_lock *fl;
+	int type = flock_translate_cmd(cmd);
+	if (type < 0)
+		return type;
+	
+	fl = locks_alloc_lock(1);
 	if (fl == NULL)
-		return NULL;
+		return -ENOMEM;
 
-	fl->fl_owner = NULL;
 	fl->fl_file = filp;
 	fl->fl_pid = current->pid;
 	fl->fl_flags = FL_FLOCK;
 	fl->fl_type = type;
-	fl->fl_start = 0;
 	fl->fl_end = OFFSET_MAX;
-	fl->fl_notify = NULL;
-	fl->fl_insert = NULL;
-	fl->fl_remove = NULL;
 	
-	return fl;
+	*lock = fl;
+	return 0;
 }
 
 static int assign_type(struct file_lock *fl, int type)
@@ -397,10 +419,8 @@
  */
 static void locks_delete_block(struct file_lock *waiter)
 {
-	list_del(&waiter->fl_block);
-	INIT_LIST_HEAD(&waiter->fl_block);
-	list_del(&waiter->fl_link);
-	INIT_LIST_HEAD(&waiter->fl_link);
+	list_del_init(&waiter->fl_block);
+	list_del_init(&waiter->fl_link);
 	waiter->fl_next = NULL;
 }
 
@@ -436,24 +456,15 @@
  * If told to wait then schedule the processes until the block list
  * is empty, otherwise empty the block list ourselves.
  */
-static void locks_wake_up_blocks(struct file_lock *blocker, unsigned int wait)
+static void locks_wake_up_blocks(struct file_lock *blocker)
 {
 	while (!list_empty(&blocker->fl_block)) {
 		struct file_lock *waiter = list_entry(blocker->fl_block.next, struct file_lock, fl_block);
-
-		if (wait) {
-			locks_notify_blocked(waiter);
-			/* Let the blocked process remove waiter from the
-			 * block list when it gets scheduled.
-			 */
-			yield();
-		} else {
-			/* Remove waiter from the block list, because by the
-			 * time it wakes up blocker won't exist any more.
-			 */
-			locks_delete_block(waiter);
-			locks_notify_blocked(waiter);
-		}
+		/* Remove waiter from the block list, because by the
+		 * time it wakes up blocker won't exist any more.
+		 */
+		locks_delete_block(waiter);
+		locks_notify_blocked(waiter);
 	}
 }
 
@@ -490,7 +501,7 @@
  * notify the FS that the lock has been cleared and
  * finally free the lock.
  */
-static inline void _delete_lock(struct file_lock *fl, unsigned int wait)
+static inline void _delete_lock(struct file_lock *fl)
 {
 	fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
 	if (fl->fl_fasync != NULL){
@@ -501,19 +512,19 @@
 	if (fl->fl_remove)
 		fl->fl_remove(fl);
 
-	locks_wake_up_blocks(fl, wait);
+	locks_wake_up_blocks(fl);
 	locks_free_lock(fl);
 }
 
 /*
  * Delete a lock and then free it.
  */
-static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
+static void locks_delete_lock(struct file_lock **thisfl_p)
 {
 	struct file_lock *fl = *thisfl_p;
 
 	_unhash_lock(thisfl_p);
-	_delete_lock(fl, wait);
+	_delete_lock(fl);
 }
 
 /*
@@ -532,7 +543,7 @@
 		fl->fl_type = F_UNLCK;
 		lock(fl->fl_file, F_SETLK, fl);
 	}
-	_delete_lock(fl, 0);
+	_delete_lock(fl);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -563,8 +574,7 @@
 	/* POSIX locks owned by the same process do not conflict with
 	 * each other.
 	 */
-	if (!(sys_fl->fl_flags & FL_POSIX) ||
-	    locks_same_owner(caller_fl, sys_fl))
+	if (!IS_POSIX(sys_fl) || locks_same_owner(caller_fl, sys_fl))
 		return (0);
 
 	/* Check whether they overlap */
@@ -582,13 +592,10 @@
 	/* FLOCK locks referring to the same filp do not conflict with
 	 * each other.
 	 */
-	if (!(sys_fl->fl_flags & FL_FLOCK) ||
-	    (caller_fl->fl_file == sys_fl->fl_file))
+	if (!IS_FLOCK(sys_fl) || (caller_fl->fl_file == sys_fl->fl_file))
 		return (0);
-#ifdef MSNFS
 	if ((caller_fl->fl_type & LOCK_MAND) || (sys_fl->fl_type & LOCK_MAND))
 		return 0;
-#endif
 
 	return (locks_conflict(caller_fl, sys_fl));
 }
@@ -636,7 +643,7 @@
 
 	lock_kernel();
 	for (cfl = filp->f_dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
-		if (!(cfl->fl_flags & FL_POSIX))
+		if (!IS_POSIX(cfl))
 			continue;
 		if (posix_locks_conflict(cfl, fl))
 			break;
@@ -698,7 +705,7 @@
 	 */
 	lock_kernel();
 	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (!(fl->fl_flags & FL_POSIX))
+		if (!IS_POSIX(fl))
 			continue;
 		if (fl->fl_owner != owner)
 			break;
@@ -734,7 +741,7 @@
 	 * the proposed read/write.
 	 */
 	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (!(fl->fl_flags & FL_POSIX))
+		if (!IS_POSIX(fl))
 			continue;
 		if (fl->fl_start > new_fl->fl_end)
 			break;
@@ -768,57 +775,45 @@
  * at the head of the list, but that's secret knowledge known only to
  * flock_lock_file and posix_lock_file.
  */
-static int flock_lock_file(struct file *filp, unsigned int lock_type,
+static int flock_lock_file(struct file *filp, struct file_lock *new_fl,
 			   unsigned int wait)
 {
-	struct file_lock *fl;
-	struct file_lock *new_fl = NULL;
 	struct file_lock **before;
 	struct inode * inode = filp->f_dentry->d_inode;
-	int error, change;
-	int unlock = (lock_type == F_UNLCK);
-
-	/*
-	 * If we need a new lock, get it in advance to avoid races.
-	 */
-	if (!unlock) {
-		error = -ENOLCK;
-		new_fl = flock_make_lock(filp, lock_type);
-		if (!new_fl)
-			return error;
-	}
+	int error = 0;
+	int found = 0;
 
-	error = 0;
-search:
-	change = 0;
-	before = &inode->i_flock;
-	while (((fl = *before) != NULL) && (fl->fl_flags & FL_FLOCK)) {
-		if (filp == fl->fl_file) {
-			if (lock_type == fl->fl_type)
-				goto out;
-			change = 1;
+	lock_kernel();
+	for_each_lock(inode, before) {
+		struct file_lock *fl = *before;
+		if (IS_POSIX(fl))
 			break;
-		}
-		before = &fl->fl_next;
-	}
-	/* change means that we are changing the type of an existing lock,
-	 * or else unlocking it.
-	 */
-	if (change) {
-		/* N.B. What if the wait argument is false? */
-		locks_delete_lock(before, !unlock);
-		/*
-		 * If we waited, another lock may have been added ...
-		 */
-		if (!unlock)
-			goto search;
+		if (IS_LEASE(fl))
+			continue;
+		if (filp != fl->fl_file)
+			continue;
+		if (new_fl->fl_type == fl->fl_type)
+			goto out;
+		found = 1;
+		locks_delete_lock(before);
+		break;
 	}
-	if (unlock)
-		goto out;
+	unlock_kernel();
+
+	if (found)
+		yield();
 
+	if (new_fl->fl_type == F_UNLCK)
+		return 0;
+
+	lock_kernel();
 repeat:
-	for (fl = inode->i_flock; (fl != NULL) && (fl->fl_flags & FL_FLOCK);
-	     fl = fl->fl_next) {
+	for_each_lock(inode, before) {
+		struct file_lock *fl = *before;
+		if (IS_POSIX(fl))
+			break;
+		if (IS_LEASE(fl))
+			continue;
 		if (!flock_locks_conflict(new_fl, fl))
 			continue;
 		error = -EAGAIN;
@@ -830,12 +825,10 @@
 		goto repeat;
 	}
 	locks_insert_lock(&inode->i_flock, new_fl);
-	new_fl = NULL;
 	error = 0;
 
 out:
-	if (new_fl)
-		locks_free_lock(new_fl);
+	unlock_kernel();
 	return error;
 }
 
@@ -882,7 +875,7 @@
 	if (caller->fl_type != F_UNLCK) {
   repeat:
 		for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-			if (!(fl->fl_flags & FL_POSIX))
+			if (!IS_POSIX(fl))
 				continue;
 			if (!posix_locks_conflict(caller, fl))
 				continue;
@@ -911,7 +904,7 @@
 
 	/* First skip locks owned by other processes.
 	 */
-	while ((fl = *before) && (!(fl->fl_flags & FL_POSIX) ||
+	while ((fl = *before) && (!IS_POSIX(fl) ||
 				  !locks_same_owner(caller, fl))) {
 		before = &fl->fl_next;
 	}
@@ -944,7 +937,7 @@
 			else
 				caller->fl_end = fl->fl_end;
 			if (added) {
-				locks_delete_lock(before, 0);
+				locks_delete_lock(before);
 				continue;
 			}
 			caller = fl;
@@ -974,7 +967,7 @@
 				 * one (This may happen several times).
 				 */
 				if (added) {
-					locks_delete_lock(before, 0);
+					locks_delete_lock(before);
 					continue;
 				}
 				/* Replace the old lock with the new one.
@@ -982,7 +975,7 @@
 				 * as the change in lock type might satisfy
 				 * their needs.
 				 */
-				locks_wake_up_blocks(fl, 0);	/* This cannot schedule()! */
+				locks_wake_up_blocks(fl);
 				fl->fl_start = caller->fl_start;
 				fl->fl_end = caller->fl_end;
 				fl->fl_type = caller->fl_type;
@@ -1016,11 +1009,11 @@
 			locks_insert_lock(before, left);
 		}
 		right->fl_start = caller->fl_end + 1;
-		locks_wake_up_blocks(right, 0);
+		locks_wake_up_blocks(right);
 	}
 	if (left) {
 		left->fl_end = caller->fl_start - 1;
-		locks_wake_up_blocks(left, 0);
+		locks_wake_up_blocks(left);
 	}
 out:
 	unlock_kernel();
@@ -1035,22 +1028,6 @@
 	return error;
 }
 
-static inline int flock_translate_cmd(int cmd) {
-#ifdef MSNFS
-	if (cmd & LOCK_MAND)
-		return cmd & (LOCK_MAND | LOCK_RW);
-#endif
-	switch (cmd &~ LOCK_NB) {
-	case LOCK_SH:
-		return F_RDLCK;
-	case LOCK_EX:
-		return F_WRLCK;
-	case LOCK_UN:
-		return F_UNLCK;
-	}
-	return -EINVAL;
-}
-
 /**
  *	__get_lease	-	revoke all outstanding leases on file
  *	@inode: the inode of the file to return
@@ -1087,7 +1064,7 @@
 			if (error != 0)
 				goto out;
 			flock = inode->i_flock;
-			if (!(flock && (flock->fl_flags & FL_LEASE)))
+			if (!(flock && IS_LEASE(flock)))
 				goto out;
 		} while (flock->fl_type & F_INPROGRESS);
 	}
@@ -1112,7 +1089,7 @@
 	do {
 		fl->fl_type = future;
 		fl = fl->fl_next;
-	} while (fl != NULL && (fl->fl_flags & FL_LEASE));
+	} while (fl != NULL && IS_LEASE(fl));
 
 	kill_fasync(&flock->fl_fasync, SIGIO, POLL_MSG);
 
@@ -1129,11 +1106,11 @@
 	error = locks_block_on_timeout(flock, new_fl, error);
 	if (error == 0) {
 		/* We timed out.  Unilaterally break the lease. */
-		locks_delete_lock(&inode->i_flock, 0);
+		locks_delete_lock(&inode->i_flock);
 		printk(KERN_WARNING "lease timed out\n");
 	} else if (error > 0) {
 		flock = inode->i_flock;
-		if (flock && (flock->fl_flags & FL_LEASE))
+		if (flock && IS_LEASE(flock))
 			goto restart;
 		error = 0;
 	}
@@ -1156,7 +1133,7 @@
 time_t lease_get_mtime(struct inode *inode)
 {
 	struct file_lock *flock = inode->i_flock;
-	if (flock && (flock->fl_flags & FL_LEASE) && (flock->fl_type & F_WRLCK))
+	if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK))
 		return CURRENT_TIME;
 	return inode->i_mtime;
 }
@@ -1179,7 +1156,7 @@
 	struct file_lock *fl;
 	
 	fl = filp->f_dentry->d_inode->i_flock;
-	if ((fl == NULL) || ((fl->fl_flags & FL_LEASE) == 0))
+	if ((fl == NULL) || !IS_LEASE(fl))
 		return F_UNLCK;
 	return fl->fl_type & ~F_INPROGRESS;
 }
@@ -1192,14 +1169,14 @@
 	if (error < 0)
 		goto out;
 
-	locks_wake_up_blocks(fl, 0);
+	locks_wake_up_blocks(fl);
 
 	if (arg == F_UNLCK) {
 		filp->f_owner.pid = 0;
 		filp->f_owner.uid = 0;
 		filp->f_owner.euid = 0;
 		filp->f_owner.signum = 0;
-		locks_delete_lock(before, 0);
+		locks_delete_lock(before);
 		fasync_helper(fd, filp, 0, &fl->fl_fasync);
 	}
 
@@ -1245,7 +1222,7 @@
 	lock_kernel();
 
 	while ((fl = *before) != NULL) {
-		if (fl->fl_flags != FL_LEASE)
+		if (!IS_LEASE(fl))
 			break;
 		if (fl->fl_file == filp)
 			my_before = before;
@@ -1319,30 +1296,26 @@
 asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
 {
 	struct file *filp;
-	int error, type;
+	struct file_lock *lock;
+	int error;
 
 	error = -EBADF;
 	filp = fget(fd);
 	if (!filp)
 		goto out;
 
-	error = flock_translate_cmd(cmd);
-	if (error < 0)
+	if ((cmd != LOCK_UN) && !(cmd & LOCK_MAND) && !(filp->f_mode & 3))
 		goto out_putf;
-	type = error;
 
-	error = -EBADF;
-	if ((type != F_UNLCK)
-#ifdef MSNFS
-		&& !(type & LOCK_MAND)
-#endif
-		&& !(filp->f_mode & 3))
+	error = flock_make_lock(filp, &lock, cmd);
+	if (error < 0)
 		goto out_putf;
 
-	lock_kernel();
-	error = flock_lock_file(filp, type,
+	error = flock_lock_file(filp, lock,
 				(cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
-	unlock_kernel();
+
+	if (error)
+		locks_free_lock(lock);
 
 out_putf:
 	fput(filp);
@@ -1353,9 +1326,8 @@
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk(unsigned int fd, struct flock *l)
+int fcntl_getlk(struct file *filp, struct flock *l)
 {
-	struct file *filp;
 	struct file_lock *fl, file_lock;
 	struct flock flock;
 	int error;
@@ -1367,19 +1339,14 @@
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
 		goto out;
 
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
 	error = flock_to_posix_lock(filp, &file_lock, &flock);
 	if (error)
-		goto out_putf;
+		goto out;
 
 	if (filp->f_op && filp->f_op->lock) {
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
-			goto out_putf;
+			goto out;
 		else if (error == LOCK_USE_CLNT)
 		  /* Bypass for NFS with no locking - 2.0.36 compat */
 		  fl = posix_test_lock(filp, &file_lock);
@@ -1399,10 +1366,10 @@
 		 */
 		error = -EOVERFLOW;
 		if (fl->fl_start > OFFT_OFFSET_MAX)
-			goto out_putf;
+			goto out;
 		if ((fl->fl_end != OFFSET_MAX)
 		    && (fl->fl_end > OFFT_OFFSET_MAX))
-			goto out_putf;
+			goto out;
 #endif
 		flock.l_start = fl->fl_start;
 		flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
@@ -1414,8 +1381,6 @@
 	if (!copy_to_user(l, &flock, sizeof(flock)))
 		error = 0;
   
-out_putf:
-	fput(filp);
 out:
 	return error;
 }
@@ -1423,9 +1388,8 @@
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
-int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l)
+int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l)
 {
-	struct file *filp;
 	struct file_lock *file_lock = locks_alloc_lock(0);
 	struct flock flock;
 	struct inode *inode;
@@ -1443,13 +1407,6 @@
 
 	/* Get arguments and validate them ...
 	 */
-
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
-	error = -EINVAL;
 	inode = filp->f_dentry->d_inode;
 
 	/* Don't allow mandatory locks on files that may be memory mapped
@@ -1461,23 +1418,23 @@
 
 		if (!list_empty(&mapping->i_mmap_shared)) {
 			error = -EAGAIN;
-			goto out_putf;
+			goto out;
 		}
 	}
 
 	error = flock_to_posix_lock(filp, file_lock, &flock);
 	if (error)
-		goto out_putf;
+		goto out;
 	
 	error = -EBADF;
 	switch (flock.l_type) {
 	case F_RDLCK:
 		if (!(filp->f_mode & FMODE_READ))
-			goto out_putf;
+			goto out;
 		break;
 	case F_WRLCK:
 		if (!(filp->f_mode & FMODE_WRITE))
-			goto out_putf;
+			goto out;
 		break;
 	case F_UNLCK:
 		break;
@@ -1495,23 +1452,21 @@
 	}
 }
 		if (!(filp->f_mode & 3))
-			goto out_putf;
+			goto out;
 		break;
 #endif
 	default:
 		error = -EINVAL;
-		goto out_putf;
+		goto out;
 	}
 
 	if (filp->f_op && filp->f_op->lock != NULL) {
 		error = filp->f_op->lock(filp, cmd, file_lock);
 		if (error < 0)
-			goto out_putf;
+			goto out;
 	}
 	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW);
 
-out_putf:
-	fput(filp);
 out:
 	locks_free_lock(file_lock);
 	return error;
@@ -1521,9 +1476,8 @@
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk64(unsigned int fd, struct flock64 *l)
+int fcntl_getlk64(struct file *filp, struct flock64 *l)
 {
-	struct file *filp;
 	struct file_lock *fl, file_lock;
 	struct flock64 flock;
 	int error;
@@ -1535,19 +1489,14 @@
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
 		goto out;
 
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
 	error = flock64_to_posix_lock(filp, &file_lock, &flock);
 	if (error)
-		goto out_putf;
+		goto out;
 
 	if (filp->f_op && filp->f_op->lock) {
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
-			goto out_putf;
+			goto out;
 		else if (error == LOCK_USE_CLNT)
 		  /* Bypass for NFS with no locking - 2.0.36 compat */
 		  fl = posix_test_lock(filp, &file_lock);
@@ -1570,8 +1519,6 @@
 	if (!copy_to_user(l, &flock, sizeof(flock)))
 		error = 0;
   
-out_putf:
-	fput(filp);
 out:
 	return error;
 }
@@ -1579,9 +1526,8 @@
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
-int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
+int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l)
 {
-	struct file *filp;
 	struct file_lock *file_lock = locks_alloc_lock(0);
 	struct flock64 flock;
 	struct inode *inode;
@@ -1599,13 +1545,6 @@
 
 	/* Get arguments and validate them ...
 	 */
-
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
-	error = -EINVAL;
 	inode = filp->f_dentry->d_inode;
 
 	/* Don't allow mandatory locks on files that may be memory mapped
@@ -1617,23 +1556,23 @@
 
 		if (!list_empty(&mapping->i_mmap_shared)) {
 			error = -EAGAIN;
-			goto out_putf;
+			goto out;
 		}
 	}
 
 	error = flock64_to_posix_lock(filp, file_lock, &flock);
 	if (error)
-		goto out_putf;
+		goto out;
 	
 	error = -EBADF;
 	switch (flock.l_type) {
 	case F_RDLCK:
 		if (!(filp->f_mode & FMODE_READ))
-			goto out_putf;
+			goto out;
 		break;
 	case F_WRLCK:
 		if (!(filp->f_mode & FMODE_WRITE))
-			goto out_putf;
+			goto out;
 		break;
 	case F_UNLCK:
 		break;
@@ -1641,18 +1580,16 @@
 	case F_EXLCK:
 	default:
 		error = -EINVAL;
-		goto out_putf;
+		goto out;
 	}
 
 	if (filp->f_op && filp->f_op->lock != NULL) {
 		error = filp->f_op->lock(filp, cmd, file_lock);
 		if (error < 0)
-			goto out_putf;
+			goto out;
 	}
 	error = posix_lock_file(filp, file_lock, cmd == F_SETLKW64);
 
-out_putf:
-	fput(filp);
 out:
 	locks_free_lock(file_lock);
 	return error;
@@ -1684,7 +1621,7 @@
 	lock_kernel();
 	before = &inode->i_flock;
 	while ((fl = *before) != NULL) {
-		if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
+		if (IS_POSIX(fl) && fl->fl_owner == owner) {
 			locks_unlock_delete(before);
 			before = &inode->i_flock;
 			continue;
@@ -1710,9 +1647,8 @@
 	before = &inode->i_flock;
 
 	while ((fl = *before) != NULL) {
-		if ((fl->fl_flags & (FL_FLOCK|FL_LEASE))
-		    && (fl->fl_file == filp)) {
-			locks_delete_lock(before, 0);
+		if ((IS_FLOCK(fl) || IS_LEASE(fl)) && (fl->fl_file == filp)) {
+			locks_delete_lock(before);
 			continue;
  		}
 		before = &fl->fl_next;
@@ -1754,35 +1690,33 @@
 		inode = fl->fl_file->f_dentry->d_inode;
 
 	out += sprintf(out, "%d:%s ", id, pfx);
-	if (fl->fl_flags & FL_POSIX) {
+	if (IS_POSIX(fl)) {
 		out += sprintf(out, "%6s %s ",
 			     (fl->fl_flags & FL_ACCESS) ? "ACCESS" : "POSIX ",
 			     (inode == NULL) ? "*NOINODE*" :
 			     (IS_MANDLOCK(inode) &&
 			      (inode->i_mode & (S_IXGRP | S_ISGID)) == S_ISGID) ?
 			     "MANDATORY" : "ADVISORY ");
-	} else if (fl->fl_flags & FL_FLOCK) {
-#ifdef MSNFS
+	} else if (IS_FLOCK(fl)) {
 		if (fl->fl_type & LOCK_MAND) {
 			out += sprintf(out, "FLOCK  MSNFS     ");
-		} else
-#endif
+		} else {
 			out += sprintf(out, "FLOCK  ADVISORY  ");
-	} else if (fl->fl_flags & FL_LEASE) {
+		}
+	} else if (IS_LEASE(fl)) {
 		out += sprintf(out, "LEASE  MANDATORY ");
 	} else {
 		out += sprintf(out, "UNKNOWN UNKNOWN  ");
 	}
-#ifdef MSNFS
 	if (fl->fl_type & LOCK_MAND) {
 		out += sprintf(out, "%s ",
 			       (fl->fl_type & LOCK_READ)
 			       ? (fl->fl_type & LOCK_WRITE) ? "RW   " : "READ "
 			       : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
-	} else
-#endif
+	} else {
 		out += sprintf(out, "%s ",
 			       (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+	}
 	out += sprintf(out, "%d %s:%ld ",
 		     fl->fl_pid,
 		     inode ? kdevname(inode->i_dev) : "<none>",
@@ -1862,7 +1796,6 @@
 	return length;
 }
 
-#ifdef MSNFS
 /**
  *	lock_may_read - checks that the region is free of locks
  *	@inode: the inode that is being read
@@ -1882,12 +1815,12 @@
 	int result = 1;
 	lock_kernel();
 	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (fl->fl_flags == FL_POSIX) {
+		if (IS_POSIX(fl)) {
 			if (fl->fl_type == F_RDLCK)
 				continue;
 			if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
 				continue;
-		} else if (fl->fl_flags == FL_FLOCK) {
+		} else if (IS_FLOCK(fl)) {
 			if (!(fl->fl_type & LOCK_MAND))
 				continue;
 			if (fl->fl_type & LOCK_READ)
@@ -1920,10 +1853,10 @@
 	int result = 1;
 	lock_kernel();
 	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (fl->fl_flags == FL_POSIX) {
+		if (IS_POSIX(fl)) {
 			if ((fl->fl_end < start) || (fl->fl_start > (start + len)))
 				continue;
-		} else if (fl->fl_flags == FL_FLOCK) {
+		} else if (IS_FLOCK(fl)) {
 			if (!(fl->fl_type & LOCK_MAND))
 				continue;
 			if (fl->fl_type & LOCK_WRITE)
@@ -1936,11 +1869,10 @@
 	unlock_kernel();
 	return result;
 }
-#endif
 
 static int __init filelock_init(void)
 {
-	filelock_cache = kmem_cache_create("file lock cache",
+	filelock_cache = kmem_cache_create("file_lock_cache",
 			sizeof(struct file_lock), 0, 0, init_once, NULL);
 	if (!filelock_cache)
 		panic("cannot create file lock slab cache");
diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
--- a/fs/ncpfs/inode.c	Sat Jun  8 22:31:43 2002
+++ b/fs/ncpfs/inode.c	Sat Jun  8 22:31:43 2002
@@ -84,7 +84,7 @@
 {
 	alloc_inode:	ncp_alloc_inode,
 	destroy_inode:	ncp_destroy_inode,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 	delete_inode:	ncp_delete_inode,
 	put_super:	ncp_put_super,
 	statfs:		ncp_statfs,
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Sat Jun  8 22:31:37 2002
+++ b/fs/nfs/dir.c	Sat Jun  8 22:31:43 2002
@@ -563,6 +563,8 @@
 		nfs_complete_unlink(dentry);
 		unlock_kernel();
 	}
+	/* When creating a negative dentry, we want to renew d_time */
+	nfs_renew_times(dentry);
 	iput(inode);
 }
 
@@ -1090,6 +1092,7 @@
 		d_rehash(rehash);
 	if (!error && !S_ISDIR(old_inode->i_mode))
 		d_move(old_dentry, new_dentry);
+	nfs_renew_times(new_dentry);
 
 	/* new dentry created? */
 	if (dentry)
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Sat Jun  8 22:31:51 2002
+++ b/fs/nfs/inode.c	Sat Jun  8 22:31:51 2002
@@ -693,6 +693,7 @@
 		inode->i_atime = new_atime;
 		NFS_CACHE_MTIME(inode) = new_mtime;
 		inode->i_mtime = nfs_time_to_secs(new_mtime);
+		NFS_MTIME_UPDATE(inode) = jiffies;
 		NFS_CACHE_ISIZE(inode) = new_size;
 		inode->i_size = new_isize;
 		inode->i_mode = fattr->mode;
@@ -1058,7 +1059,8 @@
 	inode->i_atime = new_atime;
 
 	if (NFS_CACHE_MTIME(inode) != new_mtime) {
-		NFS_MTIME_UPDATE(inode) = jiffies;
+		if (invalid)
+			NFS_MTIME_UPDATE(inode) = jiffies;
 		NFS_CACHE_MTIME(inode) = new_mtime;
 		inode->i_mtime = nfs_time_to_secs(new_mtime);
 	}
diff -Nru a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog
--- a/fs/ntfs/ChangeLog	Sat Jun  8 22:31:36 2002
+++ b/fs/ntfs/ChangeLog	Sat Jun  8 22:31:36 2002
@@ -21,8 +21,38 @@
 	  several copies of almost identicall functions and the functions are
 	  quite big. Modularising them a bit, e.g. a-la get_block(), will make
 	  them cleaner and make code reuse easier.
-	- Want to use dummy inodes for address space i/o. We need some VFS
-	  changes first, which are currently under discussion.
+	- Want to use dummy inodes for address space i/o.
+
+2.0.8 - Major updates for handling of case sensitivity and dcache aliasing.
+
+	Big thanks go to Al Viro and other inhabitants of #kernel for investing
+	their time to discuss the case sensitivity and dcache aliasing issues.
+
+	- Remove unused source file fs/ntfs/attraops.c.
+	- Remove show_inodes mount option(s), thus dropping support for
+	  displaying of short file names.
+	- Remove deprecated mount option posix.
+	- Restore show_sys_files mount option.
+	- Add new mount option case_sensitive, to determine if the driver
+	  treats file names as case sensitive or not. If case sensitive, create
+	  file names in the POSIX namespace. Otherwise create file names in the
+	  LONG/WIN32 namespace. Note, files remain accessible via their short
+	  file name, if it exists.
+	- Remove really dumb logic bug in boot sector recovery code.
+	- Fix dcache aliasing issues wrt short/long file names via changes
+	  to fs/ntfs/dir.c::ntfs_lookup_inode_by_name() and
+	  fs/ntfs/namei.c::ntfs_lookup():
+	  - Add additional argument to ntfs_lookup_inode_by_name() in which we
+	    return information about the matching file name if the case is not
+	    matching or the match is a short file name. See comments above the
+	    function definition for details.
+	  - Change ntfs_lookup() to only create dcache entries for the correctly
+	    cased file name and only for the WIN32 namespace counterpart of DOS
+	    namespace file names. This ensures we have only one dentry per
+	    directory and also removes all dcache aliasing issues between short
+	    and long file names once we add write support. See comments above
+	    function for details.
+	- Fix potential 1 byte overflow in fs/ntfs/unistr.c::ntfs_ucstonls().
 
 2.0.7 - Minor cleanups and updates for changes in core kernel code.
 
diff -Nru a/fs/ntfs/Makefile b/fs/ntfs/Makefile
--- a/fs/ntfs/Makefile	Sat Jun  8 22:31:35 2002
+++ b/fs/ntfs/Makefile	Sat Jun  8 22:31:35 2002
@@ -5,7 +5,7 @@
 ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
 	     mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
 
-EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.7\"
+EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.8\"
 
 ifeq ($(CONFIG_NTFS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff -Nru a/fs/ntfs/attraops.c b/fs/ntfs/attraops.c
--- a/fs/ntfs/attraops.c	Sat Jun  8 22:31:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,47 +0,0 @@
-#include "ntfs.h"
-
-/*
- * We need to define the attribute object structure. FIXME: Move these to
- * ntfs.h.
- */
-typedef struct {
-	ntfs_inode *a_ni;
-	ntfs_volume *a_vol;
-	atomic_t a_count;
-	s64 a_size;
-	struct rw_semaphore a_sem;
-	struct address_space a_mapping;
-	unsigned long a_flags;
-} attr_obj;
-
-/**
- * ntfs_attr_readpage - fill a page @page of an attribute object @aobj with data
- * @aobj:	attribute object to which the page @page belongs
- * @page:	page cache page to fill with data
- *
- */
-//static int ntfs_attr_readpage(attr_obj *aobj, struct page *page)
-static int ntfs_attr_readpage(struct file *aobj, struct page *page)
-{
-	return -EOPNOTSUPP;
-}
-
-/*
- * Address space operations for accessing attributes. Note that these functions
- * do not accept an inode as the first parameter but an attribute object. We
- * use this to implement a generic interface that is not bound to inodes in
- * order to support multiple named streams per file, multiple bitmaps per file
- * and directory, etc. Basically, this gives access to any attribute within an
- * mft record.
- *
- * We make use of a slab cache for attribute object allocations.
- */
-struct address_space_operations ntfs_attr_aops = {
-	writepage:	NULL,			/* Write dirty page to disk. */
-	readpage:	ntfs_attr_readpage,	/* Fill page with data. */
-	sync_page:	block_sync_page,	/* Currently, just unplugs the
-						   disk request queue. */
-	prepare_write:	NULL,			/* . */
-	commit_write:	NULL,			/* . */
-};
-
diff -Nru a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
--- a/fs/ntfs/attrib.c	Sat Jun  8 22:31:43 2002
+++ b/fs/ntfs/attrib.c	Sat Jun  8 22:31:43 2002
@@ -22,6 +22,7 @@
 
 #include <linux/buffer_head.h>
 #include "ntfs.h"
+#include "dir.h"
 
 /* Temporary helper functions -- might become macros */
 
diff -Nru a/fs/ntfs/dir.c b/fs/ntfs/dir.c
--- a/fs/ntfs/dir.c	Sat Jun  8 22:31:37 2002
+++ b/fs/ntfs/dir.c	Sat Jun  8 22:31:37 2002
@@ -22,6 +22,7 @@
 
 #include <linux/smp_lock.h>
 #include "ntfs.h"
+#include "dir.h"
 
 /**
  * The little endian Unicode string $I30 as a global constant.
@@ -35,6 +36,564 @@
  * @dir_ni:	ntfs inode of the directory in which to search for the name
  * @uname:	Unicode name for which to search in the directory
  * @uname_len:	length of the name @uname in Unicode characters
+ * @res:	return the found file name if necessary (see below)
+ *
+ * Look for an inode with name @uname in the directory with inode @dir_ni.
+ * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
+ * the Unicode name. If the name is found in the directory, the corresponding
+ * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it
+ * is a 64-bit number containing the sequence number.
+ *
+ * On error, a negative value is returned corresponding to the error code. In
+ * particular if the inode is not found -ENOENT is returned. Note that you
+ * can't just check the return value for being negative, you have to check the
+ * inode number for being negative which you can extract using MREC(return
+ * value).
+ *
+ * Note, @uname_len does not include the (optional) terminating NULL character.
+ *
+ * Note, we look for a case sensitive match first but we also look for a case
+ * insensitive match at the same time. If we find a case insensitive match, we
+ * save that for the case that we don't find an exact match, where we return
+ * the case insensitive match and setup @res (which we allocate!) with the mft
+ * reference, the file name type, length and with a copy of the little endian
+ * Unicode file name itself. If we match a file name which is in the DOS name
+ * space, we only return the mft reference and file name type in @res.
+ * ntfs_lookup() then uses this to find the long file name in the inode itself.
+ * This is to avoid polluting the dcache with short file names. We want them to
+ * work but we don't care for how quickly one can access them. This also fixes
+ * the dcache aliasing issues.
+ */
+u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
+		const int uname_len, ntfs_name **res)
+{
+	ntfs_volume *vol = dir_ni->vol;
+	struct super_block *sb = vol->sb;
+	MFT_RECORD *m;
+	INDEX_ROOT *ir;
+	INDEX_ENTRY *ie;
+	INDEX_ALLOCATION *ia;
+	u8 *index_end;
+	u64 mref;
+	attr_search_context *ctx;
+	int err = 0, rc;
+	VCN vcn, old_vcn;
+	struct address_space *ia_mapping;
+	struct page *page;
+	u8 *kaddr;
+	ntfs_name *name = NULL;
+
+	/* Get hold of the mft record for the directory. */
+	m = map_mft_record(READ, dir_ni);
+	if (IS_ERR(m))
+		goto map_err_out;
+
+	ctx = get_attr_search_ctx(dir_ni, m);
+	if (!ctx) {
+		err = -ENOMEM;
+		goto unm_err_out;
+	}
+
+	/* Find the index root attribute in the mft record. */
+	if (!lookup_attr(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 0, NULL, 0,
+			ctx)) {
+		ntfs_error(sb, "Index root attribute missing in directory "
+				"inode 0x%Lx.",
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto put_unm_err_out;
+	}
+	/* Get to the index root value (it's been verified in read_inode). */
+	ir = (INDEX_ROOT*)((u8*)ctx->attr +
+			le16_to_cpu(ctx->attr->_ARA(value_offset)));
+	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);
+	/* The first index entry. */
+	ie = (INDEX_ENTRY*)((u8*)&ir->index +
+			le32_to_cpu(ir->index.entries_offset));
+	/*
+	 * Loop until we exceed valid memory (corruption case) or until we
+	 * reach the last entry.
+	 */
+	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) {
+		/* Bounds checks. */
+		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +
+				sizeof(INDEX_ENTRY_HEADER) > index_end ||
+				(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
+				index_end)
+			goto dir_err_out;
+		/*
+		 * The last entry cannot contain a name. It can however contain
+		 * a pointer to a child node in the B+tree so we just break out.
+		 */
+		if (ie->_IEH(flags) & INDEX_ENTRY_END)
+			break;
+		/*
+		 * We perform a case sensitive comparison and if that matches
+		 * we are done and return the mft reference of the inode (i.e.
+		 * the inode number together with the sequence number for
+		 * consistency checking). We convert it to cpu format before
+		 * returning.
+		 */
+		if (ntfs_are_names_equal(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length,
+				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
+found_it:
+			/*
+			 * We have a perfect match, so we don't need to care
+			 * about having matched imperfectly before, so we can
+			 * free name and set *res to NULL.
+			 * However, if the perfect match is a short file name,
+			 * we need to signal this through *res, so that
+			 * ntfs_lookup() can fix dcache aliasing issues.
+			 * As an optimization we just reuse an existing
+			 * allocation of *res.
+			 */
+			if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
+				if (!name) {
+					name = kmalloc(sizeof(ntfs_name),
+							GFP_NOFS);
+					if (!name) {
+						err = -ENOMEM;
+						goto put_unm_err_out;
+					}
+				}
+				name->mref = le64_to_cpu(
+						ie->_IIF(indexed_file));
+				name->type = FILE_NAME_DOS;
+				name->len = 0;
+				*res = name;
+			} else {
+				if (name)
+					kfree(name);
+				*res = NULL;
+			}
+			mref = le64_to_cpu(ie->_IIF(indexed_file));
+			put_attr_search_ctx(ctx);
+			unmap_mft_record(READ, dir_ni);
+			return mref;
+		}
+		/*
+		 * For a case insensitive mount, we also perform a case
+		 * insensitive comparison (provided the file name is not in the
+		 * POSIX namespace). If the comparison matches, and the name is
+		 * in the WIN32 namespace, we cache the filename in *res so
+		 * that the caller, ntfs_lookup(), can work on it. If the
+		 * comparison matches, and the name is in the DOS namespace, we
+		 * only cache the mft reference and the file name type (we set
+		 * the name length to zero for simplicity).
+		 */
+		if (!NVolCaseSensitive(vol) &&
+				ie->key.file_name.file_name_type &&
+				ntfs_are_names_equal(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length,
+				IGNORE_CASE, vol->upcase, vol->upcase_len)) {
+			int name_size = sizeof(ntfs_name);
+			u8 type = ie->key.file_name.file_name_type;
+			u8 len = ie->key.file_name.file_name_length;
+
+			/* Only one case insensitive matching name allowed. */
+			if (name) {
+				ntfs_error(sb, "Found already allocated name "
+						"in phase 1. Please run chkdsk "
+						"and if that doesn't find any "
+						"errors please report you saw "
+						"this message to "
+						"linux-ntfs-dev@lists.sf.net.");
+				goto dir_err_out;
+			}
+
+			if (type != FILE_NAME_DOS)
+				name_size += len * sizeof(uchar_t);
+			name = kmalloc(name_size, GFP_NOFS);
+			if (!name) {
+				err = -ENOMEM;
+				goto put_unm_err_out;
+			}
+			name->mref = le64_to_cpu(ie->_IIF(indexed_file));
+			name->type = type;
+			if (type != FILE_NAME_DOS) {
+				name->len = len;
+				memcpy(name->name, ie->key.file_name.file_name,
+						len * sizeof(uchar_t));
+			} else
+				name->len = 0;
+			*res = name;
+		}
+		/*
+		 * Not a perfect match, need to do full blown collation so we
+		 * know which way in the B+tree we have to go.
+		 */
+		rc = ntfs_collate_names(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length, 1,
+				IGNORE_CASE, vol->upcase, vol->upcase_len);
+		/*
+		 * If uname collates before the name of the current entry, there
+		 * is definitely no such name in this index but we might need to
+		 * descend into the B+tree so we just break out of the loop.
+		 */
+		if (rc == -1)
+			break;
+		/* The names are not equal, continue the search. */
+		if (rc)
+			continue;
+		/*
+		 * Names match with case insensitive comparison, now try the
+		 * case sensitive comparison, which is required for proper
+		 * collation.
+		 */
+		rc = ntfs_collate_names(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length, 1,
+				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+		if (rc == -1)
+			break;
+		if (rc)
+			continue;
+		/*
+		 * Perfect match, this will never happen as the
+		 * ntfs_are_names_equal() call will have gotten a match but we
+		 * still treat it correctly.
+		 */
+		goto found_it;
+	}
+	/*
+	 * We have finished with this index without success. Check for the
+	 * presence of a child node and if not present return -ENOENT, unless
+	 * we have got a matching name cached in name in which case return the
+	 * mft reference associated with it.
+	 */
+	if (!(ie->_IEH(flags) & INDEX_ENTRY_NODE)) {
+		if (name) {
+			put_attr_search_ctx(ctx);
+			unmap_mft_record(READ, dir_ni);
+			return name->mref;
+		}
+		ntfs_debug("Entry not found.");
+		err = -ENOENT;
+		goto put_unm_err_out;
+	} /* Child node present, descend into it. */
+	/* Consistency check: Verify that an index allocation exists. */
+	if (!NInoIndexAllocPresent(dir_ni)) {
+		ntfs_error(sb, "No index allocation attribute but index entry "
+				"requires one. Directory inode 0x%Lx is "
+				"corrupt or driver bug.",
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto put_unm_err_out;
+	}
+	/* Get the starting vcn of the index_block holding the child node. */
+	vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->_IEH(length)) - 8);
+	ia_mapping = VFS_I(dir_ni)->i_mapping;
+descend_into_child_node:
+	/*
+	 * Convert vcn to index into the index allocation attribute in units
+	 * of PAGE_CACHE_SIZE and map the page cache page, reading it from
+	 * disk if necessary.
+	 */
+	page = ntfs_map_page(ia_mapping, vcn <<
+			dir_ni->_IDM(index_vcn_size_bits) >> PAGE_CACHE_SHIFT);
+	if (IS_ERR(page)) {
+		ntfs_error(sb, "Failed to map directory index page, error %ld.",
+				-PTR_ERR(page));
+		goto put_unm_err_out;
+	}
+	kaddr = (u8*)page_address(page);
+fast_descend_into_child_node:
+	/* Get to the index allocation block. */
+	ia = (INDEX_ALLOCATION*)(kaddr + ((vcn <<
+			dir_ni->_IDM(index_vcn_size_bits)) & ~PAGE_CACHE_MASK));
+	/* Bounds checks. */
+	if ((u8*)ia < kaddr || (u8*)ia > kaddr + PAGE_CACHE_SIZE) {
+		ntfs_error(sb, "Out of bounds check failed. Corrupt directory "
+				"inode 0x%Lx or driver bug.",
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {
+		ntfs_error(sb, "Actual VCN (0x%Lx) of index buffer is "
+				"different from expected VCN (0x%Lx). "
+				"Directory inode 0x%Lx is corrupt or driver "
+				"bug.",
+				(long long)sle64_to_cpu(ia->index_block_vcn),
+				(long long)vcn,
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	if (le32_to_cpu(ia->index.allocated_size) + 0x18 !=
+			dir_ni->_IDM(index_block_size)) {
+		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+				"0x%Lx has a size (%u) differing from the "
+				"directory specified size (%u). Directory "
+				"inode is corrupt or driver bug.",
+				(long long)vcn,
+				(unsigned long long)dir_ni->mft_no,
+				le32_to_cpu(ia->index.allocated_size) + 0x18,
+				dir_ni->_IDM(index_block_size));
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	index_end = (u8*)ia + dir_ni->_IDM(index_block_size);
+	if (index_end > kaddr + PAGE_CACHE_SIZE) {
+		ntfs_error(sb, "Index buffer (VCN 0x%Lx) of directory inode "
+				"0x%Lx crosses page boundary. Impossible! "
+				"Cannot access! This is probably a bug in the "
+				"driver.", (long long)vcn,
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);
+	if (index_end > (u8*)ia + dir_ni->_IDM(index_block_size)) {
+		ntfs_error(sb, "Size of index buffer (VCN 0x%Lx) of directory "
+				"inode 0x%Lx exceeds maximum size.",
+				(long long)vcn,
+				(unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	/* The first index entry. */
+	ie = (INDEX_ENTRY*)((u8*)&ia->index +
+			le32_to_cpu(ia->index.entries_offset));
+	/*
+	 * Iterate similar to above big loop but applied to index buffer, thus
+	 * loop until we exceed valid memory (corruption case) or until we
+	 * reach the last entry.
+	 */
+	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->_IEH(length)))) {
+		/* Bounds check. */
+		if ((u8*)ie < (u8*)ia || (u8*)ie +
+				sizeof(INDEX_ENTRY_HEADER) > index_end ||
+				(u8*)ie + le16_to_cpu(ie->_IEH(key_length)) >
+				index_end) {
+			ntfs_error(sb, "Index entry out of bounds in "
+					"directory inode 0x%Lx.",
+					(unsigned long long)dir_ni->mft_no);
+			err = -EIO;
+			goto unm_unm_err_out;
+		}
+		/*
+		 * The last entry cannot contain a name. It can however contain
+		 * a pointer to a child node in the B+tree so we just break out.
+		 */
+		if (ie->_IEH(flags) & INDEX_ENTRY_END)
+			break;
+		/*
+		 * We perform a case sensitive comparison and if that matches
+		 * we are done and return the mft reference of the inode (i.e.
+		 * the inode number together with the sequence number for
+		 * consistency checking). We convert it to cpu format before
+		 * returning.
+		 */
+		if (ntfs_are_names_equal(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length,
+				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {
+found_it2:
+			/*
+			 * We have a perfect match, so we don't need to care
+			 * about having matched imperfectly before, so we can
+			 * free name and set *res to NULL.
+			 * However, if the perfect match is a short file name,
+			 * we need to signal this through *res, so that
+			 * ntfs_lookup() can fix dcache aliasing issues.
+			 * As an optimization we just reuse an existing
+			 * allocation of *res.
+			 */
+			if (ie->key.file_name.file_name_type == FILE_NAME_DOS) {
+				if (!name) {
+					name = kmalloc(sizeof(ntfs_name),
+							GFP_NOFS);
+					if (!name) {
+						err = -ENOMEM;
+						goto unm_unm_err_out;
+					}
+				}
+				name->mref = le64_to_cpu(
+						ie->_IIF(indexed_file));
+				name->type = FILE_NAME_DOS;
+				name->len = 0;
+				*res = name;
+			} else {
+				if (name)
+					kfree(name);
+				*res = NULL;
+			}
+			mref = le64_to_cpu(ie->_IIF(indexed_file));
+			ntfs_unmap_page(page);
+			put_attr_search_ctx(ctx);
+			unmap_mft_record(READ, dir_ni);
+			return mref;
+		}
+		/*
+		 * For a case insensitive mount, we also perform a case
+		 * insensitive comparison (provided the file name is not in the
+		 * POSIX namespace). If the comparison matches, and the name is
+		 * in the WIN32 namespace, we cache the filename in *res so
+		 * that the caller, ntfs_lookup(), can work on it. If the
+		 * comparison matches, and the name is in the DOS namespace, we
+		 * only cache the mft reference and the file name type (we set
+		 * the name length to zero for simplicity).
+		 */
+		if (!NVolCaseSensitive(vol) &&
+				ie->key.file_name.file_name_type &&
+				ntfs_are_names_equal(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length,
+				IGNORE_CASE, vol->upcase, vol->upcase_len)) {
+			int name_size = sizeof(ntfs_name);
+			u8 type = ie->key.file_name.file_name_type;
+			u8 len = ie->key.file_name.file_name_length;
+
+			/* Only one case insensitive matching name allowed. */
+			if (name) {
+				ntfs_error(sb, "Found already allocated name "
+						"in phase 2. Please run chkdsk "
+						"and if that doesn't find any "
+						"errors please report you saw "
+						"this message to "
+						"linux-ntfs-dev@lists.sf.net.");
+				ntfs_unmap_page(page);
+				goto dir_err_out;
+			}
+
+			if (type != FILE_NAME_DOS)
+				name_size += len * sizeof(uchar_t);
+			name = kmalloc(name_size, GFP_NOFS);
+			if (!name) {
+				err = -ENOMEM;
+				goto put_unm_err_out;
+			}
+			name->mref = le64_to_cpu(ie->_IIF(indexed_file));
+			name->type = type;
+			if (type != FILE_NAME_DOS) {
+				name->len = len;
+				memcpy(name->name, ie->key.file_name.file_name,
+						len * sizeof(uchar_t));
+			} else
+				name->len = 0;
+			*res = name;
+		}
+		/*
+		 * Not a perfect match, need to do full blown collation so we
+		 * know which way in the B+tree we have to go.
+		 */
+		rc = ntfs_collate_names(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length, 1,
+				IGNORE_CASE, vol->upcase, vol->upcase_len);
+		/*
+		 * If uname collates before the name of the current entry, there
+		 * is definitely no such name in this index but we might need to
+		 * descend into the B+tree so we just break out of the loop.
+		 */
+		if (rc == -1)
+			break;
+		/* The names are not equal, continue the search. */
+		if (rc)
+			continue;
+		/*
+		 * Names match with case insensitive comparison, now try the
+		 * case sensitive comparison, which is required for proper
+		 * collation.
+		 */
+		rc = ntfs_collate_names(uname, uname_len,
+				(uchar_t*)&ie->key.file_name.file_name,
+				ie->key.file_name.file_name_length, 1,
+				CASE_SENSITIVE, vol->upcase, vol->upcase_len);
+		if (rc == -1)
+			break;
+		if (rc)
+			continue;
+		/*
+		 * Perfect match, this will never happen as the
+		 * ntfs_are_names_equal() call will have gotten a match but we
+		 * still treat it correctly.
+		 */
+		goto found_it2;
+	}
+	/*
+	 * We have finished with this index buffer without success. Check for
+	 * the presence of a child node.
+	 */
+	if (ie->_IEH(flags) & INDEX_ENTRY_NODE) {
+		if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {
+			ntfs_error(sb, "Index entry with child node found in "
+					"a leaf node in directory inode 0x%Lx.",
+					(unsigned long long)dir_ni->mft_no);
+			err = -EIO;
+			goto unm_unm_err_out;
+		}
+		/* Child node present, descend into it. */
+		old_vcn = vcn;
+		vcn = sle64_to_cpup((u8*)ie +
+				le16_to_cpu(ie->_IEH(length)) - 8);
+		if (vcn >= 0) {
+			/* If vcn is in the same page cache page as old_vcn we
+			 * recycle the mapped page. */
+			if (old_vcn << vol->cluster_size_bits >>
+					PAGE_CACHE_SHIFT == vcn <<
+					vol->cluster_size_bits >>
+					PAGE_CACHE_SHIFT)
+				goto fast_descend_into_child_node;
+			ntfs_unmap_page(page);
+			goto descend_into_child_node;
+		}
+		ntfs_error(sb, "Negative child node vcn in directory inode "
+				"0x%Lx.", (unsigned long long)dir_ni->mft_no);
+		err = -EIO;
+		goto unm_unm_err_out;
+	}
+	/*
+	 * No child node present, return -ENOENT, unless we have got a matching
+	 * name cached in name in which case return the mft reference
+	 * associated with it.
+	 */
+	if (name) {
+		ntfs_unmap_page(page);
+		put_attr_search_ctx(ctx);
+		unmap_mft_record(READ, dir_ni);
+		return name->mref;
+	}
+	ntfs_debug("Entry not found.");
+	err = -ENOENT;
+unm_unm_err_out:
+	ntfs_unmap_page(page);
+put_unm_err_out:
+	put_attr_search_ctx(ctx);
+unm_err_out:
+	unmap_mft_record(READ, dir_ni);
+	if (name) {
+		kfree(name);
+		*res = NULL;
+	}
+	return ERR_MREF(err);
+map_err_out:
+	ntfs_error(sb, "map_mft_record(READ) failed with error code %ld.",
+			-PTR_ERR(m));
+	return ERR_MREF(PTR_ERR(m));
+dir_err_out:
+	ntfs_error(sb, "Corrupt directory. Aborting lookup.");
+	err = -EIO;
+	goto put_unm_err_out;
+}
+
+#if 0
+
+// TODO: (AIA)
+// The algorithm embedded in this code will be required for the time when we
+// want to support adding of entries to directories, where we require correct
+// collation of file names in order not to cause corruption of the file system.
+
+/**
+ * ntfs_lookup_inode_by_name - find an inode in a directory given its name
+ * @dir_ni:	ntfs inode of the directory in which to search for the name
+ * @uname:	Unicode name for which to search in the directory
+ * @uname_len:	length of the name @uname in Unicode characters
  *
  * Look for an inode with name @uname in the directory with inode @dir_ni.
  * ntfs_lookup_inode_by_name() walks the contents of the directory looking for
@@ -414,6 +973,8 @@
 	goto put_unm_err_out;
 }
 
+#endif
+
 typedef union {
 	INDEX_ROOT *ir;
 	INDEX_ALLOCATION *ia;
@@ -447,7 +1008,6 @@
 	int name_len;
 	unsigned dt_type;
 	FILE_NAME_TYPE_FLAGS name_type;
-	READDIR_OPTIONS readdir_opts;
 
 	/* Advance the position even if going to skip the entry. */
 	if (index_type == INDEX_TYPE_ALLOCATION)
@@ -457,25 +1017,17 @@
 				vol->mft_record_size;
 	else /* if (index_type == INDEX_TYPE_ROOT) */
 		filp->f_pos = (u8*)ie - (u8*)iu.ir;
-	readdir_opts = vol->readdir_opts;
 	name_type = ie->key.file_name.file_name_type;
-	if (name_type == FILE_NAME_DOS && RHideDosNames(readdir_opts)) {
+	if (name_type == FILE_NAME_DOS) {
 		ntfs_debug("Skipping DOS name space entry.");
 		return 0;
 	}
-	if (RHideLongNames(readdir_opts)) {
-		if (name_type == FILE_NAME_WIN32 ||
-				name_type == FILE_NAME_POSIX) {
-			ntfs_debug("Skipping WIN32/POSIX name space entry.");
-			return 0;
-		}
-	}
 	if (MREF_LE(ie->_IIF(indexed_file)) == FILE_root) {
 		ntfs_debug("Skipping root directory self reference entry.");
 		return 0;
 	}
 	if (MREF_LE(ie->_IIF(indexed_file)) < FILE_first_user &&
-			RHideSystemFiles(readdir_opts)) {
+			!NVolShowSystemFiles(vol)) {
 		ntfs_debug("Skipping system file.");
 		return 0;
 	}
@@ -496,7 +1048,8 @@
 			(unsigned long long)MREF_LE(ie->_IIF(indexed_file)),
 			dt_type == DT_DIR ? "DIR" : "REG");
 	return filldir(dirent, name, name_len, filp->f_pos,
-			(unsigned long)MREF_LE(ie->_IIF(indexed_file)), dt_type);
+			(unsigned long)MREF_LE(ie->_IIF(indexed_file)),
+			dt_type);
 }
 
 /*
@@ -510,7 +1063,7 @@
  * index root entries and then the index allocation entries that are marked
  * as in use in the index bitmap.
  * While this will return the names in random order this doesn't matter for
- * readdir but OTOH results in faster readdir.
+ * readdir but OTOH results in a faster readdir.
  */
 static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
diff -Nru a/fs/ntfs/dir.h b/fs/ntfs/dir.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/ntfs/dir.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,47 @@
+/*
+ * dir.h - Defines for directory handling in NTFS Linux kernel driver. Part of
+ *	   the Linux-NTFS project.
+ *
+ * Copyright (c) 2002 Anton Altaparmakov.
+ *
+ * This program/include file 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/include file 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 
+ * distribution in the file COPYING); if not, write to the Free Software
+ * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LINUX_NTFS_DIR_H
+#define _LINUX_NTFS_DIR_H
+
+#include "layout.h"
+
+/*
+ * ntfs_name is used to return the file name to the caller of
+ * ntfs_lookup_inode_by_name() in order for the caller (namei.c::ntfs_lookup())
+ * to be able to deal with dcache aliasing issues.
+ */
+typedef struct {
+	MFT_REF mref;
+	FILE_NAME_TYPE_FLAGS type;
+	u8 len;
+	uchar_t name[0];
+} __attribute__ ((__packed__)) ntfs_name;
+
+/* The little endian Unicode string $I30 as a global constant. */
+extern const uchar_t I30[5];
+
+extern u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
+		const int uname_len, ntfs_name **res);
+
+#endif /* _LINUX_NTFS_FS_DIR_H */
+
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Sat Jun  8 22:31:37 2002
+++ b/fs/ntfs/inode.c	Sat Jun  8 22:31:37 2002
@@ -23,6 +23,7 @@
 #include <linux/buffer_head.h>
 
 #include "ntfs.h"
+#include "dir.h"
 
 struct inode *ntfs_alloc_big_inode(struct super_block *sb)
 {
@@ -1337,13 +1338,6 @@
 	return;
 }
 
-static const option_t si_readdir_opts_arr[] = {
-	{ SHOW_SYSTEM,	"system" },
-	{ SHOW_WIN32,	"win32" },
-	{ SHOW_DOS,	"dos" },
-	{ 0,		NULL }
-};
-
 /**
  * ntfs_show_options - show mount options in /proc/mounts
  * @sf:		seq_file in which to write our mount options
@@ -1368,20 +1362,10 @@
 		seq_printf(sf, ",dmask=0%o", vol->dmask);
 	}
 	seq_printf(sf, ",nls=%s", vol->nls_map->charset);
-	switch (vol->readdir_opts) {
-	case SHOW_ALL:
-		seq_printf(sf, ",show_inodes=all");
-		break;
-	case SHOW_POSIX:
-		seq_printf(sf, ",show_inodes=posix");
-		break;
-	default:
-		for (i = 0; si_readdir_opts_arr[i].val; i++) {
-			if (si_readdir_opts_arr[i].val & vol->readdir_opts)
-				seq_printf(sf, ",show_inodes=%s",
-						si_readdir_opts_arr[i].str);
-		}
-	}
+	if (NVolCaseSensitive(vol))
+		seq_printf(sf, ",case_sensitive");
+	if (NVolShowSystemFiles(vol))
+		seq_printf(sf, ",show_sys_files");
 	for (i = 0; on_errors_arr[i].val; i++) {
 		if (on_errors_arr[i].val & vol->on_errors)
 			seq_printf(sf, ",errors=%s", on_errors_arr[i].str);
diff -Nru a/fs/ntfs/layout.h b/fs/ntfs/layout.h
--- a/fs/ntfs/layout.h	Sat Jun  8 22:31:35 2002
+++ b/fs/ntfs/layout.h	Sat Jun  8 22:31:35 2002
@@ -29,7 +29,7 @@
 #include <linux/list.h>
 #include <asm/byteorder.h>
 
-#include "volume.h"
+#include "types.h"
 
 /*
  * Constant endianness conversion defines.
@@ -679,7 +679,7 @@
  */
 typedef enum {
 	/*
-	 * These flags are only presnt in the STANDARD_INFORMATION attribute
+	 * These flags are only present in the STANDARD_INFORMATION attribute
 	 * (in the field file_attributes).
 	 */
 	FILE_ATTR_READONLY		= const_cpu_to_le32(0x00000001),
diff -Nru a/fs/ntfs/namei.c b/fs/ntfs/namei.c
--- a/fs/ntfs/namei.c	Sat Jun  8 22:31:51 2002
+++ b/fs/ntfs/namei.c	Sat Jun  8 22:31:51 2002
@@ -20,7 +20,10 @@
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#include <linux/dcache.h>
+
 #include "ntfs.h"
+#include "dir.h"
 
 /**
  * ntfs_lookup - find the inode represented by a dentry in a directory inode
@@ -43,14 +46,55 @@
  * dentry @dent. The dentry is then termed a negative dentry.
  *
  * Only if an actual error occurs, do we return an error via ERR_PTR().
+ *
+ * In order to handle the case insensitivity issues of NTFS with regards to the
+ * dcache and the dcache requiring only one dentry per directory, we deal with
+ * dentry aliases that only differ in case in ->ntfs_lookup() while maintining
+ * a case sensitive dcache. This means that we get the full benefit of dcache
+ * speed when the file/directory is looked up with the same case as returned by
+ * ->ntfs_readdir() but that a lookup for any other case (or for the short file
+ * name) will not find anything in dcache and will enter ->ntfs_lookup()
+ * instead, where we search the directory for a fully matching file name
+ * (including case) and if that is not found, we search for a file name that
+ * matches with different case and if that has non-POSIX semantics we return
+ * that. We actually do only one search (case sensitive) and keep tabs on
+ * whether we have found a case insensitive match in the process.
+ *
+ * To simplify matters for us, we do not treat the short vs long filenames as
+ * two hard links but instead if the lookup matches a short filename, we
+ * return the dentry for the corresponding long filename instead.
+ *
+ * There are three cases we need to distinguish here:
+ *
+ * 1) @dent perfectly matches (i.e. including case) a directory entry with a
+ *    file name in the WIN32 or POSIX namespaces. In this case
+ *    ntfs_lookup_inode_by_name() will return with name set to NULL and we
+ *    just d_add() @dent.
+ * 2) @dent matches (not including case) a directory entry with a file name in
+ *    the WIN32 namespace. In this case ntfs_lookup_inode_by_name() will return
+ *    with name set to point to a kmalloc()ed ntfs_name structure containing
+ *    the properly cased little endian Unicode name. We convert the name to the
+ *    current NLS code page, search if a dentry with this name already exists
+ *    and if so return that instead of @dent. The VFS will then destroy the old
+ *    @dent and use the one we returned. If a dentry is not found, we allocate
+ *    a new one, d_add() it, and return it as above.
+ * 3) @dent matches either perfectly or not (i.e. we don't care about case) a
+ *    directory entry with a file name in the DOS namespace. In this case
+ *    ntfs_lookup_inode_by_name() will return with name set to point to a
+ *    kmalloc()ed ntfs_name structure containing the mft reference (cpu endian)
+ *    of the inode. We use the mft reference to read the inode and to find the
+ *    file name in the WIN32 namespace corresponding to the matched short file
+ *    name. We then convert the name to the current NLS code page, and proceed
+ *    searching for a dentry with this name, etc, as in case 2), above.
  */
 static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent)
 {
 	ntfs_volume *vol = NTFS_SB(dir_ino->i_sb);
 	struct inode *dent_inode;
+	uchar_t *uname;
+	ntfs_name *name = NULL;
 	u64 mref;
 	unsigned long dent_ino;
-	uchar_t *uname;
 	int uname_len;
 
 	ntfs_debug("Looking up %s in directory inode 0x%lx.",
@@ -62,7 +106,8 @@
 		ntfs_error(vol->sb, "Failed to convert name to Unicode.");
 		return ERR_PTR(uname_len);
 	}
-	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len);
+	mref = ntfs_lookup_inode_by_name(NTFS_I(dir_ino), uname, uname_len,
+			&name);
 	kmem_cache_free(ntfs_name_cache, uname);
 	if (!IS_ERR_MREF(mref)) {
 		dent_ino = (unsigned long)MREF(mref);
@@ -72,9 +117,17 @@
 			/* Consistency check. */
 			if (MSEQNO(mref) == NTFS_I(dent_inode)->seq_no ||
 					dent_ino == FILE_MFT) {
-				d_add(dent, dent_inode);
-				ntfs_debug("Done.");
-				return NULL;
+				/* Perfect WIN32/POSIX match. -- Case 1. */
+				if (!name) {
+					d_add(dent, dent_inode);
+					ntfs_debug("Done.");
+					return NULL;
+				}
+				/*
+				 * We are too indented. Handle imperfect
+				 * matches and short file names further below.
+				 */
+				goto handle_name;
 			}
 			ntfs_error(vol->sb, "Found stale reference to inode "
 					"0x%Lx (reference sequence number = "
@@ -88,8 +141,11 @@
 			ntfs_error(vol->sb, "iget(0x%Lx) failed, returning "
 					"-EACCES.",
 					(unsigned long long)MREF(mref));
+		if (name)
+			kfree(name);
 		return ERR_PTR(-EACCES);
 	}
+	/* It is guaranteed that name is no longer allocated at this point. */
 	if (MREF_ERR(mref) == -ENOENT) {
 		ntfs_debug("Entry was not found, adding negative dentry.");
 		/* The dcache will handle negative entries. */
@@ -100,9 +156,133 @@
 	ntfs_error(vol->sb, "ntfs_lookup_ino_by_name() failed with error "
 			"code %i.", -MREF_ERR(mref));
 	return ERR_PTR(MREF_ERR(mref));
+
+	// TODO: Consider moving this lot to a separate function! (AIA)
+handle_name:
+   {
+	struct dentry *real_dent;
+	attr_search_context *ctx;
+	ntfs_inode *ni = NTFS_I(dent_inode);
+	int err;
+	struct qstr nls_name;
+
+	nls_name.name = NULL;
+	if (name->type != FILE_NAME_DOS) {			/* Case 2. */
+		nls_name.len = (unsigned)ntfs_ucstonls(vol,
+				(uchar_t*)&name->name, name->len,
+				(unsigned char**)&nls_name.name,
+				name->len * 3 + 1);
+		kfree(name);
+	} else /* if (name->type == FILE_NAME_DOS) */ {		/* Case 3. */
+		MFT_RECORD *m;
+		FILE_NAME_ATTR *fn;
+
+		kfree(name);
+
+		/* Find the WIN32 name corresponding to the matched DOS name. */
+		ni = NTFS_I(dent_inode);
+		m = map_mft_record(READ, ni);
+		if (IS_ERR(m)) {
+			err = PTR_ERR(m);
+			goto name_err_out;
+		}
+		ctx = get_attr_search_ctx(ni, m);
+		if (!ctx) {
+			err = -ENOMEM;
+			goto unm_err_out;
+		}
+		do {
+			ATTR_RECORD *a;
+			u32 val_len;
+
+			if (!lookup_attr(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0,
+					ctx)) {
+				ntfs_error(vol->sb, "Inode corrupt: No WIN32 "
+						"namespace counterpart to DOS "
+						"file name. Run chkdsk.");
+				err = -EIO;
+				goto put_unm_err_out;
+			}
+			/* Consistency checks. */
+			a = ctx->attr;
+			if (a->non_resident || a->flags)
+				goto eio_put_unm_err_out;
+			val_len = le32_to_cpu(a->_ARA(value_length));
+			if (le16_to_cpu(a->_ARA(value_offset)) + val_len >
+					le32_to_cpu(a->length))
+				goto eio_put_unm_err_out;
+			fn = (FILE_NAME_ATTR*)((u8*)ctx->attr + le16_to_cpu(
+					ctx->attr->_ARA(value_offset)));
+			if ((u32)(fn->file_name_length * sizeof(uchar_t) +
+					sizeof(FILE_NAME_ATTR)) > val_len)
+				goto eio_put_unm_err_out;
+		} while (fn->file_name_type != FILE_NAME_WIN32);
+
+		/* Convert the found WIN32 name to current NLS code page. */
+		nls_name.len = (unsigned)ntfs_ucstonls(vol,
+				(uchar_t*)&fn->file_name, fn->file_name_length,
+				(unsigned char**)&nls_name.name,
+				fn->file_name_length * 3 + 1);
+
+		put_attr_search_ctx(ctx);
+		unmap_mft_record(READ, ni);
+	}
+
+	/* Check if a conversion error occured. */
+	if ((signed)nls_name.len < 0) {
+		err = (signed)nls_name.len;
+		goto name_err_out;
+	}
+	nls_name.hash = full_name_hash(nls_name.name, nls_name.len);
+
+	// FIXME: Do we need dcache_lock or dparent_lock here or is the
+	// fact that i_sem is held on the parent inode sufficient? (AIA)
+
+	/* Does a dentry matching the nls_name exist already? */
+	real_dent = d_lookup(dent->d_parent, &nls_name);
+	/* If not, create it now. */
+	if (!real_dent) {
+		real_dent = d_alloc(dent->d_parent, &nls_name);
+		kfree(nls_name.name);
+		if (!real_dent) {
+			err = -ENOMEM;
+			goto name_err_out;
+		}
+		d_add(real_dent, dent_inode);
+		return real_dent;
+	}
+	kfree(nls_name.name);
+	/* Matching dentry exists, check if it is negative. */
+	if (real_dent->d_inode) {
+		BUG_ON(real_dent->d_inode != dent_inode);
+		/*
+		 * Already have the inode and the dentry attached, decrement
+		 * the reference count to balance the iget() we did earlier on.
+		 */
+		iput(dent_inode);
+		return real_dent;
+	}
+	/* Negative dentry: instantiate it. */
+	d_instantiate(real_dent, dent_inode);
+	return real_dent;
+
+eio_put_unm_err_out:
+	ntfs_error(vol->sb, "Illegal file name attribute. Run chkdsk.");
+	err = -EIO;
+put_unm_err_out:
+	put_attr_search_ctx(ctx);
+unm_err_out:
+	unmap_mft_record(READ, ni);
+name_err_out:
+	iput(dent_inode);
+	return ERR_PTR(err);
+   }
 }
 
+/*
+ * Inode operations for directories.
+ */
 struct inode_operations ntfs_dir_inode_ops = {
-	lookup:		ntfs_lookup,	/* lookup directory. */
+	lookup:		ntfs_lookup,	/* VFS: Lookup directory. */
 };
 
diff -Nru a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
--- a/fs/ntfs/ntfs.h	Sat Jun  8 22:31:37 2002
+++ b/fs/ntfs/ntfs.h	Sat Jun  8 22:31:37 2002
@@ -96,9 +96,6 @@
 extern kmem_cache_t *ntfs_big_inode_cache;
 extern kmem_cache_t *ntfs_attr_ctx_cache;
 
-/* The little endian Unicode string $I30 as a global constant. */
-extern const uchar_t I30[5];
-
 /* The various operations structs defined throughout the driver files. */
 extern struct super_operations ntfs_mount_sops;
 extern struct super_operations ntfs_sops;
@@ -222,10 +219,6 @@
 extern inline s64 utc2ntfs(const time_t time);
 extern inline s64 get_current_ntfs_time(void);
 extern inline time_t ntfs2utc(const s64 time);
-
-/* From fs/ntfs/dir.c */
-extern u64 ntfs_lookup_inode_by_name(ntfs_inode *dir_ni, const uchar_t *uname,
-		const int uname_len);
 
 /* From fs/ntfs/unistr.c */
 extern BOOL ntfs_are_names_equal(const uchar_t *s1, size_t s1_len,
diff -Nru a/fs/ntfs/super.c b/fs/ntfs/super.c
--- a/fs/ntfs/super.c	Sat Jun  8 22:31:36 2002
+++ b/fs/ntfs/super.c	Sat Jun  8 22:31:36 2002
@@ -52,17 +52,6 @@
 	{ 0,			NULL }
 };
 
-static const option_t readdir_opts_arr[] = {
-	{ SHOW_SYSTEM,	"system" },
-	{ SHOW_WIN32,	"win32" },
-	{ SHOW_WIN32,	"long" },
-	{ SHOW_DOS,	"dos" },
-	{ SHOW_DOS,	"short" },
-	{ SHOW_POSIX,	"posix" },
-	{ SHOW_ALL,	"all" },
-	{ 0,		NULL }
-};
-
 /**
  * simple_getbool -
  *
@@ -98,7 +87,8 @@
 	uid_t uid = (uid_t)-1;
 	gid_t gid = (gid_t)-1;
 	mode_t fmask = (mode_t)-1, dmask = (mode_t)-1;
-	int mft_zone_multiplier = -1, on_errors = -1, readdir_opts = -1;
+	int mft_zone_multiplier = -1, on_errors = -1;
+	int show_sys_files = -1, case_sensitive = -1;
 	struct nls_table *nls_map = NULL, *old_nls;
 
 	/* I am lazy... (-8 */
@@ -120,6 +110,13 @@
 		if (*v)							\
 			goto needs_val;					\
 	} 
+#define NTFS_GETOPT_BOOL(option, variable)				\
+	if (!strcmp(p, option)) {					\
+		BOOL val;						\
+		if (!simple_getbool(v, &val))				\
+			goto needs_bool;				\
+		variable = val;						\
+	} 
 #define NTFS_GETOPT_OPTIONS_ARRAY(option, variable, opt_array)		\
 	if (!strcmp(p, option)) {					\
 		int _i;							\
@@ -146,47 +143,16 @@
 		else NTFS_GETOPT("umask", fmask = dmask)
 		else NTFS_GETOPT("fmask", fmask)
 		else NTFS_GETOPT("dmask", dmask)
-		else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE)
 		else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier)
+		else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE)
+		else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files)
+		else NTFS_GETOPT_BOOL("case_sensitive", case_sensitive)
 		else NTFS_GETOPT_OPTIONS_ARRAY("errors", on_errors,
 				on_errors_arr)
-		else NTFS_GETOPT_OPTIONS_ARRAY("show_inodes", readdir_opts,
-				readdir_opts_arr)
-		else if (!strcmp(p, "show_sys_files")) {
-			BOOL val = FALSE;
-			ntfs_warning(vol->sb, "Option show_sys_files is "
-				   "deprecated. Please use option "
-				   "show_inodes=system in the future.");
-			if (!v || !*v)
-				val = TRUE;
-			else if (!simple_getbool(v, &val))
-				goto needs_bool;
-			if (val) {
-				if (readdir_opts == -1)
-					readdir_opts = 0;
-				readdir_opts |= SHOW_SYSTEM;
-			}
-		} else if (!strcmp(p, "posix")) {
-			BOOL val = FALSE;
-			ntfs_warning(vol->sb, "Option posix is deprecated. "
-				   "Please use option show_inodes=posix "
-				   "instead. Be aware that some userspace "
-				   "applications may be confused by this, "
-				   "since the short and long names of "
-				   "directory inodes will have the same inode "
-				   "numbers, yet each will only have a link "
-				   "count of 1 due to Linux not supporting "
-				   "directory hard links.");
-			if (!v || !*v)
-				goto needs_arg;
-			else if (!simple_getbool(v, &val))
-				goto needs_bool;
-			if (val) {
-				if (readdir_opts == -1)
-					readdir_opts = 0;
-				readdir_opts |= SHOW_POSIX;
-			}
-		} else if (!strcmp(p, "nls") || !strcmp(p, "iocharset")) {
+		else if (!strcmp(p, "posix") || !strcmp(p, "show_inodes"))
+			ntfs_warning(vol->sb, "Ignoring obsolete option %s.",
+					p);
+		else if (!strcmp(p, "nls") || !strcmp(p, "iocharset")) {
 			if (!strcmp(p, "iocharset"))
 				ntfs_warning(vol->sb, "Option iocharset is "
 						"deprecated. Please use "
@@ -232,6 +198,7 @@
 				errors++;
 		}
 #undef NTFS_GETOPT_OPTIONS_ARRAY
+#undef NTFS_GETOPT_BOOL
 #undef NTFS_GETOPT
 #undef NTFS_GETOPT_WITH_DEFAULT
 	}
@@ -297,8 +264,18 @@
 		vol->fmask = fmask;
 	if (dmask != (mode_t)-1)
 		vol->dmask = dmask;
-	if (readdir_opts != -1)
-		vol->readdir_opts = readdir_opts;
+	if (show_sys_files != -1) {
+		if (show_sys_files)
+			NVolSetShowSystemFiles(vol);
+		else
+			NVolClearShowSystemFiles(vol);
+	}
+	if (case_sensitive != -1) {
+		if (case_sensitive)
+			NVolSetCaseSensitive(vol);
+		else
+			NVolClearCaseSensitive(vol);
+	}
 	return TRUE;
 needs_arg:
 	ntfs_error(vol->sb, "The %s option requires an argument.", p);
@@ -464,7 +441,7 @@
 			ntfs_error(sb, "Primary boot sector is invalid.");
 	} else if (!silent)
 		ntfs_error(sb, read_err_str, "primary");
-	if (NTFS_SB(sb)->on_errors & ~ON_ERRORS_RECOVER) {
+	if (!(NTFS_SB(sb)->on_errors & ON_ERRORS_RECOVER)) {
 		if (bh_primary)
 			brelse(bh_primary);
 		if (!silent)
@@ -1492,6 +1469,7 @@
 	vol->root_ino = NULL;
 	vol->secure_ino = NULL;
 	vol->uid = vol->gid = 0;
+	vol->flags = 0;
 	vol->on_errors = 0;
 	vol->mft_zone_multiplier = 0;
 	vol->nls_map = NULL;
@@ -1530,12 +1508,6 @@
 	 */
 	vol->fmask = 0177;
 	vol->dmask = 0077;
-
-	/*
-	 * Default is to show long file names (including POSIX file names), and
-	 * not to show system files and short file names.
-	 */
-	vol->readdir_opts = SHOW_WIN32;
 
 	/* Important to get the mount options dealt with now. */
 	if (!parse_options(vol, (char*)opt))
diff -Nru a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
--- a/fs/ntfs/unistr.c	Sat Jun  8 22:31:51 2002
+++ b/fs/ntfs/unistr.c	Sat Jun  8 22:31:51 2002
@@ -333,7 +333,7 @@
 		}
 		if (!ns) {
 			ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
-			ns = (unsigned char*)kmalloc(ns_len, GFP_NOFS);
+			ns = (unsigned char*)kmalloc(ns_len + 1, GFP_NOFS);
 			if (!ns)
 				goto mem_err_out;
 		}
@@ -352,7 +352,7 @@
 						~63, GFP_NOFS);
 				if (tc) {
 					memcpy(tc, ns, ns_len);
-					ns_len = (ns_len + 64) & ~63;
+					ns_len = ((ns_len + 64) & ~63) - 1;
 					kfree(ns);
 					ns = tc;
 					goto retry;
diff -Nru a/fs/ntfs/volume.h b/fs/ntfs/volume.h
--- a/fs/ntfs/volume.h	Sat Jun  8 22:31:36 2002
+++ b/fs/ntfs/volume.h	Sat Jun  8 22:31:36 2002
@@ -26,18 +26,30 @@
 
 #include "types.h"
 
-/* These are used to determine which inode names are returned by readdir(). */
+/*
+ * Defined bits for the flags field in the ntfs_volume structure.
+ */
 typedef enum {
-	SHOW_SYSTEM	= 1,
-	SHOW_WIN32	= 2,
-	SHOW_DOS	= 4,
-	SHOW_POSIX	= SHOW_WIN32 | SHOW_DOS,
-	SHOW_ALL	= SHOW_SYSTEM | SHOW_POSIX,
-} READDIR_OPTIONS;
+	NV_ShowSystemFiles,	/* 1: Return system files in ntfs_readdir(). */
+	NV_CaseSensitive,	/* 1: Treat file names as case sensitive and
+				      create filenames in the POSIX namespace.
+				      Otherwise be case insensitive and create
+				      file names in WIN32 namespace. */
+} ntfs_volume_flags;
+
+#define NVolShowSystemFiles(n_vol)	test_bit(NV_ShowSystemFiles,	\
+							&(n_vol)->flags)
+#define NVolSetShowSystemFiles(n_vol)	set_bit(NV_ShowSystemFiles,	\
+							&(n_vol)->flags)
+#define NVolClearShowSystemFiles(n_vol)	clear_bit(NV_ShowSystemFiles,	\
+							&(n_vol)->flags)
 
-#define RHideSystemFiles(x)	(!((x) & SHOW_SYSTEM))
-#define RHideLongNames(x)	(!((x) & SHOW_WIN32))
-#define RHideDosNames(x)	(!((x) & SHOW_DOS))
+#define NVolCaseSensitive(n_vol)	test_bit(NV_CaseSensitive,	\
+							&(n_vol)->flags)
+#define NVolSetCaseSensitive(n_vol)	set_bit(NV_CaseSensitive,	\
+							&(n_vol)->flags)
+#define NVolClearCaseSensitive(n_vol)	clear_bit(NV_CaseSensitive,	\
+							&(n_vol)->flags)
 
 /*
  * The NTFS in memory super block structure.
@@ -57,13 +69,13 @@
 	LCN nr_blocks;			/* Number of NTFS_BLOCK_SIZE bytes
 					   sized blocks on the device. */
 	/* Configuration provided by user at mount time. */
+	unsigned long flags;		/* Miscellaneous flags, see above. */
 	uid_t uid;			/* uid that files will be mounted as. */
 	gid_t gid;			/* gid that files will be mounted as. */
 	mode_t fmask;			/* The mask for file permissions. */
 	mode_t dmask;			/* The mask for directory
 					   permissions. */
-	READDIR_OPTIONS readdir_opts;	/* Namespace of inode names to show. */
-	u8 mft_zone_multiplier;	/* Initial mft zone multiplier. */
+	u8 mft_zone_multiplier;		/* Initial mft zone multiplier. */
 	u8 on_errors;			/* What to do on file system errors. */
 	/* NTFS bootsector provided information. */
 	u16 sector_size;		/* in bytes */
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Sat Jun  8 22:31:35 2002
+++ b/fs/open.c	Sat Jun  8 22:31:35 2002
@@ -338,7 +338,14 @@
 	current->fsuid = current->uid;
 	current->fsgid = current->gid;
 
-	/* Clear the capabilities if we switch to a non-root user */
+	/*
+	 * Clear the capabilities if we switch to a non-root user
+	 *
+	 * FIXME: There is a race here against sys_capset.  The
+	 * capabilities can change yet we will restore the old
+	 * value below.  We should hold task_capabilities_lock,
+	 * but we cannot because user_path_walk can sleep.
+	 */
 	if (current->uid)
 		cap_clear(current->cap_effective);
 	else
diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c
--- a/fs/proc/inode.c	Sat Jun  8 22:31:37 2002
+++ b/fs/proc/inode.c	Sat Jun  8 22:31:37 2002
@@ -121,7 +121,7 @@
 	alloc_inode:	proc_alloc_inode,
 	destroy_inode:	proc_destroy_inode,
 	read_inode:	proc_read_inode,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 	delete_inode:	proc_delete_inode,
 	statfs:		simple_statfs,
 };
diff -Nru a/fs/ramfs/inode.c b/fs/ramfs/inode.c
--- a/fs/ramfs/inode.c	Sat Jun  8 22:31:37 2002
+++ b/fs/ramfs/inode.c	Sat Jun  8 22:31:37 2002
@@ -277,7 +277,7 @@
 
 static struct super_operations ramfs_ops = {
 	statfs:		simple_statfs,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 };
 
 static int ramfs_fill_super(struct super_block * sb, void * data, int silent)
diff -Nru a/fs/smbfs/inode.c b/fs/smbfs/inode.c
--- a/fs/smbfs/inode.c	Sat Jun  8 22:31:36 2002
+++ b/fs/smbfs/inode.c	Sat Jun  8 22:31:36 2002
@@ -94,7 +94,7 @@
 {
 	alloc_inode:	smb_alloc_inode,
 	destroy_inode:	smb_destroy_inode,
-	put_inode:	force_delete,
+	drop_inode:	generic_delete_inode,
 	delete_inode:	smb_delete_inode,
 	put_super:	smb_put_super,
 	statfs:		smb_statfs,
diff -Nru a/include/asm-arm/mach/map.h b/include/asm-arm/mach/map.h
--- a/include/asm-arm/mach/map.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-arm/mach/map.h	Sat Jun  8 22:31:51 2002
@@ -13,20 +13,18 @@
 	unsigned long virtual;
 	unsigned long physical;
 	unsigned long length;
-	int domain:4,
-	    prot_read:1,
-	    prot_write:1,
-	    cacheable:1,
-	    bufferable:1,
-	    last:1;
+	unsigned int type;
 };
 
-#define LAST_DESC \
-  { last: 1 }
-
 struct meminfo;
 
+#define MT_DEVICE	0
+#define MT_CACHECLEAN	1
+#define MT_MINICLEAN	2
+#define MT_VECTORS	3
+#define MT_MEMORY	4
+
 extern void create_memmap_holes(struct meminfo *);
 extern void memtable_init(struct meminfo *);
-extern void iotable_init(struct map_desc *);
+extern void iotable_init(struct map_desc *, int);
 extern void setup_io_desc(void);
diff -Nru a/include/asm-arm/page.h b/include/asm-arm/page.h
--- a/include/asm-arm/page.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-arm/page.h	Sat Jun  8 22:31:36 2002
@@ -30,14 +30,14 @@
 				 unsigned long user);
 #endif
 
-#define clear_user_page(addr,vaddr)			\
+#define clear_user_page(addr,vaddr,pg)			\
 	do {						\
 		preempt_disable();			\
 		__cpu_clear_user_page(addr, vaddr);	\
 		preempt_enable();			\
 	} while (0)
 
-#define copy_user_page(to,from,vaddr)			\
+#define copy_user_page(to,from,vaddr,pg)		\
 	do {						\
 		preempt_disable();			\
 		__cpu_copy_user_page(to, from, vaddr);	\
diff -Nru a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h
--- a/include/asm-arm/thread_info.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-arm/thread_info.h	Sat Jun  8 22:31:37 2002
@@ -86,8 +86,10 @@
 #define get_thread_info(ti)	get_task_struct((ti)->task)
 #define put_thread_info(ti)	put_task_struct((ti)->task)
 
-#define thread_saved_pc(tsk)	(pc_pointer((tsk)->thread_info->cpu_context.pc))
-#define thread_saved_fp(tsk)	((tsk)->thread_info->cpu_context.fp)
+#define thread_saved_pc(tsk)	\
+	((unsigned long)(pc_pointer((tsk)->thread_info->cpu_context.pc)))
+#define thread_saved_fp(tsk)	\
+	((unsigned long)((tsk)->thread_info->cpu_context.fp))
 
 #else /* !__ASSEMBLY__ */
 
diff -Nru a/include/asm-generic/siginfo.h b/include/asm-generic/siginfo.h
--- a/include/asm-generic/siginfo.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-generic/siginfo.h	Sat Jun  8 22:31:37 2002
@@ -232,6 +232,8 @@
 
 #ifdef __KERNEL__
 
+struct siginfo;
+
 #ifndef HAVE_ARCH_COPY_SIGINFO
 
 #include <linux/string.h>
diff -Nru a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
--- a/include/asm-i386/bugs.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-i386/bugs.h	Sat Jun  8 22:31:36 2002
@@ -21,6 +21,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/init.h>
 #include <asm/processor.h>
 #include <asm/i387.h>
 #include <asm/msr.h>
diff -Nru a/include/asm-i386/desc.h b/include/asm-i386/desc.h
--- a/include/asm-i386/desc.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-i386/desc.h	Sat Jun  8 22:31:35 2002
@@ -49,6 +49,9 @@
 #define __LDT(n) (((n)<<2) + __FIRST_LDT_ENTRY)
 
 #ifndef __ASSEMBLY__
+
+#include <asm/mmu.h>
+
 struct desc_struct {
 	unsigned long a,b;
 };
diff -Nru a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
--- a/include/asm-i386/highmem.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-i386/highmem.h	Sat Jun  8 22:31:36 2002
@@ -21,7 +21,6 @@
 #ifdef __KERNEL__
 
 #include <linux/config.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/kmap_types.h>
 #include <asm/tlbflush.h>
@@ -33,7 +32,7 @@
 extern pgprot_t kmap_prot;
 extern pte_t *pkmap_page_table;
 
-extern void kmap_init(void) __init;
+extern void kmap_init(void);
 
 /*
  * Right now we initialize only a single pte table. It can be extended
diff -Nru a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
--- a/include/asm-i386/hw_irq.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-i386/hw_irq.h	Sat Jun  8 22:31:37 2002
@@ -28,9 +28,6 @@
 
 extern void (*interrupt[NR_IRQS])(void);
 
-extern asmlinkage void thermal_interrupt(void);
-extern asmlinkage void smp_thermal_interrupt(struct pt_regs);
-
 #ifdef CONFIG_SMP
 extern asmlinkage void reschedule_interrupt(void);
 extern asmlinkage void invalidate_interrupt(void);
@@ -41,6 +38,7 @@
 extern asmlinkage void apic_timer_interrupt(void);
 extern asmlinkage void error_interrupt(void);
 extern asmlinkage void spurious_interrupt(void);
+extern asmlinkage void thermal_interrupt(struct pt_regs);
 #endif
 
 extern void mask_irq(unsigned int irq);
diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h
--- a/include/asm-i386/kmap_types.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-i386/kmap_types.h	Sat Jun  8 22:31:51 2002
@@ -11,7 +11,7 @@
 
 enum km_type {
 D(0)	KM_BOUNCE_READ,
-D(1)	KM_SKB_DATA,
+D(1)	KM_SKB_SUNRPC_DATA,
 D(2)	KM_SKB_DATA_SOFTIRQ,
 D(3)	KM_USER0,
 D(4)	KM_USER1,
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-i386/msr.h	Sat Jun  8 22:31:35 2002
@@ -57,8 +57,21 @@
 #define MSR_IA32_MCG_STATUS		0x17a
 #define MSR_IA32_MCG_CTL		0x17b
 
-#define MSR_P6_EVNTSEL0		0x186
-#define MSR_P6_EVNTSEL1		0x187
+/* P4/Xeon+ specific */
+#define MSR_IA32_MCG_EAX		0x180
+#define MSR_IA32_MCG_EBX		0x181
+#define MSR_IA32_MCG_ECX		0x182
+#define MSR_IA32_MCG_EDX		0x183
+#define MSR_IA32_MCG_ESI		0x184
+#define MSR_IA32_MCG_EDI		0x185
+#define MSR_IA32_MCG_EBP		0x186
+#define MSR_IA32_MCG_ESP		0x187
+#define MSR_IA32_MCG_EFLAGS		0x188
+#define MSR_IA32_MCG_EIP		0x189
+#define MSR_IA32_MCG_RESERVED		0x18A
+
+#define MSR_P6_EVNTSEL0			0x186
+#define MSR_P6_EVNTSEL1			0x187
 
 #define MSR_IA32_THERM_CONTROL		0x19a
 #define MSR_IA32_THERM_INTERRUPT	0x19b
diff -Nru a/include/asm-i386/pci.h b/include/asm-i386/pci.h
--- a/include/asm-i386/pci.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-i386/pci.h	Sat Jun  8 22:31:37 2002
@@ -4,6 +4,7 @@
 #include <linux/config.h>
 
 #ifdef __KERNEL__
+#include <linux/mm.h>		/* for struct page */
 
 /* Can be used to override the logic in pci_scan_bus for skipping
    already-configured bus numbers - to be used for buggy BIOSes
diff -Nru a/include/asm-i386/pgalloc.h b/include/asm-i386/pgalloc.h
--- a/include/asm-i386/pgalloc.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-i386/pgalloc.h	Sat Jun  8 22:31:35 2002
@@ -5,6 +5,7 @@
 #include <asm/processor.h>
 #include <asm/fixmap.h>
 #include <linux/threads.h>
+#include <linux/mm.h>		/* for struct page */
 
 #define pmd_populate_kernel(mm, pmd, pte) \
 		set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-i386/processor.h	Sat Jun  8 22:31:35 2002
@@ -60,6 +60,7 @@
 #define X86_VENDOR_RISE 6
 #define X86_VENDOR_TRANSMETA 7
 #define X86_VENDOR_NSC 8
+#define X86_VENDOR_NUM 9
 #define X86_VENDOR_UNKNOWN 0xff
 
 /*
diff -Nru a/include/asm-i386/rwlock.h b/include/asm-i386/rwlock.h
--- a/include/asm-i386/rwlock.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-i386/rwlock.h	Sat Jun  8 22:31:37 2002
@@ -61,7 +61,7 @@
 		     ::"a" (rw) : "memory")
 
 #define __build_write_lock_const(rw, helper) \
-	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",(%0)\n\t" \
+	asm volatile(LOCK "subl $" RW_LOCK_BIAS_STR ",%0\n\t" \
 		     "jnz 2f\n" \
 		     "1:\n" \
 		     LOCK_SECTION_START("") \
diff -Nru a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
--- a/include/asm-i386/suspend.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-i386/suspend.h	Sat Jun  8 22:31:37 2002
@@ -33,264 +33,36 @@
 	u32 eflags;
 } __attribute__((packed));
 
-static struct saved_context saved_context;
-
 #define loaddebug(thread,register) \
                __asm__("movl %0,%%db" #register  \
                        : /* no output */ \
                        :"r" ((thread)->debugreg[register]))
 
- 
-/*
- * save_processor_context
- * 
- * Save the state of the processor before we go to sleep.
- *
- * return_stack is the value of the stack pointer (%esp) as the caller sees it.
- * A good way could not be found to obtain it from here (don't want to make _too_
- * many assumptions about the layout of the stack this far down.) Also, the 
- * handy little __builtin_frame_pointer(level) where level > 0, is blatantly 
- * buggy - it returns the value of the stack at the proper location, not the 
- * location, like it should (as of gcc 2.91.66)
- * 
- * Note that the context and timing of this function is pretty critical.
- * With a minimal amount of things going on in the caller and in here, gcc
- * does a good job of being just a dumb compiler.  Watch the assembly output
- * if anything changes, though, and make sure everything is going in the right
- * place. 
- */
-static inline void save_processor_context (void)
-{
-	kernel_fpu_begin();
-
-	/*
-	 * descriptor tables
-	 */
-	asm volatile ("sgdt (%0)" : "=m" (saved_context.gdt_limit));
-	asm volatile ("sidt (%0)" : "=m" (saved_context.idt_limit));
-	asm volatile ("sldt (%0)" : "=m" (saved_context.ldt));
-	asm volatile ("str (%0)"  : "=m" (saved_context.tr));
-
-	/*
-	 * save the general registers.
-	 * note that gcc has constructs to specify output of certain registers,
-	 * but they're not used here, because it assumes that you want to modify
-	 * those registers, so it tries to be smart and save them beforehand.
-	 * It's really not necessary, and kinda fishy (check the assembly output),
-	 * so it's avoided. 
-	 */
-	asm volatile ("movl %%esp, (%0)" : "=m" (saved_context.esp));
-	asm volatile ("movl %%eax, (%0)" : "=m" (saved_context.eax));
-	asm volatile ("movl %%ebx, (%0)" : "=m" (saved_context.ebx));
-	asm volatile ("movl %%ecx, (%0)" : "=m" (saved_context.ecx));
-	asm volatile ("movl %%edx, (%0)" : "=m" (saved_context.edx));
-	asm volatile ("movl %%ebp, (%0)" : "=m" (saved_context.ebp));
-	asm volatile ("movl %%esi, (%0)" : "=m" (saved_context.esi));
-	asm volatile ("movl %%edi, (%0)" : "=m" (saved_context.edi));
-
-	/*
-	 * segment registers
-	 */
-	asm volatile ("movw %%es, %0" : "=r" (saved_context.es));
-	asm volatile ("movw %%fs, %0" : "=r" (saved_context.fs));
-	asm volatile ("movw %%gs, %0" : "=r" (saved_context.gs));
-	asm volatile ("movw %%ss, %0" : "=r" (saved_context.ss));
+extern void do_fpu_end(void);
+extern void fix_processor_context(void);
+extern void do_magic(int resume);
+
+#ifdef CONFIG_ACPI_SLEEP
+extern unsigned long saved_eip;
+extern unsigned long saved_esp;
+extern unsigned long saved_ebp;
+extern unsigned long saved_ebx;
+extern unsigned long saved_esi;
+extern unsigned long saved_edi;
 
-	/*
-	 * control registers 
-	 */
-	asm volatile ("movl %%cr0, %0" : "=r" (saved_context.cr0));
-	asm volatile ("movl %%cr2, %0" : "=r" (saved_context.cr2));
-	asm volatile ("movl %%cr3, %0" : "=r" (saved_context.cr3));
-	asm volatile ("movl %%cr4, %0" : "=r" (saved_context.cr4));
-
-	/*
-	 * eflags
-	 */
-	asm volatile ("pushfl ; popl (%0)" : "=m" (saved_context.eflags));
-}
-
-static void fix_processor_context(void)
+static inline void acpi_save_register_state(unsigned long return_point)
 {
-	int nr = smp_processor_id();
-	struct tss_struct * t = &init_tss[nr];
-
-	set_tss_desc(nr,t);	/* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy tsc or some similar stupidity. */
-        gdt_table[__TSS(nr)].b &= 0xfffffdff;
-
-	load_TR(nr);		/* This does ltr */
-
-	load_LDT(&current->mm->context);	/* This does lldt */
-
-	/*
-	 * Now maybe reload the debug registers
-	 */
-	if (current->thread.debugreg[7]){
-                loaddebug(&current->thread, 0);
-                loaddebug(&current->thread, 1);
-                loaddebug(&current->thread, 2);
-                loaddebug(&current->thread, 3);
-                /* no 4 and 5 */
-                loaddebug(&current->thread, 6);
-                loaddebug(&current->thread, 7);
-	}
-
+	saved_eip = return_point;
+	asm volatile ("movl %%esp,(%0)" : "=m" (saved_esp));
+	asm volatile ("movl %%ebp,(%0)" : "=m" (saved_ebp));
+	asm volatile ("movl %%ebx,(%0)" : "=m" (saved_ebx));
+	asm volatile ("movl %%edi,(%0)" : "=m" (saved_edi));
+	asm volatile ("movl %%esi,(%0)" : "=m" (saved_esi));
 }
 
-static void
-do_fpu_end(void)
-{
-        /* restore FPU regs if necessary */
-	/* Do it out of line so that gcc does not move cr0 load to some stupid place */
-        kernel_fpu_end();
-}
-
-/*
- * restore_processor_context
- * 
- * Restore the processor context as it was before we went to sleep
- * - descriptor tables
- * - control registers
- * - segment registers
- * - flags
- * 
- * Note that it is critical that this function is declared inline.  
- * It was separated out from restore_state to make that function
- * a little clearer, but it needs to be inlined because we won't have a
- * stack when we get here (so we can't push a return address).
- */
-static inline void restore_processor_context (void)
-{
-	/*
-	 * first restore %ds, so we can access our data properly
-	 */
-	asm volatile (".align 4");
-	asm volatile ("movw %0, %%ds" :: "r" ((u16)__KERNEL_DS));
-
-
-	/*
-	 * control registers
-	 */
-	asm volatile ("movl %0, %%cr4" :: "r" (saved_context.cr4));
-	asm volatile ("movl %0, %%cr3" :: "r" (saved_context.cr3));
-	asm volatile ("movl %0, %%cr2" :: "r" (saved_context.cr2));
-	asm volatile ("movl %0, %%cr0" :: "r" (saved_context.cr0));
-	
-	/*
-	 * segment registers
-	 */
-	asm volatile ("movw %0, %%es" :: "r" (saved_context.es));
-	asm volatile ("movw %0, %%fs" :: "r" (saved_context.fs));
-	asm volatile ("movw %0, %%gs" :: "r" (saved_context.gs));
-	asm volatile ("movw %0, %%ss" :: "r" (saved_context.ss));
-
-	/*
-	 * the other general registers
-	 *
-	 * note that even though gcc has constructs to specify memory 
-	 * input into certain registers, it will try to be too smart
-	 * and save them at the beginning of the function.  This is esp.
-	 * bad since we don't have a stack set up when we enter, and we 
-	 * want to preserve the values on exit. So, we set them manually.
-	 */
-	asm volatile ("movl %0, %%esp" :: "m" (saved_context.esp));
-	asm volatile ("movl %0, %%ebp" :: "m" (saved_context.ebp));
-	asm volatile ("movl %0, %%eax" :: "m" (saved_context.eax));
-	asm volatile ("movl %0, %%ebx" :: "m" (saved_context.ebx));
-	asm volatile ("movl %0, %%ecx" :: "m" (saved_context.ecx));
-	asm volatile ("movl %0, %%edx" :: "m" (saved_context.edx));
-	asm volatile ("movl %0, %%esi" :: "m" (saved_context.esi));
-	asm volatile ("movl %0, %%edi" :: "m" (saved_context.edi));
-
-	/*
-	 * now restore the descriptor tables to their proper values
-	 * ltr is done i fix_processor_context().
-	 */
-	asm volatile ("lgdt (%0)" :: "m" (saved_context.gdt_limit));
-	asm volatile ("lidt (%0)" :: "m" (saved_context.idt_limit));
-	asm volatile ("lldt (%0)" :: "m" (saved_context.ldt));
-
-	fix_processor_context();
-
-	/*
-	 * the flags
-	 */
-	asm volatile ("pushl %0 ; popfl" :: "m" (saved_context.eflags));
-
-	do_fpu_end();
-}
-
-#ifdef SUSPEND_C
-/* Local variables for do_magic */
-static int loop __nosavedata = 0;
-static int loop2 __nosavedata = 0;
-
-/*
- * (KG): Since we affect stack here, we make this function as flat and easy
- * as possible in order to not provoke gcc to use local variables on the stack.
- * Note that on resume, all (expect nosave) variables will have the state from
- * the time of writing (suspend_save_image) and the registers (including the
- * stack pointer, but excluding the instruction pointer) will be loaded with 
- * the values saved at save_processor_context() time.
- */
-static void do_magic(int resume)
-{
-	/* DANGER WILL ROBINSON!
-	 *
-	 * If this function is too difficult for gcc to optimize, it will crash and burn!
-	 * see above.
-	 *
-	 * DO NOT TOUCH.
-	 */
-
-	if (!resume) {
-		do_magic_suspend_1();
-		save_processor_context();	/* We need to capture registers and memory at "same time" */
-		do_magic_suspend_2();		/* If everything goes okay, this function does not return */
-		return;
-	}
-
-	/* We want to run from swapper_pg_dir, since swapper_pg_dir is stored in constant
-	 * place in memory 
-	 */
-
-        __asm__( "movl %%ecx,%%cr3\n" ::"c"(__pa(swapper_pg_dir)));
-
-/*
- * Final function for resuming: after copying the pages to their original
- * position, it restores the register state.
- *
- * What about page tables? Writing data pages may toggle
- * accessed/dirty bits in our page tables. That should be no problems
- * with 4MB page tables. That's why we require have_pse.  
- *
- * This loops destroys stack from under itself, so it better should
- * not use any stack space, itself. When this function is entered at
- * resume time, we move stack to _old_ place.  This is means that this
- * function must use no stack and no local variables in registers,
- * until calling restore_processor_context();
- *
- * Critical section here: noone should touch saved memory after
- * do_magic_resume_1; copying works, because nr_copy_pages,
- * pagedir_nosave, loop and loop2 are nosavedata.
- */
-	do_magic_resume_1();
-
-	for (loop=0; loop < nr_copy_pages; loop++) {
-		/* You may not call something (like copy_page) here: see above */
-		for (loop2=0; loop2 < PAGE_SIZE; loop2++) {
-			*(((char *)((pagedir_nosave+loop)->orig_address))+loop2) =
-				*(((char *)((pagedir_nosave+loop)->address))+loop2);
-			__flush_tlb();
-		}
-	}
-
-	restore_processor_context();
-
-/* Ahah, we now run with our old stack, and with registers copied from
-   suspend time */
-
-	do_magic_resume_2();
-}
-#endif 
+#define acpi_restore_register_state()  do {} while (0)
 
+/* routines for saving/restoring kernel state */
+extern int acpi_save_state_mem(void);
+extern int acpi_save_state_disk(void);
+#endif
diff -Nru a/include/asm-i386/system.h b/include/asm-i386/system.h
--- a/include/asm-i386/system.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-i386/system.h	Sat Jun  8 22:31:35 2002
@@ -3,7 +3,6 @@
 
 #include <linux/config.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <asm/segment.h>
 #include <linux/bitops.h> /* for LOCK_PREFIX */
 
diff -Nru a/include/asm-ppc/kmap_types.h b/include/asm-ppc/kmap_types.h
--- a/include/asm-ppc/kmap_types.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-ppc/kmap_types.h	Sat Jun  8 22:31:36 2002
@@ -7,7 +7,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -Nru a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
--- a/include/asm-s390/atomic.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/atomic.h	Sat Jun  8 22:31:36 2002
@@ -26,29 +26,17 @@
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
 #define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)		\
-        __asm__ __volatile__("   l     %0,0(%2)\n"			\
+        __asm__ __volatile__("   l     %0,0(%3)\n"			\
                              "0: lr    %1,%0\n"				\
-                             op_string "  %1,%3\n"			\
-                             "   cs    %0,%1,0(%2)\n"			\
+                             op_string "  %1,%4\n"			\
+                             "   cs    %0,%1,0(%3)\n"			\
                              "   jl    0b"				\
-                             : "=&d" (old_val), "=&d" (new_val)		\
+                             : "=&d" (old_val), "=&d" (new_val),	\
+			       "+m" (((atomic_t *)(ptr))->counter)	\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
-static __inline__ int atomic_read(atomic_t *v)
-{
-        int retval;
-        __asm__ __volatile__("bcr      15,0\n\t"
-                             "l        %0,%1"
-                             : "=d" (retval) : "m" (*v) );
-        return retval;
-}
-
-static __inline__ void atomic_set(atomic_t *v, int i)
-{
-        __asm__ __volatile__("st  %1,%0\n\t"
-                             "bcr 15,0"
-                             : "=m" (*v) : "d" (i) );
-}
+#define atomic_read(v)          ((v)->counter)
+#define atomic_set(v,i)         (((v)->counter) = (i))
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
@@ -138,14 +126,14 @@
         int retval;
 
         __asm__ __volatile__(
-                "  lr   0,%2\n"
-                "  cs   0,%3,0(%1)\n"
+                "  lr   %0,%3\n"
+                "  cs   %0,%4,0(%2)\n"
                 "  ipm  %0\n"
                 "  srl  %0,28\n"
                 "0:"
-                : "=&d" (retval)
+                : "=&d" (retval), "+m" (v->counter)
                 : "a" (v), "d" (expected_oldval) , "d" (new_val)
-                : "0", "cc");
+                : "cc" );
         return retval;
 }
 
@@ -155,12 +143,14 @@
 static __inline__ void
 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 {
+	unsigned long tmp;
         __asm__ __volatile__(
-                "0: lr  0,%1\n"
-                "   cs  0,%2,0(%0)\n"
+                "0: lr  %1,%3\n"
+                "   cs  %1,%4,0(%2)\n"
                 "   jl  0b\n"
-                : : "a" (v), "d" (expected_oldval) , "d" (new_val)
-                : "cc", "0" );
+                : "+m" (v->counter), "=&d" (tmp)
+		: "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "cc" );
 }
 
 #define atomic_compare_and_swap_debug(where,from,to) \
diff -Nru a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
--- a/include/asm-s390/bitops.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390/bitops.h	Sat Jun  8 22:31:35 2002
@@ -47,265 +47,217 @@
 extern const char _oi_bitmap[];
 extern const char _ni_bitmap[];
 extern const char _zb_findmap[];
+extern const char _sb_findmap[];
 
 #ifdef CONFIG_SMP
 /*
  * SMP save set_bit routine based on compare and swap (CS)
  */
-static __inline__ void set_bit_cs(int nr, volatile void * addr)
+static inline void set_bit_cs(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   lhi   2,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"       /* make OR mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   or    1,2\n"          /* set bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 31);	/* make OR mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   or  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save clear_bit routine based on compare and swap (CS)
  */
-static __inline__ void clear_bit_cs(int nr, volatile void * addr)
+static inline void clear_bit_cs(int nr, volatile void *ptr)
 {
-        static const int mask = -1;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   lhi   2,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"
-             "   x     2,%2\n"         /* make AND mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   nr    1,2\n"          /* clear bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr) : "m" (mask)
-             : "cc", "memory", "1", "2" );
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = ~(1UL << (nr & 31));	/* make AND mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   nr  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save change_bit routine based on compare and swap (CS)
  */
-static __inline__ void change_bit_cs(int nr, volatile void * addr)
+static inline void change_bit_cs(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   lhi   2,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sll   2,0(1)\n"       /* make XR mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   xr    1,2\n"          /* change bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr) : 
-             : "cc", "memory", "1", "2" );
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 31);	/* make XOR mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   xr  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save test_and_set_bit routine based on compare and swap (CS)
  */
-static __inline__ int test_and_set_bit_cs(int nr, volatile void * addr)
+static inline int test_and_set_bit_cs(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"       /* make OR mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   or    1,2\n"          /* set bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
-        return nr;
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 31);	/* make OR/test mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   or  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old & mask) != 0;
 }
 
 /*
  * SMP save test_and_clear_bit routine based on compare and swap (CS)
  */
-static __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr)
+static inline int test_and_clear_bit_cs(int nr, volatile void *ptr)
 {
-        static const int mask = -1;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"
-             "   x     2,%2\n"         /* make AND mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   nr    1,2\n"          /* clear bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b\n"
-             "   x     2,%2\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) : "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return nr;
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = ~(1UL << (nr & 31));	/* make AND mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   nr  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old ^ new) != 0;
 }
 
 /*
  * SMP save test_and_change_bit routine based on compare and swap (CS) 
  */
-static __inline__ int test_and_change_bit_cs(int nr, volatile void * addr)
+static inline int test_and_change_bit_cs(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lhi   1,3\n"          /* CS must be aligned on 4 byte b. */
-             "   nr    1,%1\n"         /* isolate last 2 bits of address */
-             "   xr    %1,1\n"         /* make addr % 4 == 0 */
-             "   sll   1,3\n"
-             "   ar    %0,1\n"         /* add alignement to bitnr */
+	addr ^= addr & 3;		/* align address to 4 */
+	nr += (addr & 3) << 3;		/* add alignment to bit number */
 #endif
-             "   lhi   1,31\n"
-             "   nr    1,%0\n"         /* make shift value */
-             "   xr    %0,1\n"
-             "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lhi   2,1\n"
-             "   sll   2,0(1)\n"       /* make OR mask */
-             "   l     %0,0(%1)\n"
-             "0: lr    1,%0\n"         /* CS loop starts here */
-             "   xr    1,2\n"          /* change bit */
-             "   cs    %0,1,0(%1)\n"
-             "   jl    0b\n"
-             "   nr    %0,2\n"         /* isolate old bit */
-             : "+a" (nr), "+a" (addr) :
-             : "cc", "memory", "1", "2" );
-        return nr;
+	addr += (nr ^ (nr & 31)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 31);	/* make XOR mask */
+	asm volatile(
+		"   l   %0,0(%4)\n"
+		"0: lr  %1,%0\n"
+		"   xr  %1,%3\n"
+		"   cs  %0,%1,0(%4)\n"
+		"   jl  0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned int *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old & mask) != 0;
 }
 #endif /* CONFIG_SMP */
 
 /*
  * fast, non-SMP set_bit routine
  */
-static __inline__ void __set_bit(int nr, volatile void * addr)
+static inline void __set_bit(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   oc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_set_bit(const int nr, volatile void * addr)
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x01"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3))) 
-                          : : "1", "cc", "memory");
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x02"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x04"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x08"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x10"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x20"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x40"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x80"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+        asm volatile("oc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_set_bit(const int nr, volatile void *ptr)
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 3);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("oi 0(%1),0x01"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("oi 0(%1),0x02"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("oi 0(%1),0x04" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("oi 0(%1),0x08" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("oi 0(%1),0x10" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("oi 0(%1),0x20" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("oi 0(%1),0x40" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("oi 0(%1),0x80" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define set_bit_simple(nr,addr) \
@@ -316,75 +268,58 @@
 /*
  * fast, non-SMP clear_bit routine
  */
-static __inline__ void 
-__clear_bit(int nr, volatile void * addr)
+static inline void 
+__clear_bit(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   nc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_clear_bit(const int nr, volatile void * addr)
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFE"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFD"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFB"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xF7"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xEF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xDF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xBF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0x7F"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+        asm volatile("nc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_ni_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_clear_bit(const int nr, volatile void *ptr)
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 3);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("ni 0(%1),0xFE"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("ni 0(%1),0xFD" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("ni 0(%1),0xFB" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("ni 0(%1),0xF7" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("ni 0(%1),0xEF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("ni 0(%1),0xDF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("ni 0(%1),0xBF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("ni 0(%1),0x7F" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define clear_bit_simple(nr,addr) \
@@ -395,74 +330,57 @@
 /* 
  * fast, non-SMP change_bit routine 
  */
-static __inline__ void __change_bit(int nr, volatile void * addr)
+static inline void __change_bit(int nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%0\n"
-             "   nr    1,%0\n"
-             "   srl   2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   xc    0(1,2),0(1)"
-             :  : "r" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_change_bit(const int nr, volatile void * addr) 
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x01"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x02"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x04"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x08"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x10"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x20"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x40"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x80"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^3)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+        asm volatile("xc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_change_bit(const int nr, volatile void *ptr) 
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 3);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("xi 0(%1),0x01" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("xi 0(%1),0x02" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("xi 0(%1),0x04" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("xi 0(%1),0x08" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("xi 0(%1),0x10" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("xi 0(%1),0x20" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("xi 0(%1),0x40" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("xi 0(%1),0x80" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define change_bit_simple(nr,addr) \
@@ -473,80 +391,54 @@
 /*
  * fast, non-SMP test_and_set_bit routine
  */
-static __inline__ int test_and_set_bit_simple(int nr, volatile void * addr)
+static inline int test_and_set_bit_simple(int nr, volatile void *ptr)
 {
-        static const int mask = 1;
-        int oldbit;
-        __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   oc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_oi_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+	unsigned long addr;
+	unsigned char ch;
+
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("oc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_clear_bit routine
  */
-static __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr)
+static inline int test_and_clear_bit_simple(int nr, volatile void *ptr)
 {
-        static const int mask = 1;
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   nc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_ni_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("nc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_ni_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_change_bit routine
  */
-static __inline__ int test_and_change_bit_simple(int nr, volatile void * addr)
+static inline int test_and_change_bit_simple(int nr, volatile void *ptr)
 {
-        static const int mask = 1;
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lhi   1,24\n"
-             "   lhi   2,7\n"
-             "   xr    1,%1\n"
-             "   nr    2,1\n"
-             "   srl   1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   n     %0,%4\n"
-             "   la    2,0(2,%3)\n"
-             "   xc    0(1,1),0(2)"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "a" (&_oi_bitmap), "m" (mask)
-             : "cc", "memory", "1", "2" );
-        return oldbit;
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("xc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
 
@@ -571,27 +463,17 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int __test_bit(int nr, volatile void * addr)
+static inline int __test_bit(int nr, volatile void *ptr)
 {
-        static const int mask = 1;
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lhi   2,24\n"
-             "   lhi   1,7\n"
-             "   xr    2,%1\n"
-             "   nr    1,%1\n"
-             "   srl   2,3\n"
-             "   ic    %0,0(2,%2)\n"
-             "   srl   %0,0(1)\n"
-             "   n     %0,%3"
-             : "=d&" (oldbit) : "r" (nr), "a" (addr),
-               "m" (mask)
-             : "cc", "1", "2" );
-        return oldbit;
+	addr = (unsigned long) ptr + ((nr ^ 24) >> 3);
+	ch = *(unsigned char *) addr;
+	return (ch >> (nr & 7)) & 1;
 }
 
-static __inline__ int __constant_test_bit(int nr, volatile void * addr) {
+static inline int __constant_test_bit(int nr, volatile void * addr) {
     return (((volatile char *) addr)[(nr>>3)^3] & (1<<(nr&7))) != 0;
 }
 
@@ -603,50 +485,86 @@
 /*
  * Find-bit routines..
  */
-static __inline__ int find_first_zero_bit(void * addr, unsigned size)
+static inline int find_first_zero_bit(void * addr, unsigned size)
 {
-        static const int mask = 0xffL;
+	unsigned long cmp, count;
         int res;
 
         if (!size)
                 return 0;
-        __asm__("   lhi  0,-1\n"
-                "   lr   1,%1\n"
-                "   ahi  1,31\n"
-                "   srl  1,5\n"
-                "   sr   2,2\n"
-                "0: c    0,0(2,%2)\n"
+        __asm__("   lhi  %1,-1\n"
+                "   lr   %2,%3\n"
+                "   slr  %0,%0\n"
+                "   ahi  %2,31\n"
+                "   srl  %2,5\n"
+                "0: c    %1,0(%0,%4)\n"
                 "   jne  1f\n"
-                "   ahi  2,4\n"
-                "   brct 1,0b\n"
-                "   lr   2,%1\n"
+                "   ahi  %0,4\n"
+                "   brct %2,0b\n"
+                "   lr   %0,%3\n"
                 "   j    4f\n"
-                "1: l    1,0(2,%2)\n"
-                "   sll  2,3\n"
-                "   tml  1,0xFFFF\n"
+                "1: l    %2,0(%0,%4)\n"
+                "   sll  %0,3\n"
+                "   lhi  %1,0xff\n"
+                "   tml  %2,0xffff\n"
                 "   jno  2f\n"
-                "   ahi  2,16\n"
-                "   srl  1,16\n"
-                "2: tml  1,0x00FF\n"
+                "   ahi  %0,16\n"
+                "   srl  %2,16\n"
+                "2: tml  %2,0x00ff\n"
                 "   jno  3f\n"
-                "   ahi  2,8\n"
-                "   srl  1,8\n"
-                "3: n    1,%3\n"
-                "   ic   1,0(1,%4)\n"
-                "   n    1,%3\n"
-                "   ar   2,1\n"
-                "4: lr   %0,2"
-                : "=d" (res) : "a" (size), "a" (addr),
-                  "m" (mask), "a" (&_zb_findmap)
-                : "cc", "0", "1", "2" );
+                "   ahi  %0,8\n"
+                "   srl  %2,8\n"
+                "3: nr   %2,%1\n"
+                "   ic   %2,0(%2,%5)\n"
+                "   alr  %0,%2\n"
+                "4:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+                : "a" (size), "a" (addr), "a" (&_zb_findmap) : "cc" );
+        return (res < size) ? res : size;
+}
+
+static inline int find_first_bit(void * addr, unsigned size)
+{
+	unsigned long cmp, count;
+        int res;
+
+        if (!size)
+                return 0;
+        __asm__("   slr  %1,%1\n"
+                "   lr   %2,%3\n"
+                "   slr  %0,%0\n"
+                "   ahi  %2,31\n"
+                "   srl  %2,5\n"
+                "0: c    %1,0(%0,%4)\n"
+                "   jne  1f\n"
+                "   ahi  %0,4\n"
+                "   brct %2,0b\n"
+                "   lr   %0,%3\n"
+                "   j    4f\n"
+                "1: l    %2,0(%0,%4)\n"
+                "   sll  %0,3\n"
+                "   lhi  %1,0xff\n"
+                "   tml  %2,0xffff\n"
+                "   jnz  2f\n"
+                "   ahi  %0,16\n"
+                "   srl  %2,16\n"
+                "2: tml  %2,0x00ff\n"
+                "   jnz  3f\n"
+                "   ahi  %0,8\n"
+                "   srl  %2,8\n"
+                "3: nr   %2,%1\n"
+                "   ic   %2,0(%2,%5)\n"
+                "   alr  %0,%2\n"
+                "4:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+                : "a" (size), "a" (addr), "a" (&_sb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
-static __inline__ int find_next_zero_bit (void * addr, int size, int offset)
+static inline int find_next_zero_bit (void * addr, int size, int offset)
 {
-        static const int mask = 0xffL;
         unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
-        unsigned long bitvec;
+        unsigned long bitvec, reg;
         int set, bit = offset & 31, res;
 
         if (bit) {
@@ -654,23 +572,21 @@
                  * Look for zero in first word
                  */
                 bitvec = (*p) >> bit;
-                __asm__("   lr   1,%1\n"
-                        "   sr   %0,%0\n"
-                        "   tml  1,0xFFFF\n"
+                __asm__("   slr  %0,%0\n"
+                        "   lhi  %2,0xff\n"
+                        "   tml  %1,0xffff\n"
                         "   jno  0f\n"
                         "   ahi  %0,16\n"
-                        "   srl  1,16\n"
-                        "0: tml  1,0x00FF\n"
+                        "   srl  %1,16\n"
+                        "0: tml  %1,0x00ff\n"
                         "   jno  1f\n"
                         "   ahi  %0,8\n"
-                        "   srl  1,8\n"
-                        "1: n    1,%2\n"
-                        "   ic   1,0(1,%3)\n"
-                        "   n    1,%2\n"
-                        "   ar   %0,1"
-                        : "=d&" (set) : "d" (bitvec),
-                          "m" (mask), "a" (&_zb_findmap)
-                          : "cc", "1" );
+                        "   srl  %1,8\n"
+                        "1: nr   %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   alr  %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_zb_findmap) : "cc" );
                 if (set < (32 - bit))
                         return set + offset;
                 offset += 32 - bit;
@@ -683,72 +599,175 @@
         return (offset + res);
 }
 
+static inline int find_next_bit (void * addr, int size, int offset)
+{
+        unsigned long * p = ((unsigned long *) addr) + (offset >> 5);
+        unsigned long bitvec, reg;
+        int set, bit = offset & 31, res;
+
+        if (bit) {
+                /*
+                 * Look for set bit in first word
+                 */
+                bitvec = (*p) >> bit;
+                __asm__("   slr  %0,%0\n"
+                        "   lhi  %2,0xff\n"
+                        "   tml  %1,0xffff\n"
+                        "   jnz  0f\n"
+                        "   ahi  %0,16\n"
+                        "   srl  %1,16\n"
+                        "0: tml  %1,0x00ff\n"
+                        "   jnz  1f\n"
+                        "   ahi  %0,8\n"
+                        "   srl  %1,8\n"
+                        "1: nr   %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   alr  %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_sb_findmap) : "cc" );
+                if (set < (32 - bit))
+                        return set + offset;
+                offset += 32 - bit;
+                p++;
+        }
+        /*
+         * No set bit yet, search remaining full words for a bit
+         */
+        res = find_first_bit (p, size - 32 * (p - (unsigned long *) addr));
+        return (offset + res);
+}
+
 /*
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
 {
-        static const int mask = 0xffL;
+	unsigned long reg;
         int result;
 
-        __asm__("   lr   1,%1\n"
-                "   sr   %0,%0\n"
-                "   tml  1,0xFFFF\n"
+        __asm__("   slr  %0,%0\n"
+                "   lhi  %2,0xff\n"
+                "   tml  %1,0xffff\n"
                 "   jno  0f\n"
                 "   ahi  %0,16\n"
-                "   srl  1,16\n"
-                "0: tml  1,0x00FF\n"
+                "   srl  %1,16\n"
+                "0: tml  %1,0x00ff\n"
                 "   jno  1f\n"
                 "   ahi  %0,8\n"
-                "   srl  1,8\n"
-                "1: n    1,%2\n"
-                "   ic   1,0(1,%3)\n"
-                "   n    1,%2\n"
-                "   ar   %0,1"
-                : "=d&" (result) : "d" (word), 
-                  "m" (mask), "a" (&_zb_findmap)
-                : "cc", "1" );
+                "   srl  %1,8\n"
+                "1: nr   %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   alr  %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_zb_findmap) : "cc" );
+        return result;
+}
 
+/*
+ * __ffs = find first bit in word. Undefined if no bit exists,
+ * so code should check against 0UL first..
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+	unsigned long reg, result;
+
+        __asm__("   slr  %0,%0\n"
+                "   lhi  %2,0xff\n"
+                "   tml  %1,0xffff\n"
+                "   jnz  0f\n"
+                "   ahi  %0,16\n"
+                "   srl  %1,16\n"
+                "0: tml  %1,0x00ff\n"
+                "   jnz  1f\n"
+                "   ahi  %0,8\n"
+                "   srl  %1,8\n"
+                "1: nr   %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   alr  %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_sb_findmap) : "cc" );
         return result;
 }
 
 /*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(unsigned long *b)
+{
+	return find_first_bit(b, 140);
+}
+
+/*
  * 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).
  */
 
-extern int __inline__ ffs (int x)
+extern int inline ffs (int x)
 {
-        int r;
+        int r = 1;
 
         if (x == 0)
-          return 0;
-        __asm__("    lr   %%r1,%1\n"
-                "    sr   %0,%0\n"
-                "    tml  %%r1,0xFFFF\n"
+		return 0;
+        __asm__("    tml  %1,0xffff\n"
                 "    jnz  0f\n"
+                "    srl  %1,16\n"
                 "    ahi  %0,16\n"
-                "    srl  %%r1,16\n"
-                "0:  tml  %%r1,0x00FF\n"
+                "0:  tml  %1,0x00ff\n"
                 "    jnz  1f\n"
+                "    srl  %1,8\n"
                 "    ahi  %0,8\n"
-                "    srl  %%r1,8\n"
-                "1:  tml  %%r1,0x000F\n"
+                "1:  tml  %1,0x000f\n"
                 "    jnz  2f\n"
+                "    srl  %1,4\n"
                 "    ahi  %0,4\n"
-                "    srl  %%r1,4\n"
-                "2:  tml  %%r1,0x0003\n"
+                "2:  tml  %1,0x0003\n"
                 "    jnz  3f\n"
+                "    srl  %1,2\n"
                 "    ahi  %0,2\n"
-                "    srl  %%r1,2\n"
-                "3:  tml  %%r1,0x0001\n"
+                "3:  tml  %1,0x0001\n"
                 "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
-                : "=&d" (r) : "d" (x) : "cc", "1" );
-        return r+1;
+                : "=&d" (r), "+d" (x) : : "cc" );
+        return r;
+}
+
+/*
+ * fls: find last bit set.
+ */
+extern __inline__ int fls(int x)
+{
+	int r = 32;
+
+	if (x == 0)
+		return 0;
+	__asm__("    tmh  %1,0xffff\n"
+		"    jz   0f\n"
+		"    sll  %1,16\n"
+		"    ahi  %0,-16\n"
+		"0:  tmh  %1,0xff00\n"
+		"    jz   1f\n"
+		"    sll  %1,8\n"
+		"    ahi  %0,-8\n"
+		"1:  tmh  %1,0xf000\n"
+		"    jz   2f\n"
+		"    sll  %1,4\n"
+		"    ahi  %0,-4\n"
+		"2:  tmh  %1,0xc000\n"
+		"    jz   3f\n"
+		"    sll  %1,2\n"
+		"    ahi  %0,-2\n"
+		"3:  tmh  %1,0x8000\n"
+		"    jz   4f\n"
+		"    ahi  %0,-1\n"
+		"4:"
+		: "+d" (r), "+d" (x) : : "cc" );
+	return r;
 }
 
 /*
@@ -776,51 +795,51 @@
 #define ext2_set_bit(nr, addr)       test_and_set_bit((nr)^24, addr)
 #define ext2_clear_bit(nr, addr)     test_and_clear_bit((nr)^24, addr)
 #define ext2_test_bit(nr, addr)      test_bit((nr)^24, addr)
-static __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
+static inline int ext2_find_first_zero_bit(void *vaddr, unsigned size)
 {
+	unsigned long cmp, count;
         int res;
 
         if (!size)
                 return 0;
-        __asm__("   lhi  0,-1\n"
-                "   lr   1,%1\n"
-                "   ahi  1,31\n"
-                "   srl  1,5\n"
-                "   sr   2,2\n"
-                "0: c    0,0(2,%2)\n"
+        __asm__("   lhi  %1,-1\n"
+                "   lr   %2,%3\n"
+                "   ahi  %2,31\n"
+                "   srl  %2,5\n"
+                "   slr  %0,%0\n"
+                "0: cl   %1,0(%0,%4)\n"
                 "   jne  1f\n"
-                "   ahi  2,4\n"
-                "   brct 1,0b\n"
-                "   lr   2,%1\n"
+                "   ahi  %0,4\n"
+                "   brct %2,0b\n"
+                "   lr   %0,%3\n"
                 "   j    4f\n"
-                "1: l    1,0(2,%2)\n"
-                "   sll  2,3\n"
-                "   lhi  0,0xff\n"
-                "   ahi  2,24\n"
-                "   tmh  1,0xFFFF\n"
+                "1: l    %2,0(%0,%4)\n"
+                "   sll  %0,3\n"
+                "   ahi  %0,24\n"
+                "   lhi  %1,0xff\n"
+                "   tmh  %2,0xffff\n"
                 "   jo   2f\n"
-                "   ahi  2,-16\n"
-                "   srl  1,16\n"
-                "2: tml  1,0xFF00\n"
+                "   ahi  %0,-16\n"
+                "   srl  %2,16\n"
+                "2: tml  %2,0xff00\n"
                 "   jo   3f\n"
-                "   ahi  2,-8\n"
-                "   srl  1,8\n"
-                "3: nr   1,0\n"
-                "   ic   1,0(1,%3)\n"
-                "   ar   2,1\n"
-                "4: lr   %0,2"
-                : "=d" (res) : "a" (size), "a" (vaddr),
-                  "a" (&_zb_findmap)
-                  : "cc", "0", "1", "2" );
+                "   ahi  %0,-8\n"
+                "   srl  %2,8\n"
+                "3: nr   %2,%1\n"
+                "   ic   %2,0(%2,%5)\n"
+                "   alr  %0,%2\n"
+                "4:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+                : "a" (size), "a" (vaddr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
-static __inline__ int 
+static inline int 
 ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
 {
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 5);
-        unsigned long word;
+        unsigned long word, reg;
         int bit = offset & 31UL, res;
 
         if (offset >= size)
@@ -835,21 +854,20 @@
 		word >>= bit;
                 res = bit;
                 /* Look for zero in first longword */
-                __asm__("   lhi  0,0xff\n"
+                __asm__("   lhi  %2,0xff\n"
                         "   tml  %1,0xffff\n"
-                	"   jno   0f\n"
+                	"   jno  0f\n"
                 	"   ahi  %0,16\n"
                 	"   srl  %1,16\n"
                 	"0: tml  %1,0x00ff\n"
                 	"   jno  1f\n"
                 	"   ahi  %0,8\n"
                 	"   srl  %1,8\n"
-                	"1: nr   %1,0\n"
-                	"   ic   %1,0(%1,%2)\n"
+                	"1: nr   %1,%2\n"
+                	"   ic   %1,0(%1,%3)\n"
                 	"   alr  %0,%1"
-                	: "+&d" (res), "+&a" (word)
-                  	: "a" (&_zb_findmap)
-                	: "cc", "0" );
+                	: "+&d" (res), "+&a" (word), "=&d" (reg)
+                  	: "a" (&_zb_findmap) : "cc" );
                 if (res < 32)
 			return (p - addr)*32 + res;
                 p++;
diff -Nru a/include/asm-s390/byteorder.h b/include/asm-s390/byteorder.h
--- a/include/asm-s390/byteorder.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390/byteorder.h	Sat Jun  8 22:31:52 2002
@@ -13,75 +13,48 @@
 
 #ifdef __GNUC__
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
 {
-  __u32 temp;
-
-  __asm__ __volatile__ (
-          "        st    %0,0(%1)\n"
-          "        icm   %0,8,3(%1)\n"
-          "        icm   %0,4,2(%1)\n"
-          "        icm   %0,2,1(%1)\n"
-          "        ic    %0,0(%1)"
-          : "+&d" (x) : "a" (&temp) : "cc" );
-  return x;
+	__u32 result;
+	
+	__asm__ __volatile__ (
+		"        icm   %0,8,3(%1)\n"
+		"        icm   %0,4,2(%1)\n"
+		"        icm   %0,2,1(%1)\n"
+		"        ic    %0,0(%1)"
+		: "=&d" (result) : "a" (x) : "cc" );
+	return result;
 }
 
-static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
-  __u32 result;
-
-  __asm__ __volatile__ (
-          "        icm   %0,8,3(%1)\n"
-          "        icm   %0,4,2(%1)\n"
-          "        icm   %0,2,1(%1)\n"
-          "        ic    %0,0(%1)"
-          : "=&d" (result) : "a" (x) : "cc" );
-  return result;
+	return ___arch__swab32p(&x);
 }
 
 static __inline__ void ___arch__swab32s(__u32 *x)
 {
-  __asm__ __volatile__ (
-          "        icm   0,8,3(%0)\n"
-          "        icm   0,4,2(%0)\n"
-          "        icm   0,2,1(%0)\n"
-          "        ic    0,0(%0)\n"
-          "        st    0,0(%0)"
-          : : "a" (x) : "0", "memory", "cc");
+	*x = ___arch__swab32p(x);
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
 {
-  __u16 temp;
-
-  __asm__ __volatile__ (
-          "        sth   %0,0(%1)\n"
-          "        icm   %0,2,1(%1)\n"
-          "        ic    %0,0(%1)\n"
-          : "+&d" (x) : "a" (&temp) : "memory", "cc" );
-  return x;
+	__u16 result;
+	
+	__asm__ __volatile__ (
+		"        icm   %0,2,1(%1)\n"
+		"        ic    %0,0(%1)\n"
+		: "=&d" (result) : "a" (x) : "cc" );
+	return result;
 }
 
-static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
-  __u16 result;
-
-  __asm__ __volatile__ (
-          "        sr    %0,%0\n"
-          "        icm   %0,2,1(%1)\n"
-          "        ic    %0,0(%1)\n"
-          : "=&d" (result) : "a" (x) : "cc" );
-  return result;
+	return ___arch__swab16p(&x);
 }
 
 static __inline__ void ___arch__swab16s(__u16 *x)
 {
-  __asm__ __volatile__(
-          "        icm   0,2,1(%0)\n"
-          "        ic    0,0(%0)\n"
-          "        sth   0,0(%0)"
-          : : "a" (x) : "0", "memory", "cc" );
+	*x = ___arch__swab16p(x);
 }
 
 #define __arch__swab32(x) ___arch__swab32(x)
diff -Nru a/include/asm-s390/cacheflush.h b/include/asm-s390/cacheflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/cacheflush.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,18 @@
+#ifndef _S390_CACHEFLUSH_H
+#define _S390_CACHEFLUSH_H
+
+/* Keep includes the same across arches.  */
+#include <linux/mm.h>
+
+/* Caches aren't brain-dead on the s390. */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
+#define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+
+#endif /* _S390_CACHEFLUSH_H */
diff -Nru a/include/asm-s390/ccwcache.h b/include/asm-s390/ccwcache.h
--- a/include/asm-s390/ccwcache.h	Sat Jun  8 22:31:52 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/* 
-   * File...........: linux/include/asm-s390/ccwcache.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- */
-#ifndef CCWCACHE_H
-#define CCWCACHE_H
-#include <linux/slab.h>
-#include <asm/irq.h>
-
-#ifndef __KERNEL__
-#define kmem_cache_t void
-#endif /* __KERNEL__ */
-
-typedef struct ccw_req_t {
-	/* eye catcher plus queueing information  */
-	unsigned int magic;	
-	struct ccw_req_t *next;	/* pointer to next ccw_req_t in queue */
-	struct ccw_req_t *int_next;	/* for internal queueing */
-	struct ccw_req_t *int_prev;	/* for internal queueing */
-
-	/* Where to execute what... */
-	void *device;		/* index of the device the req is for */
-	void *req;		/* pointer to originating request */
-	ccw1_t *cpaddr;		/* address of channel program */
-	char status;	        /* reflecting the status of this request */
-	char flags;              /* see below */
-	short retries;		/* A retry counter to be set when filling */
-
-	/* ... and how */
-	int options;		/* options for execution */
-	char lpm;               /* logical path mask                      */
-	void *data;		/* pointer to data area */
-	devstat_t *dstat;	/* The device status in case of an error */
-
-	/* these are important for recovering erroneous requests          */
-	struct ccw_req_t *refers;	/* Does this request refer to another one? */
-	void *function; /* refers to the originating ERP action */ ;
-
-	unsigned long long expires;	/* expiratioj period */
-	/* these are for profiling purposes */
-	unsigned long long buildclk;	/* TOD-clock of request generation */
-	unsigned long long startclk;	/* TOD-clock of request start */
-	unsigned long long stopclk;	/* TOD-clock of request interrupt */
-	unsigned long long endclk;	/* TOD-clock of request termination */
-
-	/* these are for internal use */
-	int cplength;		/* length of the channel program in CCWs */
-	int datasize;		/* amount of additional data in bytes */
-	kmem_cache_t *cache;	/* the cache this data comes from */
-
-} __attribute__ ((aligned(4))) ccw_req_t;
-
-/* 
- * ccw_req_t -> status can be:
- */
-#define CQR_STATUS_EMPTY    0x00	/* request is empty */
-#define CQR_STATUS_FILLED   0x01	/* request is ready to be preocessed */
-#define CQR_STATUS_QUEUED   0x02	/* request is queued to be processed */
-#define CQR_STATUS_IN_IO    0x03	/* request is currently in IO */
-#define CQR_STATUS_DONE     0x04	/* request is completed successfully */
-#define CQR_STATUS_ERROR    0x05	/* request is completed with error */
-#define CQR_STATUS_FAILED   0x06	/* request is finally failed */
-#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
-
-#define CQR_FLAGS_CHAINED  0x01	/* request is chained by another (last CCW is TIC) */
-
-#ifdef __KERNEL__
-#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
- sizeof(struct ccw_req_t) <= 256 ? 256 : 512 )
-
-/* SMALLEST_SLAB(1),... PAGE_SIZE(CCW_NUMBER_CACHES) */
-#define CCW_NUMBER_CACHES (sizeof(struct ccw_req_t) <= 128 ? 6 :\
- sizeof(struct ccw_req_t) <= 256 ? 5 : 4 )
-
-int ccwcache_init (void);
-
-ccw_req_t *ccw_alloc_request (char *magic, int cplength, int additional_data);
-void ccw_free_request (ccw_req_t * request);
-#endif /* __KERNEL__ */
-#endif				/* CCWCACHE_H */
-
-
-
diff -Nru a/include/asm-s390/current.h b/include/asm-s390/current.h
--- a/include/asm-s390/current.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/current.h	Sat Jun  8 22:31:37 2002
@@ -13,16 +13,14 @@
 
 #ifdef __KERNEL__
 
+#include <asm/thread_info.h>
+
 struct task_struct;
 
 static inline struct task_struct * get_current(void)
 {
-        struct task_struct *current;
-        __asm__("lhi   %0,-8192\n\t"
-                "al    %0,0xc40"
-                : "=&r" (current) : : "cc" );
-        return current;
- }
+	return current_thread_info()->task;
+}
 
 #define current get_current()
 
diff -Nru a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
--- a/include/asm-s390/dasd.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/dasd.h	Sat Jun  8 22:31:36 2002
@@ -10,6 +10,10 @@
  *
  * History of changes (starts July 2000)
  * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
+ * 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
+ * 01/23/02 DASD_API_VERSION 3 - added BIODASDPSRD (and BIODASDENAPAV) IOCTL
+ * 02/15/02 DASD_API_VERSION 4 - added BIODASDSATTR IOCTL
+ *         
  */
 
 #ifndef DASD_H
@@ -18,11 +22,126 @@
 
 #define DASD_IOCTL_LETTER 'D'
 
-#if (DASD_API_VERSION == 0)
+#define DASD_API_VERSION 4
+
+/* 
+ * struct dasd_information2_t
+ * represents any data about the device, which is visible to userspace.
+ *  including foramt and featueres.
+ */
+typedef struct dasd_information2_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;     /* length of chanq */
+        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 */
+        unsigned int format;          /* format info like formatted/cdl/ldl/... */
+        unsigned int features;        /* dasd features like 'ro',...            */
+        unsigned int reserved0;       /* reserved for further use ,...          */
+        unsigned int reserved1;       /* reserved for further use ,...          */
+        unsigned int reserved2;       /* reserved for further use ,...          */
+        unsigned int reserved3;       /* reserved for further use ,...          */
+        unsigned int reserved4;       /* reserved for further use ,...          */
+        unsigned int reserved5;       /* reserved for further use ,...          */
+        unsigned int reserved6;       /* reserved for further use ,...          */
+        unsigned int reserved7;       /* reserved for further use ,...          */
+} dasd_information2_t;
+
+/*
+ * values to be used for dasd_information_t.format
+ * 0x00: NOT formatted
+ * 0x01: Linux disc layout
+ * 0x02: Common disc layout
+ */
+#define DASD_FORMAT_NONE 0
+#define DASD_FORMAT_LDL  1
+#define DASD_FORMAT_CDL  2
+/*
+ * values to be used for dasd_information_t.features
+ * 0x00: default features
+ * 0x01: readonly (ro)
+ */
+#define DASD_FEATURE_DEFAULT  0
+#define DASD_FEATURE_READONLY 1
 
 #define DASD_PARTN_BITS 2
 
 /* 
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
+ */
+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;     /* length of chanq */
+        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;
+
+/*
+ * Read Subsystem Data - Perfomance Statistics
+ */ 
+typedef struct dasd_rssd_perf_stats_t {
+	unsigned char  invalid:1;
+	unsigned char  format:3;
+	unsigned char  data_format:4;
+	unsigned char  unit_address;
+	unsigned short device_status;
+	unsigned int   nr_read_normal;
+	unsigned int   nr_read_normal_hits;
+	unsigned int   nr_write_normal;
+	unsigned int   nr_write_fast_normal_hits;
+	unsigned int   nr_read_seq;
+	unsigned int   nr_read_seq_hits;
+	unsigned int   nr_write_seq;
+	unsigned int   nr_write_fast_seq_hits;
+	unsigned int   nr_read_cache;
+	unsigned int   nr_read_cache_hits;
+	unsigned int   nr_write_cache;
+	unsigned int   nr_write_fast_cache_hits;
+	unsigned int   nr_inhibit_cache;
+	unsigned int   nr_bybass_cache;
+	unsigned int   nr_seq_dasd_to_cache;
+	unsigned int   nr_dasd_to_cache;
+	unsigned int   nr_cache_to_dasd;
+	unsigned int   nr_delayed_fast_write;
+	unsigned int   nr_normal_fast_write;
+	unsigned int   nr_seq_fast_write;
+	unsigned int   nr_cache_miss;
+	unsigned char  status2;
+	unsigned int   nr_quick_write_promotes;
+	unsigned char  reserved;
+	unsigned short ssid;
+	unsigned char  reseved2[96];
+} __attribute__((packed)) dasd_rssd_perf_stats_t;
+
+/* 
  * struct profile_info_t
  * holds the profinling information 
  */
@@ -62,30 +181,36 @@
 #define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
 #define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
+
 /* 
- * struct dasd_information_t
- * represents any data about the data, which is visible to userspace
+ * struct attrib_data_t
+ * represents the operation (cache) bits for the device.
+ * Used in DE to influence caching of the DASD.
  */
-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;
+typedef struct attrib_data_t {
+	unsigned char operation:3;     /* cache operation mode */
+	unsigned char reserved:5;      /* cache operation mode */
+	__u16         nr_cyl;          /* no of cyliners for read ahaed */
+	__u8          reserved2[29];   /* for future use */
+} __attribute__ ((packed)) attrib_data_t;
+
+/* definition of operation (cache) bits within attributes of DE */
+#define DASD_NORMAL_CACHE  0x0
+#define DASD_BYPASS_CACHE  0x1
+#define DASD_INHIBIT_LOAD  0x2
+#define DASD_SEQ_ACCESS    0x3
+#define DASD_SEQ_PRESTAGE  0x4
+#define DASD_REC_ACCESS    0x5
+
+
+/********************************************************************************
+ * SECTION: Definition of IOCTLs
+ *
+ * Here ist how the ioctl-nr should be used:
+ *    0 -   31   DASD driver itself
+ *   32 -  239   still open
+ *  240 -  255   reserved for EMC 
+ *******************************************************************************/
 
 /* Disable the volume (for Linux) */
 #define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
@@ -97,15 +222,28 @@
 #define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
 /* reset profiling information of a device */
 #define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* enable PAV */
+#define BIODASDENAPAV  _IO(DASD_IOCTL_LETTER,6)
+
+
 /* 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)
+/* Get information on a dasd device (enhanced) */
+#define BIODASDINFO2   _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
+/* Performance Statistics Read */
+#define BIODASDPSRD    _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_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 */
+/* Set Attributes (cache operations) */
+#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
+
+
 #endif				/* DASD_H */
 
 /*
diff -Nru a/include/asm-s390/debug.h b/include/asm-s390/debug.h
--- a/include/asm-s390/debug.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390/debug.h	Sat Jun  8 22:31:35 2002
@@ -54,7 +54,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
+#define STCK(x)	asm volatile ("STCK 0(%1)" : "=m" (x) : "a" (&(x)) : "cc")
 
 typedef struct __debug_entry debug_entry_t;
 
diff -Nru a/include/asm-s390/ebcdic.h b/include/asm-s390/ebcdic.h
--- a/include/asm-s390/ebcdic.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/ebcdic.h	Sat Jun  8 22:31:37 2002
@@ -24,7 +24,7 @@
 extern __inline__ 
 void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr)
 {
-	if (nr <= 0)
+	if (nr-- <= 0)
 		return;
         __asm__ __volatile__(
 		"   bras 1,1f\n"
@@ -34,7 +34,7 @@
 		"1: ahi  %1,-256\n"
 		"   jp   0b\n"
 		"   ex   %1,0(1)"
-                : "+&a" (addr), "+&a" (nr-1)
+                : "+&a" (addr), "+&a" (nr)
                 : "a" (codepage) : "cc", "memory", "1" );
 }
 
diff -Nru a/include/asm-s390/fsf.h b/include/asm-s390/fsf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/fsf.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,326 @@
+/*
+ * header file for FCP adapter driver for IBM eServer zSeries
+ *
+ * Authors:
+ *      Martin Peschke <mpeschke@de.ibm.com>
+ *      Raimund Schroeder <raimund.schroeder@de.ibm.com>
+ *      Aron Zeh <arzeh@de.ibm.com>
+ *      Wolfgang Taphorn <taphorn@de.ibm.com>
+ *
+ * Copyright (C) 2002 IBM Entwicklung GmbH, IBM Corporation
+ */
+
+#ifndef FSF_H
+#define FSF_H
+
+#define FSF_QTCB_VERSION1			0x00000001
+#define FSF_QTCB_CURRENT_VERSION		FSF_QTCB_VERSION1
+
+/* FSF commands */
+#define	FSF_QTCB_FCP_CMND			0x00000001
+#define	FSF_QTCB_ABORT_FCP_CMND			0x00000002
+#define	FSF_QTCB_OPEN_PORT_WITH_DID		0x00000005
+#define	FSF_QTCB_OPEN_LUN			0x00000006
+#define	FSF_QTCB_CLOSE_LUN			0x00000007
+#define	FSF_QTCB_CLOSE_PORT			0x00000008
+#define	FSF_QTCB_CLOSE_PHYSICAL_PORT		0x00000009
+#define	FSF_QTCB_SEND_ELS			0x0000000B
+#define	FSF_QTCB_SEND_GENERIC			0x0000000C
+#define	FSF_QTCB_EXCHANGE_CONFIG_DATA		0x0000000D
+
+/* FSF QTCB types */
+#define FSF_IO_COMMAND				0x00000001
+#define FSF_SUPPORT_COMMAND			0x00000002
+#define FSF_CONFIG_COMMAND			0x00000003
+
+/* association between FSF command and FSF QTCB type */
+u32 fsf_qtcb_type[] = {
+	[ FSF_QTCB_FCP_CMND ]			= FSF_IO_COMMAND,
+	[ FSF_QTCB_ABORT_FCP_CMND ]		= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_OPEN_PORT_WITH_DID ] 	= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_OPEN_LUN ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_LUN ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_PORT ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_PHYSICAL_PORT ]	= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_SEND_ELS ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_SEND_GENERIC ]		= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_EXCHANGE_CONFIG_DATA ]	= FSF_CONFIG_COMMAND
+};
+
+/* FSF protocol stati */
+#define FSF_PROT_GOOD				0x00000001
+#define FSF_PROT_QTCB_VERSION_ERROR		0x00000010
+#define FSF_PROT_SEQ_NUMB_ERROR			0x00000020
+#define FSF_PROT_UNSUPP_QTCB_TYPE		0x00000040
+#define FSF_PROT_HOST_CONNECTION_INITIALIZING	0x00000080
+#define FSF_PROT_FSF_STATUS_PRESENTED		0x00000100
+#define FSF_PROT_DUPLICATE_REQUEST_ID		0x00000200
+#define FSF_PROT_LINK_DOWN                      0x00000400
+#define FSF_PROT_REEST_QUEUE                    0x00000800
+#define FSF_PROT_ERROR_STATE			0x01000000
+
+/* FSF stati */
+#define FSF_GOOD				0x00000000
+#define FSF_PORT_ALREADY_OPEN			0x00000001
+#define FSF_LUN_ALREADY_OPEN			0x00000002
+#define FSF_PORT_HANDLE_NOT_VALID		0x00000003
+#define FSF_LUN_HANDLE_NOT_VALID		0x00000004
+#define FSF_HANDLE_MISMATCH			0x00000005
+#define FSF_SERVICE_CLASS_NOT_SUPPORTED		0x00000006
+#define FSF_FCPLUN_NOT_VALID			0x00000009
+//#define FSF_ACCESS_DENIED			0x00000010
+#define FSF_ACCESS_TYPE_NOT_VALID		0x00000011
+#define FSF_LUN_IN_USE				0x00000012
+#define FSF_COMMAND_ABORTED_ULP			0x00000020
+#define FSF_COMMAND_ABORTED_ADAPTER		0x00000021
+#define FSF_FCP_COMMAND_DOES_NOT_EXIST		0x00000022
+#define FSF_DIRECTION_INDICATOR_NOT_VALID	0x00000030
+#define FSF_INBOUND_DATA_LENGTH_NOT_VALID	0x00000031	/* FIXME: obsolete? */
+#define FSF_OUTBOUND_DATA_LENGTH_NOT_VALID	0x00000032	/* FIXME: obsolete? */
+#define FSF_CMND_LENGTH_NOT_VALID		0x00000033
+#define FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED	0x00000040
+#define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED	0x00000041
+#define FSF_REQUEST_BUF_NOT_VALID		0x00000042
+#define FSF_RESPONSE_BUF_NOT_VALID		0x00000043
+#define FSF_ELS_COMMAND_REJECTED		0x00000050
+#define FSF_GENERIC_COMMAND_REJECTED		0x00000051
+//#define FSF_AUTHORIZATION_FAILURE		0x00000053
+#define FSF_PORT_BOXED				0x00000059
+//#define FSF_LUN_BOXED				0x0000005A
+#define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
+#define FSF_FCP_RSP_AVAILABLE			0x000000AF
+#define FSF_UNKNOWN_COMMAND			0x000000E2
+//#define FSF_ERROR				0x000000FF 
+
+/* FSF status qualifier, recommendations */
+#define FSF_SQ_NO_RECOM				0x00
+#define FSF_SQ_FCP_RSP_AVAILABLE		0x01
+#define FSF_SQ_RETRY_IF_POSSIBLE		0x02
+#define FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED	0x03
+#define FSF_SQ_INVOKE_LINK_TEST_PROCEDURE	0x04
+#define FSF_SQ_ULP_PROGRAMMING_ERROR		0x05
+#define FSF_SQ_COMMAND_ABORTED			0x06
+#define FSF_SQ_NO_RETRY_POSSIBLE		0x07
+
+/* FSF status qualifier (most significant 4 bytes), local link down */
+#define FSF_PSQ_LINK_NOLIGHT			0x00000004
+#define FSF_PSQ_LINK_WRAPPLUG			0x00000008
+#define FSF_PSQ_LINK_NOFCP			0x00000010
+
+/* payload size in status read buffer */
+#define FSF_STATUS_READ_PAYLOAD_SIZE		4032
+
+/* status types in status read buffer */
+#define FSF_STATUS_READ_PORT_CLOSED		0x00000001
+#define FSF_STATUS_READ_INCOMING_ELS		0x00000002
+#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD	0x00000004
+#define FSF_STATUS_READ_LINK_DOWN		0x00000005	/* FIXME: really? */
+#define FSF_STATUS_READ_LINK_UP          	0x00000006
+
+/* status subtypes in status read buffer */
+#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT	0x00000001
+#define FSF_STATUS_READ_SUB_ERROR_PORT		0x00000002
+
+/* topologie that is detected by the adapter */
+#define FSF_TOPO_ERROR				0x00000000
+#define FSF_TOPO_P2P				0x00000001
+#define FSF_TOPO_FABRIC				0x00000002
+#define FSF_TOPO_AL				0x00000003
+#define FSF_TOPO_FABRIC_VIRT			0x00000004
+
+/* data direction for FCP commands */
+#define FSF_DATADIR_WRITE			0x00000001
+#define FSF_DATADIR_READ			0x00000002
+#define FSF_DATADIR_READ_WRITE			0x00000003
+#define FSF_DATADIR_CMND			0x00000004
+
+/* fc service class */
+#define FSF_CLASS_1				0x00000001
+#define FSF_CLASS_2				0x00000002
+#define FSF_CLASS_3				0x00000003
+
+struct fsf_queue_designator;
+struct fsf_status_read_buffer;
+struct fsf_port_closed_payload;
+struct fsf_bit_error_payload;
+union fsf_prot_status_qual;
+struct fsf_qual_version_error;
+struct fsf_qual_sequence_error;
+struct fsf_qtcb_prefix;
+struct fsf_qtcb_header;
+struct fsf_qtcb_bottom_config;
+struct fsf_qtcb_bottom_support;
+struct fsf_qtcb_bottom_io;
+union fsf_qtcb_bottom;
+
+typedef struct fsf_queue_designator {
+	u8			cssid;
+	u8			chpid;
+	u8			hla;
+	u8			ua;
+	u32			res1;
+} __attribute__ ((packed)) fsf_queue_designator_t;
+
+typedef struct fsf_port_closed_payload {
+	fsf_queue_designator_t	queue_designator;
+	u32			port_handle;
+} __attribute__ ((packed)) fsf_port_closed_payload_t;
+
+typedef struct fsf_bit_error_payload {
+	u32			res1;
+	u32			link_failure_error_count;
+	u32			loss_of_sync_error_count;
+	u32			loss_of_signal_error_count;
+	u32			primitive_sequence_error_count;
+	u32			invalid_transmission_word_error_count;
+	u32			crc_error_count;
+	u32			primitive_sequence_event_timeout_count;
+	u32			elastic_buffer_overrun_error_count;
+	u32			fcal_arbitration_timeout_count;
+	u32			advertised_receive_b2b_credit;
+	u32			current_receive_b2b_credit;
+	u32			advertised_transmit_b2b_credit;
+	u32			current_transmit_b2b_credit;
+} __attribute__ ((packed)) fsf_bit_error_payload_t;
+
+typedef struct fsf_status_read_buffer {
+        u32			status_type;
+        u32			status_subtype;
+        u32			length;
+        u32			res1;
+        fsf_queue_designator_t	queue_designator;
+        u32			d_id;
+        u32			class;
+        u64			fcp_lun;
+        u8			res3[24];
+        u8			payload[FSF_STATUS_READ_PAYLOAD_SIZE];
+} __attribute__ ((packed)) fsf_status_read_buffer_t;
+
+typedef struct fsf_qual_version_error {
+	u32			fsf_version;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_version_error_t;
+
+typedef struct fsf_qual_sequence_error {
+	u32			exp_req_seq_no;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_sequence_error_t;
+
+typedef struct fsf_qual_locallink_error {
+	u32			code;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_locallink_error_t;
+
+typedef union fsf_prot_status_qual {
+	fsf_qual_version_error_t	version_error;
+	fsf_qual_sequence_error_t	sequence_error;
+	fsf_qual_locallink_error_t	locallink_error;
+} __attribute__ ((packed)) fsf_prot_status_qual_t;
+
+typedef struct fsf_qtcb_prefix {
+	u64			req_id;
+	u32			qtcb_version;
+	u32			ulp_info;
+	u32			qtcb_type;
+	u32			req_seq_no;
+	u32			prot_status;
+	fsf_prot_status_qual_t	prot_status_qual;
+	u8			res1[20];
+} __attribute__ ((packed)) fsf_qtcb_prefix_t;
+
+typedef struct fsf_qtcb_header {
+	u64			req_handle;
+	u32			fsf_command;
+	u32			res1;
+	u32			port_handle;
+	u32			lun_handle;
+	u32			res2;
+	u32			fsf_status;
+	u32			fsf_status_qual[4];
+//	fsf_status_qual_t	fsf_status_qual;	FIXME: define union
+	u8			res3[28];
+	u16			log_start;
+	u16			log_length;
+	u8			res4[16];
+} __attribute__ ((packed)) fsf_qtcb_header_t;
+
+typedef u64 fsf_wwn_t;
+
+typedef struct fsf_nport_serv_param {
+	u8			common_serv_param[16];
+	fsf_wwn_t		wwpn;
+	fsf_wwn_t		wwnn;
+	u8			class1_serv_param[16];
+	u8			class2_serv_param[16];
+	u8			class3_serv_param[16];
+	u8			class4_serv_param[16];
+	u8			vendor_version_level[16];
+	u8			res1[16];
+} __attribute__ ((packed)) fsf_nport_serv_param_t;
+
+typedef struct fsf_plogi {
+	u32			code;
+	fsf_nport_serv_param_t	serv_param;
+} __attribute__ ((packed)) fsf_plogi_t;
+
+#define FSF_FCP_CMND_SIZE	288
+#define FSF_FCP_RSP_SIZE	128
+
+typedef struct fsf_qtcb_bottom_io {
+	u32			data_direction;
+	u32			service_class;
+	u8			res1[8];
+	u32			fcp_cmnd_length;
+	u8			res2[12];
+	u8			fcp_cmnd[FSF_FCP_CMND_SIZE];
+	u8			fcp_rsp[FSF_FCP_RSP_SIZE];
+	u8			res3[64];
+} __attribute__ ((packed)) fsf_qtcb_bottom_io_t;
+
+typedef struct fsf_qtcb_bottom_support {
+	u8			res1[16];
+	u32			d_id;
+	u32			res2;
+	u64			fcp_lun;
+	u64			res3;
+	u64			req_handle;
+	u32			service_class;
+	u8			res4[3];
+	u8			timeout;
+	u8			res5[184];
+	u32			els1_length;
+	u32			els2_length;
+	u64			res6;
+	u8			els[256];
+} __attribute__ ((packed)) fsf_qtcb_bottom_support_t;
+
+typedef struct fsf_qtcb_bottom_config {
+	u32			lic_version;
+	u32			res1;
+	u32			high_qtcb_version;
+	u32			low_qtcb_version;
+	u32			max_qtcb_size;
+	u8			res2[12];
+	u32			fc_topology;
+	u32			fc_link_speed;
+	u32			adapter_type;
+	u32			peer_d_id;
+	u8			res3[12];
+	u32			s_id;
+	fsf_nport_serv_param_t	nport_serv_param;
+	u8			res4[320];
+} __attribute__ ((packed)) fsf_qtcb_bottom_config_t;
+
+typedef union fsf_qtcb_bottom {
+	fsf_qtcb_bottom_io_t		io;
+	fsf_qtcb_bottom_support_t	support;
+	fsf_qtcb_bottom_config_t	config;
+} fsf_qtcb_bottom_t;
+
+typedef struct fsf_qtcb {
+	fsf_qtcb_prefix_t	prefix;
+	fsf_qtcb_header_t	header;
+	fsf_qtcb_bottom_t	bottom;
+} __attribute__ ((packed)) fsf_qtcb_t;
+
+#endif	/* FSF_H */
diff -Nru a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
--- a/include/asm-s390/hardirq.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390/hardirq.h	Sat Jun  8 22:31:52 2002
@@ -16,6 +16,7 @@
 #include <linux/threads.h>
 #include <asm/lowcore.h>
 #include <linux/sched.h>
+#include <linux/cache.h>
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
diff -Nru a/include/asm-s390/idals.h b/include/asm-s390/idals.h
--- a/include/asm-s390/idals.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/idals.h	Sat Jun  8 22:31:36 2002
@@ -1,74 +1,117 @@
 /* 
-   * File...........: linux/include/asm-s390x/idals.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
+ * File...........: linux/include/asm-s390x/idals.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+ 
+ * History of changes
+ * 07/24/00 new file
+ * 05/04/02 code restructuring.
  */
+
+#ifndef _S390_IDALS_H
+#define _S390_IDALS_H
+
 #include <linux/config.h>
+#include <linux/errno.h>
 #include <asm/irq.h>
 
-#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */
 #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline addr_t *
-idal_alloc ( int nridaws )
+/*
+ * Test if an address/length pair needs an idal list.
+ */
+static inline int
+idal_is_needed(void *vaddr, unsigned int length)
 {
-	if ( nridaws > 33 )
-		BUG();
-	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
+#if defined(CONFIG_ARCH_S390X)
+	return ((__pa(vaddr) + length) >> 31) != 0;
+#else
+	return 0;
+#endif
 }
 
-static inline void 
-idal_free ( addr_t *idal )
+
+/*
+ * Return the number of idal words needed for an address/length pair.
+ */
+static inline unsigned int
+idal_nr_words(void *vaddr, unsigned int length)
 {
-	kfree (idal);
+#if defined(CONFIG_ARCH_S390X)
+	if (idal_is_needed(vaddr, length))
+		return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + 
+			(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+#endif
+	return 0;
 }
 
+/*
+ * Create the list of idal words for an address/length pair.
+ */
+static inline unsigned long *
+idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
+{
 #if defined(CONFIG_ARCH_S390X)
-extern unsigned long __create_idal(unsigned long address, int count);
+	unsigned long paddr;
+	unsigned int cidaw;
+
+	paddr = __pa(vaddr);
+	cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length + 
+		 (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	*idaws++ = paddr;
+	paddr &= -IDA_BLOCK_SIZE;
+	while (--cidaw > 0) {
+		paddr += IDA_BLOCK_SIZE;
+		*idaws++ = paddr;
+	}
 #endif
+	return idaws;
+}
 
 /*
- * Function: set_normalized_cda
- * sets the address of the data in CCW
- * if necessary it allocates an IDAL and sets sthe appropriate flags
+ * Sets the address of the data in CCW.
+ * If necessary it allocates an IDAL and sets the appropriate flags.
  */
 static inline int
-set_normalized_cda(ccw1_t * ccw, unsigned long address)
+set_normalized_cda(ccw1_t * ccw, void *vaddr)
 {
-	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;
+	unsigned int nridaws;
+	unsigned long *idal;
+
+	if (ccw->flags & CCW_FLAG_IDA)
+		return -EINVAL;
+	nridaws = idal_nr_words(vaddr, ccw->count);
+	if (nridaws > 0) {
+		idal = kmalloc(nridaws * sizeof(unsigned long),
+			       GFP_ATOMIC | GFP_DMA );
+		if (idal == NULL)
+			return -ENOMEM;
+		idal_create_words(idal, vaddr, ccw->count);
+		ccw->flags |= CCW_FLAG_IDA;
+		vaddr = idal;
 	}
 #endif
-	ccw->cda = (__u32) address;
-	return ret;
+	ccw->cda = (__u32)(unsigned long) vaddr;
+	return 0;
 }
 
 /*
- * Function: clear_normalized_cda
- * releases any allocated IDAL related to the CCW
+ * Releases any allocated IDAL related to the CCW.
  */
 static inline void
-clear_normalized_cda ( ccw1_t * ccw ) 
+clear_normalized_cda(ccw1_t * ccw)
 {
 #if defined(CONFIG_ARCH_S390X)
-	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
-		ccw -> flags &= ~CCW_FLAG_IDA;
+	if (ccw->flags & CCW_FLAG_IDA) {
+		kfree((void *)(unsigned long) ccw->cda);
+		ccw->flags &= ~CCW_FLAG_IDA;
 	}
 #endif
-	ccw -> cda = 0;
+	ccw->cda = 0;
 }
 
+#endif
diff -Nru a/include/asm-s390/init.h b/include/asm-s390/init.h
--- a/include/asm-s390/init.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/init.h	Sat Jun  8 22:31:37 2002
@@ -4,26 +4,4 @@
  *  S390 version
  */
 
-#ifndef _S390_INIT_H
-#define _S390_INIT_H
-
-#define __init __attribute__ ((constructor))
-
-/* don't know, if need on S390 */
-#define __initdata
-#define __initfunc(__arginit) \
-        __arginit __init; \
-        __arginit
-/* For assembly routines
- * need to define ?
- */
-/*
-#define __INIT          .section        ".text.init",#alloc,#execinstr
-#define __FINIT .previous
-#define __INITDATA      .section        ".data.init",#alloc,#write
-*/
-
-#define __cacheline_aligned __attribute__ ((__aligned__(256)))
-
-#endif
-
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -Nru a/include/asm-s390/io.h b/include/asm-s390/io.h
--- a/include/asm-s390/io.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/io.h	Sat Jun  8 22:31:51 2002
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Nru a/include/asm-s390/irq.h b/include/asm-s390/irq.h
--- a/include/asm-s390/irq.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/irq.h	Sat Jun  8 22:31:37 2002
@@ -10,14 +10,12 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
 #define INVALID_STORAGE_AREA ((void *)(-1 - 0x3FFF ))
 
-extern int disable_irq(unsigned int);
-extern int enable_irq(unsigned int);
-
 /*
  * path management control word
  */
@@ -362,6 +360,92 @@
   /* extended part */
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
 
 #endif /* __KERNEL__ */
 /*
@@ -491,6 +575,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -513,11 +598,6 @@
            __u8           lpm,          /* logical path mask */
            unsigned long  flag);        /* flags : see above */
 
-int start_IO( int           irq,       /* IRQ aka. subchannel number */
-              ccw1_t       *cpa,       /* logical channel program address */
-              unsigned long  intparm,   /* interruption parameter */
-              __u8          lpm,       /* logical path mask */
-              unsigned int  flag);     /* flags : see above */
 
 void do_crw_pending( void  );	         /* CRW handler */
 
@@ -531,14 +611,6 @@
               unsigned long intparm,     /* dummy intparm */
               unsigned long flag);       /* possible DOIO_WAIT_FOR_INTERRUPT */
 
-int process_IRQ( struct pt_regs regs,
-                 unsigned int   irq,
-                 unsigned int   intparm);
-
-
-int enable_cpu_sync_isc ( int irq );
-int disable_cpu_sync_isc( int irq );
-
 typedef struct {
      int          irq;                  /* irq, aka. subchannel */
      __u16        devno;                /* device number */
@@ -546,8 +618,6 @@
      senseid_t    sid_data;             /* senseID data */
      } s390_dev_info_t;
 
-int get_dev_info( int irq, s390_dev_info_t *);   /* to be eliminated - don't use */
-
 int get_dev_info_by_irq  ( int irq, s390_dev_info_t *pdi);
 int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi);
 
@@ -560,8 +630,6 @@
 int read_dev_chars( int irq, void **buffer, int length );
 int read_conf_data( int irq, void **buffer, int *length, __u8 lpm );
 
-int  s390_DevicePathVerification( int irq, __u8 domask );
-
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -570,7 +638,6 @@
                               void                    *dev_id);
 
 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 );
 
@@ -630,11 +697,6 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-                "    lr   1,%1\n"
-                "    msch 0(%2)\n"
-                "0:  ipm  %0\n"
-                "    srl  %0,28\n"
-                "1:\n"
 #else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
@@ -743,6 +805,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -805,6 +882,20 @@
                 : "cc" );
         return ccode;
 }
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
@@ -813,13 +904,6 @@
  * Interrupt entry/exit code at both C and assembly level
  */
 
-void mask_irq(unsigned int irq);
-void unmask_irq(unsigned int irq);
-
-#define MAX_IRQ_SOURCES 128
-
-extern spinlock_t irq_controller_lock;
-
 #ifdef CONFIG_SMP
 
 #include <asm/atomic.h>
@@ -849,17 +933,10 @@
 #define __STR(x) #x
 #define STR(x) __STR(x)
 
-#ifdef CONFIG_SMP
-
-/*
- *      SMP has a few special interrupts for IPI messages
- */
-
-#endif /* CONFIG_SMP */
-
 /*
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
+ * is this ever used anyway?
  */
 extern char _stext;
 static inline void s390_do_profile (unsigned long addr)
@@ -883,16 +960,19 @@
 
 #include <asm/s390io.h>
 
+#define get_irq_lock(irq) &ioinfo[irq]->irq_lock
+
 #define s390irq_spin_lock(irq) \
-        spin_lock(&(ioinfo[irq]->irq_lock))
+        spin_lock(get_irq_lock(irq))
 
 #define s390irq_spin_unlock(irq) \
-        spin_unlock(&(ioinfo[irq]->irq_lock))
+        spin_unlock(get_irq_lock(irq))
 
 #define s390irq_spin_lock_irqsave(irq,flags) \
-        spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
+        spin_lock_irqsave(get_irq_lock(irq), flags)
+
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
-        spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+        spin_unlock_irqrestore(get_irq_lock(irq), flags)
 
 #define touch_nmi_watchdog() do { } while(0)
 
diff -Nru a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
--- a/include/asm-s390/lowcore.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/lowcore.h	Sat Jun  8 22:31:37 2002
@@ -45,6 +45,9 @@
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
+
+#define __LC_JIFFY_TIMER		0xC80
+
 #define __LC_PANIC_MAGIC                0xE00
 
 #define __LC_PFAULT_INTPARM             0x080
@@ -161,7 +164,7 @@
 	/* entry.S sensitive area end */
 
         /* SMP info area: defined by DJB */
-        __u64        jiffy_timer_cc;           /* 0xc80 */
+        __u64        jiffy_timer;              /* 0xc80 */
 	atomic_t     ext_call_fast;            /* 0xc88 */
         __u8         pad11[0xe00-0xc8c];       /* 0xc8c */
 
@@ -182,12 +185,12 @@
 extern struct _lowcore *lowcore_ptr[];
 
 #ifndef CONFIG_SMP
-#define get_cpu_lowcore(cpu)    S390_lowcore
-#define safe_get_cpu_lowcore(cpu) S390_lowcore
+#define get_cpu_lowcore(cpu)      (&S390_lowcore)
+#define safe_get_cpu_lowcore(cpu) (&S390_lowcore)
 #else
-#define get_cpu_lowcore(cpu)    (*lowcore_ptr[cpu])
+#define get_cpu_lowcore(cpu)      (lowcore_ptr[(cpu)])
 #define safe_get_cpu_lowcore(cpu) \
-        ((cpu)==smp_processor_id() ? S390_lowcore:(*lowcore_ptr[(cpu)]))
+        ((cpu) == smp_processor_id() ? &S390_lowcore : lowcore_ptr[(cpu)])
 #endif
 #endif /* __ASSEMBLY__ */
 
diff -Nru a/include/asm-s390/mman.h b/include/asm-s390/mman.h
--- a/include/asm-s390/mman.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390/mman.h	Sat Jun  8 22:31:35 2002
@@ -12,6 +12,7 @@
 #define PROT_READ	0x1		/* page can be read */
 #define PROT_WRITE	0x2		/* page can be written */
 #define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_SEM	0x8		/* page may be used for atomic ops */
 #define PROT_NONE	0x0		/* page can not be accessed */
 
 #define MAP_SHARED	0x01		/* Share changes */
diff -Nru a/include/asm-s390/page.h b/include/asm-s390/page.h
--- a/include/asm-s390/page.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/page.h	Sat Jun  8 22:31:36 2002
@@ -59,8 +59,8 @@
 			      : "memory" );
 }
 
-#define clear_user_page(page, vaddr)	clear_page(page)
-#define copy_user_page(to, from, vaddr)	copy_page(to, from)
+#define clear_user_page(page, vaddr, pg)	clear_page(page)
+#define copy_user_page(to, from, vaddr, pg)	copy_page(to, from)
 
 #define BUG() do { \
         printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
@@ -116,9 +116,13 @@
 #define __PAGE_OFFSET           0x0UL
 #define PAGE_OFFSET             0x0UL
 #define __pa(x)                 (unsigned long)(x)
-#define __va(x)                 (void *)(x)
-#define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define __va(x)                 (void *)(unsigned long)(x)
+#define pfn_to_page(pfn)	(mem_map + (pfn))
+#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
+#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -Nru a/include/asm-s390/pci.h b/include/asm-s390/pci.h
--- a/include/asm-s390/pci.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/pci.h	Sat Jun  8 22:31:51 2002
@@ -4,6 +4,7 @@
 /* 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.
  */
+#define PCI_DMA_BUS_IS_PHYS (1)
 
 #endif /* __ASM_S390_PCI_H */
 
diff -Nru a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/percpu.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_S390_PERCPU__
+#define __ARCH_S390_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_S390_PERCPU__ */
diff -Nru a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
--- a/include/asm-s390/pgalloc.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/pgalloc.h	Sat Jun  8 22:31:51 2002
@@ -17,10 +17,7 @@
 #include <asm/processor.h>
 #include <linux/threads.h>
 
-#define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist (S390_lowcore.cpu_data.pte_quick)
-#define pgtable_cache_size (S390_lowcore.cpu_data.pgtable_cache_sz)
+#define check_pgt_cache()	do {} while (0)
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
@@ -28,67 +25,35 @@
  * if any.
  */
 
-extern __inline__ pgd_t* get_pgd_slow(void)
-{
-	pgd_t *ret;
-        int i;
-
-	ret = (pgd_t *) __get_free_pages(GFP_KERNEL,1);
-        if (ret != NULL)
-		for (i = 0; i < USER_PTRS_PER_PGD; i++)
-			pmd_clear(pmd_offset(ret + i, i*PGDIR_SIZE));
-	return ret;
-}
-
-extern __inline__ pgd_t* get_pgd_fast(void)
-{
-        unsigned long *ret = pgd_quicklist;
-	
-        if (ret != NULL) {
-                pgd_quicklist = (unsigned long *)(*ret);
-                ret[0] = ret[1];
-                pgtable_cache_size -= 2;
-        }
-        return (pgd_t *)ret;
-}
-
-extern __inline__ pgd_t *pgd_alloc(struct mm_struct *mm)
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 {
 	pgd_t *pgd;
+	int i;
 
-	pgd = get_pgd_fast();
-	if (!pgd)
-		pgd = get_pgd_slow();
+	pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,1);
+        if (pgd != NULL)
+		for (i = 0; i < USER_PTRS_PER_PGD; i++)
+			pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
 	return pgd;
 }
 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
-{
-        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
-        pgd_quicklist = (unsigned long *) pgd;
-        pgtable_cache_size += 2;
-}
-
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static inline void pgd_free(pgd_t *pgd)
 {
         free_pages((unsigned long) pgd, 1);
 }
 
-#define pgd_free(pgd)           free_pgd_fast(pgd)
-
 /*
  * page middle directory allocation/free routines.
  * We don't use pmd cache, so these are dummy routines. This
  * code never triggers because the pgd will always be present.
  */
-#define pmd_alloc_one_fast(mm, address) ({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm,address)       ({ BUG(); ((pmd_t *)2); })
 #define pmd_free(x)                     do { } while (0)
-#define pmd_free_slow(x)		do { } while (0)
-#define pmd_free_fast(x)                do { } while (0)
+#define pmd_free_tlb(tlb,x)		do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
 
-extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
+static inline void 
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
 	pmd_val(pmd[0]) = _PAGE_TABLE + __pa(pte);
 	pmd_val(pmd[1]) = _PAGE_TABLE + __pa(pte+256);
@@ -96,50 +61,53 @@
 	pmd_val(pmd[3]) = _PAGE_TABLE + __pa(pte+768);
 }
 
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
+{
+	pmd_populate_kernel(mm, pmd, (pte_t *)((page-mem_map) << PAGE_SHIFT));
+}
+
 /*
  * page table entry allocation/free routines.
  */
-extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
 {
 	pte_t *pte;
+	int count;
         int i;
 
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pte != NULL) {
-		for (i=0; i < PTRS_PER_PTE; i++)
-			pte_clear(pte+i);
-	}
+	count = 0;
+	do {
+		pte = (pte_t *) __get_free_page(GFP_KERNEL);
+		if (pte != NULL) {
+			for (i=0; i < PTRS_PER_PTE; i++)
+				pte_clear(pte+i);
+		} else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pte && (count++ < 10));
 	return pte;
 }
 
-extern __inline__ pte_t *
-pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
-        unsigned long *ret = (unsigned long *) pte_quicklist;
-
-        if (ret != NULL) {
-                pte_quicklist = (unsigned long *)(*ret);
-                ret[0] = ret[1];
-                pgtable_cache_size--;
-        }
-        return (pte_t *)ret;
+	return virt_to_page(pte_alloc_one_kernel(mm, vmaddr));
 }
 
-extern __inline__ void pte_free_fast(pte_t *pte)
+static inline void pte_free_kernel(pte_t *pte)
 {
-        *(unsigned long *)pte = (unsigned long) pte_quicklist;
-        pte_quicklist = (unsigned long *) pte;
-        pgtable_cache_size++;
+        free_page((unsigned long) pte);
 }
 
-extern __inline__ void pte_free_slow(pte_t *pte)
+static inline void pte_free(struct page *pte)
 {
-        free_page((unsigned long) pte);
+        __free_page(pte);
 }
 
-#define pte_free(pte)           pte_free_fast(pte)
-
-extern int do_check_pgt_cache(int, int);
+#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
 
 /*
  * This establishes kernel virtual mappings (e.g., as a result of a
@@ -147,151 +115,6 @@
  * there is nothing to do here... :)
  */
 #define set_pgdir(addr,entry) do { } while(0)
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs 
- *    called only from vmalloc/vfree
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(vma, start, end) flushes a range of pages
- *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
- */
-
-/*
- * S/390 has three ways of flushing TLBs
- * 'ptlb' does a flush of the local processor
- * 'csp' flushes the TLBs on all PUs of a SMP
- * 'ipte' invalidates a pte in a page table and flushes that out of
- * the TLBs of all PUs of a SMP
- */
-
-#define local_flush_tlb() \
-do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
-
-
-#ifndef CONFIG_SMP
-
-/*
- * We always need to flush, since s390 does not flush tlb
- * on each context switch
- */
-
-static inline void flush_tlb(void)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_all(void)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long addr)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	local_flush_tlb();
-}
-
-#else
-
-#include <asm/smp.h>
-
-extern void smp_ptlb_all(void);
-static inline void global_flush_tlb_csp(void)
-{
-	int cs1=0,dum=0;
-	int *adr;
-	long long dummy=0;
-	adr = (int*) (((int)(((int*) &dummy)+1) & 0xfffffffc)|1);
-	__asm__ __volatile__("lr    2,%0\n\t"
-                             "lr    3,%1\n\t"
-                             "lr    4,%2\n\t"
-                             "csp   2,4" :
-                             : "d" (cs1), "d" (dum), "d" (adr)
-                             : "2", "3", "4");
-}
-static inline void global_flush_tlb(void)
-{
-	if (MACHINE_HAS_CSP)
-		global_flush_tlb_csp();
-	else
-		smp_ptlb_all();
-}
-
-/*
- * We only have to do global flush of tlb if process run since last
- * flush on any other pu than current. 
- * If we have threads (mm->count > 1) we always do a global flush, 
- * since the process runs on more than one processor at the same time.
- */
-
-static inline void __flush_tlb_mm(struct mm_struct * mm)
-{
-	if ((smp_num_cpus > 1) &&
-	    ((atomic_read(&mm->mm_count) != 1) ||
-	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
-		global_flush_tlb();
-	} else {                 
-		local_flush_tlb();
-	}
-}
-
-static inline void flush_tlb(void)
-{
-	__flush_tlb_mm(current->mm);
-}
-static inline void flush_tlb_all(void)
-{
-	global_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-	__flush_tlb_mm(mm); 
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long addr)
-{
-	__flush_tlb_mm(vma->vm_mm);
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	__flush_tlb_mm(vma->vm_mm); 
-}
-
-#endif
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-                                      unsigned long start, unsigned long end)
-{
-        /* S/390 does not keep any page table caches in TLB */
-}
-
-
-static inline int ptep_test_and_clear_and_flush_young(struct vm_area_struct *vma, 
-                                                      unsigned long address, pte_t *ptep)
-{
-	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_young(ptep);
-}
-
-static inline int ptep_test_and_clear_and_flush_dirty(struct vm_area_struct *vma, 
-                                                      unsigned long address, pte_t *ptep)
-{
-	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_dirty(ptep);
-}
 
 static inline pte_t ptep_invalidate(struct vm_area_struct *vma, 
                                     unsigned long address, pte_t *ptep)
diff -Nru a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
--- a/include/asm-s390/pgtable.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/pgtable.h	Sat Jun  8 22:31:51 2002
@@ -33,17 +33,6 @@
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
 
-/* Caches aren't brain-dead on S390. */
-#define flush_cache_all()                       do { } while (0)
-#define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(vma, start, end)      do { } while (0)
-#define flush_cache_page(vma, vmaddr)           do { } while (0)
-#define flush_page_to_ram(page)                 do { } while (0)
-#define flush_dcache_page(page)			do { } while (0)
-#define flush_icache_range(start, end)          do { } while (0)
-#define flush_icache_page(vma,pg)               do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
-
 /*
  * The S390 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
@@ -156,7 +145,8 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004	       /* Software			   */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -189,12 +179,14 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID  __pgprot(_PAGE_INVALID)
-#define PAGE_NONE     __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY     __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED   __pgprot(_PAGE_PRESENT)
-#define PAGE_KERNEL   __pgprot(_PAGE_PRESENT)
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
@@ -202,21 +194,21 @@
  * the closest we can get..
  */
          /*xwr*/
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -227,10 +219,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -239,8 +231,6 @@
 	*pteptr = pteval;
 }
 
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-
 /*
  * pgd/pmd/pte query functions
  */
@@ -277,6 +267,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -307,15 +299,14 @@
 	pte_val(*ptep) = _PAGE_INVALID; 
 }
 
-#define PTE_INIT(x) pte_clear(x)
-
 /*
  * The following pte modification functions only work if
  * pte_present() is true. Undefined behaviour if not..
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte;
 }
 
@@ -342,13 +333,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 {
-	/* We can't set the changed bit atomically. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -382,6 +371,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -414,7 +405,7 @@
  * Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  */
-extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
+static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
 {
 	pte_t __pte;
 	pte_val(__pte) = physpage + pgprot_val(pgprot);
@@ -424,24 +415,41 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
 	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!PagePrivate(__page) + !!__page->mapping;     \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!PagePrivate(__page) + !!__page->mapping;  \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
+	__pte;                                                            \
+})
+
+#define pfn_pte(pfn, pgprot)                                              \
+({                                                                        \
+	struct page *__page = mem_map+(pfn);                              \
+	pgprot_t __pgprot = (pgprot);					  \
+	unsigned long __physpage = __pa((pfn) << PAGE_SHIFT);             \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!PagePrivate(__page) + !!__page->mapping;  \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
-#define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
+#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+#define pmd_page_kernel(pmd) (pmd_val(pmd) & PAGE_MASK)
+
+#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT))
 
-#define pmd_page(pmd) \
-        ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pgd_page_kernel(pgd) (pgd_val(pgd) & PAGE_MASK)
 
 /* to find an entry in a page-table-directory */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
@@ -457,8 +465,13 @@
 }
 
 /* Find an entry in the third-level page table.. */
-#define pte_offset(pmd, address) \
-        ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2))))
+#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
+#define pte_offset_kernel(pmd, address) \
+	((pte_t *) pmd_page_kernel(*(pmd)) + __pte_offset(address))
+#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
+#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
 
 /*
  * A page-table entry has some bits we have to treat in a special way.
diff -Nru a/include/asm-s390/processor.h b/include/asm-s390/processor.h
--- a/include/asm-s390/processor.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/processor.h	Sat Jun  8 22:31:37 2002
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
+#ifdef __KERNEL__
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -61,11 +62,8 @@
  */
 #define TASK_UNMAPPED_BASE      (TASK_SIZE / 2)
 
-#define THREAD_SIZE (2*PAGE_SIZE)
-
 typedef struct {
-        unsigned long seg;
-        unsigned long acc4;
+        __u32 ar4;
 } mm_segment_t;
 
 /* if you change the thread_struct structure, you must
@@ -74,8 +72,6 @@
 
 struct thread_struct
  {
-
-        struct pt_regs *regs;         /* the user registers can be found on*/
 	s390_fp_regs fp_regs;
         __u32   ar2;                   /* kernel access register 2         */
         __u32   ar4;                   /* kernel access register 4         */
@@ -84,8 +80,6 @@
         __u32   error_code;            /* error-code of last prog-excep.   */
         __u32   prot_addr;             /* address of protection-excep.     */
         __u32   trap_no;
-        /* perform syscall argument validation (get/set_fs) */
-        mm_segment_t fs;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
 	/* Used to give failing instruction back to user for ieee exceptions */
 	addr_t  ieee_instruction_pointer; 
@@ -95,14 +89,12 @@
 
 typedef struct thread_struct thread_struct;
 
-#define INIT_THREAD { (struct pt_regs *) 0,                       \
-                    { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
+#define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
 			    {0},{0},{0},{0},{0},{0}}},            \
                      0, 0,                                        \
                     sizeof(init_stack) + (__u32) &init_stack,     \
               (__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
                      0,0,0,                                       \
-                     (mm_segment_t) { 0,1},                       \
                      (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
                      0, 0                                         \
 }
@@ -115,6 +107,7 @@
 } while (0)
 
 /* Forward declaration, a strange C thing */
+struct task_struct;
 struct mm_struct;
 
 /* Free all resources held by a thread. */
@@ -126,28 +119,20 @@
 #define release_segments(mm)            do { } while (0)
 
 /*
- * Return saved PC of a blocked thread. used in kernel/sched
+ * Return saved PC of a blocked thread.
  */
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
-{
-        return (t->regs) ? ((unsigned long)t->regs->psw.addr) : 0;
-}
-
-unsigned long get_wchan(struct task_struct *p);
-#define KSTK_EIP(tsk)   ((tsk)->thread.regs->psw.addr)
-#define KSTK_ESP(tsk)   ((tsk)->thread.ksp)
+extern unsigned long thread_saved_pc(struct task_struct *t);
 
-/* Allocation and freeing of basic task resources. */
 /*
- * NOTE! The task struct and the stack go together
+ * Print register of task into buffer. Used in fs/proc/array.c.
  */
-#define alloc_task_struct() \
-        ((struct task_struct *) __get_free_pages(GFP_KERNEL,1))
-#define free_task_struct(p)     free_pages((unsigned long)(p),1)
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+extern char *task_show_regs(struct task_struct *task, char *buffer);
 
-#define init_task       (init_task_union.task)
-#define init_stack      (init_task_union.stack)
+unsigned long get_wchan(struct task_struct *p);
+#define __KSTK_PTREGS(tsk) ((struct pt_regs *) \
+        (((addr_t) tsk->thread_info + THREAD_SIZE - sizeof(struct pt_regs)) & -8L))
+#define KSTK_EIP(tsk)	(__KSTK_PTREGS(tsk)->psw.addr)
+#define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
 #define cpu_relax()	do { } while (0)
 
@@ -165,6 +150,46 @@
 #define PSW_PROBLEM_STATE       0x00010000UL
 
 /*
+ * Set PSW mask to specified value, while leaving the
+ * PSW addr pointing to the next instruction.
+ */
+
+static inline void __load_psw_mask (unsigned long mask)
+{
+	unsigned long addr;
+
+	psw_t psw;
+	psw.mask = mask;
+
+	asm volatile (
+		"    basr %0,0\n"
+		"0:  ahi  %0,1f-0b\n"
+		"    st   %0,4(%1)\n"
+		"    lpsw 0(%1)\n"
+		"1:"
+		: "=&d" (addr) : "a" (&psw) : "memory", "cc" );
+}
+ 
+/*
+ * Function to stop a processor until an interruption occured
+ */
+static inline void enabled_wait(void)
+{
+	unsigned long reg;
+	psw_t wait_psw;
+
+	wait_psw.mask = 0x070e0000;
+	asm volatile (
+		"    basr %0,0\n"
+		"0:  la   %0,1f-0b(%0)\n"
+		"    st   %0,4(%1)\n"
+		"    oi   4(%1),0x80\n"
+		"    lpsw 0(%1)\n"
+		"1:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+/*
  * Function to drop a processor into disabled wait state
  */
 
@@ -199,5 +224,7 @@
                       "    lpsw 0(%0)"
                       : : "a" (dw_psw), "a" (&ctl_buf) : "cc" );
 }
+
+#endif
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -Nru a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
--- a/include/asm-s390/ptrace.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/ptrace.h	Sat Jun  8 22:31:36 2002
@@ -105,12 +105,16 @@
 
 #define STACK_FRAME_OVERHEAD	96	/* size of minimum stack frame */
 
+#define PTRACE_SETOPTIONS         21
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD     0x00000001
+
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
 
-#include <asm/current.h>
 #include <asm/setup.h>
 
 /* this typedef defines how a Program Status Word looks like */
@@ -118,7 +122,7 @@
 {
         __u32   mask;
         __u32   addr;
-} psw_t __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(8))) psw_t;
 
 #ifdef __KERNEL__
 #define FIX_PSW(addr) ((unsigned long)(addr)|0x80000000UL)
@@ -150,8 +154,8 @@
 #define FPC_VALID_MASK          0xF8F8FF03
 
 /*
- * The first entries in pt_regs, gdb_pt_regs and user_regs_struct
- * are common for all three structures. The s390_regs structure
+ * The first entries in pt_regs and user_regs_struct
+ * are common for the two structures. The s390_regs structure
  * covers the common parts. It simplifies copying the common part
  * between the three structures.
  */
@@ -174,34 +178,15 @@
 	__u32 acrs[NUM_ACRS];
 	__u32 orig_gpr2;
 	__u32 trap;
-        __u32 old_ilc;
 };
 
 /*
- * The gdb_pt_regs struct is used instead of the pt_regs structure
- * if kernel remote debugging is used.
- */
-#if CONFIG_REMOTE_DEBUG
-struct gdb_pt_regs
-{
-	psw_t psw;
-	__u32 gprs[NUM_GPRS];
-	__u32 acrs[NUM_ACRS];
-	__u32 orig_gpr2;
-	__u32 trap;
-	__u32 crs[16];
-	s390_fp_regs fp_regs;
-	__u32 old_ilc;
-};
-#endif
-
-/*
  * Now for the program event recording (trace) definitions.
  */
 typedef struct
 {
 	__u32 cr[3];
-} per_cr_words  __attribute__((packed));
+} per_cr_words;
 
 #define PER_EM_MASK 0xE8000000
 
@@ -223,14 +208,14 @@
 	unsigned                       : 21;
 	addr_t   starting_addr;
 	addr_t   ending_addr;
-} per_cr_bits  __attribute__((packed));
+} per_cr_bits;
 
 typedef struct
 {
 	__u16          perc_atmid;          /* 0x096 */
 	__u32          address;             /* 0x098 */
 	__u8           access_id;           /* 0x0a1 */
-} per_lowcore_words  __attribute__((packed));
+} per_lowcore_words;
 
 typedef struct
 {
@@ -249,14 +234,14 @@
 	addr_t   address;                     /* 0x098 */
 	unsigned                         : 4; /* 0x0a1 */
 	unsigned access_id               : 4;
-} per_lowcore_bits __attribute__((packed));
+} per_lowcore_bits;
 
 typedef struct
 {
 	union {
 		per_cr_words   words;
 		per_cr_bits    bits;
-	} control_regs  __attribute__((packed));
+	} control_regs;
 	/*
 	 * Use these flags instead of setting em_instruction_fetch
 	 * directly they are used so that single stepping can be
@@ -275,7 +260,7 @@
 		per_lowcore_words words;
 		per_lowcore_bits  bits;
 	} lowcore; 
-} per_struct __attribute__((packed));
+} per_struct;
 
 typedef struct
 {
@@ -294,6 +279,7 @@
 #define PTRACE_PEEKDATA_AREA	      0x5003
 #define PTRACE_POKETEXT_AREA	      0x5004
 #define PTRACE_POKEDATA_AREA 	      0x5005
+
 /*
  * PT_PROT definition is loosely based on hppa bsd definition in
  * gdb/hppab-nat.c
@@ -345,7 +331,6 @@
 #define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr)
 extern void show_regs(struct pt_regs * regs);
-extern char *task_show_regs(struct task_struct *task, char *buffer);
 #endif
 
 #endif /* __ASSEMBLY__ */
diff -Nru a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/qdio.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,933 @@
+/*
+ * linux/include/asm/qdio.h
+ *
+ * Linux for S/390 QDIO base support, Hipersocket base support
+ * version 2
+ *
+ * Copyright 2000,2002 IBM Corporation
+ * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
+ *
+ */
+#ifndef __QDIO_H__
+#define __QDIO_H__
+
+#define VERSION_QDIO_H "$Revision: 1.57 $"
+
+/* note, that most of the typedef's are from ingo. */
+
+#include <linux/interrupt.h>
+
+//#define QDIO_DBF_LIKE_HELL
+
+#define QDIO_NAME "qdio "
+
+#define QDIO_VERBOSE_LEVEL 9
+
+#ifndef CONFIG_ARCH_S390X
+#define QDIO_32_BIT
+#endif /* CONFIG_ARCH_S390X */
+
+#define QDIO_USE_PROCESSING_STATE
+
+#ifdef CONFIG_QDIO_PERF_STATS
+#define QDIO_PERFORMANCE_STATS
+#endif /* CONFIG_QDIO_PERF_STATS */
+
+#define QDIO_MINIMAL_BH_RELIEF_TIME 16
+#define QDIO_TIMER_POLL_VALUE 1
+#define IQDIO_TIMER_POLL_VALUE 1
+
+/**** CONSTANTS, that are relied on without using these symbols *****/
+#define QDIO_MAX_QUEUES_PER_IRQ 32 /* used in width of unsigned int */
+/************************ END of CONSTANTS **************************/
+#define QDIO_MAX_BUFFERS_PER_Q 128 /* must be a power of 2 (%x=&(x-1)*/
+#define QDIO_BUF_ORDER 7 /* 2**this == number of pages used for sbals in 1 q */
+#define QDIO_MAX_ELEMENTS_PER_BUFFER 16
+#define SBAL_SIZE 256
+
+#define IQDIO_FILL_LEVEL_TO_POLL (QDIO_MAX_BUFFERS_PER_Q*4/3)
+
+#define IQDIO_THININT_ISC 3
+#define IQDIO_DELAY_TARGET 0
+#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */
+#define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */
+#define IQDIO_GLOBAL_LAPS_INT 1 /* dont global summary */
+#define IQDIO_LOCAL_LAPS 4
+#define IQDIO_LOCAL_LAPS_INT 1
+#define IQDIO_GLOBAL_SUMMARY_CC_MASK 2
+/*#define IQDIO_IQDC_INT_PARM 0x1234*/
+
+#define QDIO_Q_LAPS 5
+
+#define QDIO_STORAGE_KEY 0
+
+#define L2_CACHELINE_SIZE 256
+#define INDICATORS_PER_CACHELINE (L2_CACHELINE_SIZE/sizeof(__u32))
+
+#define QDIO_PERF "qdio_perf"
+
+/* must be a power of 2 */
+/*#define QDIO_STATS_NUMBER 4
+
+#define QDIO_STATS_CLASSES 2
+#define QDIO_STATS_COUNT_NEEDED 2*/
+
+#define QDIO_NO_USE_COUNT_TIME 10
+#define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
+					  exiting without having use_count
+					  of the queue to 0 */
+
+#define QDIO_ESTABLISH_TIMEOUT 1000
+#define QDIO_ACTIVATE_TIMEOUT 100
+#define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
+#define QDIO_CLEANUP_HALT_TIMEOUT 10000
+
+#define QDIO_BH AURORA_BH
+
+#define QDIO_IRQ_BUCKETS 256 /* heavy..., but does only use a few bytes, but
+			      be rather faster in cases of collisions
+			      (if there really is a collision, it is
+			      on every (traditional) interrupt and every
+			      do_QDIO, so we rather are generous */
+#define QDIO_QETH_QFMT 0
+#define QDIO_ZFCP_QFMT 1
+#define QDIO_IQDIO_QFMT 2
+
+#define QDIO_IRQ_STATE_FRESH 0 /* must be 0 -> memset has set it to 0 */
+#define QDIO_IRQ_STATE_INACTIVE 1
+#define QDIO_IRQ_STATE_ESTABLISHED 2
+#define QDIO_IRQ_STATE_ACTIVE 3
+#define QDIO_IRQ_STATE_STOPPED 4
+
+/* used as intparm in do_IO: */
+#define QDIO_DOING_SENSEID 0
+#define QDIO_DOING_ESTABLISH 1
+#define QDIO_DOING_ACTIVATE 2
+#define QDIO_DOING_CLEANUP 3
+
+/************************* DEBUG FACILITY STUFF *********************/
+/* #define QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_HEX(ex,name,level,addr,len) \
+	do { \
+	if (ex) \
+		debug_exception(qdio_dbf_##name,level,(void*)(addr),len); \
+	else \
+		debug_event(qdio_dbf_##name,level,(void*)(addr),len); \
+	} while (0)
+#define QDIO_DBF_TEXT(ex,name,level,text) \
+	do { \
+	if (ex) \
+		debug_text_exception(qdio_dbf_##name,level,text); \
+	else \
+		debug_text_event(qdio_dbf_##name,level,text); \
+	} while (0)
+
+#define QDIO_DBF_HEX0(ex,name,addr,len) QDIO_DBF_HEX(ex,name,0,addr,len)
+#define QDIO_DBF_HEX1(ex,name,addr,len) QDIO_DBF_HEX(ex,name,1,addr,len)
+#define QDIO_DBF_HEX2(ex,name,addr,len) QDIO_DBF_HEX(ex,name,2,addr,len)
+#define QDIO_DBF_HEX3(ex,name,addr,len) QDIO_DBF_HEX(ex,name,3,addr,len)
+#define QDIO_DBF_HEX4(ex,name,addr,len) QDIO_DBF_HEX(ex,name,4,addr,len)
+#define QDIO_DBF_HEX5(ex,name,addr,len) QDIO_DBF_HEX(ex,name,5,addr,len)
+#define QDIO_DBF_HEX6(ex,name,addr,len) QDIO_DBF_HEX(ex,name,6,addr,len)
+#ifdef QDIO_DBF_LIKE_HELL
+#endif /* QDIO_DBF_LIKE_HELL */
+#if 0
+#define QDIO_DBF_HEX0(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX1(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX2(ex,name,addr,len) do {} while (0)
+#ifndef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_HEX3(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX4(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX5(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX6(ex,name,addr,len) do {} while (0)
+#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* 0 */
+
+#define QDIO_DBF_TEXT0(ex,name,text) QDIO_DBF_TEXT(ex,name,0,text)
+#define QDIO_DBF_TEXT1(ex,name,text) QDIO_DBF_TEXT(ex,name,1,text)
+#define QDIO_DBF_TEXT2(ex,name,text) QDIO_DBF_TEXT(ex,name,2,text)
+#define QDIO_DBF_TEXT3(ex,name,text) QDIO_DBF_TEXT(ex,name,3,text)
+#define QDIO_DBF_TEXT4(ex,name,text) QDIO_DBF_TEXT(ex,name,4,text)
+#define QDIO_DBF_TEXT5(ex,name,text) QDIO_DBF_TEXT(ex,name,5,text)
+#define QDIO_DBF_TEXT6(ex,name,text) QDIO_DBF_TEXT(ex,name,6,text)
+#ifdef QDIO_DBF_LIKE_HELL
+#endif /* QDIO_DBF_LIKE_HELL */
+#if 0
+#define QDIO_DBF_TEXT0(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT1(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT2(ex,name,text) do {} while (0)
+#ifndef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_TEXT3(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT4(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT5(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT6(ex,name,text) do {} while (0)
+#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* 0 */
+
+#define QDIO_DBF_SETUP_NAME "qdio_setup"
+#define QDIO_DBF_SETUP_LEN 8
+#define QDIO_DBF_SETUP_INDEX 2
+#define QDIO_DBF_SETUP_NR_AREAS 1
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SETUP_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SETUP_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */
+#define QDIO_DBF_SBAL_LEN 256
+#define QDIO_DBF_SBAL_INDEX 2
+#define QDIO_DBF_SBAL_NR_AREAS 2
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SBAL_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SBAL_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_TRACE_NAME "qdio_trace"
+#define QDIO_DBF_TRACE_LEN 8
+#define QDIO_DBF_TRACE_NR_AREAS 2
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_TRACE_INDEX 4
+#define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_TRACE_INDEX 2
+#define QDIO_DBF_TRACE_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_SENSE_NAME "qdio_sense"
+#define QDIO_DBF_SENSE_LEN 64
+#define QDIO_DBF_SENSE_INDEX 1
+#define QDIO_DBF_SENSE_NR_AREAS 1
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SENSE_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SENSE_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_TRACE_QTYPE QDIO_ZFCP_QFMT
+
+#define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
+#define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q
+#define QDIO_DBF_SLSB_OUT_INDEX 8
+#define QDIO_DBF_SLSB_OUT_NR_AREAS 1
+#define QDIO_DBF_SLSB_OUT_LEVEL 6
+
+#define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in"
+#define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q
+#define QDIO_DBF_SLSB_IN_INDEX 8
+#define QDIO_DBF_SLSB_IN_NR_AREAS 1
+#define QDIO_DBF_SLSB_IN_LEVEL 6
+#endif /* QDIO_DBF_LIKE_HELL */
+
+/****************** END OF DEBUG FACILITY STUFF *********************/
+
+typedef struct qdio_buffer_element_t {
+	unsigned int flags;
+	unsigned int length;
+#ifdef QDIO_32_BIT
+	void *reserved;
+#endif /* QDIO_32_BIT */
+	void *addr;
+} __attribute__ ((packed,aligned(16))) qdio_buffer_element_t;
+
+typedef struct qdio_buffer_t {
+	volatile qdio_buffer_element_t element[16];
+} __attribute__ ((packed,aligned(256))) qdio_buffer_t;
+
+
+/* params are: irq, status, qdio_error, siga_error,
+   queue_number, first element processed, number of elements processed,
+   int_parm */
+typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
+			    unsigned int,int,int,unsigned long);
+
+
+#define QDIO_STATUS_INBOUND_INT 0x01
+#define QDIO_STATUS_OUTBOUND_INT 0x02
+#define QDIO_STATUS_LOOK_FOR_ERROR 0x04
+#define QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR 0x08
+#define QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR 0x10
+#define QDIO_STATUS_ACTIVATE_CHECK_CONDITION 0x20
+
+#define QDIO_SIGA_ERROR_ACCESS_EXCEPTION 0x10
+#define QDIO_SIGA_ERROR_B_BIT_SET 0x20
+
+/* for qdio_initialize */
+#define QDIO_INBOUND_0COPY_SBALS 0x01
+#define QDIO_OUTBOUND_0COPY_SBALS 0x02
+#define QDIO_USE_OUTBOUND_PCIS 0x04
+
+/* for qdio_cleanup */
+#define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
+#define QDIO_FLAG_CLEANUP_USING_HALT 0x02
+
+typedef struct qdio_initialize_t {
+	int irq;
+	unsigned char q_format;
+	unsigned char adapter_name[8];
+       	unsigned int qib_param_field_format; /*adapter dependent*/
+	/* pointer to 128 bytes or NULL, if no param field */
+	unsigned char *qib_param_field; /* adapter dependent */
+	/* pointer to no_queues*128 words of data or NULL */
+	unsigned long *input_slib_elements;
+	unsigned long *output_slib_elements;
+	unsigned int min_input_threshold;
+	unsigned int max_input_threshold;
+	unsigned int min_output_threshold;
+	unsigned int max_output_threshold;
+	unsigned int no_input_qs;
+	unsigned int no_output_qs;
+	qdio_handler_t *input_handler;
+	qdio_handler_t *output_handler;
+	unsigned long int_parm;
+	unsigned long flags;
+	void **input_sbal_addr_array; /* addr of n*128 void ptrs */
+	void **output_sbal_addr_array; /* addr of n*128 void ptrs */
+} qdio_initialize_t;
+extern int qdio_initialize(qdio_initialize_t *init_data);
+
+extern int qdio_activate(int irq,int flags);
+
+#define QDIO_STATE_MUST_USE_OUTB_PCI	0x00000001
+#define QDIO_STATE_INACTIVE 		0x00000002 /* after qdio_cleanup */
+#define QDIO_STATE_ESTABLISHED 		0x00000004 /* after qdio_initialize */
+#define QDIO_STATE_ACTIVE 		0x00000008 /* after qdio_activate */
+#define QDIO_STATE_STOPPED 		0x00000010 /* after queues went down */
+extern unsigned long qdio_get_status(int irq);
+
+
+#define QDIO_FLAG_SYNC_INPUT     0x01
+#define QDIO_FLAG_SYNC_OUTPUT    0x02
+#define QDIO_FLAG_UNDER_INTERRUPT 0x04
+#define QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT 0x08 /* no effect on
+						     adapter interrupts */
+#define QDIO_FLAG_DONT_SIGA 0x10
+
+extern int do_QDIO(int irq,unsigned int flags, unsigned int queue_number,
+		   unsigned int qidx,unsigned int count,
+		   qdio_buffer_t *buffers);
+
+extern int qdio_synchronize(int irq,unsigned int flags,
+			    unsigned int queue_number);
+
+extern int qdio_cleanup(int irq,int how);
+
+unsigned char qdio_get_slsb_state(int irq,unsigned int flag,
+				  unsigned int queue_number,
+				  unsigned int qidx);
+
+extern void qdio_init_scrubber(void);
+/*
+ * QDIO device commands returned by extended Sense-ID
+ */
+#define DEFAULT_ESTABLISH_QS_CMD 0x1b
+#define DEFAULT_ESTABLISH_QS_COUNT 0x1000
+#define DEFAULT_ACTIVATE_QS_CMD 0x1f
+#define DEFAULT_ACTIVATE_QS_COUNT 0
+typedef struct _qdio_cmds {
+	unsigned char rcd;            /* read configuration data */
+	unsigned short count_rcd;
+	unsigned char sii;            /* set interface identifier */
+	unsigned short count_sii;
+	unsigned char rni;            /* read node identifier */
+	unsigned short count_rni;
+	unsigned char eq;             /* establish QDIO queues */
+	unsigned short count_eq;
+	unsigned char aq;             /* activate QDIO queues */
+	unsigned short count_aq;
+} qdio_cmds_t;
+
+/*
+ * additional CIWs returned by extended Sense-ID
+ */
+#define CIW_TYPE_EQUEUE 0x3       /* establish QDIO queues */
+#define CIW_TYPE_AQUEUE 0x4       /* activate QDIO queues */
+
+typedef struct _qdesfmt0 {
+#ifdef QDIO_32_BIT
+	unsigned long res1;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sliba;            /* storage-list-information-block
+					   address */
+#ifdef QDIO_32_BIT
+	unsigned long res2;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sla;              /* storage-list address */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long slsba;            /* storage-list-state-block address */
+	unsigned int  res4;		/* reserved */
+	unsigned int  akey  :  4;       /* access key for DLIB */
+	unsigned int  bkey  :  4;       /* access key for SL */
+	unsigned int  ckey  :  4;       /* access key for SBALs */
+	unsigned int  dkey  :  4;       /* access key for SLSB */
+	unsigned int  res5  : 16;       /* reserved */
+} __attribute__ ((packed)) qdesfmt0_t;
+
+/*
+ * Queue-Description record (QDR)
+ */
+typedef struct _qdr {
+	unsigned int  qfmt    :  8;     /* queue format */
+	unsigned int  pfmt    :  8;     /* impl. dep. parameter format */
+	unsigned int  res1    :  8;     /* reserved */
+	unsigned int  ac      :  8;     /* adapter characteristics */
+	unsigned int  res2    :  8;     /* reserved */
+	unsigned int  iqdcnt  :  8;     /* input-queue-descriptor count */
+	unsigned int  res3    :  8;     /* reserved */
+	unsigned int  oqdcnt  :  8;     /* output-queue-descriptor count */
+	unsigned int  res4    :  8;     /* reserved */
+	unsigned int  iqdsz   :  8;     /* input-queue-descriptor size */
+	unsigned int  res5    :  8;     /* reserved */
+	unsigned int  oqdsz   :  8;     /* output-queue-descriptor size */
+	unsigned int  res6[9];          /* reserved */
+#ifdef QDIO_32_BIT
+	unsigned long res7;		/* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long qiba;             /* queue-information-block address */
+	unsigned int  res8;             /* reserved */
+	unsigned int  qkey    :  4;     /* queue-informatio-block key */
+	unsigned int  res9    : 28;     /* reserved */
+/*	union _qd {*/ /* why this? */
+		qdesfmt0_t qdf0[126];
+/*	} qd;*/
+} __attribute__ ((packed,aligned(4096))) qdr_t;
+
+
+/*
+ * queue information block (QIB)
+ */
+#define QIB_AC_INBOUND_PCI_SUPPORTED 0x80
+#define QIB_AC_OUTBOUND_PCI_SUPPORTED 0x40
+typedef struct _qib {
+	unsigned int  qfmt    :  8;     /* queue format */
+	unsigned int  pfmt    :  8;     /* impl. dep. parameter format */
+	unsigned int  res1    :  8;     /* reserved */
+	unsigned int  ac      :  8;     /* adapter characteristics */
+	unsigned int  res2;             /* reserved */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long isliba;           /* absolute address of 1st
+					   input SLIB */
+#ifdef QDIO_32_BIT
+	unsigned long res4;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long osliba;           /* absolute address of 1st
+					   output SLIB */
+	unsigned int  res5;             /* reserved */
+	unsigned int  res6;             /* reserved */
+	unsigned char ebcnam[8];        /* adapter identifier in EBCDIC */
+	unsigned char res7[88];         /* reserved */
+	unsigned char parm[QDIO_MAX_BUFFERS_PER_Q];
+					/* implementation dependent
+					   parameters */
+} __attribute__ ((packed,aligned(256))) qib_t;
+
+
+/*
+ * storage-list-information block element (SLIBE)
+ */
+typedef struct _slibe {
+#ifdef QDIO_32_BIT
+	unsigned long res;              /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long parms;            /* implementation dependent
+					   parameters */
+} slibe_t;
+
+/*
+ * storage-list-information block (SLIB)
+ */
+typedef struct _slib {
+#ifdef QDIO_32_BIT
+	unsigned long res1;             /* reserved */
+#endif /* QDIO_32_BIT */
+        unsigned long nsliba;           /* next SLIB address (if any) */
+#ifdef QDIO_32_BIT
+	unsigned long res2;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sla;              /* SL address */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long slsba;            /* SLSB address */
+	unsigned char res4[1000];       /* reserved */
+	slibe_t       slibe[QDIO_MAX_BUFFERS_PER_Q];    /* SLIB elements */
+} __attribute__ ((packed,aligned(2048))) slib_t;
+
+typedef struct _sbal_flags {
+	unsigned char res1  : 1;   /* reserved */
+	unsigned char last  : 1;   /* last entry */
+	unsigned char cont  : 1;   /* contiguous storage */
+	unsigned char res2  : 1;   /* reserved */
+	unsigned char frag  : 2;   /* fragmentation (s.below) */
+	unsigned char res3  : 2;   /* reserved */
+} __attribute__ ((packed)) sbal_flags_t;
+
+#define SBAL_FLAGS_FIRST_FRAG	     0x04000000UL
+#define SBAL_FLAGS_MIDDLE_FRAG	     0x08000000UL
+#define SBAL_FLAGS_LAST_FRAG	     0x0c000000UL
+#define SBAL_FLAGS_LAST_ENTRY	     0x40000000UL
+#define SBAL_FLAGS_CONTIGUOUS	     0x20000000UL
+
+#define SBAL_FLAGS0_DATA_CONTINUATION 0x20UL
+
+/* Awesome OpenFCP extensions */
+#define SBAL_FLAGS0_TYPE_STATUS       0x00UL
+#define SBAL_FLAGS0_TYPE_WRITE        0x08UL
+#define SBAL_FLAGS0_TYPE_READ         0x10UL
+#define SBAL_FLAGS0_TYPE_WRITE_READ   0x18UL
+#define SBAL_FLAGS0_MORE_SBALS	      0x04UL
+#define SBAL_FLAGS0_COMMAND           0x02UL
+#define SBAL_FLAGS0_LAST_SBAL         0x00UL
+#define SBAL_FLAGS0_ONLY_SBAL         SBAL_FLAGS0_COMMAND
+#define SBAL_FLAGS0_MIDDLE_SBAL       SBAL_FLAGS0_MORE_SBALS
+#define SBAL_FLAGS0_FIRST_SBAL        SBAL_FLAGS0_MORE_SBALS | SBAL_FLAGS0_COMMAND
+/* Naught of interest beyond this point */
+
+#define SBAL_FLAGS0_PCI		0x40
+typedef struct _sbal_sbalf_0 {
+	unsigned char res1  : 1;   /* reserved */
+	unsigned char pci   : 1;   /* PCI indicator */
+	unsigned char cont  : 1;   /* data continuation */
+	unsigned char sbtype: 2;   /* storage-block type (OpenFCP) */
+	unsigned char res2  : 3;   /* reserved */
+} __attribute__ ((packed)) sbal_sbalf_0_t;
+
+typedef struct _sbal_sbalf_1 {
+	unsigned char res1  : 4;   /* reserved */
+	unsigned char key   : 4;   /* storage key */
+} __attribute__ ((packed)) sbal_sbalf_1_t;
+
+typedef struct _sbal_sbalf_14 {
+	unsigned char res1   : 4;  /* reserved */
+	unsigned char erridx : 4;  /* error index */
+} __attribute__ ((packed)) sbal_sbalf_14_t;
+
+typedef struct _sbal_sbalf_15 {
+	unsigned char reason;      /* reserved */
+} __attribute__ ((packed)) sbal_sbalf_15_t;
+
+typedef union _sbal_sbalf {
+	sbal_sbalf_0_t  i0;
+	sbal_sbalf_1_t  i1;
+	sbal_sbalf_14_t i14;
+	sbal_sbalf_15_t i15;
+	unsigned char value;
+} sbal_sbalf_t;
+
+typedef struct _sbale {
+	union {
+		sbal_flags_t  bits;       /* flags */
+		unsigned char value;
+	} flags;
+	unsigned int  res1  : 16;   /* reserved */
+	sbal_sbalf_t  sbalf;       /* SBAL flags */
+	unsigned int  res2  : 16;  /* reserved */
+	unsigned int  count : 16;  /* data count */
+#ifdef QDIO_32_BIT
+	unsigned long res3;        /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long addr;        /* absolute data address */
+} __attribute__ ((packed,aligned(16))) sbal_element_t;
+
+/*
+ * strorage-block access-list (SBAL)
+ */
+typedef struct _sbal {
+	sbal_element_t element[QDIO_MAX_ELEMENTS_PER_BUFFER];
+} __attribute__ ((packed,aligned(256))) sbal_t;
+
+/*
+ * storage-list (SL)
+ */
+typedef struct _sl_element {
+#ifdef QDIO_32_BIT
+        unsigned long res;     /* reserved */
+#endif /* QDIO_32_BIT */
+        unsigned long sbal;    /* absolute SBAL address */
+} __attribute__ ((packed)) sl_element_t;
+
+typedef struct _sl {
+	sl_element_t element[QDIO_MAX_BUFFERS_PER_Q];
+} __attribute__ ((packed,aligned(1024))) sl_t;
+
+/*
+ * storage-list-state block (SLSB)
+ */
+/*typedef struct _slsb_val {*/
+/*	unsigned char value;       */ /* SLSB entry as a single byte value */
+/*} __attribute__ ((packed)) slsb_val_t;*/
+
+typedef struct _slsb_flags {
+	unsigned char owner  : 2;   /* SBAL owner */
+	unsigned char type   : 1;   /* buffer type */
+	unsigned char state  : 5;   /* processing state */
+} __attribute__ ((packed)) slsb_flags_t;
+
+
+typedef struct _slsb {
+	union _acc {
+		unsigned char val[QDIO_MAX_BUFFERS_PER_Q];
+		slsb_flags_t flags[QDIO_MAX_BUFFERS_PER_Q];
+	} acc;
+} __attribute__ ((packed,aligned(256))) slsb_t;
+
+/*
+ * SLSB values
+ */
+#define SLSB_OWNER_PROG              1
+#define SLSB_OWNER_CU                2
+
+#define SLSB_TYPE_INPUT              0
+#define SLSB_TYPE_OUTPUT             1
+
+#define SLSB_STATE_NOT_INIT          0
+#define SLSB_STATE_EMPTY             1
+#define SLSB_STATE_PRIMED            2
+#define SLSB_STATE_HALTED          0xe
+#define SLSB_STATE_ERROR           0xf
+
+#define SLSB_P_INPUT_NOT_INIT     0x80
+#define SLSB_P_INPUT_PROCESSING	  0x81
+#define SLSB_CU_INPUT_EMPTY       0x41
+#define SLSB_P_INPUT_PRIMED       0x82
+#define SLSB_P_INPUT_HALTED       0x8E
+#define SLSB_P_INPUT_ERROR        0x8F
+
+#define SLSB_P_OUTPUT_NOT_INIT    0xA0
+#define SLSB_P_OUTPUT_EMPTY       0xA1
+#define SLSB_CU_OUTPUT_PRIMED     0x62
+#define SLSB_P_OUTPUT_HALTED      0xAE
+#define SLSB_P_OUTPUT_ERROR       0xAF
+
+#define SLSB_ERROR_DURING_LOOKUP  0xFF
+/*
+ * path management control word (extended layout)
+ */
+typedef struct {
+	unsigned long  intparm;      /* interruption parameter */
+	unsigned int   qf   : 1;     /* qdio facility */
+	unsigned int   res0 : 1;     /* reserved */
+	unsigned int   isc  : 3;     /* interruption sublass */
+	unsigned int   res5 : 3;     /* reserved zeros */
+	unsigned int   ena  : 1;     /* enabled */
+	unsigned int   lm   : 2;     /* limit mode */
+	unsigned int   mme  : 2;     /* measurement-mode enable */
+	unsigned int   mp   : 1;     /* multipath mode */
+	unsigned int   tf   : 1;     /* timing facility */
+	unsigned int   dnv  : 1;     /* device number valid */
+	unsigned int   dev  : 16;    /* device number */
+	unsigned char  lpm;          /* logical path mask */
+	unsigned char  pnom;         /* path not operational mask */
+	unsigned char  lpum;         /* last path used mask */
+	unsigned char  pim;          /* path installed mask */
+	unsigned short mbi;          /* measurement-block index */
+	unsigned char  pom;          /* path operational mask */
+	unsigned char  pam;          /* path available mask */
+	unsigned char  chpid[8];     /* CHPID 0-7 (if available) */
+	unsigned int   res1    : 8;  /* reserved */
+	unsigned int   st      : 3;  /* */
+	unsigned int   res2    : 20; /* reserved */
+	unsigned int   csense  : 1;  /* concurrent sense; can be enabled
+					per MSCH, however, if facility
+					is not installed, this results
+					in an operand exception. */
+} pmcw_e_t;
+
+/*
+ * subchannel status word (extended layout)
+ */
+typedef struct {
+	unsigned int   key  : 4;     /* subchannel key */
+	unsigned int   sctl : 1;     /* suspend control */
+	unsigned int   eswf : 1;     /* ESW format */
+	unsigned int   cc   : 2;     /* deferred condition code */
+	unsigned int   fmt  : 1;     /* format */
+	unsigned int   pfch : 1;     /* prefetch */
+	unsigned int   isic : 1;     /* initial-status interruption control */
+	unsigned int   alcc : 1;     /* address-limit checking control */
+	unsigned int   ssi  : 1;     /* supress-suspended interruption */
+	unsigned int   zcc  : 1;     /* zero condition code */
+	unsigned int   ectl : 1;     /* extended control */
+	unsigned int   pno  : 1;     /* path not operational */
+	unsigned int   qact : 1;     /* qdio active */
+	unsigned int   fctl : 3;     /* function control */
+	unsigned int   actl : 7;     /* activity control */
+	unsigned int   stctl : 5;    /* status control */
+	unsigned long  cpa;          /* channel program address */
+	unsigned int   dstat : 8;    /* device status */
+	unsigned int   cstat : 8;    /* subchannel status */
+	unsigned int   count : 16;   /* residual count */
+} scsw_e_t;
+
+typedef struct qdio_q_t {
+	volatile slsb_t slsb;
+
+	__u32 * volatile dev_st_chg_ind;
+
+	int is_input_q;
+	int is_0copy_sbals_q;
+	int irq;
+
+	unsigned int is_iqdio_q;
+
+	/* bit 0 means queue 0, bit 1 means queue 1, ... */
+	unsigned int mask;
+	unsigned int q_no;
+
+	qdio_handler_t (*handler);
+
+	/* points to the next buffer to be checked for having
+	 * been processed by the card (outbound)
+	 * or to the next buffer the program should check for (inbound) */
+	volatile int first_to_check;
+	/* and the last time it was: */
+	volatile int last_move_ftc;
+
+	atomic_t number_of_buffers_used;
+	atomic_t polling;
+
+	unsigned int siga_in;
+	unsigned int siga_out;
+	unsigned int siga_sync;
+	unsigned int siga_sync_done_on_thinints;
+	unsigned int hydra_gives_outbound_pcis;
+
+	/* used to save beginning position when calling dd_handlers */
+	int first_element_to_kick;
+
+	atomic_t use_count;
+	atomic_t is_in_shutdown;
+
+#ifdef QDIO_USE_TIMERS_FOR_POLLING
+	struct timer_list timer;
+	atomic_t timer_already_set;
+	spinlock_t timer_lock;
+#else /* QDIO_USE_TIMERS_FOR_POLLING */
+	struct tasklet_struct tasklet;
+#endif /* QDIO_USE_TIMERS_FOR_POLLING */
+
+	unsigned int state;
+
+	/* used to store the error condition during a data transfer */
+	unsigned int qdio_error;
+	unsigned int siga_error;
+	unsigned int error_status_flags;
+
+	/* list of interesting queues */
+	volatile struct qdio_q_t *list_next;
+	volatile struct qdio_q_t *list_prev;
+
+	slib_t *slib; /* a page is allocated under this pointer,
+			 sl points into this page, offset PAGE_SIZE/2
+			 (after slib) */
+	sl_t *sl;
+	volatile sbal_t *sbal[QDIO_MAX_BUFFERS_PER_Q];
+
+	qdio_buffer_t *qdio_buffers[QDIO_MAX_BUFFERS_PER_Q];
+
+	unsigned long int_parm;
+
+	/*struct {
+		int in_bh_check_limit;
+		int threshold;
+	} threshold_classes[QDIO_STATS_CLASSES];*/
+
+	struct {
+		/* inbound: the time to stop polling
+		   outbound: the time to kick peer */
+		int threshold; /* the real value */
+
+		/* outbound: last time of do_QDIO
+		   inbound: last time of noticing incoming data */
+		/*__u64 last_transfer_times[QDIO_STATS_NUMBER];
+		int last_transfer_index; */
+
+		__u64 last_transfer_time;
+	} timing;
+        unsigned int queue_type;
+} __attribute__ ((aligned(256))) qdio_q_t;
+
+typedef struct qdio_irq_t {
+	__u32 * volatile dev_st_chg_ind;
+
+	unsigned long int_parm;
+	int irq;
+
+	unsigned int is_iqdio_irq;
+	unsigned int hydra_gives_outbound_pcis;
+	unsigned int sync_done_on_outb_pcis;
+
+	unsigned int state;
+	spinlock_t setting_up_lock;
+
+	unsigned int no_input_qs;
+	unsigned int no_output_qs;
+
+	unsigned char qdioac;
+
+	qdio_q_t *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
+	qdio_q_t *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
+
+	ccw1_t ccw;
+	int io_result_cstat;
+	int io_result_dstat;
+	int io_result_flags;
+	atomic_t interrupt_has_arrived;
+	atomic_t interrupt_has_been_cleaned;
+	wait_queue_head_t wait_q;
+
+	qdr_t *qdr;
+
+	qdio_cmds_t commands;
+
+	qib_t qib;
+
+	io_handler_func_t original_int_handler;
+
+	struct qdio_irq_t *next;
+} qdio_irq_t;
+
+#define QDIO_CHSC_RESPONSE_CODE_OK 1
+/* flags for st qdio sch data */
+#define CHSC_FLAG_QDIO_CAPABILITY 0x80
+#define CHSC_FLAG_VALIDITY 0x40
+
+#define CHSC_FLAG_SIGA_INPUT_NECESSARY 0x40
+#define CHSC_FLAG_SIGA_OUTPUT_NECESSARY 0x20
+#define CHSC_FLAG_SIGA_SYNC_NECESSARY 0x10
+#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
+#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
+
+typedef struct qdio_chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		/* word 1 */
+		__u16 operation_code;
+		__u16 first_sch;
+		/* word 2 */
+		__u8 reserved1;
+		__u8 image_id;
+		__u16 last_sch;
+		/* word 3 */
+		__u32 reserved2;
+
+		/* word 4 */
+		union {
+			struct {
+				/* word 4&5 */
+				__u64 summary_indicator_addr;
+				/* word 6&7 */
+				__u64 subchannel_indicator_addr;
+				/* word 8 */
+				int ks:4;
+				int kc:4;
+				int reserved1:21;
+				int isc:3;
+				/* word 9&10 */
+				__u32 reserved2[2];
+				/* word 11 */
+				__u32 subsystem_id;
+				/* word 12-1015 */
+				__u32 reserved3[1004];
+			} __attribute__ ((packed,aligned(4))) set_chsc;
+			struct {
+				/* word 4&5 */
+				__u32 reserved1[2];	
+				/* word 6 */
+				__u32 delay_target;
+				/* word 7-1015 */
+				__u32 reserved4[1009];
+			} __attribute__ ((packed,aligned(4))) set_chsc_fast;
+			struct {
+				/* word 0 */
+				__u16 length;
+				__u16 response_code;
+				/* word 1 */
+				__u32 reserved1;
+				/* words 2 to 9 for st sch qdio data */
+				__u8 flags;
+				__u8 reserved2;
+				__u16 sch;
+				__u8 qfmt;
+				__u8 reserved3;
+				__u8 qdioac;
+				__u8 sch_class;
+				__u8 reserved4;
+				__u8 icnt;
+				__u8 reserved5;
+				__u8 ocnt;
+				/* plus 5 words of reserved fields */
+			} __attribute__ ((packed,aligned(8)))
+			store_qdio_data_response;
+		} operation_data_area;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) qdio_chsc_area_t;
+
+
+#define QDIO_PRINTK_HEADER QDIO_NAME ": "
+
+#if QDIO_VERBOSE_LEVEL>8
+#define QDIO_PRINT_STUPID(x...) printk( KERN_DEBUG QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_STUPID(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>7
+#define QDIO_PRINT_ALL(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ALL(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>6
+#define QDIO_PRINT_INFO(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_INFO(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>5
+#define QDIO_PRINT_WARN(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_WARN(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>4
+#define QDIO_PRINT_ERR(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ERR(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>3
+#define QDIO_PRINT_CRIT(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_CRIT(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>2
+#define QDIO_PRINT_ALERT(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ALERT(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>1
+#define QDIO_PRINT_EMERG(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_EMERG(x...)
+#endif
+
+#endif /* __QDIO_H__ */
diff -Nru a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/rwsem.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,209 @@
+#ifndef _S390_RWSEM_H
+#define _S390_RWSEM_H
+
+/*
+ *  include/asm-s390/rwsem.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
+ */
+
+/*
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed long		count;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+};
+
+#define RWSEM_UNLOCKED_VALUE	0x00000000
+#define RWSEM_ACTIVE_BIAS	0x00000001
+#define RWSEM_ACTIVE_MASK	0x0000ffff
+#define RWSEM_WAITING_BIAS	(-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+/*
+ * initialisation
+ */
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (old < 0)
+		rwsem_down_read_failed(sem);
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   a    %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (old != 0)
+		rwsem_down_write_failed(sem);
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ahi  %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   a    %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ar   %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   l    %0,0(%2)\n"
+		"0: lr   %1,%0\n"
+		"   ar   %1,%3\n"
+		"   cs   %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+	return new;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _S390_RWSEM_H */
diff -Nru a/include/asm-s390/s390-gdbregs.h b/include/asm-s390/s390-gdbregs.h
--- a/include/asm-s390/s390-gdbregs.h	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/*
- *  include/asm-s390/s390-gdbregs.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *
- *  used both by the linux kernel for remote debugging & gdb 
- */
-
-#ifndef _S390_GDBREGS_H
-#define _S390_GDBREGS_H
-
-#ifdef __KERNEL__
-#include <asm/s390-regs-common.h>
-#else
-#include <s390/s390-regs-common.h>
-#endif
-#define S390_MAX_INSTR_SIZE 6
-#define NUM_REGS      (2+NUM_GPRS+NUM_ACRS+NUM_CRS+1+NUM_FPRS)
-#define FIRST_ACR     (2+NUM_GPRS)
-#define LAST_ACR      (FIRST_ACR+NUM_ACRS-1)
-#define FIRST_CR      (FIRST_ACR+NUM_ACRS)
-#define LAST_CR       (FIRST_CR+NUM_CRS-1)
-
-#define PSWM_REGNUM    0
-#define PC_REGNUM      1
-#define	GP0_REGNUM     2		    /* GPR register 0 */ 
-#define GP_LAST_REGNUM (GP0_REGNUM+NUM_GPRS-1)
-#define RETADDR_REGNUM (GP0_REGNUM+14)                   /* Usually return address */
-#define SP_REGNUM      (GP0_REGNUM+15)	    /* Contains address of top of stack */
-#define FP_REGNUM     SP_REGNUM /* needed in findvar.c still */
-#define FRAME_REGNUM  (GP0_REGNUM+11)
-#define FPC_REGNUM    (GP0_REGNUM+NUM_GPRS+NUM_ACRS+NUM_CRS)
-#define FP0_REGNUM    (FPC_REGNUM+1) /* FPR (Floating point) register 0 */
-#define FPLAST_REGNUM (FP0_REGNUM+NUM_FPRS-1)	/* Last floating point register */
-
-/* The top of this structure is as similar as possible to a pt_regs structure to */
-/* simplify code */
-typedef struct
-{
-	S390_REGS_COMMON
-	__u32         crs[NUM_CRS];
-	s390_fp_regs  fp_regs;
-} s390_gdb_regs __attribute__((packed));
-
-#define REGISTER_NAMES                                           \
-{                                                                \
-"pswm","pswa",                                                   \
-"gpr0","gpr1","gpr2","gpr3","gpr4","gpr5","gpr6","gpr7",         \
-"gpr8","gpr9","gpr10","gpr11","gpr12","gpr13","gpr14","gpr15",   \
-"acr0","acr1","acr2","acr3","acr4","acr5","acr6","acr7",         \
-"acr8","acr9","acr10","acr11","acr12","acr13","acr14","acr15",   \
-"cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",                 \
-"cr8","cr9","cr10","cr11","cr12","cr13","cr14","cr15",           \
-"fpc",                                                           \
-"fpr0","fpr1","fpr2","fpr3","fpr4","fpr5","fpr6","fpr7",         \
-"fpr8","fpr9","fpr10","fpr11","fpr12","fpr13","fpr14","fpr15"    \
-}
-
-/* Index within `registers' of the first byte of the space for
-   register N.  */
-
-#define FP0_OFFSET ((PSW_MASK_SIZE+PSW_ADDR_SIZE)+ \
-(GPR_SIZE*NUM_GPRS)+(ACR_SIZE+NUM_ACRS)+ \
-(CR_SIZE*NUM_CRS)+(FPC_SIZE+FPC_PAD_SIZE))
-
-#define REGISTER_BYTES    \
-((FP0_OFFSET)+(FPR_SIZE*NUM_FPRS))
-
-#define REGISTER_BYTE(N)  ((N) < FP0_REGNUM ? (N)*4:(FP0_OFFSET+((N)-FP0_REGNUM)*FPR_SIZE))
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h
--- a/include/asm-s390/s390_ext.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/s390_ext.h	Sat Jun  8 22:31:36 2002
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -Nru a/include/asm-s390/s390io.h b/include/asm-s390/s390io.h
--- a/include/asm-s390/s390io.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/s390io.h	Sat Jun  8 22:31:51 2002
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */
+
      union {
         unsigned int info;
         struct {
@@ -50,10 +53,9 @@
            unsigned int  esid      : 1;  /* Ext. SenseID supported by HW */
            unsigned int  rcd       : 1;  /* RCD supported by HW */
            unsigned int  repnone   : 1;  /* don't call IRQ handler on interrupt */
-           unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 23); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +77,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +92,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -Nru a/include/asm-s390/s390mach.h b/include/asm-s390/s390mach.h
--- a/include/asm-s390/s390mach.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/s390mach.h	Sat Jun  8 22:31:36 2002
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -Nru a/include/asm-s390/scatterlist.h b/include/asm-s390/scatterlist.h
--- a/include/asm-s390/scatterlist.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390/scatterlist.h	Sat Jun  8 22:31:49 2002
@@ -1,5 +1,5 @@
-#ifndef _ASMS390X_SCATTERLIST_H
-#define _ASMS390X_SCATTERLIST_H
+#ifndef _ASMS390_SCATTERLIST_H
+#define _ASMS390_SCATTERLIST_H
 
 struct scatterlist {
     struct page *page;
diff -Nru a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h
--- a/include/asm-s390/semaphore.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390/semaphore.h	Sat Jun  8 22:31:35 2002
@@ -2,7 +2,7 @@
  *  include/asm-s390/semaphore.h
  *
  *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *
  *  Derived from "include/asm-i386/semaphore.h"
  *    (C) Copyright 1996 Linus Torvalds
@@ -17,16 +17,17 @@
 #include <linux/rwsem.h>
 
 struct semaphore {
+	/*
+	 * Note that any negative value of count is equivalent to 0,
+	 * but additionally indicates that some process(es) might be
+	 * sleeping on `wait'.
+	 */
 	atomic_t count;
-	int sleepers;
 	wait_queue_head_t wait;
 };
 
-#define __SEM_DEBUG_INIT(name)
-
 #define __SEMAPHORE_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
-	__SEM_DEBUG_INIT(name) }
+	{ ATOMIC_INIT(count), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
 
 #define __MUTEX_INITIALIZER(name) \
 	__SEMAPHORE_INITIALIZER(name,1)
@@ -39,7 +40,7 @@
 
 static inline void sema_init (struct semaphore *sem, int val)
 {
-	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+	*sem = (struct semaphore) __SEMAPHORE_INITIALIZER((*sem),val);
 }
 
 static inline void init_MUTEX (struct semaphore *sem)
@@ -52,11 +53,6 @@
 	sema_init(sem, 0);
 }
 
-asmlinkage void __down_failed(void /* special register calling convention */);
-asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
-asmlinkage int  __down_failed_trylock(void  /* params in registers */);
-asmlinkage void __up_wakeup(void /* special register calling convention */);
-
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
@@ -79,11 +75,28 @@
 
 static inline int down_trylock(struct semaphore * sem)
 {
-	int ret = 0;
+	int old_val, new_val;
 
-	if (atomic_dec_return(&sem->count) < 0)
-		ret = __down_trylock(sem);
-	return ret;
+	/*
+	 * This inline assembly atomically implements the equivalent
+	 * to the following C code:
+	 *   old_val = sem->count.counter;
+	 *   if ((new_val = old_val) > 0)
+	 *       sem->count.counter = --new_val;
+	 * In the ppc code this is called atomic_dec_if_positive.
+	 */
+	__asm__ __volatile__ (
+		"   l    %0,0(%3)\n"
+		"0: ltr  %1,%0\n"
+		"   jle  1f\n"
+		"   ahi  %1,-1\n"
+		"   cs   %0,%1,0(%3)\n"
+		"   jl   0b\n"
+		"1:"
+		: "=&d" (old_val), "=&d" (new_val),
+		  "+m" (sem->count.counter)
+		: "a" (&sem->count.counter) : "cc" );
+	return old_val <= 0;
 }
 
 static inline void up(struct semaphore * sem)
diff -Nru a/include/asm-s390/setup.h b/include/asm-s390/setup.h
--- a/include/asm-s390/setup.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390/setup.h	Sat Jun  8 22:31:52 2002
@@ -13,7 +13,7 @@
 #define RAMDISK_ORIGIN		0x800000
 #define RAMDISK_SIZE		0x800000
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 #define IPL_DEVICE        (*(unsigned long *)  (0x10404))
 #define INITRD_START      (*(unsigned long *)  (0x1040C))
diff -Nru a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h
--- a/include/asm-s390/siginfo.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/siginfo.h	Sat Jun  8 22:31:37 2002
@@ -14,80 +14,73 @@
 #include <asm-generic/siginfo.h>
 
 /*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#undef SI_TIMER
-#define SI_TIMER	-2	/* sent by timer expiration */
-
-/*
  * SIGILL si_codes
  */
-#define ILL_ILLOPC	1	/* illegal opcode */
-#define ILL_ILLOPN	2	/* illegal operand */
-#define ILL_ILLADR	3	/* illegal addressing mode */
-#define ILL_ILLTRP	4	/* illegal trap */
-#define ILL_PRVOPC	5	/* privileged opcode */
-#define ILL_PRVREG	6	/* privileged register */
-#define ILL_COPROC	7	/* coprocessor error */
-#define ILL_BADSTK	8	/* internal stack error */
+#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
+#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
+#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
+#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
+#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
+#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
+#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
+#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
 #define NSIGILL		8
 
 /*
  * SIGFPE si_codes
  */
-#define FPE_INTDIV	1	/* integer divide by zero */
-#define FPE_INTOVF	2	/* integer overflow */
-#define FPE_FLTDIV	3	/* floating point divide by zero */
-#define FPE_FLTOVF	4	/* floating point overflow */
-#define FPE_FLTUND	5	/* floating point underflow */
-#define FPE_FLTRES	6	/* floating point inexact result */
-#define FPE_FLTINV	7	/* floating point invalid operation */
-#define FPE_FLTSUB	8	/* subscript out of range */
+#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
+#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
+#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
+#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
+#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
+#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
+#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
+#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
 #define NSIGFPE		8
 
 /*
  * SIGSEGV si_codes
  */
-#define SEGV_MAPERR	1	/* address not mapped to object */
-#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
+#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
+#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
 #define NSIGSEGV	2
 
 /*
  * SIGBUS si_codes
  */
-#define BUS_ADRALN	1	/* invalid address alignment */
-#define BUS_ADRERR	2	/* non-existant physical address */
-#define BUS_OBJERR	3	/* object specific hardware error */
+#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
+#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
+#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
 #define NSIGBUS		3
 
 /*
  * SIGTRAP si_codes
  */
-#define TRAP_BRKPT	1	/* process breakpoint */
-#define TRAP_TRACE	2	/* process trace trap */
+#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
+#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
 #define NSIGTRAP	2
 
 /*
  * SIGCHLD si_codes
  */
-#define CLD_EXITED	1	/* child has exited */
-#define CLD_KILLED	2	/* child was killed */
-#define CLD_DUMPED	3	/* child terminated abnormally */
-#define CLD_TRAPPED	4	/* traced child has trapped */
-#define CLD_STOPPED	5	/* child has stopped */
-#define CLD_CONTINUED	6	/* stopped child has continued */
+#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
+#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
+#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
+#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
+#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
+#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
 #define NSIGCHLD	6
 
 /*
  * SIGPOLL si_codes
  */
-#define POLL_IN		1	/* data input available */
-#define POLL_OUT	2	/* output buffers available */
-#define POLL_MSG	3	/* input message available */
-#define POLL_ERR	4	/* i/o error */
-#define POLL_PRI	5	/* high priority input available */
-#define POLL_HUP	6	/* device disconnected */
+#define POLL_IN		(__SI_POLL|1)	/* data input available */
+#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
+#define POLL_MSG	(__SI_POLL|3)	/* input message available */
+#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
+#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
+#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
 #define NSIGPOLL	6
 
 #endif
diff -Nru a/include/asm-s390/signal.h b/include/asm-s390/signal.h
--- a/include/asm-s390/signal.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/signal.h	Sat Jun  8 22:31:36 2002
@@ -13,6 +13,7 @@
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
+struct pt_regs;
 
 #ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
diff -Nru a/include/asm-s390/sigp.h b/include/asm-s390/sigp.h
--- a/include/asm-s390/sigp.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390/sigp.h	Sat Jun  8 22:31:49 2002
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
@@ -129,6 +126,6 @@
    return ccode;
 }
 
-#endif __SIGP__
+#endif /* __SIGP__ */
 
 
diff -Nru a/include/asm-s390/smp.h b/include/asm-s390/smp.h
--- a/include/asm-s390/smp.h	Sat Jun  8 22:31:43 2002
+++ b/include/asm-s390/smp.h	Sat Jun  8 22:31:43 2002
@@ -10,6 +10,8 @@
 #define __ASM_SMP_H
 
 #include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/ptrace.h>
 
 #if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
 
@@ -26,7 +28,7 @@
 	__u16      cpu;
 } sigp_info;
 
-extern unsigned long cpu_online_map;
+extern volatile unsigned long cpu_online_map;
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
@@ -42,7 +44,7 @@
  
 #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
 
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current_thread_info()->cpu)
 
 extern __inline__ int cpu_logical_map(int cpu)
 {
@@ -63,8 +65,6 @@
 }
 
 #define cpu_logical_map(cpu) (cpu)
-
-void smp_local_timer_interrupt(struct pt_regs * regs);
 
 #endif
 #endif
diff -Nru a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
--- a/include/asm-s390/spinlock.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390/spinlock.h	Sat Jun  8 22:31:49 2002
@@ -27,32 +27,34 @@
 #define spin_unlock_wait(lp)	do { barrier(); } while(((volatile spinlock_t *)(lp))->lock)
 #define spin_is_locked(x) ((x)->lock != 0)
 
-extern inline void spin_lock(spinlock_t *lp)
+extern inline void _raw_spin_lock(spinlock_t *lp)
 {
-        __asm__ __volatile("    bras  1,1f\n"
+	unsigned int reg1, reg2;
+        __asm__ __volatile("    bras  %0,1f\n"
                            "0:  diag  0,0,68\n"
-                           "1:  slr   0,0\n"
-                           "    cs    0,1,0(%0)\n"
+                           "1:  slr   %1,%1\n"
+                           "    cs    %1,%0,0(%3)\n"
                            "    jl    0b\n"
-                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
+                           : "=&d" (reg1), "=&d" (reg2), "+m" (lp->lock)
+			   : "a" (&lp->lock) : "cc" );
 }
 
-extern inline int spin_trylock(spinlock_t *lp)
+extern inline int _raw_spin_trylock(spinlock_t *lp)
 {
-	unsigned long result;
+	unsigned long result, reg;
 	__asm__ __volatile("    slr   %0,%0\n"
-			   "    basr  1,0\n"
-			   "0:  cs    %0,1,0(%1)"
-			   : "=&d" (result)
-			   : "a" (&lp->lock) : "1", "cc", "memory" );
+			   "    basr  %1,0\n"
+			   "0:  cs    %0,%1,0(%3)"
+			   : "=&d" (result), "=&d" (reg), "+m" (lp->lock)
+			   : "a" (&lp->lock) : "cc" );
 	return !result;
 }
 
-extern inline void spin_unlock(spinlock_t *lp)
+extern inline void _raw_spin_unlock(spinlock_t *lp)
 {
-	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
+	__asm__ __volatile("    xc 0(4,%1),0(%1)\n"
                            "    bcr 15,0"
-			   : : "a" (&lp->lock) : "memory", "cc" );
+			   : "+m" (lp->lock) : "a" (&lp->lock) : "cc" );
 }
 		
 /*
@@ -74,44 +76,48 @@
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
-#define read_lock(rw)   \
-        asm volatile("   l     2,0(%0)\n"   \
+#define _raw_read_lock(rw)   \
+        asm volatile("   l     2,0(%1)\n"   \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: la    2,0(2)\n"     /* clear high (=write) bit */ \
                      "   la    3,1(2)\n"     /* one more reader */ \
-                     "   cs    2,3,0(%0)\n"  /* try to write new value */ \
+                     "   cs    2,3,0(%1)\n"  /* try to write new value */ \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define read_unlock(rw) \
-        asm volatile("   l     2,0(%0)\n"   \
+#define _raw_read_unlock(rw) \
+        asm volatile("   l     2,0(%1)\n"   \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: lr    3,2\n"    \
                      "   ahi   3,-1\n"    /* one less reader */ \
-                     "   cs    2,3,0(%0)\n" \
+                     "   cs    2,3,0(%1)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define write_lock(rw) \
+#define _raw_write_lock(rw) \
         asm volatile("   lhi   3,1\n"    \
                      "   sll   3,31\n"    /* new lock value = 0x80000000 */ \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: slr   2,2\n"     /* old lock value must be 0 */ \
-                     "   cs    2,3,0(%0)\n" \
+                     "   cs    2,3,0(%1)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define write_unlock(rw) \
+#define _raw_write_unlock(rw) \
         asm volatile("   slr   3,3\n"     /* new lock value = 0 */ \
                      "   j     1f\n"     \
                      "0: diag  0,0,68\n" \
                      "1: lhi   2,1\n"    \
                      "   sll   2,31\n"    /* old lock value must be 0x80000000 */ \
-                     "   cs    2,3,0(%0)\n" \
+                     "   cs    2,3,0(%1)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
 #endif /* __ASM_SPINLOCK_H */
diff -Nru a/include/asm-s390/suspend.h b/include/asm-s390/suspend.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/suspend.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,5 @@
+#ifndef __ASM_S390_SUSPEND_H
+#define __ASM_S390_SUSPEND_H
+
+#endif
+
diff -Nru a/include/asm-s390/system.h b/include/asm-s390/system.h
--- a/include/asm-s390/system.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/system.h	Sat Jun  8 22:31:37 2002
@@ -12,18 +12,19 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #ifdef __KERNEL__
 #include <asm/lowcore.h>
 #endif
 #include <linux/kernel.h>
 
 #define prepare_to_switch()	do { } while(0)
-#define switch_to(prev,next,last) do {                                       \
-        if (prev == next)                                                    \
-                break;                                                       \
-	save_fp_regs1(&prev->thread.fp_regs);                                \
-	restore_fp_regs1(&next->thread.fp_regs);              		     \
-	last = resume(&prev->thread,&next->thread);                          \
+#define switch_to(prev,next) do {					     \
+	if (prev == next)						     \
+		break;							     \
+	save_fp_regs1(&prev->thread.fp_regs);				     \
+	restore_fp_regs1(&next->thread.fp_regs);			     \
+	resume(prev,next);						     \
 } while (0)
 
 struct task_struct;
@@ -97,8 +98,6 @@
                                 : "+d&" (x) : "a" (ptr)
                                 : "memory", "cc", "0" );
                         break;
-               default:
-                        abort();
         }
         return x;
 }
@@ -130,26 +129,26 @@
 
 /* interrupt control.. */
 #define __sti() ({ \
-        __u8 dummy; \
+        __u8 __dummy; \
         __asm__ __volatile__ ( \
-                "stosm %0,0x03" : "=m" (dummy) : : "memory"); \
+                "stosm 0(%0),0x03" : : "a" (&__dummy) : "memory"); \
         })
 
 #define __cli() ({ \
-        __u32 flags; \
+        __u32 __flags; \
         __asm__ __volatile__ ( \
-                "stnsm %0,0xFC" : "=m" (flags) : : "memory"); \
-        flags; \
+                "stnsm 0(%0),0xFC" : : "a" (&__flags) : "memory"); \
+        __flags; \
         })
 
 #define __save_flags(x) \
-        __asm__ __volatile__("stosm %0,0" : "=m" (x) : : "memory")
+        __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory")
 
 #define __restore_flags(x) \
-        __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
+        __asm__ __volatile__("ssm   0(%0)" : : "a" (&x) : "memory")
 
 #define __load_psw(psw) \
-	__asm__ __volatile__("lpsw %0" : : "m" (psw) : "cc" );
+	__asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
@@ -170,7 +169,7 @@
 	})
 
 #define __ctl_set_bit(cr, bit) ({ \
-        __u8 dummy[16]; \
+        __u8 __dummy[16]; \
         __asm__ __volatile__ ( \
                 "    la    1,%0\n"       /* align to 8 byte */ \
                 "    ahi   1,7\n" \
@@ -184,12 +183,12 @@
                 "    or    0,%2\n"       /* set the bit */ \
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
-                : "=m" (dummy) : "a" (cr*17), "a" (1<<(bit)) \
+                : "=m" (__dummy) : "a" (cr*17), "a" (1<<(bit)) \
                 : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
-        __u8 dummy[16]; \
+        __u8 __dummy[16]; \
         __asm__ __volatile__ ( \
                 "    la    1,%0\n"       /* align to 8 byte */ \
                 "    ahi   1,7\n" \
@@ -203,7 +202,7 @@
                 "    nr    0,%2\n"       /* set the bit */ \
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
-                : "=m" (dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
+                : "=m" (__dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
                 : "cc", "0", "1", "2"); \
         })
 
@@ -244,12 +243,17 @@
 #endif
 
 #ifdef __KERNEL__
-extern struct task_struct *resume(void *,void *);
+extern struct task_struct *resume(void *, void *);
 
 extern int save_fp_regs1(s390_fp_regs *fpregs);
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -Nru a/include/asm-s390/tape390.h b/include/asm-s390/tape390.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/tape390.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * tape390.h
+ *         enables user programs to display messages on the tape device
+ *
+ *  S390 and zSeries version
+ *         Copyright (C) 2001 IBM Corporation
+ *         Author(s): Despina Papadopoulou <despina_p@de.ibm.com>
+ *
+ *************************************************************************/
+
+#ifndef _TAPE390_H
+#define _TAPE390_H
+
+#define TAPE390_DISPLAY _IOW('d', 1, struct display_struct)
+
+/*
+ * The TAPE390_DISPLAY ioctl calls the Load Display command
+ * which transfers 17 bytes of data from the channel to the subsystem:
+ *     - 1 format control byte, and
+ *     - two 8-byte messages
+ *
+ * Format control byte:
+ *   0-2: New Message Overlay
+ *     3: Alternate Messages
+ *     4: Blink Message
+ *     5: Display Low/High Message
+ *     6: Reserved
+ *     7: Automatic Load Request
+ *
+ */
+
+typedef struct display_struct {
+        char cntrl;
+        char message1[8];
+        char message2[8];
+} display_struct;
+
+#endif 
diff -Nru a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/thread_info.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,87 @@
+/*
+ *  include/asm-s390/thread_info.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants must also be changed
+ */
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	unsigned long		flags;		/* low level flags */
+	unsigned int		cpu;		/* current CPU */
+	int			preempt_count; /* 0 => preemptable, <0 => BUG */
+};
+
+#define PREEMPT_ACTIVE		0x4000000
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	task:		&tsk,			\
+	exec_domain:	&default_exec_domain,	\
+	flags:		0,			\
+	cpu:		0,			\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+	return (struct thread_info *)((*(unsigned long *) 0xc40)-8192);
+}
+
+/* thread information allocation */
+#define alloc_thread_info() ((struct thread_info *) \
+	__get_free_pages(GFP_KERNEL,1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#endif
+
+/*
+ * Size of kernel stack for each process
+ */
+#define THREAD_SIZE (2*PAGE_SIZE)
+
+/*
+ * thread information flags bit numbers
+ */
+#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* resumption notification requested */
+#define TIF_SIGPENDING		2	/* signal pending */
+#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+#define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
+#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling 
+					   TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+#define _TIF_USEDFPU		(1<<TIF_USEDFPU)
+#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff -Nru a/include/asm-s390/timex.h b/include/asm-s390/timex.h
--- a/include/asm-s390/timex.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390/timex.h	Sat Jun  8 22:31:35 2002
@@ -17,13 +17,24 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
-typedef unsigned long cycles_t;
+typedef unsigned long long cycles_t;
 
 extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles(void)
 {
-        return 0;
+	cycles_t cycles;
+
+	__asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
+	return cycles >> 2;
+}
+
+static inline unsigned long long get_clock (void)
+{
+	unsigned long long clk;
+
+	__asm__("stck 0(%0)" : : "a" (&(clk)) : "memory", "cc");
+	return clk;
 }
 
 #endif
diff -Nru a/include/asm-s390/tlb.h b/include/asm-s390/tlb.h
--- a/include/asm-s390/tlb.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390/tlb.h	Sat Jun  8 22:31:37 2002
@@ -1 +1,20 @@
+#ifndef _S390_TLB_H
+#define _S390_TLB_H
+
+/*
+ * s390 doesn't need any special per-pte or
+ * per-vma handling..
+ */
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
 #include <asm-generic/tlb.h>
+
+#endif
diff -Nru a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390/tlbflush.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,138 @@
+#ifndef _S390_TLBFLUSH_H
+#define _S390_TLBFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <asm/processor.h>
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs 
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+/*
+ * S/390 has three ways of flushing TLBs
+ * 'ptlb' does a flush of the local processor
+ * 'csp' flushes the TLBs on all PUs of a SMP
+ * 'ipte' invalidates a pte in a page table and flushes that out of
+ * the TLBs of all PUs of a SMP
+ */
+
+#define local_flush_tlb() \
+do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
+
+
+#ifndef CONFIG_SMP
+
+/*
+ * We always need to flush, since s390 does not flush tlb
+ * on each context switch
+ */
+
+static inline void flush_tlb(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_all(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	local_flush_tlb();
+}
+
+#define flush_tlb_kernel_range(start, end) \
+	local_flush_tlb();
+
+#else
+
+#include <asm/smp.h>
+
+extern void smp_ptlb_all(void);
+
+static inline void global_flush_tlb(void)
+{
+	if (MACHINE_HAS_CSP) {
+		long dummy = 0;
+		__asm__ __volatile__ (
+			"    la   4,1(%0)\n"
+			"    slr  2,2\n"
+			"    slr  3,3\n"
+			"    csp  2,4"
+			: : "a" (&dummy) : "cc", "2", "3", "4" );
+	} else
+		smp_ptlb_all();
+}
+
+/*
+ * We only have to do global flush of tlb if process run since last
+ * flush on any other pu than current. 
+ * If we have threads (mm->count > 1) we always do a global flush, 
+ * since the process runs on more than one processor at the same time.
+ */
+
+static inline void __flush_tlb_mm(struct mm_struct * mm)
+{
+	if ((smp_num_cpus > 1) &&
+	    ((atomic_read(&mm->mm_count) != 1) ||
+	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
+		global_flush_tlb();
+	} else {                 
+		local_flush_tlb();
+	}
+}
+
+static inline void flush_tlb(void)
+{
+	__flush_tlb_mm(current->mm);
+}
+static inline void flush_tlb_all(void)
+{
+	global_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	__flush_tlb_mm(mm); 
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	__flush_tlb_mm(vma->vm_mm);
+}
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	__flush_tlb_mm(vma->vm_mm); 
+}
+
+#define flush_tlb_kernel_range(start, end) \
+	__flush_tlb_mm(&init_mm)
+
+#endif
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+                                      unsigned long start, unsigned long end)
+{
+        /* S/390 does not keep any page table caches in TLB */
+}
+
+#endif /* _S390_TLBFLUSH_H */
diff -Nru a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
--- a/include/asm-s390/uaccess.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390/uaccess.h	Sat Jun  8 22:31:36 2002
@@ -15,6 +15,7 @@
  * User space memory access functions
  */
 #include <linux/sched.h>
+#include <linux/errno.h>
 
 #define VERIFY_READ     0
 #define VERIFY_WRITE    1
@@ -28,21 +29,22 @@
  * For historical reasons, these macros are grossly misnamed.
  */
 
-#define MAKE_MM_SEG(s,a)  ((mm_segment_t) { (s),(a) })
+#define MAKE_MM_SEG(a)  ((mm_segment_t) { (a) })
 
 
-#define KERNEL_DS       MAKE_MM_SEG(0x7FFFFFFF,0)
-#define USER_DS         MAKE_MM_SEG(PAGE_OFFSET,1)
+#define KERNEL_DS       MAKE_MM_SEG(0)
+#define USER_DS         MAKE_MM_SEG(1)
 
 #define get_ds()        (KERNEL_DS)
-#define get_fs()        (current->thread.fs)
-#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" (x.acc4)); \
-                         current->thread.fs = (x);})
+#define get_fs()        ({ mm_segment_t __x; \
+			   asm volatile("ear   %0,4":"=a" (__x)); \
+			   __x;})
+#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));})
 
-#define segment_eq(a,b) ((a).acc4 == (b).acc4)
+#define segment_eq(a,b) ((a).ar4 == (b).ar4)
 
 
-#define __access_ok(addr,size) ((((long) addr + size)&0x7FFFFFFFL) < current->addr_limit.seg)
+#define __access_ok(addr,size) (1)
 
 #define access_ok(type,addr,size) __access_ok(addr,size)
 
@@ -78,20 +80,20 @@
  * use the right size if we just have the right pointer type.
  */
 
-extern inline int __put_user_asm_8(__u64 x, void *ptr)
+extern inline int __put_user_asm_8(void *x, void *ptr)
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    2,%2\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,01\n"
+				"   lr    2,%1\n"
+				"   lr    4,%2\n"
                                 "   sacf  512\n"
                                 "0: mvc   0(8,4),0(2)\n"
                                 "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
 				"2: sacf  0\n"
-				"   lhi   %1,%h3\n"
+				"   lhi   %0,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
 				"3: l     4,0(4)\n"
@@ -101,8 +103,8 @@
 				"   .align 4\n"
 				"   .long  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u32*) ptr)), "=&d" (err)
-                                : "m" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "d" (x), "d" (ptr), "K" (-EFAULT)
                                 : "cc", "2", "4" );
         return err;
 }
@@ -111,15 +113,15 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   lr    4,%2\n"
                                 "   sacf  512\n"
-                                "0: st    %2,0(4)\n"
+                                "0: st    %1,0(4)\n"
                                 "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
 				"2: sacf  0\n"
-				"   lhi   %1,%h3\n"
+				"   lhi   %0,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
 				"3: l     4,0(4)\n"
@@ -129,8 +131,8 @@
 				"   .align 4\n"
 				"   .long  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u32*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "d" (x), "d" (ptr), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -139,15 +141,15 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   lr    4,%2\n"
                                 "   sacf  512\n"
-                                "0: sth   %2,0(4)\n"
+                                "0: sth   %1,0(4)\n"
                                 "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
 				"2: sacf  0\n"
-				"   lhi   %1,%h3\n"
+				"   lhi   %0,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
 				"3: l     4,0(4)\n"
@@ -157,8 +159,8 @@
 				"   .align 4\n"
 				"   .long  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u16*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "d" (x), "d" (ptr), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -167,15 +169,15 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   lr    4,%2\n"
                                 "   sacf  512\n"
-                                "0: stc   %2,0(4)\n"
+                                "0: stc   %1,0(4)\n"
                                 "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
 				"2: sacf  0\n"
-				"   lhi   %1,%h3\n"
+				"   lhi   %0,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
 				"3: l     4,0(4)\n"
@@ -185,8 +187,8 @@
 				"   .align 4\n"
 				"   .long  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u8*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "d" (x), "d" (ptr), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -197,38 +199,33 @@
  */
 #define __put_user(x, ptr)                                      \
 ({                                                              \
+        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
+        __typeof__(*(ptr)) __x = (x);                           \
         int __pu_err;                                           \
         switch (sizeof (*(ptr))) {                              \
-                case 1:                                         \
-                        __pu_err = __put_user_asm_1((__u8)(__u32)x,(ptr));\
-                        break;                                  \
-                case 2:                                         \
-                        __pu_err = __put_user_asm_2((__u16)(__u32)x,(ptr));\
-                        break;                                  \
-                case 4:                                         \
-                        __pu_err = __put_user_asm_4((__u32) x,(ptr));\
-                        break;                                  \
-		case 8:						\
-			__pu_err = __put_user_asm_8((__u64) x,(ptr));\
-			break;					\
-                default:                                        \
+        case 1:                                                 \
+                __pu_err = __put_user_asm_1((__u8)(__u32) __x,  \
+                                            __pu_addr);         \
+                break;                                          \
+        case 2:                                                 \
+                __pu_err = __put_user_asm_2((__u16)(__u32) __x, \
+                                            __pu_addr);         \
+                break;                                          \
+        case 4:                                                 \
+                __pu_err = __put_user_asm_4((__u32) __x,        \
+                                            __pu_addr);         \
+                break;                                          \
+        case 8:                                                 \
+                __pu_err = __put_user_asm_8(&__x, __pu_addr);   \
+                break;                                          \
+        default:                                                \
                 __pu_err = __put_user_bad();                    \
                 break;                                          \
          }                                                      \
         __pu_err;                                               \
 })
 
-#define put_user(x, ptr)                                        \
-({                                                              \
-        long __pu_err = -EFAULT;                                \
-        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
-        __typeof__(*(ptr)) __x = (x);                           \
-        if (__access_ok((long)__pu_addr,sizeof(*(ptr)))) {      \
-                __pu_err = 0;                                   \
-                __put_user((__x), (__pu_addr));                 \
-        }                                                       \
-        __pu_err;                                               \
-})
+#define put_user(x, ptr) __put_user(x, ptr)
 
 extern int __put_user_bad(void);
 
@@ -336,42 +333,32 @@
 
 #define __get_user(x, ptr)                                      \
 ({                                                              \
+        __typeof__(ptr) __gu_addr = (ptr);                      \
+        __typeof__(*(ptr)) __x;                                 \
         int __gu_err;                                           \
-        switch (sizeof(*(ptr))) {                               \
-                case 1:                                         \
-                        __get_user_asm_1(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 2:                                         \
-                        __get_user_asm_2(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 4:                                         \
-                        __get_user_asm_4(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 8:                                         \
-                        __get_user_asm_8(x,ptr,__gu_err);       \
-                        break;                                  \
-                default:                                        \
-                        (x) = 0;                                \
-                        __gu_err = __get_user_bad();            \
+        switch (sizeof(*(__gu_addr))) {                         \
+        case 1:                                                 \
+                __get_user_asm_1(__x, __gu_addr, __gu_err);     \
+                break;                                          \
+        case 2:                                                 \
+                __get_user_asm_2(__x, __gu_addr, __gu_err);     \
+                break;                                          \
+        case 4:                                                 \
+                __get_user_asm_4(__x, __gu_addr, __gu_err);     \
+                break;                                          \
+        case 8:                                                 \
+                __get_user_asm_8(__x, __gu_addr, __gu_err);     \
+                break;                                          \
+        default:                                                \
+                __x = 0;                                        \
+                __gu_err = __get_user_bad();                    \
                 break;                                          \
         }                                                       \
+        (x) = __x;                                              \
         __gu_err;                                               \
 })
 
-#define get_user(x, ptr)                                        \
-({                                                              \
-        long __gu_err = -EFAULT;                                \
-        __typeof__(ptr) __gu_addr = (ptr);                      \
-        __typeof__(*(ptr)) __x;                                 \
-        if (__access_ok((long)__gu_addr,sizeof(*(ptr)))) {      \
-                __gu_err = 0;                                   \
-                __get_user((__x), (__gu_addr));                 \
-                (x) = __x;                                      \
-        }                                                       \
-        else                                                    \
-                (x) = 0;                                        \
-        __gu_err;                                               \
-})
+#define get_user(x, ptr) __get_user(x, ptr)
 
 extern int __get_user_bad(void);
 
@@ -379,34 +366,11 @@
  * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
  */
 
-asmlinkage void __copy_from_user_fixup(void /* special calling convention */);
-asmlinkage void __copy_to_user_fixup(void /* special calling convention */);
-
-extern inline unsigned long
-__copy_to_user_asm(void* to, const void* from,  long n)
-{
-
-        __asm__ __volatile__ (  "   lr    2,%2\n"
-                                "   lr    4,%1\n"
-                                "   lr    3,%0\n"
-                                "   lr    5,3\n"
-                                "   sacf  512\n"
-                                "0: mvcle 4,2,0\n"
-                                "   jo    0b\n"
-                                "   sacf  0\n"
-                                "   lr    %0,3\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 4\n"
-				"   .long  0b,__copy_to_user_fixup\n"
-				".previous"
-                                : "+&d" (n) : "d" (to), "d" (from)
-                                : "cc", "2", "3", "4", "5" );
-        return n;
-}
+extern long __copy_to_user_asm(const void *from, long n, const void *to);
 
 #define __copy_to_user(to, from, n)                             \
 ({                                                              \
-        __copy_to_user_asm(to,from,n);                          \
+        __copy_to_user_asm(from, n, to);                        \
 })
 
 #define copy_to_user(to, from, n)                               \
@@ -414,38 +378,18 @@
         long err = 0;                                           \
         __typeof__(n) __n = (n);                                \
         if (__access_ok(to,__n)) {                              \
-                err = __copy_to_user_asm(to,from,__n);          \
+                err = __copy_to_user_asm(from, __n, to);        \
         }                                                       \
         else                                                    \
                 err = __n;                                      \
         err;                                                    \
 })
 
-extern inline unsigned long
-__copy_from_user_asm(void* to, const void* from,  long n)
-{
-        __asm__ __volatile__ (  "   lr    2,%1\n"
-                                "   lr    4,%2\n"
-                                "   lr    3,%0\n"
-                                "   lr    5,3\n"
-                                "   sacf  512\n"
-                                "0: mvcle 2,4,0\n"
-                                "   jo    0b\n"
-                                "   sacf  0\n"
-                                "   lr    %0,5\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 4\n"
-				"   .long  0b,__copy_from_user_fixup\n"
-				".previous"
-                                : "+&d" (n) : "d" (to), "d" (from)
-                                : "cc", "2", "3", "4", "5" );
-        return n;
-}
-
+extern long __copy_from_user_asm(void *to, long n, const void *from);
 
 #define __copy_from_user(to, from, n)                           \
 ({                                                              \
-        __copy_from_user_asm(to,from,n);                        \
+        __copy_from_user_asm(to, n, from);                      \
 })
 
 #define copy_from_user(to, from, n)                             \
@@ -453,7 +397,7 @@
         long err = 0;                                           \
         __typeof__(n) __n = (n);                                \
         if (__access_ok(from,__n)) {                            \
-                err = __copy_from_user_asm(to,from,__n);        \
+                err = __copy_from_user_asm(to, __n, from);      \
         }                                                       \
         else                                                    \
                 err = __n;                                      \
@@ -550,38 +494,12 @@
  * Zero Userspace
  */
 
-static inline unsigned long
-__clear_user(void *to, unsigned long n)
-{
-        __asm__ __volatile__ (  "   sacf  512\n"
-                                "   lr    4,%1\n"
-                                "   lr    5,%0\n"
-                                "   sr    2,2\n"
-                                "   sr    3,3\n"
-                                "0: mvcle 4,2,0\n"
-                                "   jo    0b\n"
-                                "   sacf  0\n"
-                                "1: lr    %0,3\n"
-                                ".section .fixup,\"ax\"\n"
-                                "2: lhi   5,-4096\n"
-                                "   n     5,0x90\n"
-                                "   sr    5,4\n"
-                                "   mvcle 4,2,0\n"
-                                "   sacf  0\n"
-                                "   basr  4,0\n"
-                                "   l     4,3f-.(4)\n"
-                                "   br    4\n"
-                                "3: .long 1b\n"
-                                ".previous\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 4\n"
-				"   .long  0b,2b\n"
-				".previous"
-                                : "+&a" (n)
-                                : "a"   (to)
-                                : "cc", "2", "3", "4", "5" );
-        return n;
-}
+extern long __clear_user_asm(void *to, long n);
+
+#define __clear_user(to, n)                                     \
+({                                                              \
+        __clear_user_asm(to, n);                                \
+})
 
 static inline unsigned long
 clear_user(void *to, unsigned long n)
diff -Nru a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
--- a/include/asm-s390/unistd.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390/unistd.h	Sat Jun  8 22:31:49 2002
@@ -211,8 +211,26 @@
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64		220
-#define __NR_gettid		226
-#define __NR_tkill		227
+#define __NR_fcntl64		221
+#define __NR_readahead		222
+#define __NR_sendfile64		223
+#define __NR_setxattr		224
+#define __NR_lsetxattr		225
+#define __NR_fsetxattr		226
+#define __NR_getxattr		227
+#define __NR_lgetxattr		228
+#define __NR_fgetxattr		229
+#define __NR_listxattr		230
+#define __NR_llistxattr		231
+#define __NR_flistxattr		232
+#define __NR_removexattr	233
+#define __NR_lremovexattr	234
+#define __NR_fremovexattr	235
+#define __NR_gettid		236
+#define __NR_tkill		237
+#define __NR_futex		238
+#define __NR_sched_setaffinity	239
+#define __NR_sched_getaffinity	240
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
@@ -335,6 +353,8 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <asm/stat.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -363,9 +383,11 @@
 static inline _syscall1(int,delete_module,const char *,name)
 static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
 
-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
+struct rusage;
+extern long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
+static inline pid_t waitpid(int pid, int *wait_stat, int flags)
 {
-        return sys_wait4(pid, wait_stat, flags, NULL);
+	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
 static inline pid_t wait(int * wait_stat)
diff -Nru a/include/asm-s390/vtoc.h b/include/asm-s390/vtoc.h
--- a/include/asm-s390/vtoc.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390/vtoc.h	Sat Jun  8 22:31:51 2002
@@ -18,7 +18,6 @@
 #include <asm/dasd.h>
 #endif
 
-#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
diff -Nru a/include/asm-s390x/atomic.h b/include/asm-s390x/atomic.h
--- a/include/asm-s390x/atomic.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/atomic.h	Sat Jun  8 22:31:36 2002
@@ -26,29 +26,17 @@
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
 #define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)		\
-        __asm__ __volatile__("   l     %0,0(%2)\n"			\
+        __asm__ __volatile__("   l     %0,0(%3)\n"			\
                              "0: lr    %1,%0\n"				\
-                             op_string "  %1,%3\n"			\
-                             "   cs    %0,%1,0(%2)\n"			\
+                             op_string "  %1,%4\n"			\
+                             "   cs    %0,%1,0(%3)\n"			\
                              "   jl    0b"				\
-                             : "=&d" (old_val), "=&d" (new_val)		\
+                             : "=&d" (old_val), "=&d" (new_val),	\
+			       "+m" (((atomic_t *)(ptr))->counter)	\
 			     : "a" (ptr), "d" (op_val) : "cc" );
 
-static __inline__ int atomic_read(atomic_t *v)
-{
-        int retval;
-        __asm__ __volatile__("bcr      15,0\n\t"
-                             "l        %0,%1"
-                             : "=d" (retval) : "m" (*v) );
-        return retval;
-}
-
-static __inline__ void atomic_set(atomic_t *v, int i)
-{
-        __asm__ __volatile__("st  %1,%0\n\t"
-                             "bcr 15,0"
-                             : "=m" (*v) : "d" (i) );
-}
+#define atomic_read(v)          ((v)->counter)
+#define atomic_set(v,i)         (((v)->counter) = (i))
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
@@ -138,14 +126,14 @@
         int retval;
 
         __asm__ __volatile__(
-                "  lr   0,%2\n"
-                "  cs   0,%3,0(%1)\n"
+                "  lr   %0,%3\n"
+                "  cs   %0,%4,0(%2)\n"
                 "  ipm  %0\n"
                 "  srl  %0,28\n"
                 "0:"
-                : "=&d" (retval)
+                : "=&d" (retval), "+m" (v->counter)
                 : "a" (v), "d" (expected_oldval) , "d" (new_val)
-                : "0", "cc");
+                : "cc");
         return retval;
 }
 
@@ -155,12 +143,14 @@
 static __inline__ void
 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
 {
+	unsigned long tmp;
         __asm__ __volatile__(
-                "0: lr  0,%1\n"
-                "   cs  0,%2,0(%0)\n"
+                "0: lr  %1,%3\n"
+                "   cs  %1,%4,0(%2)\n"
                 "   jl  0b\n"
-                : : "a" (v), "d" (expected_oldval) , "d" (new_val)
-                : "cc", "0" );
+                : "+m" (v->counter), "=&d" (tmp)
+		: "a" (v), "d" (expected_oldval) , "d" (new_val)
+                : "cc" );
 }
 
 #define atomic_compare_and_swap_debug(where,from,to) \
diff -Nru a/include/asm-s390x/bitops.h b/include/asm-s390x/bitops.h
--- a/include/asm-s390x/bitops.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/bitops.h	Sat Jun  8 22:31:52 2002
@@ -51,270 +51,220 @@
 extern const char _oi_bitmap[];
 extern const char _ni_bitmap[];
 extern const char _zb_findmap[];
+extern const char _sb_findmap[];
 
 #ifdef CONFIG_SMP
 /*
  * SMP save set_bit routine based on compare and swap (CS)
  */
-static __inline__ void set_bit_cs(unsigned long nr, volatile void * addr)
+static inline void set_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sllg  %3,%3,0(%2)\n"  /* make OR mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   ogr   %2,%3\n"        /* set bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
-             : "cc", "memory" );
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 63);	/* make OR mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   ogr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save clear_bit routine based on compare and swap (CS)
  */
-static __inline__ void clear_bit_cs(unsigned long nr, volatile void * addr)
+static inline void clear_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,-2\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   lghi  %3,-2\n"
-             "   rllg  %3,%3,0(%2)\n"  /* make AND mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   ngr   %2,%3\n"        /* clear bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
-             : "cc", "memory" );
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = ~(1UL << (nr & 63));	/* make AND mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   ngr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save change_bit routine based on compare and swap (CS)
  */
-static __inline__ void change_bit_cs(unsigned long nr, volatile void * addr)
+static inline void change_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sllg  %3,%3,0(%2)\n"  /* make XR mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   xgr   %2,%3\n"        /* change bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b"
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) : 
-             : "cc", "memory" );
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 63);	/* make XOR mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   xgr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
 }
 
 /*
  * SMP save test_and_set_bit routine based on compare and swap (CS)
  */
-static __inline__ int 
-test_and_set_bit_cs(unsigned long nr, volatile void * addr)
+static inline int 
+test_and_set_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sllg  %3,%3,0(%2)\n"  /* make OR mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   ogr   %2,%3\n"        /* set bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b\n"
-             "   ngr   %0,%3\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
-             : "cc", "memory" );
-        return nr != 0;
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 63);	/* make OR/test mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   ogr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old & mask) != 0;
 }
 
 /*
  * SMP save test_and_clear_bit routine based on compare and swap (CS)
  */
-static __inline__ int
-test_and_clear_bit_cs(unsigned long nr, volatile void * addr)
+static inline int
+test_and_clear_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,-2\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   rllg  %3,%3,0(%2)\n"  /* make AND mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   ngr   %2,%3\n"        /* clear bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b\n"
-             "   xgr   %0,%2\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
-             : "cc", "memory" );
-        return nr != 0;
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = ~(1UL << (nr & 63));	/* make AND mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   ngr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old ^ new) != 0;
 }
 
 /*
  * SMP save test_and_change_bit routine based on compare and swap (CS) 
  */
-static __inline__ int
-test_and_change_bit_cs(unsigned long nr, volatile void * addr)
+static inline int
+test_and_change_bit_cs(unsigned long nr, volatile void *ptr)
 {
-        unsigned long bits, mask;
-        __asm__ __volatile__(
+        unsigned long addr, old, new, mask;
+
+	addr = (unsigned long) ptr;
 #if ALIGN_CS == 1
-             "   lghi  %2,7\n"         /* CS must be aligned on 4 byte b. */
-             "   ngr   %2,%1\n"        /* isolate last 2 bits of address */
-             "   xgr   %1,%2\n"        /* make addr % 4 == 0 */
-             "   sllg  %2,%2,3\n"
-             "   agr   %0,%2\n"        /* add alignement to bitnr */
+	addr ^= addr & 7;		/* align address to 8 */
+	nr += (addr & 7) << 3;		/* add alignment to bit number */
 #endif
-             "   lghi  %2,63\n"
-             "   nr    %2,%0\n"        /* make shift value */
-             "   xr    %0,%2\n"
-             "   srlg  %0,%0,3\n"
-             "   lghi  %3,1\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
-             "   sllg  %3,%3,0(%2)\n"  /* make OR mask */
-             "   lg    %0,0(%1)\n"
-             "0: lgr   %2,%0\n"        /* CS loop starts here */
-             "   xgr   %2,%3\n"        /* change bit */
-             "   csg   %0,%2,0(%1)\n"
-             "   jl    0b\n"
-             "   ngr   %0,%3\n"        /* isolate old bit */
-             : "+a" (nr), "+a" (addr), "=a" (bits), "=d" (mask) :
-             : "cc", "memory" );
-        return nr != 0;
+	addr += (nr ^ (nr & 63)) >> 3;	/* calculate address for CS */
+	mask = 1UL << (nr & 63);	/* make XOR mask */
+	asm volatile(
+		"   lg   %0,0(%4)\n"
+		"0: lgr  %1,%0\n"
+		"   xgr  %1,%3\n"
+		"   csg  %0,%1,0(%4)\n"
+		"   jl   0b"
+		: "=&d" (old), "=&d" (new), "+m" (*(unsigned long *) addr)
+		: "d" (mask), "a" (addr) 
+		: "cc" );
+	return (old & mask) != 0;
 }
 #endif /* CONFIG_SMP */
 
 /*
  * fast, non-SMP set_bit routine
  */
-static __inline__ void __set_bit(unsigned long nr, volatile void * addr)
+static inline void __set_bit(unsigned long nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   oc    0(1,2),0(1)"
-             :  : "a" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_set_bit(const unsigned long nr, volatile void * addr)
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x01"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7))) 
-                          : : "1", "cc", "memory");
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x02"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x04"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x08"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x10"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x20"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x40"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "oi 0(1),0x80"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+        asm volatile("oc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_set_bit(const unsigned long nr, volatile void *ptr)
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 7);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("oi 0(%1),0x01"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("oi 0(%1),0x02"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("oi 0(%1),0x04" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("oi 0(%1),0x08" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("oi 0(%1),0x10" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("oi 0(%1),0x20" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("oi 0(%1),0x40" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("oi 0(%1),0x80" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define set_bit_simple(nr,addr) \
@@ -325,75 +275,58 @@
 /*
  * fast, non-SMP clear_bit routine
  */
-static __inline__ void 
-__clear_bit(unsigned long nr, volatile void * addr)
+static inline void 
+__clear_bit(unsigned long nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   nc    0(1,2),0(1)"
-             :  : "d" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_clear_bit(const unsigned long nr, volatile void * addr)
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFE"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFD"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xFB"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xF7"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xEF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xDF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0xBF"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "ni 0(1),0x7F"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+        asm volatile("nc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_ni_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_clear_bit(const unsigned long nr, volatile void *ptr)
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 7);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("ni 0(%1),0xFE" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("ni 0(%1),0xFD"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("ni 0(%1),0xFB" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("ni 0(%1),0xF7" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("ni 0(%1),0xEF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("ni 0(%1),0xDF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("ni 0(%1),0xBF" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("ni 0(%1),0x7F" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define clear_bit_simple(nr,addr) \
@@ -404,74 +337,57 @@
 /* 
  * fast, non-SMP change_bit routine 
  */
-static __inline__ void __change_bit(unsigned long nr, volatile void * addr)
+static inline void __change_bit(unsigned long nr, volatile void *ptr)
 {
-        __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%0\n"
-             "   nr    1,%0\n"
-             "   srlg  2,2,3\n"
-             "   la    2,0(2,%1)\n"
-             "   la    1,0(1,%2)\n"
-             "   xc    0(1,2),0(1)"
-             :  : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-}
-
-static __inline__ void 
-__constant_change_bit(const unsigned long nr, volatile void * addr) 
-{
-  switch (nr&7) {
-  case 0:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x01"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 1:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x02"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 2:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x04"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 3:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x08"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 4:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x10"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "cc", "memory" );
-    break;
-  case 5:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x20"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 6:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x40"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  case 7:
-    __asm__ __volatile__ ("la 1,%0\n\t"
-                          "xi 0(1),0x80"
-                          : "=m" (*((volatile char *) addr + ((nr>>3)^7)))
-                          : : "1", "cc", "memory" );
-    break;
-  }
+	unsigned long addr;
+
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+        asm volatile("xc 0(1,%1),0(%2)"
+		     :  "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+}
+
+static inline void 
+__constant_change_bit(const unsigned long nr, volatile void *ptr) 
+{
+	unsigned long addr;
+
+	addr = ((unsigned long) ptr) + ((nr >> 3) ^ 7);
+	switch (nr&7) {
+	case 0:
+		asm volatile ("xi 0(%1),0x01" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 1:
+		asm volatile ("xi 0(%1),0x02" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 2:
+		asm volatile ("xi 0(%1),0x04" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 3:
+		asm volatile ("xi 0(%1),0x08" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 4:
+		asm volatile ("xi 0(%1),0x10" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 5:
+		asm volatile ("xi 0(%1),0x20" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 6:
+		asm volatile ("xi 0(%1),0x40" 
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	case 7:
+		asm volatile ("xi 0(%1),0x80"
+			      : "+m" (*(char *) addr) : "a" (addr) : "cc" );
+		break;
+	}
 }
 
 #define change_bit_simple(nr,addr) \
@@ -482,74 +398,57 @@
 /*
  * fast, non-SMP test_and_set_bit routine
  */
-static __inline__ int
-test_and_set_bit_simple(unsigned long nr, volatile void * addr)
+static inline int
+test_and_set_bit_simple(unsigned long nr, volatile void *ptr)
 {
-        int oldbit;
-        __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   oc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-        return oldbit & 1;
+	unsigned long addr;
+	unsigned char ch;
+
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("oc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_set_bit(X,Y)		test_and_set_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_clear_bit routine
  */
-static __inline__ int
-test_and_clear_bit_simple(unsigned long nr, volatile void * addr)
+static inline int
+test_and_clear_bit_simple(unsigned long nr, volatile void *ptr)
 {
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   nc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_ni_bitmap)
-             : "cc", "memory", "1", "2" );
-        return oldbit & 1;
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("nc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_ni_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_clear_bit(X,Y)	test_and_clear_bit_simple(X,Y)
 
 /*
  * fast, non-SMP test_and_change_bit routine
  */
-static __inline__ int
-test_and_change_bit_simple(unsigned long nr, volatile void * addr)
+static inline int
+test_and_change_bit_simple(unsigned long nr, volatile void *ptr)
 {
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lghi  1,56\n"
-             "   lghi  2,7\n"
-             "   xgr   1,%1\n"
-             "   nr    2,%1\n"
-             "   srlg  1,1,3\n"
-             "   la    1,0(1,%2)\n"
-             "   ic    %0,0(1)\n"
-             "   srl   %0,0(2)\n"
-             "   la    2,0(2,%3)\n"
-             "   xc    0(1,1),0(2)"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr), "a" (&_oi_bitmap)
-             : "cc", "memory", "1", "2" );
-        return oldbit & 1;
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+	ch = *(unsigned char *) addr;
+        asm volatile("xc 0(1,%1),0(%2)"
+		     : "+m" (*(char *) addr)
+		     : "a" (addr), "a" (_oi_bitmap + (nr & 7))
+		     : "cc" );
+	return (ch >> (nr & 7)) & 1;
 }
 #define __test_and_change_bit(X,Y)	test_and_change_bit_simple(X,Y)
 
@@ -574,25 +473,18 @@
  * This routine doesn't need to be atomic.
  */
 
-static __inline__ int __test_bit(unsigned long nr, volatile void * addr)
+static inline int __test_bit(unsigned long nr, volatile void *ptr)
 {
-        int oldbit;
+	unsigned long addr;
+	unsigned char ch;
 
-        __asm__ __volatile__(
-             "   lghi  2,56\n"
-             "   lghi  1,7\n"
-             "   xgr   2,%1\n"
-             "   nr    1,%1\n"
-             "   srlg  2,2,3\n"
-             "   ic    %0,0(2,%2)\n"
-             "   srl   %0,0(1)\n"
-             : "=&d" (oldbit) : "d" (nr), "a" (addr)
-             : "cc", "1", "2" );
-        return oldbit & 1;
+	addr = (unsigned long) ptr + ((nr ^ 56) >> 3);
+	ch = *(unsigned char *) addr;
+	return (ch >> (nr & 7)) & 1;
 }
 
-static __inline__ int 
-__constant_test_bit(unsigned long nr, volatile void * addr) {
+static inline int 
+__constant_test_bit(unsigned long nr, volatile void *addr) {
     return (((volatile char *) addr)[(nr>>3)^7] & (1<<(nr&7))) != 0;
 }
 
@@ -604,53 +496,95 @@
 /*
  * Find-bit routines..
  */
-static __inline__ unsigned long
+static inline unsigned long
 find_first_zero_bit(void * addr, unsigned long size)
 {
-        unsigned long res;
+        unsigned long res, cmp, count;
 
         if (!size)
                 return 0;
-        __asm__("   lghi  0,-1\n"
-                "   lgr   1,%1\n"
+        __asm__("   lghi  %1,-1\n"
+                "   lgr   %2,%3\n"
                 "   slgr  %0,%0\n"
-                "   aghi  1,63\n"
-                "   srlg  1,1,6\n"
-                "0: cg    0,0(%0,%2)\n"
+                "   aghi  %2,63\n"
+                "   srlg  %2,%2,6\n"
+                "0: cg    %1,0(%0,%4)\n"
                 "   jne   1f\n"
                 "   aghi  %0,8\n"
-                "   brct  1,0b\n"
-                "   lgr   %0,%1\n"
+                "   brct  %2,0b\n"
+                "   lgr   %0,%3\n"
                 "   j     5f\n"
-                "1: lg    1,0(%0,%2)\n"
+                "1: lg    %2,0(%0,%4)\n"
                 "   sllg  %0,%0,3\n"
-                "   clr   1,0\n"
+                "   clr   %2,%1\n"
 		"   jne   2f\n"
 		"   aghi  %0,32\n"
-                "   srlg  1,1,32\n"
-		"2: lghi  0,0xff\n"
-                "   tmll  1,0xffff\n"
+                "   srlg  %2,%2,32\n"
+		"2: lghi  %1,0xff\n"
+                "   tmll  %2,0xffff\n"
                 "   jno   3f\n"
                 "   aghi  %0,16\n"
-                "   srl   1,16\n"
-                "3: tmll  1,0x00ff\n"
+                "   srl   %2,16\n"
+                "3: tmll  %2,0x00ff\n"
                 "   jno   4f\n"
                 "   aghi  %0,8\n"
-                "   srl   1,8\n"
-                "4: ngr   1,0\n"
-                "   ic    1,0(1,%3)\n"
-                "   algr  %0,1\n"
+                "   srl   %2,8\n"
+                "4: ngr   %2,%1\n"
+                "   ic    %2,0(%2,%5)\n"
+                "   algr  %0,%2\n"
                 "5:"
-                : "=&a" (res) : "a" (size), "a" (addr), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+		: "a" (size), "a" (addr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
-static __inline__ unsigned long
+static inline unsigned long
+find_first_bit(void * addr, unsigned long size)
+{
+        unsigned long res, cmp, count;
+
+        if (!size)
+                return 0;
+        __asm__("   slgr  %1,%1\n"
+                "   lgr   %2,%3\n"
+                "   slgr  %0,%0\n"
+                "   aghi  %2,63\n"
+                "   srlg  %2,%2,6\n"
+                "0: cg    %1,0(%0,%4)\n"
+                "   jne   1f\n"
+                "   aghi  %0,8\n"
+                "   brct  %2,0b\n"
+                "   lgr   %0,%3\n"
+                "   j     5f\n"
+                "1: lg    %2,0(%0,%4)\n"
+                "   sllg  %0,%0,3\n"
+                "   clr   %2,%1\n"
+		"   jne   2f\n"
+		"   aghi  %0,32\n"
+                "   srlg  %2,%2,32\n"
+		"2: lghi  %1,0xff\n"
+                "   tmll  %2,0xffff\n"
+                "   jnz   3f\n"
+                "   aghi  %0,16\n"
+                "   srl   %2,16\n"
+                "3: tmll  %2,0x00ff\n"
+                "   jnz   4f\n"
+                "   aghi  %0,8\n"
+                "   srl   %2,8\n"
+                "4: ngr   %2,%1\n"
+                "   ic    %2,0(%2,%5)\n"
+                "   algr  %0,%2\n"
+                "5:"
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+		: "a" (size), "a" (addr), "a" (&_sb_findmap) : "cc" );
+        return (res < size) ? res : size;
+}
+
+static inline unsigned long
 find_next_zero_bit (void * addr, unsigned long size, unsigned long offset)
 {
         unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
-        unsigned long bitvec;
+        unsigned long bitvec, reg;
         unsigned long set, bit = offset & 63, res;
 
         if (bit) {
@@ -658,28 +592,26 @@
                  * Look for zero in first word
                  */
                 bitvec = (*p) >> bit;
-                __asm__("   lhi  0,-1\n"
-                        "   lgr  1,%1\n"
+                __asm__("   lhi  %2,-1\n"
                         "   slgr %0,%0\n"
-                        "   clr  1,0\n"
+                        "   clr  %1,%2\n"
                         "   jne  0f\n"
                         "   aghi %0,32\n"
-                        "   srlg 1,1,32\n"
-			"0: lghi 0,0xff\n"
-                        "   tmll 1,0xffff\n"
+                        "   srlg %1,%1,32\n"
+			"0: lghi %2,0xff\n"
+                        "   tmll %1,0xffff\n"
                         "   jno  1f\n"
                         "   aghi %0,16\n"
-                        "   srlg 1,1,16\n"
-                        "1: tmll 1,0x00ff\n"
+                        "   srlg %1,%1,16\n"
+                        "1: tmll %1,0x00ff\n"
                         "   jno  2f\n"
                         "   aghi %0,8\n"
-                        "   srlg 1,1,8\n"
-                        "2: ngr  1,0\n"
-                        "   ic   1,0(1,%2)\n"
-                        "   algr %0,1"
-                        : "=&d" (set) 
-                        : "d" (bitvec), "a" (&_zb_findmap)
-                        : "cc", "0", "1" );
+                        "   srlg %1,%1,8\n"
+                        "2: ngr  %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   algr %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_zb_findmap) : "cc" );
                 if (set < (64 - bit))
                         return set + offset;
                 offset += 64 - bit;
@@ -692,76 +624,187 @@
         return (offset + res);
 }
 
+static inline unsigned long
+find_next_bit (void * addr, unsigned long size, unsigned long offset)
+{
+        unsigned long * p = ((unsigned long *) addr) + (offset >> 6);
+        unsigned long bitvec, reg;
+        unsigned long set, bit = offset & 63, res;
+
+        if (bit) {
+                /*
+                 * Look for zero in first word
+                 */
+                bitvec = (*p) >> bit;
+                __asm__("   slgr %0,%0\n"
+                        "   ltr  %1,%1\n"
+                        "   jnz  0f\n"
+                        "   aghi %0,32\n"
+                        "   srlg %1,%1,32\n"
+			"0: lghi %2,0xff\n"
+                        "   tmll %1,0xffff\n"
+                        "   jnz  1f\n"
+                        "   aghi %0,16\n"
+                        "   srlg %1,%1,16\n"
+                        "1: tmll %1,0x00ff\n"
+                        "   jnz  2f\n"
+                        "   aghi %0,8\n"
+                        "   srlg %1,%1,8\n"
+                        "2: ngr  %1,%2\n"
+                        "   ic   %1,0(%1,%3)\n"
+                        "   algr %0,%1"
+                        : "=&d" (set), "+a" (bitvec), "=&d" (reg)
+                        : "a" (&_sb_findmap) : "cc" );
+                if (set < (64 - bit))
+                        return set + offset;
+                offset += 64 - bit;
+                p++;
+        }
+        /*
+         * No set bit yet, search remaining full words for a bit
+         */
+        res = find_first_bit (p, size - 64 * (p - (unsigned long *) addr));
+        return (offset + res);
+}
+
 /*
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
  */
-static __inline__ unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
 {
-        int result;
+	unsigned long reg, result;
 
-        __asm__("   lhi  0,-1\n"
-                "   lgr  1,%1\n"
+        __asm__("   lhi  %2,-1\n"
                 "   slgr %0,%0\n"
-                "   clr  1,0\n"
+                "   clr  %1,%2\n"
                 "   jne  0f\n"
                 "   aghi %0,32\n"
-                "   srlg 1,1,32\n"
-                "0: lghi 0,0xff\n"
-                "   tmll 1,0xffff\n"
+                "   srlg %1,%1,32\n"
+                "0: lghi %2,0xff\n"
+                "   tmll %1,0xffff\n"
                 "   jno  1f\n"
                 "   aghi %0,16\n"
-                "   srlg 1,1,16\n"
-                "1: tmll 1,0x00ff\n"
+                "   srlg %1,%1,16\n"
+                "1: tmll %1,0x00ff\n"
                 "   jno  2f\n"
                 "   aghi %0,8\n"
-                "   srlg 1,1,8\n"
-                "2: ngr  1,0\n"
-                "   ic   1,0(1,%2)\n"
-                "   algr %0,1"
-                : "=&d" (result)
-                : "d" (word), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
+                "   srlg %1,%1,8\n"
+                "2: ngr  %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   algr %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_zb_findmap) : "cc" );
+        return result;
+}
+
+/*
+ * __ffs = find first bit in word. Undefined if no bit exists,
+ * so code should check against 0UL first..
+ */
+static inline unsigned long __ffs (unsigned long word)
+{
+        unsigned long reg, result;
 
+        __asm__("   slgr %0,%0\n"
+                "   ltr  %1,%1\n"
+                "   jnz  0f\n"
+                "   aghi %0,32\n"
+                "   srlg %1,%1,32\n"
+                "0: lghi %2,0xff\n"
+                "   tmll %1,0xffff\n"
+                "   jnz  1f\n"
+                "   aghi %0,16\n"
+                "   srlg %1,%1,16\n"
+                "1: tmll %1,0x00ff\n"
+                "   jnz  2f\n"
+                "   aghi %0,8\n"
+                "   srlg %1,%1,8\n"
+                "2: ngr  %1,%2\n"
+                "   ic   %1,0(%1,%3)\n"
+                "   algr %0,%1"
+                : "=&d" (result), "+a" (word), "=&d" (reg)
+                : "a" (&_sb_findmap) : "cc" );
         return result;
 }
 
 /*
+ * Every architecture must define this function. It's the fastest
+ * way of searching a 140-bit bitmap where the first 100 bits are
+ * unlikely to be set. It's guaranteed that at least one of the 140
+ * bits is cleared.
+ */
+static inline int sched_find_first_bit(unsigned long *b)
+{
+	return find_first_bit(b, 140);
+}
+
+/*
  * 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).
  */
-
-extern int __inline__ ffs (int x)
+extern int inline ffs (int x)
 {
-        int r;
+        int r = 1;
 
         if (x == 0)
-          return 0;
-        __asm__("    lr   1,%1\n"
-                "    slr  %0,%0\n"
-                "    tml  1,0xFFFF\n"
+		return 0;
+        __asm__("    tml  %1,0xffff\n"
                 "    jnz  0f\n"
+                "    srl  %1,16\n"
                 "    ahi  %0,16\n"
-                "    srl  1,16\n"
-                "0:  tml  1,0x00FF\n"
+                "0:  tml  %1,0x00ff\n"
                 "    jnz  1f\n"
+                "    srl  %1,8\n"
                 "    ahi  %0,8\n"
-                "    srl  1,8\n"
-                "1:  tml  1,0x000F\n"
+                "1:  tml  %1,0x000f\n"
                 "    jnz  2f\n"
+                "    srl  %1,4\n"
                 "    ahi  %0,4\n"
-                "    srl  1,4\n"
-                "2:  tml  1,0x0003\n"
+                "2:  tml  %1,0x0003\n"
                 "    jnz  3f\n"
+                "    srl  %1,2\n"
                 "    ahi  %0,2\n"
-                "    srl  1,2\n"
-                "3:  tml  1,0x0001\n"
+                "3:  tml  %1,0x0001\n"
                 "    jnz  4f\n"
                 "    ahi  %0,1\n"
                 "4:"
-                : "=&d" (r) : "d" (x) : "cc", "1" );
-        return r+1;
+                : "=&d" (r), "+d" (x) : : "cc" );
+        return r;
+}
+
+/*
+ * fls: find last bit set.
+ */
+extern __inline__ int fls(int x)
+{
+	int r = 32;
+
+	if (x == 0)
+		return 0;
+	__asm__("    tmh  %1,0xffff\n"
+		"    jz   0f\n"
+		"    sll  %1,16\n"
+		"    ahi  %0,-16\n"
+		"0:  tmh  %1,0xff00\n"
+		"    jz   1f\n"
+		"    sll  %1,8\n"
+		"    ahi  %0,-8\n"
+		"1:  tmh  %1,0xf000\n"
+		"    jz   2f\n"
+		"    sll  %1,4\n"
+		"    ahi  %0,-4\n"
+		"2:  tmh  %1,0xc000\n"
+		"    jz   3f\n"
+		"    sll  %1,2\n"
+		"    ahi  %0,-2\n"
+		"3:  tmh  %1,0x8000\n"
+		"    jz   4f\n"
+		"    ahi  %0,-1\n"
+		"4:"
+		: "+d" (r), "+d" (x) : : "cc" );
+	return r;
 }
 
 /*
@@ -789,54 +832,54 @@
 #define ext2_set_bit(nr, addr)       test_and_set_bit((nr)^56, addr)
 #define ext2_clear_bit(nr, addr)     test_and_clear_bit((nr)^56, addr)
 #define ext2_test_bit(nr, addr)      test_bit((nr)^56, addr)
-static __inline__ unsigned long
+static inline unsigned long
 ext2_find_first_zero_bit(void *vaddr, unsigned long size)
 {
-        unsigned long res;
+        unsigned long res, cmp, count;
 
         if (!size)
                 return 0;
-        __asm__("   lghi  0,-1\n"
-                "   lgr   1,%1\n"
-                "   aghi  1,63\n"
-                "   srlg  1,1,6\n"
+        __asm__("   lghi  %1,-1\n"
+                "   lgr   %2,%3\n"
+                "   aghi  %2,63\n"
+                "   srlg  %2,%2,6\n"
                 "   slgr  %0,%0\n"
-                "0: clg   0,0(%0,%2)\n"
+                "0: clg   %1,0(%0,%4)\n"
                 "   jne   1f\n"
                 "   aghi  %0,8\n"
-                "   brct  1,0b\n"
-                "   lgr   %0,%1\n"
+                "   brct  %2,0b\n"
+                "   lgr   %0,%3\n"
                 "   j     5f\n"
-                "1: cl    0,0(%0,%2)\n"
+                "1: cl    %1,0(%0,%4)\n"
 		"   jne   2f\n"
 		"   aghi  %0,4\n"
-		"2: l     1,0(%0,%2)\n"
+		"2: l     %2,0(%0,%4)\n"
                 "   sllg  %0,%0,3\n"
                 "   aghi  %0,24\n"
-                "   lghi  0,0xff\n"
-                "   tmlh  1,0xffff\n"
+                "   lghi  %1,0xff\n"
+                "   tmlh  %2,0xffff\n"
                 "   jo    3f\n"
                 "   aghi  %0,-16\n"
-                "   srl   1,16\n"
-                "3: tmll  1,0xff00\n"
+                "   srl   %2,16\n"
+                "3: tmll  %2,0xff00\n"
                 "   jo    4f\n"
                 "   aghi  %0,-8\n"
-                "   srl   1,8\n"
-                "4: ngr   1,0\n"
-                "   ic    1,0(1,%3)\n"
-                "   algr  %0,1\n"
+                "   srl   %2,8\n"
+                "4: ngr   %2,%1\n"
+                "   ic    %2,0(%2,%5)\n"
+                "   algr  %0,%2\n"
                 "5:"
-                : "=&a" (res) : "a" (size), "a" (vaddr), "a" (&_zb_findmap)
-                : "cc", "0", "1" );
+                : "=&a" (res), "=&d" (cmp), "=&a" (count)
+		: "a" (size), "a" (vaddr), "a" (&_zb_findmap) : "cc" );
         return (res < size) ? res : size;
 }
 
-static __inline__ unsigned long
+static inline unsigned long
 ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
 {
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 6);
-        unsigned long word;
+        unsigned long word, reg;
         unsigned long bit = offset & 63UL, res;
 
         if (offset >= size)
@@ -848,30 +891,28 @@
                 word >>= bit;
                 res = bit;
                 /* Look for zero in first 8 byte word */
-                __asm__("   lgr  1,%1\n"
-                        "   lghi 0,0xff\n"
-			"   tmll 1,0xffff\n"
+                __asm__("   lghi %2,0xff\n"
+			"   tmll %1,0xffff\n"
 			"   jno  2f\n"
 			"   ahi  %0,16\n"
-			"   srlg 1,1,16\n"
-                	"0: tmll 1,0xffff\n"
+			"   srlg %1,%1,16\n"
+                	"0: tmll %1,0xffff\n"
                         "   jno  2f\n"
                         "   ahi  %0,16\n"
-                        "   srlg 1,1,16\n"
-                        "1: tmll 1,0xffff\n"
+                        "   srlg %1,%1,16\n"
+                        "1: tmll %1,0xffff\n"
                         "   jno  2f\n"
                         "   ahi  %0,16\n"
-                        "   srl  1,16\n"
-                        "2: tmll 1,0x00ff\n"
+                        "   srl  %1,16\n"
+                        "2: tmll %1,0x00ff\n"
                 	"   jno  3f\n"
                 	"   ahi  %0,8\n"
-                	"   srl  1,8\n"
-                	"3: ngr  1,0\n"
-                	"   ic   1,0(1,%2)\n"
-                	"   alr  %0,1"
-                	: "+&d" (res) 
-                  	: "d" (word), "a" (&_zb_findmap)
-                	: "cc", "0", "1" );
+                	"   srl  %1,8\n"
+                	"3: ngr  %1,%2\n"
+                	"   ic   %1,0(%1,%3)\n"
+                	"   alr  %0,%1"
+                	: "+&d" (res), "+a" (word), "=&d" (reg)
+                  	: "a" (&_zb_findmap) : "cc" );
                 if (res < 64)
 			return (p - addr)*64 + res;
                 p++;
diff -Nru a/include/asm-s390x/byteorder.h b/include/asm-s390x/byteorder.h
--- a/include/asm-s390x/byteorder.h	Sat Jun  8 22:31:43 2002
+++ b/include/asm-s390x/byteorder.h	Sat Jun  8 22:31:43 2002
@@ -13,88 +13,74 @@
 
 #ifdef __GNUC__
 
-static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
+static __inline__ __const__ __u64 ___arch__swab64p(__u64 *x)
 {
-  __u64 result;
+	__u64 result;
 
-  __asm__ __volatile__ (
-          "   lrvg %0,%1"
-          : "=&d" (result) : "m" (x) );
-  return result;
+	__asm__ __volatile__ (
+		"   lrvg %0,%1"
+		: "=d" (result) : "m" (*x) );
+	return result;
 }
 
-static __inline__ __const__ __u64 ___arch__swab64p(__u64 *x)
+static __inline__ __const__ __u64 ___arch__swab64(__u64 x)
 {
-  __u64 result;
+	__u64 result;
 
-  __asm__ __volatile__ (
-          "   lrvg %0,%1"
-          : "=d" (result) : "m" (*x) );
-  return result;
+	__asm__ __volatile__ (
+		"   lrvgr %0,%1"
+		: "=d" (result) : "d" (x) );
+	return result;
 }
 
 static __inline__ void ___arch__swab64s(__u64 *x)
 {
-  __asm__ __volatile__ (
-          "   lrvg 0,%0\n"
-	  "   stg  0,%0"
-          : "+m" (*x) : : "0");
+	*x = ___arch__swab64p(x);
 }
 
-static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
 {
-  __u32 result;
-
-  __asm__ __volatile__ (
-          "   lrv  %0,%1"
-          : "=&d" (result) : "m" (x) );
-  return result;
+	__u32 result;
+	
+	__asm__ __volatile__ (
+		"   lrv  %0,%1"
+		: "=d" (result) : "m" (*x) );
+	return result;
 }
 
-static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
 {
-  __u32 result;
-
-  __asm__ __volatile__ (
-          "   lrv  %0,%1"
-          : "=d" (result) : "m" (*x) );
-  return result;
+	__u32 result;
+	
+	__asm__ __volatile__ (
+		"   lrvr  %0,%1"
+		: "=d" (result) : "d" (x) );
+	return result;
 }
 
 static __inline__ void ___arch__swab32s(__u32 *x)
 {
-  __asm__ __volatile__ (
-          "   lrv  0,%0\n"
-	  "   st   0,%0"
-          : "+m" (*x) : : "0" );
+	*x = ___arch__swab32p(x);
 }
 
-static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
 {
-  __u16 result;
-
-  __asm__ __volatile__ (
-          "   lrvh %0,%1"
-          : "=d" (result) : "m" (x) );
-  return result;
+	__u16 result;
+	
+	__asm__ __volatile__ (
+		"   lrvh %0,%1"
+		: "=d" (result) : "m" (*x) );
+	return result;
 }
 
-static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
 {
-  __u16 result;
-
-  __asm__ __volatile__ (
-          "   lrvh %0,%1"
-          : "=d" (result) : "m" (*x) );
-  return result;
+	return ___arch__swab16p(&x);
 }
 
 static __inline__ void ___arch__swab16s(__u16 *x)
 {
-  __asm__ __volatile__ (
-          "   lrvh 0,%0\n"
-	  "   sth  0,%0"
-          : "+m" (*x) : : "0" );
+	*x = ___arch__swab16p(x);
 }
 
 #define __arch__swab64(x) ___arch__swab64(x)
diff -Nru a/include/asm-s390x/cacheflush.h b/include/asm-s390x/cacheflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/cacheflush.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,18 @@
+#ifndef _S390X_CACHEFLUSH_H
+#define _S390X_CACHEFLUSH_H
+
+/* Keep includes the same across arches.  */
+#include <linux/mm.h>
+
+/* Caches aren't brain-dead on the s390. */
+#define flush_cache_all()			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_range(vma, start, end)	do { } while (0)
+#define flush_cache_page(vma, vmaddr)		do { } while (0)
+#define flush_page_to_ram(page)			do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
+#define flush_icache_range(start, end)		do { } while (0)
+#define flush_icache_page(vma,pg)		do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
+
+#endif /* _S390X_CACHEFLUSH_H */
diff -Nru a/include/asm-s390x/ccwcache.h b/include/asm-s390x/ccwcache.h
--- a/include/asm-s390x/ccwcache.h	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,85 +0,0 @@
-/* 
-   * File...........: linux/include/asm-s390/ccwcache.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- */
-#ifndef CCWCACHE_H
-#define CCWCACHE_H
-#include <linux/slab.h>
-#include <asm/irq.h>
-
-#ifndef __KERNEL__
-#define kmem_cache_t void
-#endif /* __KERNEL__ */
-
-typedef struct ccw_req_t {
-	/* eye catcher plus queueing information  */
-	unsigned int magic;	
-	struct ccw_req_t *next;	/* pointer to next ccw_req_t in queue */
-	struct ccw_req_t *int_next;	/* for internal queueing */
-	struct ccw_req_t *int_prev;	/* for internal queueing */
-
-	/* Where to execute what... */
-	void *device;		/* index of the device the req is for */
-	void *req;		/* pointer to originating request */
-	ccw1_t *cpaddr;		/* address of channel program */
-	char status;	        /* reflecting the status of this request */
-	char flags;              /* see below */
-	short retries;		/* A retry counter to be set when filling */
-
-	/* ... and how */
-	int options;		/* options for execution */
-	char lpm;               /* logical path mask                      */
-	void *data;		/* pointer to data area */
-	devstat_t *dstat;	/* The device status in case of an error */
-
-	/* these are important for recovering erroneous requests          */
-	struct ccw_req_t *refers;	/* Does this request refer to another one? */
-	void *function; /* refers to the originating ERP action */ ;
-
-	unsigned long long expires;	/* expiratioj period */
-	/* these are for profiling purposes */
-	unsigned long long buildclk;	/* TOD-clock of request generation */
-	unsigned long long startclk;	/* TOD-clock of request start */
-	unsigned long long stopclk;	/* TOD-clock of request interrupt */
-	unsigned long long endclk;	/* TOD-clock of request termination */
-
-	/* these are for internal use */
-	int cplength;		/* length of the channel program in CCWs */
-	int datasize;		/* amount of additional data in bytes */
-	kmem_cache_t *cache;	/* the cache this data comes from */
-
-} __attribute__ ((aligned(4))) ccw_req_t;
-
-/* 
- * ccw_req_t -> status can be:
- */
-#define CQR_STATUS_EMPTY    0x00	/* request is empty */
-#define CQR_STATUS_FILLED   0x01	/* request is ready to be preocessed */
-#define CQR_STATUS_QUEUED   0x02	/* request is queued to be processed */
-#define CQR_STATUS_IN_IO    0x03	/* request is currently in IO */
-#define CQR_STATUS_DONE     0x04	/* request is completed successfully */
-#define CQR_STATUS_ERROR    0x05	/* request is completed with error */
-#define CQR_STATUS_FAILED   0x06	/* request is finally failed */
-#define CQR_STATUS_PENDING  0x07        /* request is waiting for interrupt - ERP only */ 
-
-#define CQR_FLAGS_CHAINED  0x01	/* request is chained by another (last CCW is TIC) */
-
-#ifdef __KERNEL__
-#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
- sizeof(struct ccw_req_t) <= 256 ? 256 : 512 )
-
-/* SMALLEST_SLAB(1),... PAGE_SIZE(CCW_NUMBER_CACHES) */
-#define CCW_NUMBER_CACHES (sizeof(struct ccw_req_t) <= 128 ? 6 :\
- sizeof(struct ccw_req_t) <= 256 ? 5 : 4 )
-
-int ccwcache_init (void);
-
-ccw_req_t *ccw_alloc_request (char *magic, int cplength, int additional_data);
-void ccw_free_request (ccw_req_t * request);
-#endif /* __KERNEL__ */
-#endif				/* CCWCACHE_H */
-
-
-
diff -Nru a/include/asm-s390x/current.h b/include/asm-s390x/current.h
--- a/include/asm-s390x/current.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/current.h	Sat Jun  8 22:31:52 2002
@@ -13,16 +13,14 @@
 
 #ifdef __KERNEL__
 
+#include <asm/thread_info.h>
+
 struct task_struct;
 
 static inline struct task_struct * get_current(void)
 {
-        struct task_struct *current;
-        __asm__("lghi  %0,-16384\n\t"
-                "alg   %0,0xd40"
-                : "=&r" (current) : : "cc" );
-        return current;
- }
+        return current_thread_info()->task;
+}
 
 #define current get_current()
 
diff -Nru a/include/asm-s390x/dasd.h b/include/asm-s390x/dasd.h
--- a/include/asm-s390x/dasd.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/dasd.h	Sat Jun  8 22:31:37 2002
@@ -10,6 +10,10 @@
  *
  * History of changes (starts July 2000)
  * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
+ * 12/06/01 DASD_API_VERSION 2 - binary compatible to 0 (new BIODASDINFO2)
+ * 01/23/02 DASD_API_VERSION 3 - added BIODASDPSRD (and BIODASDENAPAV) IOCTL
+ * 02/15/02 DASD_API_VERSION 4 - added BIODASDSATTR IOCTL
+ *         
  */
 
 #ifndef DASD_H
@@ -18,11 +22,126 @@
 
 #define DASD_IOCTL_LETTER 'D'
 
-#if (DASD_API_VERSION == 0)
+#define DASD_API_VERSION 4
+
+/* 
+ * struct dasd_information2_t
+ * represents any data about the device, which is visible to userspace.
+ *  including foramt and featueres.
+ */
+typedef struct dasd_information2_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;     /* length of chanq */
+        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 */
+        unsigned int format;          /* format info like formatted/cdl/ldl/... */
+        unsigned int features;        /* dasd features like 'ro',...            */
+        unsigned int reserved0;       /* reserved for further use ,...          */
+        unsigned int reserved1;       /* reserved for further use ,...          */
+        unsigned int reserved2;       /* reserved for further use ,...          */
+        unsigned int reserved3;       /* reserved for further use ,...          */
+        unsigned int reserved4;       /* reserved for further use ,...          */
+        unsigned int reserved5;       /* reserved for further use ,...          */
+        unsigned int reserved6;       /* reserved for further use ,...          */
+        unsigned int reserved7;       /* reserved for further use ,...          */
+} dasd_information2_t;
+
+/*
+ * values to be used for dasd_information_t.format
+ * 0x00: NOT formatted
+ * 0x01: Linux disc layout
+ * 0x02: Common disc layout
+ */
+#define DASD_FORMAT_NONE 0
+#define DASD_FORMAT_LDL  1
+#define DASD_FORMAT_CDL  2
+/*
+ * values to be used for dasd_information_t.features
+ * 0x00: default features
+ * 0x01: readonly (ro)
+ */
+#define DASD_FEATURE_DEFAULT  0
+#define DASD_FEATURE_READONLY 1
 
 #define DASD_PARTN_BITS 2
 
 /* 
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
+ */
+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;     /* length of chanq */
+        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;
+
+/*
+ * Read Subsystem Data - Perfomance Statistics
+ */ 
+typedef struct dasd_rssd_perf_stats_t {
+	unsigned char  invalid:1;
+	unsigned char  format:3;
+	unsigned char  data_format:4;
+	unsigned char  unit_address;
+	unsigned short device_status;
+	unsigned int   nr_read_normal;
+	unsigned int   nr_read_normal_hits;
+	unsigned int   nr_write_normal;
+	unsigned int   nr_write_fast_normal_hits;
+	unsigned int   nr_read_seq;
+	unsigned int   nr_read_seq_hits;
+	unsigned int   nr_write_seq;
+	unsigned int   nr_write_fast_seq_hits;
+	unsigned int   nr_read_cache;
+	unsigned int   nr_read_cache_hits;
+	unsigned int   nr_write_cache;
+	unsigned int   nr_write_fast_cache_hits;
+	unsigned int   nr_inhibit_cache;
+	unsigned int   nr_bybass_cache;
+	unsigned int   nr_seq_dasd_to_cache;
+	unsigned int   nr_dasd_to_cache;
+	unsigned int   nr_cache_to_dasd;
+	unsigned int   nr_delayed_fast_write;
+	unsigned int   nr_normal_fast_write;
+	unsigned int   nr_seq_fast_write;
+	unsigned int   nr_cache_miss;
+	unsigned char  status2;
+	unsigned int   nr_quick_write_promotes;
+	unsigned char  reserved;
+	unsigned short ssid;
+	unsigned char  reseved2[96];
+} __attribute__((packed)) dasd_rssd_perf_stats_t;
+
+/* 
  * struct profile_info_t
  * holds the profinling information 
  */
@@ -62,30 +181,36 @@
 #define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
 #define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
+
 /* 
- * struct dasd_information_t
- * represents any data about the data, which is visible to userspace
+ * struct attrib_data_t
+ * represents the operation (cache) bits for the device.
+ * Used in DE to influence caching of the DASD.
  */
-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;
+typedef struct attrib_data_t {
+	unsigned char operation:3;     /* cache operation mode */
+	unsigned char reserved:5;      /* cache operation mode */
+	__u16         nr_cyl;          /* no of cyliners for read ahaed */
+	__u8          reserved2[29];   /* for future use */
+} __attribute__ ((packed)) attrib_data_t;
+
+/* definition of operation (cache) bits within attributes of DE */
+#define DASD_NORMAL_CACHE  0x0
+#define DASD_BYPASS_CACHE  0x1
+#define DASD_INHIBIT_LOAD  0x2
+#define DASD_SEQ_ACCESS    0x3
+#define DASD_SEQ_PRESTAGE  0x4
+#define DASD_REC_ACCESS    0x5
+
+
+/********************************************************************************
+ * SECTION: Definition of IOCTLs
+ *
+ * Here ist how the ioctl-nr should be used:
+ *    0 -   31   DASD driver itself
+ *   32 -  239   still open
+ *  240 -  255   reserved for EMC 
+ *******************************************************************************/
 
 /* Disable the volume (for Linux) */
 #define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
@@ -97,15 +222,28 @@
 #define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
 /* reset profiling information of a device */
 #define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* enable PAV */
+#define BIODASDENAPAV  _IO(DASD_IOCTL_LETTER,6)
+
+
 /* 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)
+/* Get information on a dasd device (enhanced) */
+#define BIODASDINFO2   _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
+/* Performance Statistics Read */
+#define BIODASDPSRD    _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_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 */
+/* Set Attributes (cache operations) */
+#define BIODASDSATTR   _IOW(DASD_IOCTL_LETTER,2,attrib_data_t) 
+
+
 #endif				/* DASD_H */
 
 /*
diff -Nru a/include/asm-s390x/debug.h b/include/asm-s390x/debug.h
--- a/include/asm-s390x/debug.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390x/debug.h	Sat Jun  8 22:31:49 2002
@@ -54,7 +54,7 @@
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)	asm volatile ("STCK %0" : "=m" (x) : : "cc" )
+#define STCK(x)	asm volatile ("STCK 0(%1)" : "=m" (x) : "a" (&(x)) : "cc")
 
 typedef struct __debug_entry debug_entry_t;
 
diff -Nru a/include/asm-s390x/ebcdic.h b/include/asm-s390x/ebcdic.h
--- a/include/asm-s390x/ebcdic.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/ebcdic.h	Sat Jun  8 22:31:52 2002
@@ -24,7 +24,7 @@
 extern __inline__ void
 codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
 {
-	if (nr <= 0)
+	if (nr-- <= 0)
 		return;
         __asm__ __volatile__(
 		"   bras  1,1f\n"
@@ -34,7 +34,7 @@
 		"1: ahi   %1,-256\n"
 		"   jp    0b\n"
 		"   ex    %1,0(1)"
-		: "+&a" (addr), "+&a" (nr-1)
+		: "+&a" (addr), "+&a" (nr)
 		: "a" (codepage) : "cc", "memory", "1" );
 }
 
diff -Nru a/include/asm-s390x/elf.h b/include/asm-s390x/elf.h
--- a/include/asm-s390x/elf.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390x/elf.h	Sat Jun  8 22:31:49 2002
@@ -77,7 +77,13 @@
 #define ELF_PLATFORM (NULL)
 
 #ifdef __KERNEL__
-#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+#define SET_PERSONALITY(ex, ibcs2)			\
+do {							\
+	if (ibcs2)					\
+		set_personality(PER_SVR4);		\
+	else if (current->personality != PER_LINUX32)	\
+		set_personality(PER_LINUX);		\
+} while (0)
 #endif
 
 #endif
diff -Nru a/include/asm-s390x/fsf.h b/include/asm-s390x/fsf.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/fsf.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,326 @@
+/*
+ * header file for FCP adapter driver for IBM eServer zSeries
+ *
+ * Authors:
+ *      Martin Peschke <mpeschke@de.ibm.com>
+ *      Raimund Schroeder <raimund.schroeder@de.ibm.com>
+ *      Aron Zeh <arzeh@de.ibm.com>
+ *      Wolfgang Taphorn <taphorn@de.ibm.com>
+ *
+ * Copyright (C) 2002 IBM Entwicklung GmbH, IBM Corporation
+ */
+
+#ifndef FSF_H
+#define FSF_H
+
+#define FSF_QTCB_VERSION1			0x00000001
+#define FSF_QTCB_CURRENT_VERSION		FSF_QTCB_VERSION1
+
+/* FSF commands */
+#define	FSF_QTCB_FCP_CMND			0x00000001
+#define	FSF_QTCB_ABORT_FCP_CMND			0x00000002
+#define	FSF_QTCB_OPEN_PORT_WITH_DID		0x00000005
+#define	FSF_QTCB_OPEN_LUN			0x00000006
+#define	FSF_QTCB_CLOSE_LUN			0x00000007
+#define	FSF_QTCB_CLOSE_PORT			0x00000008
+#define	FSF_QTCB_CLOSE_PHYSICAL_PORT		0x00000009
+#define	FSF_QTCB_SEND_ELS			0x0000000B
+#define	FSF_QTCB_SEND_GENERIC			0x0000000C
+#define	FSF_QTCB_EXCHANGE_CONFIG_DATA		0x0000000D
+
+/* FSF QTCB types */
+#define FSF_IO_COMMAND				0x00000001
+#define FSF_SUPPORT_COMMAND			0x00000002
+#define FSF_CONFIG_COMMAND			0x00000003
+
+/* association between FSF command and FSF QTCB type */
+u32 fsf_qtcb_type[] = {
+	[ FSF_QTCB_FCP_CMND ]			= FSF_IO_COMMAND,
+	[ FSF_QTCB_ABORT_FCP_CMND ]		= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_OPEN_PORT_WITH_DID ] 	= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_OPEN_LUN ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_LUN ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_PORT ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_CLOSE_PHYSICAL_PORT ]	= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_SEND_ELS ]			= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_SEND_GENERIC ]		= FSF_SUPPORT_COMMAND,
+	[ FSF_QTCB_EXCHANGE_CONFIG_DATA ]	= FSF_CONFIG_COMMAND
+};
+
+/* FSF protocol stati */
+#define FSF_PROT_GOOD				0x00000001
+#define FSF_PROT_QTCB_VERSION_ERROR		0x00000010
+#define FSF_PROT_SEQ_NUMB_ERROR			0x00000020
+#define FSF_PROT_UNSUPP_QTCB_TYPE		0x00000040
+#define FSF_PROT_HOST_CONNECTION_INITIALIZING	0x00000080
+#define FSF_PROT_FSF_STATUS_PRESENTED		0x00000100
+#define FSF_PROT_DUPLICATE_REQUEST_ID		0x00000200
+#define FSF_PROT_LINK_DOWN                      0x00000400
+#define FSF_PROT_REEST_QUEUE                    0x00000800
+#define FSF_PROT_ERROR_STATE			0x01000000
+
+/* FSF stati */
+#define FSF_GOOD				0x00000000
+#define FSF_PORT_ALREADY_OPEN			0x00000001
+#define FSF_LUN_ALREADY_OPEN			0x00000002
+#define FSF_PORT_HANDLE_NOT_VALID		0x00000003
+#define FSF_LUN_HANDLE_NOT_VALID		0x00000004
+#define FSF_HANDLE_MISMATCH			0x00000005
+#define FSF_SERVICE_CLASS_NOT_SUPPORTED		0x00000006
+#define FSF_FCPLUN_NOT_VALID			0x00000009
+//#define FSF_ACCESS_DENIED			0x00000010
+#define FSF_ACCESS_TYPE_NOT_VALID		0x00000011
+#define FSF_LUN_IN_USE				0x00000012
+#define FSF_COMMAND_ABORTED_ULP			0x00000020
+#define FSF_COMMAND_ABORTED_ADAPTER		0x00000021
+#define FSF_FCP_COMMAND_DOES_NOT_EXIST		0x00000022
+#define FSF_DIRECTION_INDICATOR_NOT_VALID	0x00000030
+#define FSF_INBOUND_DATA_LENGTH_NOT_VALID	0x00000031	/* FIXME: obsolete? */
+#define FSF_OUTBOUND_DATA_LENGTH_NOT_VALID	0x00000032	/* FIXME: obsolete? */
+#define FSF_CMND_LENGTH_NOT_VALID		0x00000033
+#define FSF_MAXIMUM_NUMBER_OF_PORTS_EXCEEDED	0x00000040
+#define FSF_MAXIMUM_NUMBER_OF_LUNS_EXCEEDED	0x00000041
+#define FSF_REQUEST_BUF_NOT_VALID		0x00000042
+#define FSF_RESPONSE_BUF_NOT_VALID		0x00000043
+#define FSF_ELS_COMMAND_REJECTED		0x00000050
+#define FSF_GENERIC_COMMAND_REJECTED		0x00000051
+//#define FSF_AUTHORIZATION_FAILURE		0x00000053
+#define FSF_PORT_BOXED				0x00000059
+//#define FSF_LUN_BOXED				0x0000005A
+#define FSF_ADAPTER_STATUS_AVAILABLE		0x000000AD
+#define FSF_FCP_RSP_AVAILABLE			0x000000AF
+#define FSF_UNKNOWN_COMMAND			0x000000E2
+//#define FSF_ERROR				0x000000FF 
+
+/* FSF status qualifier, recommendations */
+#define FSF_SQ_NO_RECOM				0x00
+#define FSF_SQ_FCP_RSP_AVAILABLE		0x01
+#define FSF_SQ_RETRY_IF_POSSIBLE		0x02
+#define FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED	0x03
+#define FSF_SQ_INVOKE_LINK_TEST_PROCEDURE	0x04
+#define FSF_SQ_ULP_PROGRAMMING_ERROR		0x05
+#define FSF_SQ_COMMAND_ABORTED			0x06
+#define FSF_SQ_NO_RETRY_POSSIBLE		0x07
+
+/* FSF status qualifier (most significant 4 bytes), local link down */
+#define FSF_PSQ_LINK_NOLIGHT			0x00000004
+#define FSF_PSQ_LINK_WRAPPLUG			0x00000008
+#define FSF_PSQ_LINK_NOFCP			0x00000010
+
+/* payload size in status read buffer */
+#define FSF_STATUS_READ_PAYLOAD_SIZE		4032
+
+/* status types in status read buffer */
+#define FSF_STATUS_READ_PORT_CLOSED		0x00000001
+#define FSF_STATUS_READ_INCOMING_ELS		0x00000002
+#define FSF_STATUS_READ_BIT_ERROR_THRESHOLD	0x00000004
+#define FSF_STATUS_READ_LINK_DOWN		0x00000005	/* FIXME: really? */
+#define FSF_STATUS_READ_LINK_UP          	0x00000006
+
+/* status subtypes in status read buffer */
+#define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT	0x00000001
+#define FSF_STATUS_READ_SUB_ERROR_PORT		0x00000002
+
+/* topologie that is detected by the adapter */
+#define FSF_TOPO_ERROR				0x00000000
+#define FSF_TOPO_P2P				0x00000001
+#define FSF_TOPO_FABRIC				0x00000002
+#define FSF_TOPO_AL				0x00000003
+#define FSF_TOPO_FABRIC_VIRT			0x00000004
+
+/* data direction for FCP commands */
+#define FSF_DATADIR_WRITE			0x00000001
+#define FSF_DATADIR_READ			0x00000002
+#define FSF_DATADIR_READ_WRITE			0x00000003
+#define FSF_DATADIR_CMND			0x00000004
+
+/* fc service class */
+#define FSF_CLASS_1				0x00000001
+#define FSF_CLASS_2				0x00000002
+#define FSF_CLASS_3				0x00000003
+
+struct fsf_queue_designator;
+struct fsf_status_read_buffer;
+struct fsf_port_closed_payload;
+struct fsf_bit_error_payload;
+union fsf_prot_status_qual;
+struct fsf_qual_version_error;
+struct fsf_qual_sequence_error;
+struct fsf_qtcb_prefix;
+struct fsf_qtcb_header;
+struct fsf_qtcb_bottom_config;
+struct fsf_qtcb_bottom_support;
+struct fsf_qtcb_bottom_io;
+union fsf_qtcb_bottom;
+
+typedef struct fsf_queue_designator {
+	u8			cssid;
+	u8			chpid;
+	u8			hla;
+	u8			ua;
+	u32			res1;
+} __attribute__ ((packed)) fsf_queue_designator_t;
+
+typedef struct fsf_port_closed_payload {
+	fsf_queue_designator_t	queue_designator;
+	u32			port_handle;
+} __attribute__ ((packed)) fsf_port_closed_payload_t;
+
+typedef struct fsf_bit_error_payload {
+	u32			res1;
+	u32			link_failure_error_count;
+	u32			loss_of_sync_error_count;
+	u32			loss_of_signal_error_count;
+	u32			primitive_sequence_error_count;
+	u32			invalid_transmission_word_error_count;
+	u32			crc_error_count;
+	u32			primitive_sequence_event_timeout_count;
+	u32			elastic_buffer_overrun_error_count;
+	u32			fcal_arbitration_timeout_count;
+	u32			advertised_receive_b2b_credit;
+	u32			current_receive_b2b_credit;
+	u32			advertised_transmit_b2b_credit;
+	u32			current_transmit_b2b_credit;
+} __attribute__ ((packed)) fsf_bit_error_payload_t;
+
+typedef struct fsf_status_read_buffer {
+        u32			status_type;
+        u32			status_subtype;
+        u32			length;
+        u32			res1;
+        fsf_queue_designator_t	queue_designator;
+        u32			d_id;
+        u32			class;
+        u64			fcp_lun;
+        u8			res3[24];
+        u8			payload[FSF_STATUS_READ_PAYLOAD_SIZE];
+} __attribute__ ((packed)) fsf_status_read_buffer_t;
+
+typedef struct fsf_qual_version_error {
+	u32			fsf_version;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_version_error_t;
+
+typedef struct fsf_qual_sequence_error {
+	u32			exp_req_seq_no;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_sequence_error_t;
+
+typedef struct fsf_qual_locallink_error {
+	u32			code;
+	u32			res1[3];
+} __attribute__ ((packed)) fsf_qual_locallink_error_t;
+
+typedef union fsf_prot_status_qual {
+	fsf_qual_version_error_t	version_error;
+	fsf_qual_sequence_error_t	sequence_error;
+	fsf_qual_locallink_error_t	locallink_error;
+} __attribute__ ((packed)) fsf_prot_status_qual_t;
+
+typedef struct fsf_qtcb_prefix {
+	u64			req_id;
+	u32			qtcb_version;
+	u32			ulp_info;
+	u32			qtcb_type;
+	u32			req_seq_no;
+	u32			prot_status;
+	fsf_prot_status_qual_t	prot_status_qual;
+	u8			res1[20];
+} __attribute__ ((packed)) fsf_qtcb_prefix_t;
+
+typedef struct fsf_qtcb_header {
+	u64			req_handle;
+	u32			fsf_command;
+	u32			res1;
+	u32			port_handle;
+	u32			lun_handle;
+	u32			res2;
+	u32			fsf_status;
+	u32			fsf_status_qual[4];
+//	fsf_status_qual_t	fsf_status_qual;	FIXME: define union
+	u8			res3[28];
+	u16			log_start;
+	u16			log_length;
+	u8			res4[16];
+} __attribute__ ((packed)) fsf_qtcb_header_t;
+
+typedef u64 fsf_wwn_t;
+
+typedef struct fsf_nport_serv_param {
+	u8			common_serv_param[16];
+	fsf_wwn_t		wwpn;
+	fsf_wwn_t		wwnn;
+	u8			class1_serv_param[16];
+	u8			class2_serv_param[16];
+	u8			class3_serv_param[16];
+	u8			class4_serv_param[16];
+	u8			vendor_version_level[16];
+	u8			res1[16];
+} __attribute__ ((packed)) fsf_nport_serv_param_t;
+
+typedef struct fsf_plogi {
+	u32			code;
+	fsf_nport_serv_param_t	serv_param;
+} __attribute__ ((packed)) fsf_plogi_t;
+
+#define FSF_FCP_CMND_SIZE	288
+#define FSF_FCP_RSP_SIZE	128
+
+typedef struct fsf_qtcb_bottom_io {
+	u32			data_direction;
+	u32			service_class;
+	u8			res1[8];
+	u32			fcp_cmnd_length;
+	u8			res2[12];
+	u8			fcp_cmnd[FSF_FCP_CMND_SIZE];
+	u8			fcp_rsp[FSF_FCP_RSP_SIZE];
+	u8			res3[64];
+} __attribute__ ((packed)) fsf_qtcb_bottom_io_t;
+
+typedef struct fsf_qtcb_bottom_support {
+	u8			res1[16];
+	u32			d_id;
+	u32			res2;
+	u64			fcp_lun;
+	u64			res3;
+	u64			req_handle;
+	u32			service_class;
+	u8			res4[3];
+	u8			timeout;
+	u8			res5[184];
+	u32			els1_length;
+	u32			els2_length;
+	u64			res6;
+	u8			els[256];
+} __attribute__ ((packed)) fsf_qtcb_bottom_support_t;
+
+typedef struct fsf_qtcb_bottom_config {
+	u32			lic_version;
+	u32			res1;
+	u32			high_qtcb_version;
+	u32			low_qtcb_version;
+	u32			max_qtcb_size;
+	u8			res2[12];
+	u32			fc_topology;
+	u32			fc_link_speed;
+	u32			adapter_type;
+	u32			peer_d_id;
+	u8			res3[12];
+	u32			s_id;
+	fsf_nport_serv_param_t	nport_serv_param;
+	u8			res4[320];
+} __attribute__ ((packed)) fsf_qtcb_bottom_config_t;
+
+typedef union fsf_qtcb_bottom {
+	fsf_qtcb_bottom_io_t		io;
+	fsf_qtcb_bottom_support_t	support;
+	fsf_qtcb_bottom_config_t	config;
+} fsf_qtcb_bottom_t;
+
+typedef struct fsf_qtcb {
+	fsf_qtcb_prefix_t	prefix;
+	fsf_qtcb_header_t	header;
+	fsf_qtcb_bottom_t	bottom;
+} __attribute__ ((packed)) fsf_qtcb_t;
+
+#endif	/* FSF_H */
diff -Nru a/include/asm-s390x/hardirq.h b/include/asm-s390x/hardirq.h
--- a/include/asm-s390x/hardirq.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/hardirq.h	Sat Jun  8 22:31:35 2002
@@ -16,6 +16,7 @@
 #include <linux/threads.h>
 #include <asm/lowcore.h>
 #include <linux/sched.h>
+#include <linux/cache.h>
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
diff -Nru a/include/asm-s390x/idals.h b/include/asm-s390x/idals.h
--- a/include/asm-s390x/idals.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390x/idals.h	Sat Jun  8 22:31:51 2002
@@ -1,74 +1,117 @@
 /* 
-   * File...........: linux/include/asm-s390x/idals.h
-   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
-   * Bugreports.to..: <Linux390@de.ibm.com>
-   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
-   
-   * History of changes
-   * 07/24/00 new file
+ * File...........: linux/include/asm-s390x/idals.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ *		    Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+ 
+ * History of changes
+ * 07/24/00 new file
+ * 05/04/02 code restructuring.
  */
+
+#ifndef _S390_IDALS_H
+#define _S390_IDALS_H
+
 #include <linux/config.h>
+#include <linux/errno.h>
 #include <asm/irq.h>
 
 #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
 #define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline addr_t *
-idal_alloc ( int nridaws )
+/*
+ * Test if an address/length pair needs an idal list.
+ */
+static inline int
+idal_is_needed(void *vaddr, unsigned int length)
 {
-	if ( nridaws > 33 )
-		BUG();
-	return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
+#if defined(CONFIG_ARCH_S390X)
+	return ((__pa(vaddr) + length) >> 31) != 0;
+#else
+	return 0;
+#endif
 }
 
-static inline void 
-idal_free ( addr_t *idal )
+
+/*
+ * Return the number of idal words needed for an address/length pair.
+ */
+static inline unsigned int
+idal_nr_words(void *vaddr, unsigned int length)
 {
-	kfree (idal);
+#if defined(CONFIG_ARCH_S390X)
+	if (idal_is_needed(vaddr, length))
+		return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length + 
+			(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+#endif
+	return 0;
 }
 
+/*
+ * Create the list of idal words for an address/length pair.
+ */
+static inline unsigned long *
+idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
+{
 #if defined(CONFIG_ARCH_S390X)
-extern unsigned long __create_idal(unsigned long address, int count);
+	unsigned long paddr;
+	unsigned int cidaw;
+
+	paddr = __pa(vaddr);
+	cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length + 
+		 (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	*idaws++ = paddr;
+	paddr &= -IDA_BLOCK_SIZE;
+	while (--cidaw > 0) {
+		paddr += IDA_BLOCK_SIZE;
+		*idaws++ = paddr;
+	}
 #endif
+	return idaws;
+}
 
 /*
- * Function: set_normalized_cda
- * sets the address of the data in CCW
- * if necessary it allocates an IDAL and sets sthe appropriate flags
+ * Sets the address of the data in CCW.
+ * If necessary it allocates an IDAL and sets the appropriate flags.
  */
 static inline int
-set_normalized_cda(ccw1_t * ccw, unsigned long address)
+set_normalized_cda(ccw1_t * ccw, void *vaddr)
 {
-	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;
+	unsigned int nridaws;
+	unsigned long *idal;
+
+	if (ccw->flags & CCW_FLAG_IDA)
+		return -EINVAL;
+	nridaws = idal_nr_words(vaddr, ccw->count);
+	if (nridaws > 0) {
+		idal = kmalloc(nridaws * sizeof(unsigned long),
+			       GFP_ATOMIC | GFP_DMA );
+		if (idal == NULL)
+			return -ENOMEM;
+		idal_create_words(idal, vaddr, ccw->count);
+		ccw->flags |= CCW_FLAG_IDA;
+		vaddr = idal;
 	}
 #endif
-	ccw->cda = (__u32) address;
-	return ret;
+	ccw->cda = (__u32)(unsigned long) vaddr;
+	return 0;
 }
 
 /*
- * Function: clear_normalized_cda
- * releases any allocated IDAL related to the CCW
+ * Releases any allocated IDAL related to the CCW.
  */
 static inline void
-clear_normalized_cda ( ccw1_t * ccw ) 
+clear_normalized_cda(ccw1_t * ccw)
 {
 #if defined(CONFIG_ARCH_S390X)
-	if ( ccw -> flags & CCW_FLAG_IDA ) {
-		idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
-		ccw -> flags &= ~CCW_FLAG_IDA;
+	if (ccw->flags & CCW_FLAG_IDA) {
+		kfree((void *)(unsigned long) ccw->cda);
+		ccw->flags &= ~CCW_FLAG_IDA;
 	}
 #endif
-	ccw -> cda = 0;
+	ccw->cda = 0;
 }
 
+#endif
diff -Nru a/include/asm-s390x/init.h b/include/asm-s390x/init.h
--- a/include/asm-s390x/init.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/init.h	Sat Jun  8 22:31:36 2002
@@ -1,29 +1,7 @@
 /*
- *  include/asm-s390/init.h
+ *  include/asm-s390x/init.h
  *
- *  S390 version
+ *  S390 version (s390x)
  */
 
-#ifndef _S390_INIT_H
-#define _S390_INIT_H
-
-#define __init __attribute__ ((constructor))
-
-/* don't know, if need on S390 */
-#define __initdata
-#define __initfunc(__arginit) \
-        __arginit __init; \
-        __arginit
-/* For assembly routines
- * need to define ?
- */
-/*
-#define __INIT          .section        ".text.init",#alloc,#execinstr
-#define __FINIT .previous
-#define __INITDATA      .section        ".data.init",#alloc,#write
-*/
-
-#define __cacheline_aligned __attribute__ ((__aligned__(256)))
-
-#endif
-
+#error "<asm/init.h> should never be used - use <linux/init.h> instead"
diff -Nru a/include/asm-s390x/io.h b/include/asm-s390x/io.h
--- a/include/asm-s390x/io.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/io.h	Sat Jun  8 22:31:36 2002
@@ -40,6 +40,11 @@
         return __io_virt(address);
 }
 
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page)	((page - mem_map) << PAGE_SHIFT)
+
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
 extern inline void * ioremap (unsigned long offset, unsigned long size)
diff -Nru a/include/asm-s390x/irq.h b/include/asm-s390x/irq.h
--- a/include/asm-s390x/irq.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/irq.h	Sat Jun  8 22:31:52 2002
@@ -10,14 +10,12 @@
  */
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
+#define NR_CHPIDS 256
 
 #define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
 
 #define INVALID_STORAGE_AREA ((void *)(-1 - 0x3FFF ))
 
-extern int disable_irq(unsigned int);
-extern int enable_irq(unsigned int);
-
 /*
  * path management control word
  */
@@ -362,6 +360,92 @@
   /* extended part */
       ciw_t    ciw[MAX_CIWS];      /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
+/*
+ * where we put the ssd info
+ */
+typedef struct _ssd_info {
+	__u8   valid:1;
+	__u8   type:7;          /* subchannel type */
+	__u8   chpid[8];        /* chpids */
+	__u16  fla[8];          /* full link addresses */
+} __attribute__ ((packed)) ssd_info_t;
+
+/*
+ * area for store event information
+ */
+typedef struct chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		union {
+			struct {
+				/* word 1 */
+				__u32 reserved1;
+				/* word 2 */
+				__u32 reserved2;
+			} __attribute__ ((packed,aligned(8))) sei_req;
+			struct {
+				/* word 1 */
+				__u16 reserved1;
+				__u16 f_sch;     /* first subchannel */
+				/* word 2 */
+				__u16 reserved2;
+				__u16 l_sch;    /* last subchannel */
+			} __attribute__ ((packed,aligned(8))) ssd_req;
+		} request_block_data;
+		/* word 3 */
+		__u32 reserved3;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+		union {
+			struct {
+				/* word 2 */
+				__u8  flags;
+				__u8  vf;         /* validity flags */
+				__u8  rs;         /* reporting source */
+				__u8  cc;         /* content code */
+				/* word 3 */
+				__u16 fla;        /* full link address */
+				__u16 rsid;       /* reporting source id */
+				/* word 4 */
+				__u32 reserved2;
+				/* word 5 */
+				__u32 reserved3;
+				/* word 6 */
+				__u32 ccdf;       /* content-code dependent field */
+				/* word 7 */
+				__u32 reserved4;
+				/* word 8 */
+				__u32 reserved5;
+				/* word 9 */
+				__u32 reserved6;
+			} __attribute__ ((packed,aligned(8))) sei_res;
+			struct {
+				/* word 2 */
+				__u8 sch_valid : 1;
+				__u8 dev_valid : 1;
+				__u8 st        : 3; /* subchannel type */
+				__u8 zeroes    : 3;
+				__u8  unit_addr;  /* unit address */
+				__u16 devno;      /* device number */
+				/* word 3 */
+				__u8 path_mask;  
+				__u8 fla_valid_mask;
+				__u16 sch;        /* subchannel */
+				/* words 4-5 */
+				__u8 chpid[8];    /* chpids 0-7 */
+				/* words 6-9 */
+				__u16 fla[8];     /* full link addresses 0-7 */
+			} __attribute__ ((packed,aligned(8))) ssd_res;
+		} response_block_data;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) chsc_area_t;
 
 #endif /* __KERNEL__ */
 /*
@@ -491,6 +575,7 @@
                                         /* ... for suspended CCWs */
 #define DOIO_TIMEOUT             0x0080 /* 3 secs. timeout for sync. I/O */
 #define DOIO_DONT_CALL_INTHDLR   0x0100 /* don't call interrupt handler */
+#define DOIO_CANCEL_ON_TIMEOUT   0x0200 /* cancel I/O if it timed out */
 
 /*
  * do_IO()
@@ -513,11 +598,6 @@
            __u8           lpm,          /* logical path mask */
            unsigned long  flag);        /* flags : see above */
 
-int start_IO( int           irq,       /* IRQ aka. subchannel number */
-              ccw1_t       *cpa,       /* logical channel program address */
-              unsigned long  intparm,   /* interruption parameter */
-              __u8          lpm,       /* logical path mask */
-              unsigned int  flag);     /* flags : see above */
 
 void do_crw_pending( void  );	         /* CRW handler */
 
@@ -531,14 +611,6 @@
               unsigned long intparm,     /* dummy intparm */
               unsigned long flag);       /* possible DOIO_WAIT_FOR_INTERRUPT */
 
-int process_IRQ( struct pt_regs regs,
-                 unsigned int   irq,
-                 unsigned int   intparm);
-
-
-int enable_cpu_sync_isc ( int irq );
-int disable_cpu_sync_isc( int irq );
-
 typedef struct {
      int          irq;                  /* irq, aka. subchannel */
      __u16        devno;                /* device number */
@@ -546,8 +618,6 @@
      senseid_t    sid_data;             /* senseID data */
      } s390_dev_info_t;
 
-int get_dev_info( int irq, s390_dev_info_t *);   /* to be eliminated - don't use */
-
 int get_dev_info_by_irq  ( int irq, s390_dev_info_t *pdi);
 int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi);
 
@@ -560,8 +630,6 @@
 int read_dev_chars( int irq, void **buffer, int length );
 int read_conf_data( int irq, void **buffer, int *length, __u8 lpm );
 
-int  s390_DevicePathVerification( int irq, __u8 domask );
-
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -570,7 +638,6 @@
                               void                    *dev_id);
 
 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 );
 
@@ -630,11 +697,6 @@
                 "   .align 8\n"
                 "   .quad 0b,2b\n"
                 ".previous"
-                "    lr   1,%1\n"
-                "    msch 0(%2)\n"
-                "0:  ipm  %0\n"
-                "    srl  %0,28\n"
-                "1:\n"
 #else
                 ".section .fixup,\"ax\"\n"
                 "2:  l    %0,%3\n"
@@ -743,6 +805,21 @@
         return ccode;
 }
 
+extern __inline__ int xsch(int irq)
+{
+	int ccode;
+	
+	__asm__ __volatile__(
+                "   lr    1,%1\n"
+                "   .insn rre,0xb2760000,%1,0\n"
+                "   ipm   %0\n"
+                "   srl   %0,28"
+                : "=d" (ccode) 
+		: "d" (irq | 0x10000L)
+                : "cc", "1" );
+	return ccode;
+}
+
 extern __inline__ int iac( void)
 {
         int ccode;
@@ -805,6 +882,20 @@
                 : "cc" );
         return ccode;
 }
+extern __inline__ int chsc( chsc_area_t * chsc_area)
+{
+	int cc;
+	
+	__asm__ __volatile__ (
+	        ".insn	rre,0xb25f0000,%1,0	\n\t"
+		"ipm	%0	\n\t"
+		"srl	%0,28	\n\t"
+		: "=d" (cc) 
+		: "d" (chsc_area) 
+		: "cc" );
+	
+	return cc;
+}
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
@@ -813,13 +904,6 @@
  * Interrupt entry/exit code at both C and assembly level
  */
 
-void mask_irq(unsigned int irq);
-void unmask_irq(unsigned int irq);
-
-#define MAX_IRQ_SOURCES 128
-
-extern spinlock_t irq_controller_lock;
-
 #ifdef CONFIG_SMP
 
 #include <asm/atomic.h>
@@ -849,17 +933,10 @@
 #define __STR(x) #x
 #define STR(x) __STR(x)
 
-#ifdef CONFIG_SMP
-
-/*
- *      SMP has a few special interrupts for IPI messages
- */
-
-#endif /* CONFIG_SMP */
-
 /*
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
+ * is this ever used anyway?
  */
 extern char _stext;
 static inline void s390_do_profile (unsigned long addr)
@@ -883,16 +960,19 @@
 
 #include <asm/s390io.h>
 
+#define get_irq_lock(irq) &ioinfo[irq]->irq_lock
+
 #define s390irq_spin_lock(irq) \
-        spin_lock(&(ioinfo[irq]->irq_lock))
+        spin_lock(get_irq_lock(irq))
 
 #define s390irq_spin_unlock(irq) \
-        spin_unlock(&(ioinfo[irq]->irq_lock))
+        spin_unlock(get_irq_lock(irq))
 
 #define s390irq_spin_lock_irqsave(irq,flags) \
-        spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags)
+        spin_lock_irqsave(get_irq_lock(irq), flags)
+
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
-        spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+        spin_unlock_irqrestore(get_irq_lock(irq), flags)
 
 #define touch_nmi_watchdog() do { } while(0)
 
diff -Nru a/include/asm-s390x/lowcore.h b/include/asm-s390x/lowcore.h
--- a/include/asm-s390x/lowcore.h	Sat Jun  8 22:31:51 2002
+++ b/include/asm-s390x/lowcore.h	Sat Jun  8 22:31:51 2002
@@ -45,6 +45,8 @@
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
 
+#define __LC_JIFFY_TIMER		0xDC0
+
 #define __LC_PANIC_MAGIC                0xE00
 
 #define __LC_AREGS_SAVE_AREA            0x1340
@@ -60,7 +62,7 @@
 #define _SVC_PSW_MASK        0x0400000180000000
 #define _MCCK_PSW_MASK       0x0400000180000000
 #define _IO_PSW_MASK         0x0400000180000000
-#define _USER_PSW_MASK       0x0701C00180000000
+#define _USER_PSW_MASK       0x0705C00180000000
 #define _WAIT_PSW_MASK       0x0706000180000000
 #define _DW_PSW_MASK         0x0002000180000000
 
@@ -158,7 +160,7 @@
 	/* entry.S sensitive area end */
 
         /* SMP info area: defined by DJB */
-        __u64        jiffy_timer_cc;           /* 0xdc0 */
+        __u64        jiffy_timer;              /* 0xdc0 */
 	__u64        ext_call_fast;            /* 0xdc8 */
         __u8         pad12[0xe00-0xdd0];       /* 0xdd0 */
 
@@ -198,12 +200,12 @@
 extern struct _lowcore *lowcore_ptr[];
 
 #ifndef CONFIG_SMP
-#define get_cpu_lowcore(cpu)    S390_lowcore
-#define safe_get_cpu_lowcore(cpu) S390_lowcore
+#define get_cpu_lowcore(cpu)      (&S390_lowcore)
+#define safe_get_cpu_lowcore(cpu) (&S390_lowcore)
 #else
-#define get_cpu_lowcore(cpu)    (*lowcore_ptr[cpu])
+#define get_cpu_lowcore(cpu)      (lowcore_ptr[(cpu)])
 #define safe_get_cpu_lowcore(cpu) \
-        ((cpu)==smp_processor_id() ? S390_lowcore:(*lowcore_ptr[(cpu)]))
+        ((cpu) == smp_processor_id() ? &S390_lowcore : lowcore_ptr[(cpu)])
 #endif
 #endif /* __ASSEMBLY__ */
 
diff -Nru a/include/asm-s390x/mman.h b/include/asm-s390x/mman.h
--- a/include/asm-s390x/mman.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/mman.h	Sat Jun  8 22:31:36 2002
@@ -12,6 +12,7 @@
 #define PROT_READ	0x1		/* page can be read */
 #define PROT_WRITE	0x2		/* page can be written */
 #define PROT_EXEC	0x4		/* page can be executed */
+#define PROT_SEM	0x8		/* page may be used for atomic ops */
 #define PROT_NONE	0x0		/* page can not be accessed */
 
 #define MAP_SHARED	0x01		/* Share changes */
diff -Nru a/include/asm-s390x/page.h b/include/asm-s390x/page.h
--- a/include/asm-s390x/page.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/page.h	Sat Jun  8 22:31:35 2002
@@ -57,8 +57,8 @@
 			      : "memory" );
 }
 
-#define clear_user_page(page, vaddr)    clear_page(page)
-#define copy_user_page(to, from, vaddr) copy_page(to, from)
+#define clear_user_page(page, vaddr, pg)    clear_page(page)
+#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
 
 #define BUG() do { \
         printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
@@ -113,9 +113,13 @@
 #define __PAGE_OFFSET           0x0UL
 #define PAGE_OFFSET             0x0UL
 #define __pa(x)                 (unsigned long)(x)
-#define __va(x)                 (void *)(x)
-#define virt_to_page(kaddr)	(mem_map + (__pa(kaddr) >> PAGE_SHIFT))
-#define VALID_PAGE(page)	((page - mem_map) < max_mapnr)
+#define __va(x)                 (void *)(unsigned long)(x)
+#define pfn_to_page(pfn)	(mem_map + (pfn))
+#define page_to_pfn(page)	((unsigned long)((page) - mem_map))
+#define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+
+#define pfn_valid(pfn)		((pfn) < max_mapnr)
+#define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #define VM_DATA_DEFAULT_FLAGS	(VM_READ | VM_WRITE | VM_EXEC | \
 				 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff -Nru a/include/asm-s390x/pci.h b/include/asm-s390x/pci.h
--- a/include/asm-s390x/pci.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/pci.h	Sat Jun  8 22:31:35 2002
@@ -4,6 +4,7 @@
 /* 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.
  */
+#define PCI_DMA_BUS_IS_PHYS (1)
 
 #endif /* __ASM_S390_PCI_H */
 
diff -Nru a/include/asm-s390x/percpu.h b/include/asm-s390x/percpu.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/percpu.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,6 @@
+#ifndef __ARCH_S390X_PERCPU__
+#define __ARCH_S390X_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* __ARCH_S390X_PERCPU__ */
diff -Nru a/include/asm-s390x/pgalloc.h b/include/asm-s390x/pgalloc.h
--- a/include/asm-s390x/pgalloc.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/pgalloc.h	Sat Jun  8 22:31:36 2002
@@ -17,10 +17,7 @@
 #include <asm/processor.h>
 #include <linux/threads.h>
 
-#define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
-#define pmd_quicklist (S390_lowcore.cpu_data.pmd_quick)
-#define pte_quicklist (S390_lowcore.cpu_data.pte_quick)
-#define pgtable_cache_size (S390_lowcore.cpu_data.pgtable_cache_sz)
+#define check_pgt_cache()	do { } while (0)
 
 /*
  * Allocate and free page tables. The xxx_kernel() versions are
@@ -28,58 +25,24 @@
  * if any.
  */
 
-/*
- * page directory allocation/free routines.
- */
-extern __inline__ pgd_t *get_pgd_slow (void)
-{
-	pgd_t *ret;
-        int i;
-
-	ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2);
-	if (ret != NULL)
-	        for (i = 0; i < PTRS_PER_PGD; i++) 
-	                pgd_clear(ret + i);
-	return ret;
-}
-
-extern __inline__ pgd_t *get_pgd_fast (void)
-{
-	unsigned long *ret = pgd_quicklist;
-
-	if (ret != NULL) {
-		pgd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
-	}
-	return (pgd_t *) ret;
-}
-
-extern __inline__ pgd_t *pgd_alloc (struct mm_struct *mm)
+static inline pgd_t *pgd_alloc (struct mm_struct *mm)
 {
 	pgd_t *pgd;
+	int i;
 
-	pgd = get_pgd_fast();
-	if (!pgd)
-		pgd = get_pgd_slow();
+	pgd = (pgd_t *) __get_free_pages(GFP_KERNEL,2);
+        if (pgd != NULL)
+		for (i = 0; i < PTRS_PER_PGD; i++)
+			pgd_clear(pgd + i);
 	return pgd;
 }
 
-extern __inline__ void free_pgd_fast (pgd_t *pgd)
-{
-	*(unsigned long *) pgd = (unsigned long) pgd_quicklist;
-	pgd_quicklist = (unsigned long *) pgd;
-	pgtable_cache_size += 4;
-}
-
-extern __inline__ void free_pgd_slow (pgd_t *pgd)
+static inline void pgd_free (pgd_t *pgd)
 {
         free_pages((unsigned long) pgd, 2);
 }
 
-#define pgd_free(pgd)		free_pgd_fast(pgd)
-
-extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 {
 	pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
 }
@@ -87,7 +50,7 @@
 /*
  * page middle directory allocation/free routines.
  */
-extern inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
 	pmd_t *pmd;
         int i;
@@ -100,82 +63,67 @@
 	return pmd;
 }
 
-extern __inline__ pmd_t *
-pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline void pmd_free (pmd_t *pmd)
 {
-	unsigned long *ret = (unsigned long *) pmd_quicklist;
-
-	if (ret != NULL) {
-		pmd_quicklist = (unsigned long *)(*ret);
-		ret[0] = ret[1];
-		pgtable_cache_size -= 4;
-	}
-	return (pmd_t *) ret;
+	free_pages((unsigned long) pmd, 2);
 }
 
-extern __inline__ void pmd_free_fast (pmd_t *pmd)
-{
-	*(unsigned long *) pmd = (unsigned long) pmd_quicklist;
-	pmd_quicklist = (unsigned long *) pmd;
-	pgtable_cache_size += 4;
-}
+#define pmd_free_tlb(tlb,pmd) pmd_free(pmd)
 
-extern __inline__ void pmd_free_slow (pmd_t *pmd)
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 {
-	free_pages((unsigned long) pmd, 2);
+	pmd_val(*pmd) = _PMD_ENTRY + __pa(pte);
+	pmd_val1(*pmd) = _PMD_ENTRY + __pa(pte+256);
 }
 
-#define pmd_free(pmd)		pmd_free_fast(pmd)
-
-extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 {
-	pmd_val(*pmd) = _PMD_ENTRY | __pa(pte);
-	pmd_val1(*pmd) = _PMD_ENTRY | __pa(pte+256);
+	pmd_populate_kernel(mm, pmd, (pte_t *)((page-mem_map) << PAGE_SHIFT));
 }
 
 /*
  * page table entry allocation/free routines.
  */
-extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
 {
 	pte_t *pte;
+	int count;
         int i;
 
-	pte = (pte_t *) __get_free_page(GFP_KERNEL);
-	if (pte != NULL) {
-		for (i=0; i < PTRS_PER_PTE; i++)
-			pte_clear(pte+i);
-	}
+	count = 0;
+	do {
+		pte = (pte_t *) __get_free_page(GFP_KERNEL);
+		if (pte != NULL) {
+			for (i=0; i < PTRS_PER_PTE; i++)
+				pte_clear(pte+i);
+		} else {
+			current->state = TASK_UNINTERRUPTIBLE;
+			schedule_timeout(HZ);
+		}
+	} while (!pte && (count++ < 10));
 	return pte;
 }
 
-extern __inline__ pte_t* pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
+static inline struct page *
+pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 {
-        unsigned long *ret = (unsigned long *) pte_quicklist;
-
-        if (ret != NULL) {
-                pte_quicklist = (unsigned long *)(*ret);
-                ret[0] = ret[1];
-                pgtable_cache_size--;
-        }
-        return (pte_t *)ret;
+	return virt_to_page(pte_alloc_one_kernel(mm, addr));
 }
 
-extern __inline__ void pte_free_fast (pte_t *pte)
+static inline void pte_free_kernel(pte_t *pte)
 {
-	*(unsigned long *) pte = (unsigned long) pte_quicklist;
-	pte_quicklist = (unsigned long *) pte;
-	pgtable_cache_size++;
+        free_page((unsigned long) pte);
 }
 
-extern __inline__ void pte_free_slow (pte_t *pte)
+static inline void pte_free(struct page *pte)
 {
-        free_page((unsigned long) pte);
+        __free_page(pte);
 }
 
-#define pte_free(pte)		pte_free_fast(pte)
-
-extern int do_check_pgt_cache (int, int);
+#define pte_free_tlb(tlb,pte) tlb_remove_page((tlb),(pte))
 
 /*
  * This establishes kernel virtual mappings (e.g., as a result of a
@@ -183,142 +131,6 @@
  * there is nothing to do here... :)
  */
 #define set_pgdir(vmaddr, entry)	do { } while(0)
-
-/*
- * TLB flushing:
- *
- *  - flush_tlb() flushes the current mm struct TLBs
- *  - flush_tlb_all() flushes all processes TLBs 
- *    called only from vmalloc/vfree
- *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
- *  - flush_tlb_page(vma, vmaddr) flushes one page
- *  - flush_tlb_range(vma, start, end) flushes a range of pages
- *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
- */
-
-/*
- * S/390 has three ways of flushing TLBs
- * 'ptlb' does a flush of the local processor
- * 'csp' flushes the TLBs on all PUs of a SMP
- * 'ipte' invalidates a pte in a page table and flushes that out of
- * the TLBs of all PUs of a SMP
- */
-
-#define local_flush_tlb() \
-do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
-
-
-#ifndef CONFIG_SMP
-
-/*
- * We always need to flush, since s390 does not flush tlb
- * on each context switch
- */
-
-static inline void flush_tlb(void)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_all(void)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long addr)
-{
-	local_flush_tlb();
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	local_flush_tlb();
-}
-
-#else
-
-#include <asm/smp.h>
-
-static inline void global_flush_tlb(void)
-{
-	long dummy = 0;
-
-	__asm__ __volatile__ (
-                "    la   4,3(%0)\n"
-                "    nill 4,0xfffc\n"
-                "    la   4,1(4)\n"
-                "    slr  2,2\n"
-                "    slr  3,3\n"
-                "    csp  2,4"
-                : : "a" (&dummy) : "cc", "2", "3", "4" );
-}
-
-/*
- * We only have to do global flush of tlb if process run since last
- * flush on any other pu than current. 
- * If we have threads (mm->count > 1) we always do a global flush, 
- * since the process runs on more than one processor at the same time.
- */
-static inline void __flush_tlb_mm(struct mm_struct * mm)
-{
-	if ((smp_num_cpus > 1) &&
-	    ((atomic_read(&mm->mm_count) != 1) ||
-	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
-		mm->cpu_vm_mask = (1UL << smp_processor_id());
-		global_flush_tlb();
-	} else {                 
-		local_flush_tlb();
-	}
-}
-
-static inline void flush_tlb(void)
-{
-	__flush_tlb_mm(current->mm);
-}
-static inline void flush_tlb_all(void)
-{
-	global_flush_tlb();
-}
-static inline void flush_tlb_mm(struct mm_struct *mm) 
-{
-	__flush_tlb_mm(mm); 
-}
-static inline void flush_tlb_page(struct vm_area_struct *vma,
-				  unsigned long addr)
-{
-	__flush_tlb_mm(vma->vm_mm);
-}
-static inline void flush_tlb_range(struct vm_area_struct *vma,
-				   unsigned long start, unsigned long end)
-{
-	__flush_tlb_mm(vma->vm_mm);
-}
-
-#endif
-
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
-                                      unsigned long start, unsigned long end)
-{
-        /* S/390 does not keep any page table caches in TLB */
-}
-
-
-static inline int ptep_test_and_clear_and_flush_young(struct vm_area_struct *vma, 
-                                                      unsigned long address, pte_t *ptep)
-{
-	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_young(ptep);
-}
-
-static inline int ptep_test_and_clear_and_flush_dirty(struct vm_area_struct *vma, 
-                                                      unsigned long address, pte_t *ptep)
-{
-	/* No need to flush TLB; bits are in storage key */
-	return ptep_test_and_clear_dirty(ptep);
-}
 
 static inline pte_t ptep_invalidate(struct vm_area_struct *vma, 
                                     unsigned long address, pte_t *ptep)
diff -Nru a/include/asm-s390x/pgtable.h b/include/asm-s390x/pgtable.h
--- a/include/asm-s390x/pgtable.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/pgtable.h	Sat Jun  8 22:31:37 2002
@@ -29,17 +29,6 @@
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
 
-/* Caches aren't brain-dead on S390. */
-#define flush_cache_all()                       do { } while (0)
-#define flush_cache_mm(mm)                      do { } while (0)
-#define flush_cache_range(vma, start, end)      do { } while (0)
-#define flush_cache_page(vma, vmaddr)           do { } while (0)
-#define flush_page_to_ram(page)                 do { } while (0)
-#define flush_dcache_page(page)			do { } while (0)
-#define flush_icache_range(start, end)          do { } while (0)
-#define flush_icache_page(vma,pg)               do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len)	do { } while (0)
-
 /*
  * The S390 doesn't have any external MMU info: the kernel page
  * tables contain all the necessary information.
@@ -158,7 +147,8 @@
 
 /* Bits in the page table entry */
 #define _PAGE_PRESENT   0x001          /* Software                         */
-#define _PAGE_MKCLEAR   0x002          /* Software                         */
+#define _PAGE_MKCLEAN   0x002          /* Software                         */
+#define _PAGE_ISCLEAN   0x004          /* Software                         */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -185,33 +175,35 @@
 /*
  * No mapping available
  */
-#define PAGE_INVALID    __pgprot(_PAGE_INVALID)
-#define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_INVALID)
-#define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_RO)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT )
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT )
+#define PAGE_INVALID	  __pgprot(_PAGE_INVALID)
+#define PAGE_NONE_SHARED  __pgprot(_PAGE_PRESENT|_PAGE_INVALID)
+#define PAGE_NONE_PRIVATE __pgprot(_PAGE_PRESENT|_PAGE_INVALID|_PAGE_ISCLEAN)
+#define PAGE_RO_SHARED	  __pgprot(_PAGE_PRESENT|_PAGE_RO)
+#define PAGE_RO_PRIVATE	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_COPY	  __pgprot(_PAGE_PRESENT|_PAGE_RO|_PAGE_ISCLEAN)
+#define PAGE_SHARED	  __pgprot(_PAGE_PRESENT)
+#define PAGE_KERNEL	  __pgprot(_PAGE_PRESENT)
 
 /*
  * The S390 can't do page protection for execute, and considers that the
  * same are read. Also, write permissions imply read permissions. This is
  * the closest we can get..
  */
-#define __P000  PAGE_NONE
-#define __P001  PAGE_READONLY
+#define __P000  PAGE_NONE_PRIVATE
+#define __P001  PAGE_RO_PRIVATE
 #define __P010  PAGE_COPY
 #define __P011  PAGE_COPY
-#define __P100  PAGE_READONLY
-#define __P101  PAGE_READONLY
+#define __P100  PAGE_RO_PRIVATE
+#define __P101  PAGE_RO_PRIVATE
 #define __P110  PAGE_COPY
 #define __P111  PAGE_COPY
 
-#define __S000  PAGE_NONE
-#define __S001  PAGE_READONLY
+#define __S000  PAGE_NONE_SHARED
+#define __S001  PAGE_RO_SHARED
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_READONLY
-#define __S101  PAGE_READONLY
+#define __S100  PAGE_RO_SHARED
+#define __S101  PAGE_RO_SHARED
 #define __S110  PAGE_SHARED
 #define __S111  PAGE_SHARED
 
@@ -222,10 +214,10 @@
  */
 extern inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
-	if ((pte_val(pteval) & (_PAGE_MKCLEAR|_PAGE_INVALID))
-	    == _PAGE_MKCLEAR) 
+	if ((pte_val(pteval) & (_PAGE_MKCLEAN|_PAGE_INVALID))
+	    == _PAGE_MKCLEAN) 
 	{
-		pte_val(pteval) &= ~_PAGE_MKCLEAR;
+		pte_val(pteval) &= ~_PAGE_MKCLEAN;
                
 		asm volatile ("sske %0,%1" 
 				: : "d" (0), "a" (pte_val(pteval)));
@@ -234,8 +226,6 @@
 	*pteptr = pteval;
 }
 
-#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-
 /*
  * pgd/pmd/pte query functions
  */
@@ -295,6 +285,8 @@
 {
 	int skey;
 
+	if (pte_val(pte) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte)));
 	return skey & _PAGE_CHANGED;
 }
@@ -326,15 +318,14 @@
 	pte_val(*ptep) = _PAGE_INVALID;
 }
 
-#define PTE_INIT(x) pte_clear(x)
-
 /*
  * The following pte_modification functions only work if 
  * pte_present() is true. Undefined behaviour if not..
  */
 extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
-	pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot);
+	pte_val(pte) &= PAGE_MASK | _PAGE_ISCLEAN;
+	pte_val(pte) |= pgprot_val(newprot) & ~_PAGE_ISCLEAN;
 	return pte; 
 }
 
@@ -361,13 +352,11 @@
 
 extern inline pte_t pte_mkdirty(pte_t pte)
 { 
-	/* We can't set the changed bit atomically either. For now we
-         * set (!) the page referenced bit. */
-	asm volatile ("sske %0,%1" 
-	              : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED),
-		          "a" (pte_val(pte)));
-
-	pte_val(pte) &= ~_PAGE_MKCLEAR;
+	/* We do not explicitly set the dirty bit because the
+	 * sske instruction is slow. It is faster to let the
+	 * next instruction set the dirty bit.
+	 */
+	pte_val(pte) &= ~(_PAGE_MKCLEAN | _PAGE_ISCLEAN);
 	return pte;
 }
 
@@ -401,6 +390,8 @@
 {
 	int skey;
 
+	if (pte_val(*ptep) & _PAGE_ISCLEAN)
+		return 0;
 	asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep));
 	if ((skey & _PAGE_CHANGED) == 0)
 		return 0;
@@ -443,42 +434,70 @@
 #define mk_pte(pg, pgprot)                                                \
 ({                                                                        \
 	struct page *__page = (pg);                                       \
+	pgprot_t __pgprot = (pgprot);					  \
 	unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT);  \
-	pte_t __pte = mk_pte_phys(__physpage, (pgprot));                  \
-	                                                                  \
-	if (__page != ZERO_PAGE(__physpage)) {                            \
-		int __users = page_count(__page);                         \
-		__users -= !!PagePrivate(page) + !!__page->mapping;       \
-	                                                                  \
-		if (__users == 1)                                         \
-			pte_val(__pte) |= _PAGE_MKCLEAR;                  \
-        }                                                                 \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
+ 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!PagePrivate(__page) + !!__page->mapping;  \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
+	__pte;                                                            \
+})
+
+#define pfn_pte(pfn, pgprot)                                              \
+({                                                                        \
+	struct page *__page = mem_map+(pfn);                              \
+	pgprot_t __pgprot = (pgprot);					  \
+	unsigned long __physpage = __pa((pfn) << PAGE_SHIFT);             \
+	pte_t __pte = mk_pte_phys(__physpage, __pgprot);                  \
 	                                                                  \
+	if (!(pgprot_val(__pgprot) & _PAGE_ISCLEAN)) {			  \
+		int __users = !!PagePrivate(__page) + !!__page->mapping;  \
+		if (__users + page_count(__page) == 1)                    \
+			pte_val(__pte) |= _PAGE_MKCLEAN;                  \
+	}								  \
 	__pte;                                                            \
 })
 
-#define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT)))
+#define pfn_pmd(pfn, pgprot)                                              \
+({                                                                        \
+	pgprot_t __pgprot = (pgprot);                                     \
+	unsigned long __physpage = __pa((pfn) << PAGE_SHIFT);             \
+	pmd_t __pmd = __pmd(__physpage + pgprot_val(__pgprot));           \
+	__pmd;                                                            \
+})
 
-#define pmd_page(pmd) \
-        ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK))
+#define pte_pfn(x) (pte_val(x) >> PAGE_SHIFT)
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+#define pmd_page_kernel(pmd) (pmd_val(pmd) & PAGE_MASK)
+
+#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT))
+
+#define pgd_page_kernel(pgd) (pgd_val(pgd) & PAGE_MASK)
 
 /* to find an entry in a page-table-directory */
 #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
-#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address))
-
-#define pgd_page(pmd) \
-        ((unsigned long) __va(pgd_val(pmd) & PAGE_MASK))
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
 
 /* to find an entry in a kernel page-table-directory */
 #define pgd_offset_k(address) pgd_offset(&init_mm, address)
 
 /* Find an entry in the second-level page table.. */
+#define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
 #define pmd_offset(dir,addr) \
-	((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))
+	((pmd_t *) pgd_page_kernel(*(dir)) + __pmd_offset(addr))
 
 /* Find an entry in the third-level page table.. */
-#define pte_offset(dir,addr) \
-	((pte_t *) pmd_page(*(dir)) + (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+#define __pte_offset(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE-1))
+#define pte_offset_kernel(pmd, address) \
+	((pte_t *) pmd_page_kernel(*(pmd)) + __pte_offset(address))
+#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
+#define pte_offset_map_nested(pmd, address) pte_offset_kernel(pmd, address)
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
 
 /*
  * A page-table entry has some bits we have to treat in a special way.
diff -Nru a/include/asm-s390x/processor.h b/include/asm-s390x/processor.h
--- a/include/asm-s390x/processor.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/processor.h	Sat Jun  8 22:31:37 2002
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 
+#ifdef __KERNEL__
 /*
  * Default implementation of macro that returns current
  * instruction pointer ("program counter").
@@ -59,7 +60,7 @@
 /*
  * User space process size: 4TB (default).
  */
-#define TASK_SIZE       (0x40000000000UL)
+#define TASK_SIZE       (0x20000000000UL)
 #define TASK31_SIZE     (0x80000000UL)
 
 /* This decides where the kernel will search for a free chunk of vm
@@ -80,7 +81,6 @@
 
 struct thread_struct
  {
-        struct pt_regs *regs;         /* the user registers can be found on*/
 	s390_fp_regs fp_regs;
         __u32   ar2;                   /* kernel access register 2         */
         __u32   ar4;                   /* kernel access register 4         */
@@ -99,8 +99,7 @@
 
 typedef struct thread_struct thread_struct;
 
-#define INIT_THREAD { (struct pt_regs *) 0,                       \
-                    { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
+#define INIT_THREAD {{0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \
 			    {0},{0},{0},{0},{0},{0}}},            \
                      0, 0,                                        \
                     sizeof(init_stack) + (addr_t) &init_stack,    \
@@ -125,6 +124,7 @@
 
 
 /* Forward declaration, a strange C thing */
+struct task_struct;
 struct mm_struct;
 
 /* Free all resources held by a thread. */
@@ -136,28 +136,20 @@
 #define release_segments(mm)            do { } while (0)
 
 /*
- * Return saved PC of a blocked thread. used in kernel/sched
+ * Return saved PC of a blocked thread.
  */
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
-{
-        return (t->regs) ? ((unsigned long)t->regs->psw.addr) : 0;
-}
+extern inline unsigned long thread_saved_pc(struct task_struct *t);
 
-unsigned long get_wchan(struct task_struct *p);
-#define KSTK_EIP(tsk)   ((tsk)->thread.regs->psw.addr)
-#define KSTK_ESP(tsk)   ((tsk)->thread.ksp)
-
-/* Allocation and freeing of basic task resources. */
 /*
- * NOTE! The task struct and the stack go together
+ * Print register of task into buffer. Used in fs/proc/array.c.
  */
-#define alloc_task_struct() \
-        ((struct task_struct *) __get_free_pages(GFP_KERNEL,2))
-#define free_task_struct(p)     free_pages((unsigned long)(p),2)
-#define get_task_struct(tsk)      atomic_inc(&virt_to_page(tsk)->count)
+extern char *task_show_regs(struct task_struct *task, char *buffer);
 
-#define init_task       (init_task_union.task)
-#define init_stack      (init_task_union.stack)
+unsigned long get_wchan(struct task_struct *p);
+#define __KSTK_PTREGS(tsk) ((struct pt_regs *) \
+        (((addr_t) tsk->thread_info + THREAD_SIZE - sizeof(struct pt_regs)) & -8L))
+#define KSTK_EIP(tsk)	(__KSTK_PTREGS(tsk)->psw.addr)
+#define KSTK_ESP(tsk)	(__KSTK_PTREGS(tsk)->gprs[15])
 
 #define cpu_relax()	do { } while (0)
 
@@ -175,6 +167,43 @@
 #define PSW_PROBLEM_STATE       0x0001000000000000UL
 
 /*
+ * Set PSW mask to specified value, while leaving the
+ * PSW addr pointing to the next instruction.
+ */
+
+static inline void __load_psw_mask (unsigned long mask)
+{
+	unsigned long addr;
+
+	psw_t psw;
+	psw.mask = mask;
+
+	asm volatile (
+		"    larl  %0,1f\n"
+		"    stg   %0,8(%1)\n"
+		"    lpswe 0(%1)\n"
+		"1:"
+		: "=&d" (addr) : "a" (&psw) : "memory", "cc" );
+}
+
+/*
+ * Function to stop a processor until an interruption occured
+ */
+static inline void enabled_wait(void)
+{
+	unsigned long reg;
+	psw_t wait_psw;
+
+	wait_psw.mask = 0x0706000180000000;
+	asm volatile (
+		"    larl  %0,0f\n"
+		"    stg   %0,8(%1)\n"
+		"    lpswe 0(%1)\n"
+		"0:"
+		: "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
+}
+
+/*
  * Function to drop a processor into disabled wait state
  */
 
@@ -222,6 +251,8 @@
                       "    lpswe 0(%0)"
                       : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
 }
+
+#endif
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
 
diff -Nru a/include/asm-s390x/ptrace.h b/include/asm-s390x/ptrace.h
--- a/include/asm-s390x/ptrace.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/ptrace.h	Sat Jun  8 22:31:36 2002
@@ -85,12 +85,16 @@
 
 #define STACK_FRAME_OVERHEAD    160      /* size of minimum stack frame */
 
+#define PTRACE_SETOPTIONS         21
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD     0x00000001
+
 #ifndef __ASSEMBLY__
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/types.h>
 
-#include <asm/current.h>
 #include <asm/setup.h>
 
 /* this typedef defines how a Program Status Word looks like */
@@ -98,7 +102,7 @@
 {
         __u64   mask;
         __u64   addr;
-} psw_t __attribute__ ((aligned(8)));
+} __attribute__ ((aligned(8))) psw_t;
 
 #ifdef __KERNEL__
 #define FIX_PSW(addr) ((unsigned long)(addr))
@@ -130,8 +134,8 @@
 #define FPC_VALID_MASK          0xF8F8FF03
 
 /*
- * The first entries in pt_regs, gdb_pt_regs and user_regs_struct
- * are common for all three structures. The s390_regs structure
+ * The first entries in pt_regs and user_regs_struct
+ * are common for the two structures. The s390_regs structure
  * covers the common parts. It simplifies copying the common part
  * between the three structures.
  */
@@ -154,33 +158,15 @@
 	__u32 acrs[NUM_ACRS];
 	__u64 orig_gpr2;
 	__u32 trap;
-	__u32 old_ilc;
 } __attribute__ ((packed));
 
 /*
- * The gdb_pt_regs struct is used instead of the pt_regs structure
- * if kernel remote debugging is used.
- */
-#if CONFIG_REMOTE_DEBUG
-struct gdb_pt_regs
-{
-	psw_t psw;
-	__u64 gprs[NUM_GPRS];
-	__u32 acrs[NUM_ACRS];
-	__u64 orig_gpr2;
-	__u32 trap;
-	__u32 crs[16];
-	s390_fp_regs fp_regs;
-};
-#endif
-
-/*
  * Now for the program event recording (trace) definitions.
  */
 typedef struct
 {
 	__u64 cr[3];
-} per_cr_words  __attribute__((packed));
+} per_cr_words;
 
 #define PER_EM_MASK 0x00000000E8000000UL
 
@@ -203,14 +189,14 @@
 	unsigned                       : 21;
 	addr_t   starting_addr;
 	addr_t   ending_addr;
-} per_cr_bits  __attribute__((packed));
+} per_cr_bits;
 
 typedef struct
 {
 	__u16          perc_atmid;
 	addr_t         address;
 	__u8           access_id;
-} per_lowcore_words  __attribute__((packed));
+} per_lowcore_words;
 
 typedef struct
 {
@@ -230,14 +216,14 @@
 	addr_t   address;                     /* 0x098 */
 	unsigned                         : 4; /* 0x0a1 */
 	unsigned access_id               : 4;
-} per_lowcore_bits __attribute__((packed));
+} per_lowcore_bits;
 
 typedef struct
 {
 	union {
 		per_cr_words   words;
 		per_cr_bits    bits;
-	} control_regs  __attribute__((packed));
+	} control_regs;
 	/*
 	 * Use these flags instead of setting em_instruction_fetch
 	 * directly they are used so that single stepping can be
@@ -256,7 +242,7 @@
 		per_lowcore_words words;
 		per_lowcore_bits  bits;
 	} lowcore; 
-} per_struct __attribute__((packed));
+} per_struct;
 
 typedef struct
 {
@@ -326,7 +312,6 @@
 #define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0)
 #define instruction_pointer(regs) ((regs)->psw.addr)
 extern void show_regs(struct pt_regs * regs);
-extern char *task_show_regs(struct task_struct *task, char *buffer);
 #endif
 
 #endif /* __ASSEMBLY__ */
diff -Nru a/include/asm-s390x/qdio.h b/include/asm-s390x/qdio.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/qdio.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,934 @@
+/*
+ * linux/include/asm/qdio.h
+ *
+ * Linux for S/390 QDIO base support, Hipersocket base support
+ * version 2
+ *
+ * Copyright 2000,2002 IBM Corporation
+ * Author(s): Utz Bacher <utz.bacher@de.ibm.com>
+ *
+ */
+#ifndef __QDIO_H__
+#define __QDIO_H__
+
+#define VERSION_QDIO_H "$Revision: 1.48 $"
+
+/* note, that most of the typedef's are from ingo. */
+
+#include <linux/interrupt.h>
+
+//#define QDIO_DBF_LIKE_HELL
+
+#define QDIO_NAME "qdio "
+
+#define QDIO_VERBOSE_LEVEL 9
+
+#ifndef CONFIG_ARCH_S390X
+#define QDIO_32_BIT
+#endif /* CONFIG_ARCH_S390X */
+
+#define QDIO_USE_PROCESSING_STATE
+
+#ifdef CONFIG_QDIO_PERF_STATS
+#define QDIO_PERFORMANCE_STATS
+#endif /* CONFIG_QDIO_PERF_STATS */
+
+#define QDIO_MINIMAL_BH_RELIEF_TIME 16
+#define QDIO_TIMER_POLL_VALUE 1
+#define IQDIO_TIMER_POLL_VALUE 1
+
+
+/**** CONSTANTS, that are relied on without using these symbols *****/
+#define QDIO_MAX_QUEUES_PER_IRQ 32 /* used in width of unsigned int */
+/************************ END of CONSTANTS **************************/
+#define QDIO_MAX_BUFFERS_PER_Q 128 /* must be a power of 2 (%x=&(x-1)*/
+#define QDIO_BUF_ORDER 7 /* 2**this == number of pages used for sbals in 1 q */
+#define QDIO_MAX_ELEMENTS_PER_BUFFER 16
+#define SBAL_SIZE 256
+
+#define IQDIO_FILL_LEVEL_TO_POLL (QDIO_MAX_BUFFERS_PER_Q*4/3)
+
+#define IQDIO_THININT_ISC 3
+#define IQDIO_DELAY_TARGET 0
+#define QDIO_BUSY_BIT_PATIENCE 2000 /* in microsecs */
+#define IQDIO_GLOBAL_LAPS 2 /* GLOBAL_LAPS are not used as we */
+#define IQDIO_GLOBAL_LAPS_INT 1 /* dont global summary */
+#define IQDIO_LOCAL_LAPS 4
+#define IQDIO_LOCAL_LAPS_INT 1
+#define IQDIO_GLOBAL_SUMMARY_CC_MASK 2
+/*#define IQDIO_IQDC_INT_PARM 0x1234*/
+
+#define QDIO_Q_LAPS 5
+
+#define QDIO_STORAGE_KEY 0
+
+#define L2_CACHELINE_SIZE 256
+#define INDICATORS_PER_CACHELINE (L2_CACHELINE_SIZE/sizeof(__u32))
+
+#define QDIO_PERF "qdio_perf"
+
+/* must be a power of 2 */
+/*#define QDIO_STATS_NUMBER 4
+
+#define QDIO_STATS_CLASSES 2
+#define QDIO_STATS_COUNT_NEEDED 2*/
+
+#define QDIO_NO_USE_COUNT_TIME 10
+#define QDIO_NO_USE_COUNT_TIMEOUT 1000 /* wait for 1 sec on each q before
+					  exiting without having use_count
+					  of the queue to 0 */
+
+#define QDIO_ESTABLISH_TIMEOUT 1000
+#define QDIO_ACTIVATE_TIMEOUT 100
+#define QDIO_CLEANUP_CLEAR_TIMEOUT 20000
+#define QDIO_CLEANUP_HALT_TIMEOUT 10000
+
+#define QDIO_BH AURORA_BH
+
+#define QDIO_IRQ_BUCKETS 256 /* heavy..., but does only use a few bytes, but
+			      be rather faster in cases of collisions
+			      (if there really is a collision, it is
+			      on every (traditional) interrupt and every
+			      do_QDIO, so we rather are generous */
+#define QDIO_QETH_QFMT 0
+#define QDIO_ZFCP_QFMT 1
+#define QDIO_IQDIO_QFMT 2
+
+#define QDIO_IRQ_STATE_FRESH 0 /* must be 0 -> memset has set it to 0 */
+#define QDIO_IRQ_STATE_INACTIVE 1
+#define QDIO_IRQ_STATE_ESTABLISHED 2
+#define QDIO_IRQ_STATE_ACTIVE 3
+#define QDIO_IRQ_STATE_STOPPED 4
+
+/* used as intparm in do_IO: */
+#define QDIO_DOING_SENSEID 0
+#define QDIO_DOING_ESTABLISH 1
+#define QDIO_DOING_ACTIVATE 2
+#define QDIO_DOING_CLEANUP 3
+
+/************************* DEBUG FACILITY STUFF *********************/
+/* #define QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_HEX(ex,name,level,addr,len) \
+	do { \
+	if (ex) \
+		debug_exception(qdio_dbf_##name,level,(void*)(addr),len); \
+	else \
+		debug_event(qdio_dbf_##name,level,(void*)(addr),len); \
+	} while (0)
+#define QDIO_DBF_TEXT(ex,name,level,text) \
+	do { \
+	if (ex) \
+		debug_text_exception(qdio_dbf_##name,level,text); \
+	else \
+		debug_text_event(qdio_dbf_##name,level,text); \
+	} while (0)
+
+#define QDIO_DBF_HEX0(ex,name,addr,len) QDIO_DBF_HEX(ex,name,0,addr,len)
+#define QDIO_DBF_HEX1(ex,name,addr,len) QDIO_DBF_HEX(ex,name,1,addr,len)
+#define QDIO_DBF_HEX2(ex,name,addr,len) QDIO_DBF_HEX(ex,name,2,addr,len)
+#define QDIO_DBF_HEX3(ex,name,addr,len) QDIO_DBF_HEX(ex,name,3,addr,len)
+#define QDIO_DBF_HEX4(ex,name,addr,len) QDIO_DBF_HEX(ex,name,4,addr,len)
+#define QDIO_DBF_HEX5(ex,name,addr,len) QDIO_DBF_HEX(ex,name,5,addr,len)
+#define QDIO_DBF_HEX6(ex,name,addr,len) QDIO_DBF_HEX(ex,name,6,addr,len)
+#ifdef QDIO_DBF_LIKE_HELL
+#endif /* QDIO_DBF_LIKE_HELL */
+#if 0
+#define QDIO_DBF_HEX0(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX1(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX2(ex,name,addr,len) do {} while (0)
+#ifndef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_HEX3(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX4(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX5(ex,name,addr,len) do {} while (0)
+#define QDIO_DBF_HEX6(ex,name,addr,len) do {} while (0)
+#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* 0 */
+
+#define QDIO_DBF_TEXT0(ex,name,text) QDIO_DBF_TEXT(ex,name,0,text)
+#define QDIO_DBF_TEXT1(ex,name,text) QDIO_DBF_TEXT(ex,name,1,text)
+#define QDIO_DBF_TEXT2(ex,name,text) QDIO_DBF_TEXT(ex,name,2,text)
+#define QDIO_DBF_TEXT3(ex,name,text) QDIO_DBF_TEXT(ex,name,3,text)
+#define QDIO_DBF_TEXT4(ex,name,text) QDIO_DBF_TEXT(ex,name,4,text)
+#define QDIO_DBF_TEXT5(ex,name,text) QDIO_DBF_TEXT(ex,name,5,text)
+#define QDIO_DBF_TEXT6(ex,name,text) QDIO_DBF_TEXT(ex,name,6,text)
+#ifdef QDIO_DBF_LIKE_HELL
+#endif /* QDIO_DBF_LIKE_HELL */
+#if 0
+#define QDIO_DBF_TEXT0(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT1(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT2(ex,name,text) do {} while (0)
+#ifndef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_TEXT3(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT4(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT5(ex,name,text) do {} while (0)
+#define QDIO_DBF_TEXT6(ex,name,text) do {} while (0)
+#endif /* QDIO_DBF_LIKE_HELL */
+#endif /* 0 */
+
+#define QDIO_DBF_SETUP_NAME "qdio_setup"
+#define QDIO_DBF_SETUP_LEN 8
+#define QDIO_DBF_SETUP_INDEX 2
+#define QDIO_DBF_SETUP_NR_AREAS 1
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SETUP_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SETUP_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */
+#define QDIO_DBF_SBAL_LEN 256
+#define QDIO_DBF_SBAL_INDEX 2
+#define QDIO_DBF_SBAL_NR_AREAS 2
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SBAL_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SBAL_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_TRACE_NAME "qdio_trace"
+#define QDIO_DBF_TRACE_LEN 8
+#define QDIO_DBF_TRACE_NR_AREAS 2
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_TRACE_INDEX 4
+#define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_TRACE_INDEX 2
+#define QDIO_DBF_TRACE_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#define QDIO_DBF_SENSE_NAME "qdio_sense"
+#define QDIO_DBF_SENSE_LEN 64
+#define QDIO_DBF_SENSE_INDEX 1
+#define QDIO_DBF_SENSE_NR_AREAS 1
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_DBF_SENSE_LEVEL 6
+#else /* QDIO_DBF_LIKE_HELL */
+#define QDIO_DBF_SENSE_LEVEL 2
+#endif /* QDIO_DBF_LIKE_HELL */
+
+#ifdef QDIO_DBF_LIKE_HELL
+#define QDIO_TRACE_QTYPE QDIO_ZFCP_QFMT
+
+#define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
+#define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q
+#define QDIO_DBF_SLSB_OUT_INDEX 8
+#define QDIO_DBF_SLSB_OUT_NR_AREAS 1
+#define QDIO_DBF_SLSB_OUT_LEVEL 6
+
+#define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in"
+#define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q
+#define QDIO_DBF_SLSB_IN_INDEX 8
+#define QDIO_DBF_SLSB_IN_NR_AREAS 1
+#define QDIO_DBF_SLSB_IN_LEVEL 6
+#endif /* QDIO_DBF_LIKE_HELL */
+
+/****************** END OF DEBUG FACILITY STUFF *********************/
+
+typedef struct qdio_buffer_element_t {
+	unsigned int flags;
+	unsigned int length;
+#ifdef QDIO_32_BIT
+	void *reserved;
+#endif /* QDIO_32_BIT */
+	void *addr;
+} __attribute__ ((packed,aligned(16))) qdio_buffer_element_t;
+
+typedef struct qdio_buffer_t {
+	volatile qdio_buffer_element_t element[16];
+} __attribute__ ((packed,aligned(256))) qdio_buffer_t;
+
+
+/* params are: irq, status, qdio_error, siga_error,
+   queue_number, first element processed, number of elements processed,
+   int_parm */
+typedef void qdio_handler_t(int,unsigned int,unsigned int,unsigned int,
+			    unsigned int,int,int,unsigned long);
+
+
+#define QDIO_STATUS_INBOUND_INT 0x01
+#define QDIO_STATUS_OUTBOUND_INT 0x02
+#define QDIO_STATUS_LOOK_FOR_ERROR 0x04
+#define QDIO_STATUS_MORE_THAN_ONE_QDIO_ERROR 0x08
+#define QDIO_STATUS_MORE_THAN_ONE_SIGA_ERROR 0x10
+#define QDIO_STATUS_ACTIVATE_CHECK_CONDITION 0x20
+
+#define QDIO_SIGA_ERROR_ACCESS_EXCEPTION 0x10
+#define QDIO_SIGA_ERROR_B_BIT_SET 0x20
+
+/* for qdio_initialize */
+#define QDIO_INBOUND_0COPY_SBALS 0x01
+#define QDIO_OUTBOUND_0COPY_SBALS 0x02
+#define QDIO_USE_OUTBOUND_PCIS 0x04
+
+/* for qdio_cleanup */
+#define QDIO_FLAG_CLEANUP_USING_CLEAR 0x01
+#define QDIO_FLAG_CLEANUP_USING_HALT 0x02
+
+typedef struct qdio_initialize_t {
+	int irq;
+	unsigned char q_format;
+	unsigned char adapter_name[8];
+       	unsigned int qib_param_field_format; /*adapter dependent*/
+	/* pointer to 128 bytes or NULL, if no param field */
+	unsigned char *qib_param_field; /* adapter dependent */
+	/* pointer to no_queues*128 words of data or NULL */
+	unsigned long *input_slib_elements;
+	unsigned long *output_slib_elements;
+	unsigned int min_input_threshold;
+	unsigned int max_input_threshold;
+	unsigned int min_output_threshold;
+	unsigned int max_output_threshold;
+	unsigned int no_input_qs;
+	unsigned int no_output_qs;
+	qdio_handler_t *input_handler;
+	qdio_handler_t *output_handler;
+	unsigned long int_parm;
+	unsigned long flags;
+	void **input_sbal_addr_array; /* addr of n*128 void ptrs */
+	void **output_sbal_addr_array; /* addr of n*128 void ptrs */
+} qdio_initialize_t;
+extern int qdio_initialize(qdio_initialize_t *init_data);
+
+extern int qdio_activate(int irq,int flags);
+
+#define QDIO_STATE_MUST_USE_OUTB_PCI	0x00000001
+#define QDIO_STATE_INACTIVE 		0x00000002 /* after qdio_cleanup */
+#define QDIO_STATE_ESTABLISHED 		0x00000004 /* after qdio_initialize */
+#define QDIO_STATE_ACTIVE 		0x00000008 /* after qdio_activate */
+#define QDIO_STATE_STOPPED 		0x00000010 /* after queues went down */
+extern unsigned long qdio_get_status(int irq);
+
+
+#define QDIO_FLAG_SYNC_INPUT     0x01
+#define QDIO_FLAG_SYNC_OUTPUT    0x02
+#define QDIO_FLAG_UNDER_INTERRUPT 0x04
+#define QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT 0x08 /* no effect on
+						     adapter interrupts */
+#define QDIO_FLAG_DONT_SIGA 0x10
+
+extern int do_QDIO(int irq,unsigned int flags, unsigned int queue_number,
+		   unsigned int qidx,unsigned int count,
+		   qdio_buffer_t *buffers);
+
+extern int qdio_synchronize(int irq,unsigned int flags,
+			    unsigned int queue_number);
+
+extern int qdio_cleanup(int irq,int how);
+
+unsigned char qdio_get_slsb_state(int irq,unsigned int flag,
+				  unsigned int queue_number,
+				  unsigned int qidx);
+
+extern void qdio_init_scrubber(void);
+/*
+ * QDIO device commands returned by extended Sense-ID
+ */
+#define DEFAULT_ESTABLISH_QS_CMD 0x1b
+#define DEFAULT_ESTABLISH_QS_COUNT 0x1000
+#define DEFAULT_ACTIVATE_QS_CMD 0x1f
+#define DEFAULT_ACTIVATE_QS_COUNT 0
+typedef struct _qdio_cmds {
+	unsigned char rcd;            /* read configuration data */
+	unsigned short count_rcd;
+	unsigned char sii;            /* set interface identifier */
+	unsigned short count_sii;
+	unsigned char rni;            /* read node identifier */
+	unsigned short count_rni;
+	unsigned char eq;             /* establish QDIO queues */
+	unsigned short count_eq;
+	unsigned char aq;             /* activate QDIO queues */
+	unsigned short count_aq;
+} qdio_cmds_t;
+
+/*
+ * additional CIWs returned by extended Sense-ID
+ */
+#define CIW_TYPE_EQUEUE 0x3       /* establish QDIO queues */
+#define CIW_TYPE_AQUEUE 0x4       /* activate QDIO queues */
+
+typedef struct _qdesfmt0 {
+#ifdef QDIO_32_BIT
+	unsigned long res1;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sliba;            /* storage-list-information-block
+					   address */
+#ifdef QDIO_32_BIT
+	unsigned long res2;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sla;              /* storage-list address */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long slsba;            /* storage-list-state-block address */
+	unsigned int  res4;		/* reserved */
+	unsigned int  akey  :  4;       /* access key for DLIB */
+	unsigned int  bkey  :  4;       /* access key for SL */
+	unsigned int  ckey  :  4;       /* access key for SBALs */
+	unsigned int  dkey  :  4;       /* access key for SLSB */
+	unsigned int  res5  : 16;       /* reserved */
+} __attribute__ ((packed)) qdesfmt0_t;
+
+/*
+ * Queue-Description record (QDR)
+ */
+typedef struct _qdr {
+	unsigned int  qfmt    :  8;     /* queue format */
+	unsigned int  pfmt    :  8;     /* impl. dep. parameter format */
+	unsigned int  res1    :  8;     /* reserved */
+	unsigned int  ac      :  8;     /* adapter characteristics */
+	unsigned int  res2    :  8;     /* reserved */
+	unsigned int  iqdcnt  :  8;     /* input-queue-descriptor count */
+	unsigned int  res3    :  8;     /* reserved */
+	unsigned int  oqdcnt  :  8;     /* output-queue-descriptor count */
+	unsigned int  res4    :  8;     /* reserved */
+	unsigned int  iqdsz   :  8;     /* input-queue-descriptor size */
+	unsigned int  res5    :  8;     /* reserved */
+	unsigned int  oqdsz   :  8;     /* output-queue-descriptor size */
+	unsigned int  res6[9];          /* reserved */
+#ifdef QDIO_32_BIT
+	unsigned long res7;		/* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long qiba;             /* queue-information-block address */
+	unsigned int  res8;             /* reserved */
+	unsigned int  qkey    :  4;     /* queue-informatio-block key */
+	unsigned int  res9    : 28;     /* reserved */
+/*	union _qd {*/ /* why this? */
+		qdesfmt0_t qdf0[126];
+/*	} qd;*/
+} __attribute__ ((packed,aligned(4096))) qdr_t;
+
+
+/*
+ * queue information block (QIB)
+ */
+#define QIB_AC_INBOUND_PCI_SUPPORTED 0x80
+#define QIB_AC_OUTBOUND_PCI_SUPPORTED 0x40
+typedef struct _qib {
+	unsigned int  qfmt    :  8;     /* queue format */
+	unsigned int  pfmt    :  8;     /* impl. dep. parameter format */
+	unsigned int  res1    :  8;     /* reserved */
+	unsigned int  ac      :  8;     /* adapter characteristics */
+	unsigned int  res2;             /* reserved */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long isliba;           /* absolute address of 1st
+					   input SLIB */
+#ifdef QDIO_32_BIT
+	unsigned long res4;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long osliba;           /* absolute address of 1st
+					   output SLIB */
+	unsigned int  res5;             /* reserved */
+	unsigned int  res6;             /* reserved */
+	unsigned char ebcnam[8];        /* adapter identifier in EBCDIC */
+	unsigned char res7[88];         /* reserved */
+	unsigned char parm[QDIO_MAX_BUFFERS_PER_Q];
+					/* implementation dependent
+					   parameters */
+} __attribute__ ((packed,aligned(256))) qib_t;
+
+
+/*
+ * storage-list-information block element (SLIBE)
+ */
+typedef struct _slibe {
+#ifdef QDIO_32_BIT
+	unsigned long res;              /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long parms;            /* implementation dependent
+					   parameters */
+} slibe_t;
+
+/*
+ * storage-list-information block (SLIB)
+ */
+typedef struct _slib {
+#ifdef QDIO_32_BIT
+	unsigned long res1;             /* reserved */
+#endif /* QDIO_32_BIT */
+        unsigned long nsliba;           /* next SLIB address (if any) */
+#ifdef QDIO_32_BIT
+	unsigned long res2;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long sla;              /* SL address */
+#ifdef QDIO_32_BIT
+	unsigned long res3;             /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long slsba;            /* SLSB address */
+	unsigned char res4[1000];       /* reserved */
+	slibe_t       slibe[QDIO_MAX_BUFFERS_PER_Q];    /* SLIB elements */
+} __attribute__ ((packed,aligned(2048))) slib_t;
+
+typedef struct _sbal_flags {
+	unsigned char res1  : 1;   /* reserved */
+	unsigned char last  : 1;   /* last entry */
+	unsigned char cont  : 1;   /* contiguous storage */
+	unsigned char res2  : 1;   /* reserved */
+	unsigned char frag  : 2;   /* fragmentation (s.below) */
+	unsigned char res3  : 2;   /* reserved */
+} __attribute__ ((packed)) sbal_flags_t;
+
+#define SBAL_FLAGS_FIRST_FRAG	     0x04000000UL
+#define SBAL_FLAGS_MIDDLE_FRAG	     0x08000000UL
+#define SBAL_FLAGS_LAST_FRAG	     0x0c000000UL
+#define SBAL_FLAGS_LAST_ENTRY	     0x40000000UL
+#define SBAL_FLAGS_CONTIGUOUS	     0x20000000UL
+
+#define SBAL_FLAGS0_DATA_CONTINUATION 0x20UL
+
+/* Awesome OpenFCP extensions */
+#define SBAL_FLAGS0_TYPE_STATUS       0x00UL
+#define SBAL_FLAGS0_TYPE_WRITE        0x08UL
+#define SBAL_FLAGS0_TYPE_READ         0x10UL
+#define SBAL_FLAGS0_TYPE_WRITE_READ   0x18UL
+#define SBAL_FLAGS0_MORE_SBALS	      0x04UL
+#define SBAL_FLAGS0_COMMAND           0x02UL
+#define SBAL_FLAGS0_LAST_SBAL         0x00UL
+#define SBAL_FLAGS0_ONLY_SBAL         SBAL_FLAGS0_COMMAND
+#define SBAL_FLAGS0_MIDDLE_SBAL       SBAL_FLAGS0_MORE_SBALS
+#define SBAL_FLAGS0_FIRST_SBAL        SBAL_FLAGS0_MORE_SBALS | SBAL_FLAGS0_COMMAND
+/* Naught of interest beyond this point */
+
+#define SBAL_FLAGS0_PCI		0x40
+typedef struct _sbal_sbalf_0 {
+	unsigned char res1  : 1;   /* reserved */
+	unsigned char pci   : 1;   /* PCI indicator */
+	unsigned char cont  : 1;   /* data continuation */
+	unsigned char sbtype: 2;   /* storage-block type (OpenFCP) */
+	unsigned char res2  : 3;   /* reserved */
+} __attribute__ ((packed)) sbal_sbalf_0_t;
+
+typedef struct _sbal_sbalf_1 {
+	unsigned char res1  : 4;   /* reserved */
+	unsigned char key   : 4;   /* storage key */
+} __attribute__ ((packed)) sbal_sbalf_1_t;
+
+typedef struct _sbal_sbalf_14 {
+	unsigned char res1   : 4;  /* reserved */
+	unsigned char erridx : 4;  /* error index */
+} __attribute__ ((packed)) sbal_sbalf_14_t;
+
+typedef struct _sbal_sbalf_15 {
+	unsigned char reason;      /* reserved */
+} __attribute__ ((packed)) sbal_sbalf_15_t;
+
+typedef union _sbal_sbalf {
+	sbal_sbalf_0_t  i0;
+	sbal_sbalf_1_t  i1;
+	sbal_sbalf_14_t i14;
+	sbal_sbalf_15_t i15;
+	unsigned char value;
+} sbal_sbalf_t;
+
+typedef struct _sbale {
+	union {
+		sbal_flags_t  bits;       /* flags */
+		unsigned char value;
+	} flags;
+	unsigned int  res1  : 16;   /* reserved */
+	sbal_sbalf_t  sbalf;       /* SBAL flags */
+	unsigned int  res2  : 16;  /* reserved */
+	unsigned int  count : 16;  /* data count */
+#ifdef QDIO_32_BIT
+	unsigned long res3;        /* reserved */
+#endif /* QDIO_32_BIT */
+	unsigned long addr;        /* absolute data address */
+} __attribute__ ((packed,aligned(16))) sbal_element_t;
+
+/*
+ * strorage-block access-list (SBAL)
+ */
+typedef struct _sbal {
+	sbal_element_t element[QDIO_MAX_ELEMENTS_PER_BUFFER];
+} __attribute__ ((packed,aligned(256))) sbal_t;
+
+/*
+ * storage-list (SL)
+ */
+typedef struct _sl_element {
+#ifdef QDIO_32_BIT
+        unsigned long res;     /* reserved */
+#endif /* QDIO_32_BIT */
+        unsigned long sbal;    /* absolute SBAL address */
+} __attribute__ ((packed)) sl_element_t;
+
+typedef struct _sl {
+	sl_element_t element[QDIO_MAX_BUFFERS_PER_Q];
+} __attribute__ ((packed,aligned(1024))) sl_t;
+
+/*
+ * storage-list-state block (SLSB)
+ */
+/*typedef struct _slsb_val {*/
+/*	unsigned char value;       */ /* SLSB entry as a single byte value */
+/*} __attribute__ ((packed)) slsb_val_t;*/
+
+typedef struct _slsb_flags {
+	unsigned char owner  : 2;   /* SBAL owner */
+	unsigned char type   : 1;   /* buffer type */
+	unsigned char state  : 5;   /* processing state */
+} __attribute__ ((packed)) slsb_flags_t;
+
+
+typedef struct _slsb {
+	union _acc {
+		unsigned char val[QDIO_MAX_BUFFERS_PER_Q];
+		slsb_flags_t flags[QDIO_MAX_BUFFERS_PER_Q];
+	} acc;
+} __attribute__ ((packed,aligned(256))) slsb_t;
+
+/*
+ * SLSB values
+ */
+#define SLSB_OWNER_PROG              1
+#define SLSB_OWNER_CU                2
+
+#define SLSB_TYPE_INPUT              0
+#define SLSB_TYPE_OUTPUT             1
+
+#define SLSB_STATE_NOT_INIT          0
+#define SLSB_STATE_EMPTY             1
+#define SLSB_STATE_PRIMED            2
+#define SLSB_STATE_HALTED          0xe
+#define SLSB_STATE_ERROR           0xf
+
+#define SLSB_P_INPUT_NOT_INIT     0x80
+#define SLSB_P_INPUT_PROCESSING	  0x81
+#define SLSB_CU_INPUT_EMPTY       0x41
+#define SLSB_P_INPUT_PRIMED       0x82
+#define SLSB_P_INPUT_HALTED       0x8E
+#define SLSB_P_INPUT_ERROR        0x8F
+
+#define SLSB_P_OUTPUT_NOT_INIT    0xA0
+#define SLSB_P_OUTPUT_EMPTY       0xA1
+#define SLSB_CU_OUTPUT_PRIMED     0x62
+#define SLSB_P_OUTPUT_HALTED      0xAE
+#define SLSB_P_OUTPUT_ERROR       0xAF
+
+#define SLSB_ERROR_DURING_LOOKUP  0xFF
+/*
+ * path management control word (extended layout)
+ */
+typedef struct {
+	unsigned long  intparm;      /* interruption parameter */
+	unsigned int   qf   : 1;     /* qdio facility */
+	unsigned int   res0 : 1;     /* reserved */
+	unsigned int   isc  : 3;     /* interruption sublass */
+	unsigned int   res5 : 3;     /* reserved zeros */
+	unsigned int   ena  : 1;     /* enabled */
+	unsigned int   lm   : 2;     /* limit mode */
+	unsigned int   mme  : 2;     /* measurement-mode enable */
+	unsigned int   mp   : 1;     /* multipath mode */
+	unsigned int   tf   : 1;     /* timing facility */
+	unsigned int   dnv  : 1;     /* device number valid */
+	unsigned int   dev  : 16;    /* device number */
+	unsigned char  lpm;          /* logical path mask */
+	unsigned char  pnom;         /* path not operational mask */
+	unsigned char  lpum;         /* last path used mask */
+	unsigned char  pim;          /* path installed mask */
+	unsigned short mbi;          /* measurement-block index */
+	unsigned char  pom;          /* path operational mask */
+	unsigned char  pam;          /* path available mask */
+	unsigned char  chpid[8];     /* CHPID 0-7 (if available) */
+	unsigned int   res1    : 8;  /* reserved */
+	unsigned int   st      : 3;  /* */
+	unsigned int   res2    : 20; /* reserved */
+	unsigned int   csense  : 1;  /* concurrent sense; can be enabled
+					per MSCH, however, if facility
+					is not installed, this results
+					in an operand exception. */
+} pmcw_e_t;
+
+/*
+ * subchannel status word (extended layout)
+ */
+typedef struct {
+	unsigned int   key  : 4;     /* subchannel key */
+	unsigned int   sctl : 1;     /* suspend control */
+	unsigned int   eswf : 1;     /* ESW format */
+	unsigned int   cc   : 2;     /* deferred condition code */
+	unsigned int   fmt  : 1;     /* format */
+	unsigned int   pfch : 1;     /* prefetch */
+	unsigned int   isic : 1;     /* initial-status interruption control */
+	unsigned int   alcc : 1;     /* address-limit checking control */
+	unsigned int   ssi  : 1;     /* supress-suspended interruption */
+	unsigned int   zcc  : 1;     /* zero condition code */
+	unsigned int   ectl : 1;     /* extended control */
+	unsigned int   pno  : 1;     /* path not operational */
+	unsigned int   qact : 1;     /* qdio active */
+	unsigned int   fctl : 3;     /* function control */
+	unsigned int   actl : 7;     /* activity control */
+	unsigned int   stctl : 5;    /* status control */
+	unsigned long  cpa;          /* channel program address */
+	unsigned int   dstat : 8;    /* device status */
+	unsigned int   cstat : 8;    /* subchannel status */
+	unsigned int   count : 16;   /* residual count */
+} scsw_e_t;
+
+typedef struct qdio_q_t {
+	volatile slsb_t slsb;
+
+	__u32 * volatile dev_st_chg_ind;
+
+	int is_input_q;
+	int is_0copy_sbals_q;
+	int irq;
+
+	unsigned int is_iqdio_q;
+
+	/* bit 0 means queue 0, bit 1 means queue 1, ... */
+	unsigned int mask;
+	unsigned int q_no;
+
+	qdio_handler_t (*handler);
+
+	/* points to the next buffer to be checked for having
+	 * been processed by the card (outbound)
+	 * or to the next buffer the program should check for (inbound) */
+	volatile int first_to_check;
+	/* and the last time it was: */
+	volatile int last_move_ftc;
+
+	atomic_t number_of_buffers_used;
+	atomic_t polling;
+
+	unsigned int siga_in;
+	unsigned int siga_out;
+	unsigned int siga_sync;
+	unsigned int siga_sync_done_on_thinints;
+	unsigned int hydra_gives_outbound_pcis;
+
+	/* used to save beginning position when calling dd_handlers */
+	int first_element_to_kick;
+
+	atomic_t use_count;
+	atomic_t is_in_shutdown;
+
+#ifdef QDIO_USE_TIMERS_FOR_POLLING
+	struct timer_list timer;
+	atomic_t timer_already_set;
+	spinlock_t timer_lock;
+#else /* QDIO_USE_TIMERS_FOR_POLLING */
+	struct tasklet_struct tasklet;
+#endif /* QDIO_USE_TIMERS_FOR_POLLING */
+
+	unsigned int state;
+
+	/* used to store the error condition during a data transfer */
+	unsigned int qdio_error;
+	unsigned int siga_error;
+	unsigned int error_status_flags;
+
+	/* list of interesting queues */
+	volatile struct qdio_q_t *list_next;
+	volatile struct qdio_q_t *list_prev;
+
+	slib_t *slib; /* a page is allocated under this pointer,
+			 sl points into this page, offset PAGE_SIZE/2
+			 (after slib) */
+	sl_t *sl;
+	volatile sbal_t *sbal[QDIO_MAX_BUFFERS_PER_Q];
+
+	qdio_buffer_t *qdio_buffers[QDIO_MAX_BUFFERS_PER_Q];
+
+	unsigned long int_parm;
+
+	/*struct {
+		int in_bh_check_limit;
+		int threshold;
+	} threshold_classes[QDIO_STATS_CLASSES];*/
+
+	struct {
+		/* inbound: the time to stop polling
+		   outbound: the time to kick peer */
+		int threshold; /* the real value */
+
+		/* outbound: last time of do_QDIO
+		   inbound: last time of noticing incoming data */
+		/*__u64 last_transfer_times[QDIO_STATS_NUMBER];
+		int last_transfer_index; */
+
+		__u64 last_transfer_time;
+	} timing;
+        unsigned int queue_type;
+} __attribute__ ((aligned(256))) qdio_q_t;
+
+typedef struct qdio_irq_t {
+	__u32 * volatile dev_st_chg_ind;
+
+	unsigned long int_parm;
+	int irq;
+
+	unsigned int is_iqdio_irq;
+	unsigned int hydra_gives_outbound_pcis;
+	unsigned int sync_done_on_outb_pcis;
+
+	unsigned int state;
+	spinlock_t setting_up_lock;
+
+	unsigned int no_input_qs;
+	unsigned int no_output_qs;
+
+	unsigned char qdioac;
+
+	qdio_q_t *input_qs[QDIO_MAX_QUEUES_PER_IRQ];
+	qdio_q_t *output_qs[QDIO_MAX_QUEUES_PER_IRQ];
+
+	ccw1_t ccw;
+	int io_result_cstat;
+	int io_result_dstat;
+	int io_result_flags;
+	atomic_t interrupt_has_arrived;
+	atomic_t interrupt_has_been_cleaned;
+	wait_queue_head_t wait_q;
+
+	qdr_t *qdr;
+
+	qdio_cmds_t commands;
+
+	qib_t qib;
+
+	io_handler_func_t original_int_handler;
+
+	struct qdio_irq_t *next;
+} qdio_irq_t;
+
+#define QDIO_CHSC_RESPONSE_CODE_OK 1
+/* flags for st qdio sch data */
+#define CHSC_FLAG_QDIO_CAPABILITY 0x80
+#define CHSC_FLAG_VALIDITY 0x40
+
+#define CHSC_FLAG_SIGA_INPUT_NECESSARY 0x40
+#define CHSC_FLAG_SIGA_OUTPUT_NECESSARY 0x20
+#define CHSC_FLAG_SIGA_SYNC_NECESSARY 0x10
+#define CHSC_FLAG_SIGA_SYNC_DONE_ON_THININTS 0x08
+#define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04
+
+typedef struct qdio_chsc_area_t {
+	struct {
+		/* word 0 */
+		__u16 command_code1;
+		__u16 command_code2;
+		/* word 1 */
+		__u16 operation_code;
+		__u16 first_sch;
+		/* word 2 */
+		__u8 reserved1;
+		__u8 image_id;
+		__u16 last_sch;
+		/* word 3 */
+		__u32 reserved2;
+
+		/* word 4 */
+		union {
+			struct {
+				/* word 4&5 */
+				__u64 summary_indicator_addr;
+				/* word 6&7 */
+				__u64 subchannel_indicator_addr;
+				/* word 8 */
+				int ks:4;
+				int kc:4;
+				int reserved1:21;
+				int isc:3;
+				/* word 9&10 */
+				__u32 reserved2[2];
+				/* word 11 */
+				__u32 subsystem_id;
+				/* word 12-1015 */
+				__u32 reserved3[1004];
+			} __attribute__ ((packed,aligned(4))) set_chsc;
+			struct {
+				/* word 4&5 */
+				__u32 reserved1[2];	
+				/* word 6 */
+				__u32 delay_target;
+				/* word 7-1015 */
+				__u32 reserved4[1009];
+			} __attribute__ ((packed,aligned(4))) set_chsc_fast;
+			struct {
+				/* word 0 */
+				__u16 length;
+				__u16 response_code;
+				/* word 1 */
+				__u32 reserved1;
+				/* words 2 to 9 for st sch qdio data */
+				__u8 flags;
+				__u8 reserved2;
+				__u16 sch;
+				__u8 qfmt;
+				__u8 reserved3;
+				__u8 qdioac;
+				__u8 sch_class;
+				__u8 reserved4;
+				__u8 icnt;
+				__u8 reserved5;
+				__u8 ocnt;
+				/* plus 5 words of reserved fields */
+			} __attribute__ ((packed,aligned(8)))
+			store_qdio_data_response;
+		} operation_data_area;
+	} __attribute__ ((packed,aligned(8))) request_block;
+	struct {
+		/* word 0 */
+		__u16 length;
+		__u16 response_code;
+		/* word 1 */
+		__u32 reserved1;
+	} __attribute__ ((packed,aligned(8))) response_block;
+} __attribute__ ((packed,aligned(PAGE_SIZE))) qdio_chsc_area_t;
+
+
+#define QDIO_PRINTK_HEADER QDIO_NAME ": "
+
+#if QDIO_VERBOSE_LEVEL>8
+#define QDIO_PRINT_STUPID(x...) printk( KERN_DEBUG QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_STUPID(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>7
+#define QDIO_PRINT_ALL(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ALL(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>6
+#define QDIO_PRINT_INFO(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_INFO(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>5
+#define QDIO_PRINT_WARN(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_WARN(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>4
+#define QDIO_PRINT_ERR(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ERR(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>3
+#define QDIO_PRINT_CRIT(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_CRIT(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>2
+#define QDIO_PRINT_ALERT(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_ALERT(x...)
+#endif
+
+#if QDIO_VERBOSE_LEVEL>1
+#define QDIO_PRINT_EMERG(x...) printk( QDIO_PRINTK_HEADER x)
+#else
+#define QDIO_PRINT_EMERG(x...)
+#endif
+
+#endif /* __QDIO_H__ */
diff -Nru a/include/asm-s390x/rwsem.h b/include/asm-s390x/rwsem.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/rwsem.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,209 @@
+#ifndef _S390X_RWSEM_H
+#define _S390X_RWSEM_H
+
+/*
+ *  include/asm-s390x/rwsem.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *
+ *  Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
+ */
+
+/*
+ *
+ * The MSW of the count is the negated number of active writers and waiting
+ * lockers, and the LSW is the total number of active locks
+ *
+ * The lock count is initialized to 0 (no active and no waiting lockers).
+ *
+ * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
+ * uncontended lock. This can be determined because XADD returns the old value.
+ * Readers increment by 1 and see a positive value when uncontended, negative
+ * if there are writers (and maybe) readers waiting (in which case it goes to
+ * sleep).
+ *
+ * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
+ * be extended to 65534 by manually checking the whole MSW rather than relying
+ * on the S flag.
+ *
+ * The value of ACTIVE_BIAS supports up to 65535 active processes.
+ *
+ * This should be totally fair - if anything is waiting, a process that wants a
+ * lock will go to the back of the queue. When the currently active lock is
+ * released, if there's a writer at the front of the queue, then that and only
+ * that will be woken up; if there's a bunch of consequtive readers at the
+ * front, then they'll all be woken up, but no other readers will be.
+ */
+
+#ifndef _LINUX_RWSEM_H
+#error please dont include asm/rwsem.h directly, use linux/rwsem.h instead
+#endif
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct rwsem_waiter;
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+	signed long		count;
+	spinlock_t		wait_lock;
+	struct list_head	wait_list;
+};
+
+#define RWSEM_UNLOCKED_VALUE	0x0000000000000000L
+#define RWSEM_ACTIVE_BIAS	0x0000000000000001L
+#define RWSEM_ACTIVE_MASK	0x00000000ffffffffL
+#define RWSEM_WAITING_BIAS	(-0x0000000100000000L)
+#define RWSEM_ACTIVE_READ_BIAS	RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS	(RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+
+/*
+ * initialisation
+ */
+#define __RWSEM_INITIALIZER(name) \
+{ RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, LIST_HEAD_INIT((name).wait_list) }
+
+#define DECLARE_RWSEM(name) \
+	struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+	sem->count = RWSEM_UNLOCKED_VALUE;
+	spin_lock_init(&sem->wait_lock);
+	INIT_LIST_HEAD(&sem->wait_list);
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   aghi %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (old < 0)
+		rwsem_down_read_failed(sem);
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   ag   %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (old != 0)
+		rwsem_down_write_failed(sem);
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   aghi %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+	signed long old, new, tmp;
+
+	tmp = -RWSEM_ACTIVE_WRITE_BIAS;
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   ag   %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "m" (tmp)
+		: "cc", "memory" );
+	if (new < 0)
+		if ((new & RWSEM_ACTIVE_MASK) == 0)
+			rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   agr  %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
+{
+	signed long old, new;
+
+	__asm__ __volatile__(
+		"   lg   %0,0(%2)\n"
+		"0: lgr  %1,%0\n"
+		"   agr  %1,%3\n"
+		"   csg  %0,%1,0(%2)\n"
+		"   jl   0b"
+                : "=&d" (old), "=&d" (new)
+		: "a" (&sem->count), "d" (delta)
+		: "cc", "memory" );
+	return new;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _S390X_RWSEM_H */
diff -Nru a/include/asm-s390x/s390-gdbregs.h b/include/asm-s390x/s390-gdbregs.h
--- a/include/asm-s390x/s390-gdbregs.h	Sat Jun  8 22:31:43 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-/*
- *  include/asm-s390/s390-gdbregs.h
- *
- *  S390 version
- *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
- *
- *  used both by the linux kernel for remote debugging & gdb 
- */
-
-#ifndef _S390_GDBREGS_H
-#define _S390_GDBREGS_H
-
-#ifdef __KERNEL__
-#include <asm/s390-regs-common.h>
-#else
-#include <s390x/s390-regs-common.h>
-#endif
-#define S390_MAX_INSTR_SIZE 6
-#define NUM_REGS      (2+NUM_GPRS+NUM_ACRS+NUM_CRS+1+NUM_FPRS)
-#define FIRST_ACR     (2+NUM_GPRS)
-#define LAST_ACR      (FIRST_ACR+NUM_ACRS-1)
-#define FIRST_CR      (FIRST_ACR+NUM_ACRS)
-#define LAST_CR       (FIRST_CR+NUM_CRS-1)
-
-#define PSWM_REGNUM    0
-#define PC_REGNUM      1
-#define	GP0_REGNUM     2		    /* GPR register 0 */ 
-#define GP_LAST_REGNUM (GP0_REGNUM+NUM_GPRS-1)
-#define RETADDR_REGNUM (GP0_REGNUM+14)                   /* Usually return address */
-#define SP_REGNUM      (GP0_REGNUM+15)	    /* Contains address of top of stack */
-#define FP_REGNUM     SP_REGNUM /* needed in findvar.c still */
-#define FRAME_REGNUM  (GP0_REGNUM+11)
-#define FPC_REGNUM    (GP0_REGNUM+NUM_GPRS+NUM_ACRS+NUM_CRS)
-#define FP0_REGNUM    (FPC_REGNUM+1) /* FPR (Floating point) register 0 */
-#define FPLAST_REGNUM (FP0_REGNUM+NUM_FPRS-1)	/* Last floating point register */
-
-/* The top of this structure is as similar as possible to a pt_regs structure to */
-/* simplify code */
-typedef struct
-{
-	S390_REGS_COMMON
-	__u32         crs[NUM_CRS];
-	s390_fp_regs  fp_regs;
-} s390_gdb_regs __attribute__((packed));
-
-#define REGISTER_NAMES                                           \
-{                                                                \
-"pswm","pswa",                                                   \
-"gpr0","gpr1","gpr2","gpr3","gpr4","gpr5","gpr6","gpr7",         \
-"gpr8","gpr9","gpr10","gpr11","gpr12","gpr13","gpr14","gpr15",   \
-"acr0","acr1","acr2","acr3","acr4","acr5","acr6","acr7",         \
-"acr8","acr9","acr10","acr11","acr12","acr13","acr14","acr15",   \
-"cr0","cr1","cr2","cr3","cr4","cr5","cr6","cr7",                 \
-"cr8","cr9","cr10","cr11","cr12","cr13","cr14","cr15",           \
-"fpc",                                                           \
-"fpr0","fpr1","fpr2","fpr3","fpr4","fpr5","fpr6","fpr7",         \
-"fpr8","fpr9","fpr10","fpr11","fpr12","fpr13","fpr14","fpr15"    \
-}
-
-/* Index within `registers' of the first byte of the space for
-   register N.  */
-
-#define ACR0_OFFSET ((PSW_MASK_SIZE+PSW_ADDR_SIZE)+(GPR_SIZE*NUM_GPRS))
-#define CR0_OFFSET (ACR0_OFFSET+(ACR_SIZE+NUM_ACRS))
-#define FPC_OFFSET (CR0_OFFSET+(CR_SIZE*NUM_CRS))
-#define FP0_OFFSET (FPC_OFFSET+(FPC_SIZE+FPC_PAD_SIZE))
-
-#define REGISTER_BYTES    \
-((FP0_OFFSET)+(FPR_SIZE*NUM_FPRS))
-
-#define REGISTER_BYTE(N)  ((N)<=GP_LAST_REGNUM ? (N)*8: \
-(N) <= LAST_ACR ? (ACR0_OFFSET+(((N)-FIRST_ACR)*ACR_SIZE)): \
-(N) <= LAST_CR ? (CR0_OFFSET+(((N)-FIRST_CR)*CR_SIZE)): \
-(N) == FPC_REGNUM ? FPC_OFFSET:(FP0_OFFSET+(((N)-FP0_REGNUM)*FPR_SIZE)))
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
diff -Nru a/include/asm-s390x/s390_ext.h b/include/asm-s390x/s390_ext.h
--- a/include/asm-s390x/s390_ext.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/s390_ext.h	Sat Jun  8 22:31:37 2002
@@ -25,6 +25,10 @@
 extern ext_int_info_t *ext_int_hash[];
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler);
+int register_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+				      ext_int_info_t *info);
 int unregister_external_interrupt(__u16 code, ext_int_handler_t handler);
+int unregister_early_external_interrupt(__u16 code, ext_int_handler_t handler,
+					ext_int_info_t *info);
 
 #endif
diff -Nru a/include/asm-s390x/s390io.h b/include/asm-s390x/s390io.h
--- a/include/asm-s390x/s390io.h	Sat Jun  8 22:31:49 2002
+++ b/include/asm-s390x/s390io.h	Sat Jun  8 22:31:49 2002
@@ -18,10 +18,13 @@
 typedef struct _ioinfo {
      unsigned int  irq;           /* aka. subchannel number */
      spinlock_t    irq_lock;      /* irq lock */
+     void          *private_data; /* pointer to private data */
 
      struct _ioinfo *prev;
      struct _ioinfo *next;
 
+     __u8          st;            /* subchannel type */	
+
      union {
         unsigned int info;
         struct {
@@ -50,10 +53,9 @@
            unsigned int  esid      : 1;  /* Ext. SenseID supported by HW */
            unsigned int  rcd       : 1;  /* RCD supported by HW */
            unsigned int  repnone   : 1;  /* don't call IRQ handler on interrupt */
-           unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
            unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 23); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
@@ -75,6 +77,7 @@
      unsigned long qintparm;      /* queued interruption parameter  */
      unsigned long qflag;         /* queued flags */
      __u8          qlpm;          /* queued logical path mask */
+     ssd_info_t    ssd_info;      /* subchannel description */
 
    } __attribute__ ((aligned(8))) ioinfo_t;
 
@@ -89,6 +92,12 @@
 #define IOINFO_FLAGS_REPALL  0x00800000
 
 extern ioinfo_t *ioinfo[];
+int s390_set_private_data(int irq, void * data);
+void * s390_get_private_data(int irq);
+
+#define CHSC_SEI_ACC_CHPID        1
+#define CHSC_SEI_ACC_LINKADDR     2
+#define CHSC_SEI_ACC_FULLLINKADDR 3
 
 #endif  /* __s390io_h */
 
diff -Nru a/include/asm-s390x/s390mach.h b/include/asm-s390x/s390mach.h
--- a/include/asm-s390x/s390mach.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/s390mach.h	Sat Jun  8 22:31:37 2002
@@ -13,10 +13,23 @@
 #include <asm/types.h>
 
 typedef struct _mci {
-	__u32	to_be_defined_1 :  9;
-	__u32 cp              :  1; /* channel-report pending */
-	__u32	to_be_defined_2 : 22;
-	__u32	to_be_defined_3;
+	__u32   sd              :  1; /* 00 system damage */
+	__u32   pd              :  1; /* 01 instruction-processing damage */
+	__u32   sr              :  1; /* 02 system recovery */
+	__u32   to_be_defined_1 :  4; /* 03-06 */
+	__u32   dg              :  1; /* 07 degradation */
+	__u32   w               :  1; /* 08 warning pending */
+	__u32   cp              :  1; /* 09 channel-report pending */
+	__u32   to_be_defined_2 :  6; /* 10-15 */
+	__u32   se              :  1; /* 16 storage error uncorrected */
+	__u32   sc              :  1; /* 17 storage error corrected */
+	__u32   ke              :  1; /* 18 storage-key error uncorrected */
+	__u32   ds              :  1; /* 19 storage degradation */
+	__u32	to_be_defined_3 :  4; /* 20-23 */
+	__u32   fa              :  1; /* 24 failing storage address validity */
+	__u32   to_be_defined_4 :  7; /* 25-31 */
+	__u32   ie              :  1; /* 32 indirect storage error */
+	__u32	to_be_defined_5 : 31; /* 33-63 */
 	} mci_t;
 
 //
diff -Nru a/include/asm-s390x/semaphore.h b/include/asm-s390x/semaphore.h
--- a/include/asm-s390x/semaphore.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/semaphore.h	Sat Jun  8 22:31:36 2002
@@ -1,5 +1,5 @@
 /*
- *  include/asm-s390/semaphore.h
+ *  include/asm-s390x/semaphore.h
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -18,15 +18,11 @@
 
 struct semaphore {
 	atomic_t count;
-	int sleepers;
 	wait_queue_head_t wait;
 };
 
-#define __SEM_DEBUG_INIT(name)
-
 #define __SEMAPHORE_INITIALIZER(name,count) \
-{ ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
-	__SEM_DEBUG_INIT(name) }
+	{ ATOMIC_INIT(count), __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }
 
 #define __MUTEX_INITIALIZER(name) \
 	__SEMAPHORE_INITIALIZER(name,1)
@@ -39,7 +35,7 @@
 
 static inline void sema_init (struct semaphore *sem, int val)
 {
-	*sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+	*sem = (struct semaphore) __SEMAPHORE_INITIALIZER((*sem),val);
 }
 
 static inline void init_MUTEX (struct semaphore *sem)
@@ -52,11 +48,6 @@
 	sema_init(sem, 0);
 }
 
-asmlinkage void __down_failed(void /* special register calling convention */);
-asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
-asmlinkage int  __down_failed_trylock(void  /* params in registers */);
-asmlinkage void __up_wakeup(void /* special register calling convention */);
-
 asmlinkage void __down(struct semaphore * sem);
 asmlinkage int  __down_interruptible(struct semaphore * sem);
 asmlinkage int  __down_trylock(struct semaphore * sem);
@@ -79,11 +70,28 @@
 
 static inline int down_trylock(struct semaphore * sem)
 {
-	int ret = 0;
+	int old_val, new_val;
 
-	if (atomic_dec_return(&sem->count) < 0)
-		ret = __down_trylock(sem);
-	return ret;
+	/*
+	 * This inline assembly atomically implements the equivalent
+	 * to the following C code:
+	 *   old_val = sem->count.counter;
+	 *   if ((new_val = old_val) > 0)
+	 *       sem->count.counter = --new_val;
+	 * In the ppc code this is called atomic_dec_if_positive.
+	 */
+	__asm__ __volatile__ (
+		"   l    %0,0(%3)\n"
+		"0: ltr  %1,%0\n"
+		"   jle  1f\n"
+		"   ahi  %1,-1\n"
+		"   cs   %0,%1,0(%3)\n"
+		"   jl   0b\n"
+		"1:"
+		: "=&d" (old_val), "=&d" (new_val),
+		  "+m" (sem->count.counter)
+		: "a" (&sem->count.counter) : "cc" );
+	return old_val <= 0;
 }
 
 static inline void up(struct semaphore * sem)
diff -Nru a/include/asm-s390x/setup.h b/include/asm-s390x/setup.h
--- a/include/asm-s390x/setup.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/setup.h	Sat Jun  8 22:31:35 2002
@@ -13,7 +13,7 @@
 #define RAMDISK_ORIGIN		0x800000
 #define RAMDISK_SIZE		0x800000
 
-#ifndef __ASSEMBLER__
+#ifndef __ASSEMBLY__
 
 #define IPL_DEVICE        (*(unsigned long *)  (0x10400))
 #define INITRD_START      (*(unsigned long *)  (0x10408))
diff -Nru a/include/asm-s390x/siginfo.h b/include/asm-s390x/siginfo.h
--- a/include/asm-s390x/siginfo.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/siginfo.h	Sat Jun  8 22:31:52 2002
@@ -14,80 +14,73 @@
 #include <asm-generic/siginfo.h>
 
 /*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#undef SI_TIMER
-#define SI_TIMER	-2	/* sent by timer expiration */
-
-/*
  * SIGILL si_codes
  */
-#define ILL_ILLOPC	1	/* illegal opcode */
-#define ILL_ILLOPN	2	/* illegal operand */
-#define ILL_ILLADR	3	/* illegal addressing mode */
-#define ILL_ILLTRP	4	/* illegal trap */
-#define ILL_PRVOPC	5	/* privileged opcode */
-#define ILL_PRVREG	6	/* privileged register */
-#define ILL_COPROC	7	/* coprocessor error */
-#define ILL_BADSTK	8	/* internal stack error */
+#define ILL_ILLOPC	(__SI_FAULT|1)	/* illegal opcode */
+#define ILL_ILLOPN	(__SI_FAULT|2)	/* illegal operand */
+#define ILL_ILLADR	(__SI_FAULT|3)	/* illegal addressing mode */
+#define ILL_ILLTRP	(__SI_FAULT|4)	/* illegal trap */
+#define ILL_PRVOPC	(__SI_FAULT|5)	/* privileged opcode */
+#define ILL_PRVREG	(__SI_FAULT|6)	/* privileged register */
+#define ILL_COPROC	(__SI_FAULT|7)	/* coprocessor error */
+#define ILL_BADSTK	(__SI_FAULT|8)	/* internal stack error */
 #define NSIGILL		8
 
 /*
  * SIGFPE si_codes
  */
-#define FPE_INTDIV	1	/* integer divide by zero */
-#define FPE_INTOVF	2	/* integer overflow */
-#define FPE_FLTDIV	3	/* floating point divide by zero */
-#define FPE_FLTOVF	4	/* floating point overflow */
-#define FPE_FLTUND	5	/* floating point underflow */
-#define FPE_FLTRES	6	/* floating point inexact result */
-#define FPE_FLTINV	7	/* floating point invalid operation */
-#define FPE_FLTSUB	8	/* subscript out of range */
+#define FPE_INTDIV	(__SI_FAULT|1)	/* integer divide by zero */
+#define FPE_INTOVF	(__SI_FAULT|2)	/* integer overflow */
+#define FPE_FLTDIV	(__SI_FAULT|3)	/* floating point divide by zero */
+#define FPE_FLTOVF	(__SI_FAULT|4)	/* floating point overflow */
+#define FPE_FLTUND	(__SI_FAULT|5)	/* floating point underflow */
+#define FPE_FLTRES	(__SI_FAULT|6)	/* floating point inexact result */
+#define FPE_FLTINV	(__SI_FAULT|7)	/* floating point invalid operation */
+#define FPE_FLTSUB	(__SI_FAULT|8)	/* subscript out of range */
 #define NSIGFPE		8
 
 /*
  * SIGSEGV si_codes
  */
-#define SEGV_MAPERR	1	/* address not mapped to object */
-#define SEGV_ACCERR	2	/* invalid permissions for mapped object */
+#define SEGV_MAPERR	(__SI_FAULT|1)	/* address not mapped to object */
+#define SEGV_ACCERR	(__SI_FAULT|2)	/* invalid permissions for mapped object */
 #define NSIGSEGV	2
 
 /*
  * SIGBUS si_codes
  */
-#define BUS_ADRALN	1	/* invalid address alignment */
-#define BUS_ADRERR	2	/* non-existant physical address */
-#define BUS_OBJERR	3	/* object specific hardware error */
+#define BUS_ADRALN	(__SI_FAULT|1)	/* invalid address alignment */
+#define BUS_ADRERR	(__SI_FAULT|2)	/* non-existant physical address */
+#define BUS_OBJERR	(__SI_FAULT|3)	/* object specific hardware error */
 #define NSIGBUS		3
 
 /*
  * SIGTRAP si_codes
  */
-#define TRAP_BRKPT	1	/* process breakpoint */
-#define TRAP_TRACE	2	/* process trace trap */
+#define TRAP_BRKPT	(__SI_FAULT|1)	/* process breakpoint */
+#define TRAP_TRACE	(__SI_FAULT|2)	/* process trace trap */
 #define NSIGTRAP	2
 
 /*
  * SIGCHLD si_codes
  */
-#define CLD_EXITED	1	/* child has exited */
-#define CLD_KILLED	2	/* child was killed */
-#define CLD_DUMPED	3	/* child terminated abnormally */
-#define CLD_TRAPPED	4	/* traced child has trapped */
-#define CLD_STOPPED	5	/* child has stopped */
-#define CLD_CONTINUED	6	/* stopped child has continued */
+#define CLD_EXITED	(__SI_CHLD|1)	/* child has exited */
+#define CLD_KILLED	(__SI_CHLD|2)	/* child was killed */
+#define CLD_DUMPED	(__SI_CHLD|3)	/* child terminated abnormally */
+#define CLD_TRAPPED	(__SI_CHLD|4)	/* traced child has trapped */
+#define CLD_STOPPED	(__SI_CHLD|5)	/* child has stopped */
+#define CLD_CONTINUED	(__SI_CHLD|6)	/* stopped child has continued */
 #define NSIGCHLD	6
 
 /*
  * SIGPOLL si_codes
  */
-#define POLL_IN		1	/* data input available */
-#define POLL_OUT	2	/* output buffers available */
-#define POLL_MSG	3	/* input message available */
-#define POLL_ERR	4	/* i/o error */
-#define POLL_PRI	5	/* high priority input available */
-#define POLL_HUP	6	/* device disconnected */
+#define POLL_IN		(__SI_POLL|1)	/* data input available */
+#define POLL_OUT	(__SI_POLL|2)	/* output buffers available */
+#define POLL_MSG	(__SI_POLL|3)	/* input message available */
+#define POLL_ERR	(__SI_POLL|4)	/* i/o error */
+#define POLL_PRI	(__SI_POLL|5)	/* high priority input available */
+#define POLL_HUP	(__SI_POLL|6)	/* device disconnected */
 #define NSIGPOLL	6
 
 #endif
diff -Nru a/include/asm-s390x/signal.h b/include/asm-s390x/signal.h
--- a/include/asm-s390x/signal.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/signal.h	Sat Jun  8 22:31:35 2002
@@ -13,6 +13,7 @@
 
 /* Avoid too many header ordering problems.  */
 struct siginfo;
+struct pt_regs;
 
 #ifdef __KERNEL__
 /* Most things should be clean enough to redefine this at will, if care
diff -Nru a/include/asm-s390x/sigp.h b/include/asm-s390x/sigp.h
--- a/include/asm-s390x/sigp.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/sigp.h	Sat Jun  8 22:31:37 2002
@@ -59,9 +59,6 @@
 typedef enum
 {
 	ec_schedule=0,
-        ec_restart,
-        ec_halt,
-        ec_power_off,
 	ec_call_function,
 	ec_bit_last
 } ec_bit_sig;
@@ -130,6 +127,6 @@
    return ccode;
 }
 
-#endif __SIGP__
+#endif /* __SIGP__ */
 
 
diff -Nru a/include/asm-s390x/smp.h b/include/asm-s390x/smp.h
--- a/include/asm-s390x/smp.h	Sat Jun  8 22:31:43 2002
+++ b/include/asm-s390x/smp.h	Sat Jun  8 22:31:43 2002
@@ -10,6 +10,8 @@
 #define __ASM_SMP_H
 
 #include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/ptrace.h>
 
 #if defined(__KERNEL__) && defined(CONFIG_SMP) && !defined(__ASSEMBLY__)
 
@@ -26,7 +28,7 @@
 	__u16      cpu;
 } sigp_info;
 
-extern unsigned long cpu_online_map;
+extern volatile unsigned long cpu_online_map;
 
 #define NO_PROC_ID		0xFF		/* No processor magic marker */
 
@@ -42,7 +44,7 @@
  
 #define PROC_CHANGE_PENALTY	20		/* Schedule penalty */
 
-#define smp_processor_id() (current->processor)
+#define smp_processor_id() (current_thread_info()->cpu)
 
 extern __inline__ int cpu_logical_map(int cpu)
 {
@@ -63,8 +65,6 @@
 }
 
 #define cpu_logical_map(cpu) (cpu)
-
-void smp_local_timer_interrupt(struct pt_regs * regs);
 
 #endif
 #endif
diff -Nru a/include/asm-s390x/spinlock.h b/include/asm-s390x/spinlock.h
--- a/include/asm-s390x/spinlock.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/spinlock.h	Sat Jun  8 22:31:36 2002
@@ -27,32 +27,34 @@
 #define spin_unlock_wait(lp)	do { barrier(); } while(((volatile spinlock_t *)(lp))->lock)
 #define spin_is_locked(x) ((x)->lock != 0)
 
-extern inline void spin_lock(spinlock_t *lp)
+extern inline void _raw_spin_lock(spinlock_t *lp)
 {
-        __asm__ __volatile("    bras  1,1f\n"
+	unsigned long reg1, reg2;
+        __asm__ __volatile("    bras  %1,1f\n"
                            "0:  # diag  0,0,68\n"
-                           "1:  slr   0,0\n"
-                           "    cs    0,1,0(%0)\n"
+                           "1:  slr   %0,%0\n"
+                           "    cs    %0,%1,0(%3)\n"
                            "    jl    0b\n"
-                           : : "a" (&lp->lock) : "0", "1", "cc", "memory" );
+                           : "=&d" (reg1), "=&d" (reg2), "+m" (lp->lock)
+                           : "a" (&lp->lock) : "cc" );
 }
 
-extern inline int spin_trylock(spinlock_t *lp)
+extern inline int _raw_spin_trylock(spinlock_t *lp)
 {
-	unsigned int result;
+	unsigned int result, reg;
 	__asm__ __volatile("    slr   %0,%0\n"
-			   "    basr  1,0\n"
-			   "0:  cs    %0,1,0(%1)"
-			   : "=&d" (result)
-			   : "a" (&lp->lock) : "1", "cc", "memory" );
+			   "    basr  %1,0\n"
+			   "0:  cs    %0,%1,0(%3)"
+			   : "=&d" (result), "=&d" (reg), "+m" (lp->lock)
+			   : "a" (&lp->lock) : "cc" );
 	return !result;
 }
 
-extern inline void spin_unlock(spinlock_t *lp)
+extern inline void _raw_spin_unlock(spinlock_t *lp)
 {
-	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
+	__asm__ __volatile("    xc 0(4,%1),0(%1)\n"
                            "    bcr 15,0"
-			   : : "a" (&lp->lock) : "memory", "cc" );
+			   : "+m" (lp->lock) : "a" (&lp->lock) : "cc" );
 }
 		
 /*
@@ -74,43 +76,47 @@
 
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 
-#define read_lock(rw)   \
-        asm volatile("   lg    2,0(%0)\n"   \
+#define _raw_read_lock(rw)   \
+        asm volatile("   lg    2,0(%1)\n"   \
                      "   j     1f\n"     \
                      "0: # diag  0,0,68\n" \
                      "1: nihh  2,0x7fff\n" /* clear high (=write) bit */ \
                      "   la    3,1(2)\n"   /* one more reader */  \
-                     "   csg   2,3,0(%0)\n" /* try to write new value */ \
+                     "   csg   2,3,0(%1)\n" /* try to write new value */ \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define read_unlock(rw) \
-        asm volatile("   lg    2,0(%0)\n"   \
+#define _raw_read_unlock(rw) \
+        asm volatile("   lg    2,0(%1)\n"   \
                      "   j     1f\n"     \
                      "0: # diag  0,0,68\n" \
                      "1: lgr   3,2\n"    \
                      "   bctgr 3,0\n"    /* one less reader */ \
-                     "   csg   2,3,0(%0)\n" \
+                     "   csg   2,3,0(%1)\n" \
                      "   jl    0b"       \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define write_lock(rw) \
+#define _raw_write_lock(rw) \
         asm volatile("   llihh 3,0x8000\n" /* new lock value = 0x80...0 */ \
                      "   j     1f\n"       \
                      "0: # diag  0,0,68\n"   \
                      "1: slgr  2,2\n"      /* old lock value must be 0 */ \
-                     "   csg   2,3,0(%0)\n" \
+                     "   csg   2,3,0(%1)\n" \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
-#define write_unlock(rw) \
+#define _raw_write_unlock(rw) \
         asm volatile("   slgr  3,3\n"      /* new lock value = 0 */ \
                      "   j     1f\n"       \
                      "0: # diag  0,0,68\n"   \
                      "1: llihh 2,0x8000\n" /* old lock value must be 0x8..0 */\
-                     "   csg   2,3,0(%0)\n"   \
+                     "   csg   2,3,0(%1)\n"   \
                      "   jl    0b"         \
-                     : : "a" (&(rw)->lock) : "2", "3", "cc", "memory" );
+                     : "+m" ((rw)->lock) : "a" (&(rw)->lock) \
+		     : "2", "3", "cc" )
 
 #endif /* __ASM_SPINLOCK_H */
 
diff -Nru a/include/asm-s390x/suspend.h b/include/asm-s390x/suspend.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/suspend.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,5 @@
+#ifndef __ASM_S390X_SUSPEND_H
+#define __ASM_S390X_SUSPEND_H
+
+#endif
+
diff -Nru a/include/asm-s390x/system.h b/include/asm-s390x/system.h
--- a/include/asm-s390x/system.h	Sat Jun  8 22:31:52 2002
+++ b/include/asm-s390x/system.h	Sat Jun  8 22:31:52 2002
@@ -12,18 +12,19 @@
 #define __ASM_SYSTEM_H
 
 #include <linux/config.h>
+#include <asm/types.h>
 #ifdef __KERNEL__
 #include <asm/lowcore.h>
 #endif
 #include <linux/kernel.h>
 
 #define prepare_to_switch()	do { } while(0)
-#define switch_to(prev,next,last) do {                                       \
-        if (prev == next)                                                    \
-                break;                                                       \
-	save_fp_regs(&prev->thread.fp_regs);                                 \
-	restore_fp_regs(&next->thread.fp_regs);              		     \
-	last = resume(&prev->thread,&next->thread);                          \
+#define switch_to(prev,next) do {					     \
+	if (prev == next)						     \
+		break;							     \
+	save_fp_regs(&prev->thread.fp_regs);				     \
+	restore_fp_regs(&next->thread.fp_regs);				     \
+	resume(prev,next);						     \
 } while (0)
 
 struct task_struct;
@@ -110,8 +111,6 @@
                                 : "+d" (x) : "a" (ptr)
                                 : "memory", "cc", "0" );
                         break;
-               default:
-                        abort();
         }
         return x;
 }
@@ -142,26 +141,26 @@
 
 /* interrupt control.. */
 #define __sti() ({ \
-        unsigned long dummy; \
+        unsigned long __dummy; \
         __asm__ __volatile__ ( \
-                "stosm %0,0x03" : "=m" (dummy) : : "memory"); \
+                "stosm 0(%0),0x03" : : "a" (&__dummy) : "memory"); \
         })
 
 #define __cli() ({ \
-        unsigned long flags; \
+        unsigned long __flags; \
         __asm__ __volatile__ ( \
-                "stnsm %0,0xFC" : "=m" (flags) : : "memory"); \
-        flags; \
+                "stnsm 0(%0),0xFC" : : "a" (&__flags) : "memory"); \
+        __flags; \
         })
 
 #define __save_flags(x) \
-        __asm__ __volatile__("stosm %0,0" : "=m" (x) : : "memory")
+        __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory")
 
 #define __restore_flags(x) \
-        __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
+        __asm__ __volatile__("ssm   0(%0)" : : "a" (&x) : "memory")
 
 #define __load_psw(psw) \
-        __asm__ __volatile__("lpswe %0" : : "m" (psw) : "cc" );
+        __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
 	__asm__ __volatile__ ( \
@@ -182,7 +181,7 @@
 	})
 
 #define __ctl_set_bit(cr, bit) ({ \
-        __u8 dummy[24]; \
+        __u8 __dummy[24]; \
         __asm__ __volatile__ ( \
                 "    la    1,%0\n"       /* align to 8 byte */ \
                 "    aghi  1,7\n" \
@@ -195,12 +194,12 @@
                 "    ogr   0,%2\n"       /* set the bit */ \
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
-                : "=m" (dummy) : "a" (cr*17), "a" (1L<<(bit)) \
+                : "=m" (__dummy) : "a" (cr*17), "a" (1L<<(bit)) \
                 : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
-        __u8 dummy[24]; \
+        __u8 __dummy[24]; \
         __asm__ __volatile__ ( \
                 "    la    1,%0\n"       /* align to 8 byte */ \
                 "    aghi  1,7\n" \
@@ -213,7 +212,7 @@
                 "    ngr   0,%2\n"       /* set the bit */ \
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
-                : "=m" (dummy) : "a" (cr*17), "a" (~(1L<<(bit))) \
+                : "=m" (__dummy) : "a" (cr*17), "a" (~(1L<<(bit))) \
                 : "cc", "0", "1", "2"); \
         })
 
@@ -254,12 +253,17 @@
 #endif
 
 #ifdef __KERNEL__
-extern struct task_struct *resume(void *,void *);
+extern struct task_struct *resume(void *, void *);
 
 extern int save_fp_regs1(s390_fp_regs *fpregs);
 extern void save_fp_regs(s390_fp_regs *fpregs);
 extern int restore_fp_regs1(s390_fp_regs *fpregs);
 extern void restore_fp_regs(s390_fp_regs *fpregs);
+
+extern void (*_machine_restart)(char *command);
+extern void (*_machine_halt)(void);
+extern void (*_machine_power_off)(void);
+
 #endif
 
 #endif
diff -Nru a/include/asm-s390x/tape390.h b/include/asm-s390x/tape390.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/tape390.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,39 @@
+/*************************************************************************
+ *
+ * tape390.h
+ *         enables user programs to display messages on the tape device
+ *
+ *  S390 and zSeries version
+ *         Copyright (C) 2001 IBM Corporation
+ *         Author(s): Despina Papadopoulou <despina_p@de.ibm.com>
+ *
+ *************************************************************************/
+
+#ifndef _TAPE390_H
+#define _TAPE390_H
+
+#define TAPE390_DISPLAY _IOW('d', 1, struct display_struct)
+
+/*
+ * The TAPE390_DISPLAY ioctl calls the Load Display command
+ * which transfers 17 bytes of data from the channel to the subsystem:
+ *     - 1 format control byte, and
+ *     - two 8-byte messages
+ *
+ * Format control byte:
+ *   0-2: New Message Overlay
+ *     3: Alternate Messages
+ *     4: Blink Message
+ *     5: Display Low/High Message
+ *     6: Reserved
+ *     7: Automatic Load Request
+ *
+ */
+
+typedef struct display_struct {
+        char cntrl;
+        char message1[8];
+        char message2[8];
+} display_struct;
+
+#endif 
diff -Nru a/include/asm-s390x/thread_info.h b/include/asm-s390x/thread_info.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/thread_info.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,87 @@
+/*
+ *  include/asm-s390/thread_info.h
+ *
+ *  S390 version
+ *    Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#ifndef _ASM_THREAD_INFO_H
+#define _ASM_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants must also be changed
+ */
+struct thread_info {
+	struct task_struct	*task;		/* main task structure */
+	struct exec_domain	*exec_domain;	/* execution domain */
+	unsigned long		flags;		/* low level flags */
+	unsigned int		cpu;		/* current CPU */
+	int 			preempt_count; /* 0 => preemptable, <0 => BUG */
+};
+
+#define PREEMPT_ACTIVE		0x4000000
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ */
+#define INIT_THREAD_INFO(tsk)			\
+{						\
+	task:		&tsk,			\
+	exec_domain:	&default_exec_domain,	\
+	flags:		0,			\
+	cpu:		0,			\
+}
+
+#define init_thread_info	(init_thread_union.thread_info)
+#define init_stack		(init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+	return (struct thread_info *)((*(unsigned long *) 0xd40)-16384);
+}
+
+/* thread information allocation */
+#define alloc_thread_info() ((struct thread_info *) \
+	__get_free_pages(GFP_KERNEL,2))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 2)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#endif
+
+/*
+ * Size of kernel stack for each process
+ */
+#define THREAD_SIZE (4*PAGE_SIZE)
+
+/*
+ * thread information flags bit numbers
+ */
+#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
+#define TIF_NOTIFY_RESUME	1	/* resumption notification requested */
+#define TIF_SIGPENDING		2	/* signal pending */
+#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
+#define TIF_USEDFPU		16	/* FPU was used by this task this quantum (SMP) */
+#define TIF_POLLING_NRFLAG	17	/* true if poll_idle() is polling 
+					   TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE	(1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME	(1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
+#define _TIF_USEDFPU		(1<<TIF_USEDFPU)
+#define _TIF_POLLING_NRFLAG	(1<<TIF_POLLING_NRFLAG)
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_THREAD_INFO_H */
diff -Nru a/include/asm-s390x/timex.h b/include/asm-s390x/timex.h
--- a/include/asm-s390x/timex.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/timex.h	Sat Jun  8 22:31:36 2002
@@ -17,13 +17,24 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
-typedef unsigned long cycles_t;
+typedef unsigned long long cycles_t;
 
 extern cycles_t cacheflush_time;
 
 static inline cycles_t get_cycles(void)
 {
-        return 0;
+	cycles_t cycles;
+
+	__asm__("stck 0(%0)" : : "a" (&(cycles)) : "memory", "cc");
+	return cycles >> 2;
+}
+
+static inline unsigned long long get_clock (void)
+{
+	unsigned long long clock;
+
+	__asm__("stck 0(%0)" : : "a" (&(clock)) : "memory", "cc");
+	return clock;
 }
 
 #endif
diff -Nru a/include/asm-s390x/tlb.h b/include/asm-s390x/tlb.h
--- a/include/asm-s390x/tlb.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/tlb.h	Sat Jun  8 22:31:35 2002
@@ -1 +1,20 @@
+#ifndef _S390X_TLB_H
+#define _S390X_TLB_H
+
+/*
+ * s390x doesn't need any special per-pte or
+ * per-vma handling..
+ */
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
+
+/*
+ * .. because we flush the whole mm when it
+ * fills up.
+ */
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
 #include <asm-generic/tlb.h>
+
+#endif
diff -Nru a/include/asm-s390x/tlbflush.h b/include/asm-s390x/tlbflush.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-s390x/tlbflush.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,135 @@
+#ifndef _S390X_TLBFLUSH_H
+#define _S390X_TLBFLUSH_H
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <asm/processor.h>
+
+/*
+ * TLB flushing:
+ *
+ *  - flush_tlb() flushes the current mm struct TLBs
+ *  - flush_tlb_all() flushes all processes TLBs 
+ *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ *  - flush_tlb_page(vma, vmaddr) flushes one page
+ *  - flush_tlb_range(vma, start, end) flushes a range of pages
+ *  - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
+ */
+
+/*
+ * S/390 has three ways of flushing TLBs
+ * 'ptlb' does a flush of the local processor
+ * 'csp' flushes the TLBs on all PUs of a SMP
+ * 'ipte' invalidates a pte in a page table and flushes that out of
+ * the TLBs of all PUs of a SMP
+ */
+
+#define local_flush_tlb() \
+do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
+
+#ifndef CONFIG_SMP
+
+/*
+ * We always need to flush, since s390 does not flush tlb
+ * on each context switch
+ */
+
+static inline void flush_tlb(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_all(void)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	local_flush_tlb();
+}
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	local_flush_tlb();
+}
+
+#define flush_tlb_kernel_range(start, end) \
+	local_flush_tlb();
+
+#else
+
+#include <asm/smp.h>
+
+extern void smp_ptlb_all(void);
+
+static inline void global_flush_tlb(void)
+{
+	long dummy = 0;
+
+	__asm__ __volatile__ (
+                "    la   4,1(%0)\n"
+                "    slr  2,2\n"
+                "    slr  3,3\n"
+                "    csp  2,4"
+                : : "a" (&dummy) : "cc", "2", "3", "4" );
+}
+
+/*
+ * We only have to do global flush of tlb if process run since last
+ * flush on any other pu than current. 
+ * If we have threads (mm->count > 1) we always do a global flush, 
+ * since the process runs on more than one processor at the same time.
+ */
+
+static inline void __flush_tlb_mm(struct mm_struct * mm)
+{
+	if ((smp_num_cpus > 1) &&
+	    ((atomic_read(&mm->mm_count) != 1) ||
+	     (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
+		mm->cpu_vm_mask = (1UL << smp_processor_id());
+		global_flush_tlb();
+	} else {                 
+		local_flush_tlb();
+	}
+}
+
+static inline void flush_tlb(void)
+{
+	__flush_tlb_mm(current->mm);
+}
+static inline void flush_tlb_all(void)
+{
+	global_flush_tlb();
+}
+static inline void flush_tlb_mm(struct mm_struct *mm) 
+{
+	__flush_tlb_mm(mm); 
+}
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+				  unsigned long addr)
+{
+	__flush_tlb_mm(vma->vm_mm);
+}
+static inline void flush_tlb_range(struct vm_area_struct *vma,
+				   unsigned long start, unsigned long end)
+{
+	__flush_tlb_mm(vma->vm_mm); 
+}
+
+#define flush_tlb_kernel_range(start, end) \
+	__flush_tlb_mm(&init_mm)
+
+#endif
+
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
+                                      unsigned long start, unsigned long end)
+{
+        /* S/390 does not keep any page table caches in TLB */
+}
+
+#endif /* _S390X_TLBFLUSH_H */
diff -Nru a/include/asm-s390x/uaccess.h b/include/asm-s390x/uaccess.h
--- a/include/asm-s390x/uaccess.h	Sat Jun  8 22:31:35 2002
+++ b/include/asm-s390x/uaccess.h	Sat Jun  8 22:31:35 2002
@@ -15,6 +15,7 @@
  * User space memory access functions
  */
 #include <linux/sched.h>
+#include <linux/errno.h>
 
 #define VERIFY_READ     0
 #define VERIFY_WRITE    1
@@ -35,9 +36,10 @@
 #define USER_DS		MAKE_MM_SEG(1)
 
 #define get_ds()	(KERNEL_DS)
-#define get_fs()	(current->addr_limit)
-#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));\
-                          current->addr_limit = (x);})
+#define get_fs()        ({ mm_segment_t __x; \
+			   asm volatile("ear   %0,4":"=a" (__x)); \
+			   __x;})
+#define set_fs(x)       ({asm volatile("sar   4,%0"::"a" ((x).ar4));})
 
 #define segment_eq(a,b)	((a).ar4 == (b).ar4)
 
@@ -82,21 +84,21 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   la    4,%1\n"
                                 "   sacf  512\n"
                                 "0: stg   %2,0(4)\n"
                                 "1: sacf  0\n"
 				".section .fixup,\"ax\"\n"
-				"2: lhi   %1,%h3\n"
+				"2: lhi   %0,%h3\n"
 				"   jg    1b\n"
 				".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 8\n"
 				"   .quad  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u64*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "m" (*((__u64*) ptr)), "d" (x), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -104,21 +106,21 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   la    4,%1\n"
                                 "   sacf  512\n"
                                 "0: st    %2,0(4)\n"
                                 "1: sacf  0\n"
 				".section .fixup,\"ax\"\n"
-				"2: lhi   %1,%h3\n"
+				"2: lhi   %0,%h3\n"
 				"   jg    1b\n"
 				".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 8\n"
 				"   .quad  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u32*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "m" (*((__u32*) ptr)), "d" (x), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -127,21 +129,21 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   la    4,%1\n"
                                 "   sacf  512\n"
                                 "0: sth   %2,0(4)\n"
                                 "1: sacf  0\n"
 				".section .fixup,\"ax\"\n"
-				"2: lhi   %1,%h3\n"
+				"2: lhi   %0,%h3\n"
 				"   jg    1b\n"
 				".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 8\n"
 				"   .quad  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u16*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
+                                : "=&d" (err)
+                                : "m" (*((__u16*) ptr)), "d" (x), "K" (-EFAULT)
                                 : "cc", "4" );
         return err;
 }
@@ -150,22 +152,22 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   sr    %1,%1\n"
-				"   la    4,%0\n"
+        __asm__ __volatile__ (  "   sr    %0,%0\n"
+				"   la    4,%1\n"
                                 "   sacf  512\n"
                                 "0: stc   %2,0(4)\n"
                                 "1: sacf  0\n"
 				".section .fixup,\"ax\"\n"
-				"2: lhi   %1,%h3\n"
+				"2: lhi   %0,%h3\n"
 				"   jg    1b\n"
 				".previous\n"
 				".section __ex_table,\"a\"\n"
 				"   .align 8\n"
 				"   .quad  0b,2b\n"
 				".previous"
-                                : "=m" (*((__u8*) ptr)) , "=&d" (err)
-                                : "d" (x), "K" (-EFAULT)
-                                : "cc", "1", "4" );
+                                : "=&d" (err)
+                                : "m" (*((__u8*) ptr)), "d" (x), "K" (-EFAULT)
+                                : "cc", "4" );
         return err;
 }
 
@@ -175,42 +177,37 @@
  */
 #define __put_user(x, ptr)                                      \
 ({                                                              \
+        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
+        __typeof__(*(ptr)) __x = (x);                           \
         int __pu_err;                                           \
-        switch (sizeof (*(ptr))) {                              \
-                case 1:                                         \
-                        __pu_err = __put_user_asm_1((__u8)(__u64)(x),(ptr));\
-                        break;                                  \
-                case 2:                                         \
-                        __pu_err = __put_user_asm_2((__u16)(__u64)(x),(ptr));\
-                        break;                                  \
-                case 4:                                         \
-                        __pu_err = __put_user_asm_4((__u32)(__u64)(x),(ptr));\
-                        break;                                  \
-                case 8:                                         \
-                        __pu_err = __put_user_asm_8((__u64)(x),(ptr));\
-                        break;                                  \
-                default:                                        \
+        switch (sizeof (*(__pu_addr))) {                        \
+        case 1:                                                 \
+                __pu_err = __put_user_asm_1((__u8)(__u64)(__x), \
+                                            __pu_addr);         \
+                break;                                          \
+        case 2:                                                 \
+                __pu_err = __put_user_asm_2((__u16)(__u64)(__x),\
+                                            __pu_addr);         \
+                break;                                          \
+        case 4:                                                 \
+                __pu_err = __put_user_asm_4((__u32)(__u64)(__x),\
+                                            __pu_addr);         \
+                break;                                          \
+        case 8:                                                 \
+                __pu_err = __put_user_asm_8((__u64)(__x),       \
+                                            __pu_addr);         \
+                break;                                          \
+        default:                                                \
                 __pu_err = __put_user_bad();                    \
                 break;                                          \
          }                                                      \
         __pu_err;                                               \
 })
 
-#define put_user(x, ptr)                                        \
-({                                                              \
-        long __pu_err = -EFAULT;                                \
-        __typeof__(*(ptr)) *__pu_addr = (ptr);                  \
-        __typeof__(*(ptr)) __x = (x);                           \
-        if (__access_ok((long)__pu_addr,sizeof(*(ptr)))) {      \
-                __pu_err = 0;                                   \
-                __put_user((__x), (__pu_addr));                 \
-        }                                                       \
-        __pu_err;                                               \
-})
+#define put_user(x, ptr) __put_user(x, ptr)
 
 extern int __put_user_bad(void);
 
-
 #define __get_user_asm_8(x, ptr, err)                                      \
 ({                                                                         \
         __asm__ __volatile__ (  "   sr    %1,%1\n"                         \
@@ -293,42 +290,32 @@
 
 #define __get_user(x, ptr)                                      \
 ({                                                              \
+        __typeof__(ptr) __gu_addr = (ptr);                      \
+        __typeof__(*(ptr)) __x;                                 \
         int __gu_err;                                           \
         switch (sizeof(*(ptr))) {                               \
-                case 1:                                         \
-                        __get_user_asm_1(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 2:                                         \
-                        __get_user_asm_2(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 4:                                         \
-                        __get_user_asm_4(x,ptr,__gu_err);       \
-                        break;                                  \
-                case 8:                                         \
-                        __get_user_asm_8(x,ptr,__gu_err);       \
-                        break;                                  \
-                default:                                        \
-                        (x) = 0;                                \
-                        __gu_err = __get_user_bad();            \
+        case 1:                                                 \
+                __get_user_asm_1(__x,__gu_addr,__gu_err);       \
+                break;                                          \
+        case 2:                                                 \
+                __get_user_asm_2(__x,__gu_addr,__gu_err);       \
+                break;                                          \
+        case 4:                                                 \
+                __get_user_asm_4(__x,__gu_addr,__gu_err);       \
+                break;                                          \
+        case 8:                                                 \
+                __get_user_asm_8(__x,__gu_addr,__gu_err);       \
+                break;                                          \
+        default:                                                \
+                __x = 0;                                        \
+                __gu_err = __get_user_bad();                    \
                 break;                                          \
         }                                                       \
+        (x) = __x;                                              \
         __gu_err;                                               \
 })
 
-#define get_user(x, ptr)                                        \
-({                                                              \
-        long __gu_err = -EFAULT;                                \
-        __typeof__(ptr) __gu_addr = (ptr);                      \
-        __typeof__(*(ptr)) __x;                                 \
-        if (__access_ok((long)__gu_addr,sizeof(*(ptr)))) {      \
-                __gu_err = 0;                                   \
-                __get_user((__x), (__gu_addr));                 \
-                (x) = __x;                                      \
-        }                                                       \
-        else                                                    \
-                (x) = 0;                                        \
-        __gu_err;                                               \
-})
+#define get_user(x, ptr) __get_user(x, ptr)
 
 extern int __get_user_bad(void);
 
@@ -336,34 +323,11 @@
  * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel)
  */
 
-asmlinkage void __copy_from_user_fixup(void /* special calling convention */);
-asmlinkage void __copy_to_user_fixup(void /* special calling convention */);
-
-extern inline unsigned long
-__copy_to_user_asm(void* to, const void* from,  long n)
-{
-
-        __asm__ __volatile__ (  "   lgr   2,%2\n"
-                                "   lgr   4,%1\n"
-                                "   lgr   3,%0\n"
-                                "   lgr   5,3\n"
-                                "   sacf  512\n"
-                                "0: mvcle 4,2,0\n"
-                                "   jo    0b\n"
-                                "   sacf  0\n"
-                                "   lgr   %0,3\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 8\n"
-				"   .quad  0b,__copy_to_user_fixup\n"
-				".previous"
-                                : "+&d" (n) : "d" (to), "d" (from)
-                                : "cc", "1", "2", "3", "4", "5" );
-        return n;
-}
+extern long __copy_to_user_asm(const void *from, long n, void *to);
 
 #define __copy_to_user(to, from, n)                             \
 ({                                                              \
-        __copy_to_user_asm(to,from,n);                          \
+        __copy_to_user_asm(from, n, to);                        \
 })
 
 #define copy_to_user(to, from, n)                               \
@@ -371,38 +335,18 @@
         long err = 0;                                           \
         __typeof__(n) __n = (n);                                \
         if (__access_ok(to,__n)) {                              \
-                err = __copy_to_user_asm(to,from,__n);          \
+                err = __copy_to_user_asm(from, __n, to);        \
         }                                                       \
         else                                                    \
                 err = __n;                                      \
         err;                                                    \
 })
 
-extern inline unsigned long
-__copy_from_user_asm(void* to, const void* from,  long n)
-{
-        __asm__ __volatile__ (  "   lgr   2,%1\n"
-                                "   lgr   4,%2\n"
-                                "   lgr   3,%0\n"
-                                "   lgr   5,3\n"
-                                "   sacf  512\n"
-                                "0: mvcle 2,4,0\n"
-                                "   jo    0b\n"
-                                "   sacf  0\n"
-                                "   lgr   %0,5\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 8\n"
-				"   .quad  0b,__copy_from_user_fixup\n"
-				".previous"
-                                : "+&d" (n) : "d" (to), "d" (from)
-                                : "cc", "1", "2", "3", "4", "5" );
-        return n;
-}
-
+extern long __copy_from_user_asm(void *to, long n, const void *from);
 
 #define __copy_from_user(to, from, n)                           \
 ({                                                              \
-        __copy_from_user_asm(to,from,n);                        \
+        __copy_from_user_asm(to, n, from);                      \
 })
 
 #define copy_from_user(to, from, n)                             \
@@ -410,7 +354,7 @@
         long err = 0;                                           \
         __typeof__(n) __n = (n);                                \
         if (__access_ok(from,__n)) {                            \
-                err = __copy_from_user_asm(to,from,__n);        \
+                err = __copy_from_user_asm(to, __n, from);      \
         }                                                       \
         else                                                    \
                 err = __n;                                      \
@@ -520,27 +464,12 @@
  * Zero Userspace
  */
 
-static inline unsigned long
-__clear_user(void *to, unsigned long n)
-{
-        __asm__ __volatile__ (  "   sacf  512\n"
-                                "   lgr   4,%1\n"
-                                "   lgr   5,%0\n"
-                                "   sgr   2,2\n"
-                                "   sgr   3,3\n"
-                                "0: mvcle 4,2,0\n"
-                                "   jo    0b\n"
-                                "1: sacf  0\n"
-                                "   lgr   %0,5\n"
-				".section __ex_table,\"a\"\n"
-				"   .align 8\n"
-				"   .quad  0b,__copy_to_user_fixup\n"
-				".previous"
-                                : "+&a" (n)
-                                : "a"   (to)
-                                : "cc", "1", "2", "3", "4", "5" );
-        return n;
-}
+extern long __clear_user_asm(void *to, long n);
+
+#define __clear_user(to, n)                                     \
+({                                                              \
+        __clear_user_asm(to, n);                                \
+})
 
 static inline unsigned long
 clear_user(void *to, unsigned long n)
diff -Nru a/include/asm-s390x/unistd.h b/include/asm-s390x/unistd.h
--- a/include/asm-s390x/unistd.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-s390x/unistd.h	Sat Jun  8 22:31:36 2002
@@ -180,9 +180,24 @@
 #define __NR_pivot_root         217
 #define __NR_mincore            218
 #define __NR_madvise            219
-#define __NR_getdents64         220
-#define __NR_gettid		226
-#define __NR_tkill 	        227
+#define __NR_readahead		222
+#define __NR_setxattr		224
+#define __NR_lsetxattr		225
+#define __NR_fsetxattr		226
+#define __NR_getxattr		227
+#define __NR_lgetxattr		228
+#define __NR_fgetxattr		229
+#define __NR_listxattr		230
+#define __NR_llistxattr		231
+#define __NR_flistxattr		232
+#define __NR_removexattr	233
+#define __NR_lremovexattr	234
+#define __NR_fremovexattr	235
+#define __NR_gettid		236
+#define __NR_tkill		237
+#define __NR_futex		238
+#define __NR_sched_setaffinity	239
+#define __NR_sched_getaffinity	240
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
@@ -305,6 +320,8 @@
 
 #ifdef __KERNEL_SYSCALLS__
 
+#include <asm/stat.h>
+
 /*
  * we need this inline - forking from kernel space will result
  * in NO COPY ON WRITE (!!!), until an execve is executed. This
@@ -333,9 +350,11 @@
 static inline _syscall1(int,delete_module,const char *,name)
 static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
 
-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
+struct rusage;
+extern long sys_wait4(pid_t, unsigned int *, int, struct rusage *);
+static inline pid_t waitpid(int pid, int *wait_stat, int flags)
 {
-        return sys_wait4(pid, wait_stat, flags, NULL);
+	return sys_wait4(pid, wait_stat, flags, NULL);
 }
 
 static inline pid_t wait(int * wait_stat)
diff -Nru a/include/asm-s390x/vtoc.h b/include/asm-s390x/vtoc.h
--- a/include/asm-s390x/vtoc.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-s390x/vtoc.h	Sat Jun  8 22:31:37 2002
@@ -18,7 +18,6 @@
 #include <asm/dasd.h>
 #endif
 
-#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
diff -Nru a/include/asm-sparc/btfixup.h b/include/asm-sparc/btfixup.h
--- a/include/asm-sparc/btfixup.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-sparc/btfixup.h	Sat Jun  8 22:31:37 2002
@@ -16,7 +16,22 @@
 extern unsigned int ___illegal_use_of_BTFIXUP_SETHI_in_module(void);
 extern unsigned int ___illegal_use_of_BTFIXUP_HALF_in_module(void);
 extern unsigned int ___illegal_use_of_BTFIXUP_INT_in_module(void);
-#endif
+
+#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module()
+#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module()
+#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module()
+#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module()
+#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module
+
+#else
+
+#define BTFIXUP_SIMM13(__name) ___sf_##__name()
+#define BTFIXUP_HALF(__name) ___af_##__name()
+#define BTFIXUP_SETHI(__name) ___hf_##__name()
+#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name)
+/* This must be written in assembly and present in a sethi */
+#define BTFIXUP_BLACKBOX(__name) ___b_##__name
+#endif /* MODULE */
 
 /* Fixup call xx */
 
@@ -30,12 +45,6 @@
 
 #define BTFIXUPDEF_BLACKBOX(__name)							\
 	extern unsigned ___bs_##__name[2];
-#ifdef MODULE
-#define BTFIXUP_BLACKBOX(__name) ___illegal_use_of_BTFIXUP_BLACKBOX_in_module
-#else
-/* This must be written in assembly and present in a sethi */
-#define BTFIXUP_BLACKBOX(__name) ___b_##__name
-#endif
 
 /* Put bottom 13bits into some register variable */
 
@@ -55,11 +64,6 @@
 		__asm__ ("or %%g0, ___s_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_SIMM13(__name) ___illegal_use_of_BTFIXUP_SIMM13_in_module()
-#else
-#define BTFIXUP_SIMM13(__name) ___sf_##__name()
-#endif
 
 /* Put either bottom 13 bits, or upper 22 bits into some register variable
  * (depending on the value, this will lead into sethi FIX, reg; or
@@ -82,11 +86,6 @@
 		__asm__ ("or %%g0, ___a_" #__name "__btset_" #__val ", %0" : "=r"(ret));\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_HALF(__name) ___illegal_use_of_BTFIXUP_HALF_in_module()
-#else
-#define BTFIXUP_HALF(__name) ___af_##__name()
-#endif
 
 /* Put upper 22 bits into some register variable */
 
@@ -107,22 +106,12 @@
 			 "=r"(ret));							\
 		return ret;								\
 	}
-#ifdef MODULE
-#define BTFIXUP_SETHI(__name) ___illegal_use_of_BTFIXUP_SETHI_in_module()
-#else
-#define BTFIXUP_SETHI(__name) ___hf_##__name()
-#endif
 
 /* Put a full 32bit integer into some register variable */
 
 #define BTFIXUPDEF_INT(__name)								\
 	extern unsigned char ___i_##__name;						\
 	extern unsigned ___is_##__name[2];
-#ifdef MODULE
-#define BTFIXUP_INT(__name) ___illegal_use_of_BTFIXUP_INT_in_module()
-#else
-#define BTFIXUP_INT(__name) ((unsigned int)&___i_##__name)
-#endif
 
 #define BTFIXUPCALL_NORM	0x00000000			/* Always call */
 #define BTFIXUPCALL_NOP		0x01000000			/* Possibly optimize to nop */
diff -Nru a/include/asm-sparc/kmap_types.h b/include/asm-sparc/kmap_types.h
--- a/include/asm-sparc/kmap_types.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-sparc/kmap_types.h	Sat Jun  8 22:31:36 2002
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -Nru a/include/asm-sparc/page.h b/include/asm-sparc/page.h
--- a/include/asm-sparc/page.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-sparc/page.h	Sat Jun  8 22:31:36 2002
@@ -54,8 +54,8 @@
 
 #define clear_page(page)	 memset((void *)(page), 0, PAGE_SIZE)
 #define copy_page(to,from) 	memcpy((void *)(to), (void *)(from), PAGE_SIZE)
-#define clear_user_page(page, vaddr)	clear_page(page)
-#define copy_user_page(to, from, vaddr)	copy_page(to, from)
+#define clear_user_page(addr, vaddr, page)	clear_page(addr)
+#define copy_user_page(to, from, vaddr, page)	copy_page(to, from)
 
 /* The following structure is used to hold the physical
  * memory configuration of the machine.  This is filled in
diff -Nru a/include/asm-sparc/ultra.h b/include/asm-sparc/ultra.h
--- a/include/asm-sparc/ultra.h	Sat Jun  8 22:31:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/* $Id: ultra.h,v 1.2 1995/11/25 02:33:10 davem Exp $
- * ultra.h: Definitions and defines for the TI V9 UltraSparc.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-
-#ifndef _SPARC_ULTRA_H
-#define _SPARC_ULTRA_H
-
-/* Spitfire MMU control register:
- *
- * ----------------------------------------------------------
- * |        | IMPL  | VERS  |     |  MID  |                 |
- * ----------------------------------------------------------
- *  64        31-28   27-24  23-22  21-17   16             0
- *
- * IMPL: Implementation of this Spitfire.
- * VERS: Version of this Spitfire.
- * MID: Module ID of this processor.
- */
-
-#define SPITFIRE_MIDMASK     0x00000000003e0000
-
-/* Spitfire Load Store Unit control register:
- *
- * ---------------------------------------------------------------------
- * | RSV | PWR | PWW | VWR | VWW | RSV | PMASK | DME | IME | DCE | ICE |
- * ---------------------------------------------------------------------
- *  63-25  24    23     22    21    20   19-4      3     2     1     0
- *
- * PWR: Physical Watchpoint Read enable: 0=off 1=on
- * PWW: Physical Watchpoint Write enable: 0=off 1=on
- * VWR: Virtual Watchpoint Read enable: 0=off 1=on
- * VWW: Virtual Watchpoint Write enable: 0=off 1=on
- * PMASK: Parity MASK  ???
- * DME: Data MMU Enable: 0=off 1=on
- * IME: Instruction MMU Enable: 0=off 1=on
- * DCE: Data Cache Enable: 0=off 1=on
- * ICE: Instruction Cache Enable: 0=off 1=on
- */
-
-#define SPITFIRE_LSU_PWR      0x01000000
-#define SPITFIRE_LSU_PWW      0x00800000
-#define SPITFIRE_LSU_VWR      0x00400000
-#define SPITFIRE_LSU_VWW      0x00200000
-#define SPITFIRE_LSU_PMASK    0x000ffff0
-#define SPITFIRE_LSU_DME      0x00000008
-#define SPITFIRE_LSU_IME      0x00000004
-#define SPITFIRE_LSU_DCE      0x00000002
-#define SPITFIRE_LSU_ICE      0x00000001
-
-#endif /* !(_SPARC_ULTRA_H) */
diff -Nru a/include/asm-sparc/vac-ops.h b/include/asm-sparc/vac-ops.h
--- a/include/asm-sparc/vac-ops.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-sparc/vac-ops.h	Sat Jun  8 22:31:36 2002
@@ -107,8 +107,6 @@
 
 extern struct sun4c_vac_props sun4c_vacinfo;
 
-extern void sun4c_flush_all(void);
-
 /* sun4c_enable_vac() enables the sun4c virtual address cache. */
 extern __inline__ void sun4c_enable_vac(void)
 {
diff -Nru a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h
--- a/include/asm-sparc64/page.h	Sat Jun  8 22:31:37 2002
+++ b/include/asm-sparc64/page.h	Sat Jun  8 22:31:37 2002
@@ -35,8 +35,9 @@
 
 extern void _clear_page(void *page);
 #define clear_page(X)	_clear_page((void *)(X))
-extern void clear_user_page(void *page, unsigned long vaddr);
-extern void copy_user_page(void *to, void *from, unsigned long vaddr);
+struct page;
+extern void clear_user_page(void *addr, unsigned long vaddr, struct page *page);
+extern void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topage);
 
 /* GROSS, defining this makes gcc pass these types as aggregates,
  * and thus on the stack, turn this crap off... -DaveM
diff -Nru a/include/asm-x86_64/kmap_types.h b/include/asm-x86_64/kmap_types.h
--- a/include/asm-x86_64/kmap_types.h	Sat Jun  8 22:31:36 2002
+++ b/include/asm-x86_64/kmap_types.h	Sat Jun  8 22:31:36 2002
@@ -3,7 +3,7 @@
 
 enum km_type {
 	KM_BOUNCE_READ,
-	KM_SKB_DATA,
+	KM_SKB_SUNRPC_DATA,
 	KM_SKB_DATA_SOFTIRQ,
 	KM_USER0,
 	KM_USER1,
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Sat Jun  8 22:31:51 2002
+++ b/include/linux/bio.h	Sat Jun  8 22:31:51 2002
@@ -20,6 +20,7 @@
 #ifndef __LINUX_BIO_H
 #define __LINUX_BIO_H
 
+#include <linux/kdev_t.h>
 /* Platforms may set this to teach the BIO layer about IOMMU hardware. */
 #include <asm/io.h>
 #ifndef BIO_VMERGE_BOUNDARY
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/blkdev.h	Sat Jun  8 22:31:36 2002
@@ -81,13 +81,11 @@
 	/*
 	 * for ATA/ATAPI devices
 	 */
-	__REQ_DRIVE_ACB,
-
 	__REQ_PC,	/* packet command (special) */
 	__REQ_BLOCK_PC,	/* queued down pc from block layer */
 	__REQ_SENSE,	/* sense retrival */
 
-	__REQ_SPECIAL,	/* driver special command (currently reset) */
+	__REQ_SPECIAL,	/* driver suplied command */
 
 	__REQ_NR_BITS,	/* stops here */
 };
@@ -100,7 +98,6 @@
 #define REQ_STARTED	(1 << __REQ_STARTED)
 #define REQ_DONTPREP	(1 << __REQ_DONTPREP)
 #define REQ_QUEUED	(1 << __REQ_QUEUED)
-#define REQ_DRIVE_ACB	(1 << __REQ_DRIVE_ACB)
 #define REQ_PC		(1 << __REQ_PC)
 #define REQ_BLOCK_PC	(1 << __REQ_BLOCK_PC)
 #define REQ_SENSE	(1 << __REQ_SENSE)
diff -Nru a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
--- a/include/linux/byteorder/generic.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/byteorder/generic.h	Sat Jun  8 22:31:35 2002
@@ -123,6 +123,7 @@
 #endif
 
 
+#if defined(__KERNEL__)
 /*
  * Handle ntohl and suches. These have various compatibility
  * issues - like we want to give the prototype even though we
@@ -146,17 +147,11 @@
  * Do the prototypes. Somebody might want to take the
  * address or some such sick thing..
  */
-#if defined(__KERNEL__) || (defined (__GLIBC__) && __GLIBC__ >= 2)
 extern __u32			ntohl(__u32);
 extern __u32			htonl(__u32);
-#else
-extern unsigned long int	ntohl(unsigned long int);
-extern unsigned long int	htonl(unsigned long int);
-#endif
 extern unsigned short int	ntohs(unsigned short int);
 extern unsigned short int	htons(unsigned short int);
 
-
 #if defined(__GNUC__) && (__GNUC__ >= 2) && defined(__OPTIMIZE__)
 
 #define ___htonl(x) __cpu_to_be32(x)
@@ -164,17 +159,14 @@
 #define ___ntohl(x) __be32_to_cpu(x)
 #define ___ntohs(x) __be16_to_cpu(x)
 
-#if defined(__KERNEL__) || (defined (__GLIBC__) && __GLIBC__ >= 2)
 #define htonl(x) ___htonl(x)
 #define ntohl(x) ___ntohl(x)
-#else
-#define htonl(x) ((unsigned long)___htonl(x))
-#define ntohl(x) ((unsigned long)___ntohl(x))
-#endif
 #define htons(x) ___htons(x)
 #define ntohs(x) ___ntohs(x)
 
 #endif /* OPTIMIZE */
+
+#endif /* KERNEL */
 
 
 #endif /* _LINUX_BYTEORDER_GENERIC_H */
diff -Nru a/include/linux/capability.h b/include/linux/capability.h
--- a/include/linux/capability.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/capability.h	Sat Jun  8 22:31:36 2002
@@ -41,6 +41,10 @@
   
 #ifdef __KERNEL__
 
+#include <linux/spinlock.h>
+
+extern spinlock_t task_capability_lock;
+
 /* #define STRICT_CAP_T_TYPECHECKS */
 
 #ifdef STRICT_CAP_T_TYPECHECKS
diff -Nru a/include/linux/compatmac.h b/include/linux/compatmac.h
--- a/include/linux/compatmac.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/compatmac.h	Sat Jun  8 22:31:36 2002
@@ -102,8 +102,6 @@
 
 #define my_iounmap(x, b)             (((long)x<0x100000)?0:vfree ((void*)x))
 
-#define capable(x)                   suser()
-
 #define tty_flip_buffer_push(tty)    queue_task(&tty->flip.tqueue, &tq_timer)
 #define signal_pending(current)      (current->signal & ~current->blocked)
 #define schedule_timeout(to)         do {current->timeout = jiffies + (to);schedule ();} while (0)
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Sat Jun  8 22:31:37 2002
+++ b/include/linux/device.h	Sat Jun  8 22:31:37 2002
@@ -64,7 +64,7 @@
 	struct driver_dir_entry	device_dir;
 	struct driver_dir_entry	driver_dir;
 
-	int	(*bind)		(struct device * dev, struct device_driver * drv);
+	int	(*match)	(struct device * dev, struct device_driver * drv);
 };
 
 
@@ -118,6 +118,7 @@
 }
 
 extern void put_driver(struct device_driver * drv);
+extern void remove_driver(struct device_driver * drv);
 
 extern int driver_for_each_dev(struct device_driver * drv, void * data, 
 			       int (*callback)(struct device * dev, void * data));
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/fs.h	Sat Jun  8 22:31:36 2002
@@ -576,11 +576,11 @@
 
 #include <linux/fcntl.h>
 
-extern int fcntl_getlk(unsigned int, struct flock *);
-extern int fcntl_setlk(unsigned int, unsigned int, struct flock *);
+extern int fcntl_getlk(struct file *, struct flock *);
+extern int fcntl_setlk(struct file *, unsigned int, struct flock *);
 
-extern int fcntl_getlk64(unsigned int, struct flock64 *);
-extern int fcntl_setlk64(unsigned int, unsigned int, struct flock64 *);
+extern int fcntl_getlk64(struct file *, struct flock64 *);
+extern int fcntl_setlk64(struct file *, unsigned int, struct flock64 *);
 
 /* fs/locks.c */
 extern void locks_init_lock(struct file_lock *);
@@ -800,6 +800,7 @@
    	void (*dirty_inode) (struct inode *);
 	void (*write_inode) (struct inode *, int);
 	void (*put_inode) (struct inode *);
+	void (*drop_inode) (struct inode *);
 	void (*delete_inode) (struct inode *);
 	void (*put_super) (struct super_block *);
 	void (*write_super) (struct super_block *);
@@ -1183,10 +1184,10 @@
 
 extern void inode_init_once(struct inode *);
 extern void iput(struct inode *);
-extern void force_delete(struct inode *);
 extern struct inode * igrab(struct inode *);
 extern ino_t iunique(struct super_block *, ino_t);
 extern int inode_needs_sync(struct inode *inode);
+extern void generic_delete_inode(struct inode *inode);
 
 extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *);
 extern struct inode * iget_locked(struct super_block *, unsigned long);
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/ide.h	Sat Jun  8 22:31:36 2002
@@ -610,11 +610,7 @@
 extern void ide_set_handler(struct ata_device *drive, ata_handler_t handler,
 		unsigned long timeout, ata_expiry_t expiry);
 
-/*
- * Error reporting, in human readable form (luxurious, but a memory hog).
- */
-extern u8 ide_dump_status(struct ata_device *, struct request *rq, const char *, u8);
-
+extern u8 ata_dump(struct ata_device *, struct request *, const char *);
 extern ide_startstop_t ata_error(struct ata_device *, struct request *rq, const char *);
 
 extern void ide_fixstring(char *s, const int bytecount, const int byteswap);
@@ -658,17 +654,11 @@
 
 extern int ide_do_drive_cmd(struct ata_device *, struct request *, ide_action_t);
 
-/*
- * Clean up after success/failure of an explicit drive cmd.
- */
-extern void ide_end_drive_cmd(struct ata_device *, struct request *);
-
 struct ata_taskfile {
 	struct hd_drive_task_hdr taskfile;
 	struct hd_drive_task_hdr  hobfile;
 	u8 cmd;					/* actual ATA command */
 	int command_type;
-	ide_startstop_t (*prehandler)(struct ata_device *, struct request *);
 	ide_startstop_t (*handler)(struct ata_device *, struct request *);
 };
 
@@ -682,17 +672,31 @@
  * Special Flagged Register Validation Caller
  */
 
-extern ide_startstop_t recal_intr(struct ata_device *, struct request *);
-extern ide_startstop_t task_no_data_intr(struct ata_device *, struct request *);
+/*
+ * for now, taskfile requests are special :/
+ */
+static inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+	if (rq->bio)
+		return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
+	else
+		return rq->buffer + ((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE;
+}
+
+static inline void ide_unmap_rq(struct request *rq, char *to,
+				unsigned long *flags)
+{
+	if (rq->bio)
+		bio_kunmap_irq(to, flags);
+}
 
-extern void ide_cmd_type_parser(struct ata_taskfile *args);
+extern ide_startstop_t ata_special_intr(struct ata_device *, struct request *);
 extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *);
 
 extern void ide_fix_driveid(struct hd_driveid *id);
 extern int ide_config_drive_speed(struct ata_device *, byte);
 extern byte eighty_ninty_three(struct ata_device *);
 
-
 extern void ide_stall_queue(struct ata_device *, unsigned long);
 
 extern int system_bus_speed;
@@ -799,7 +803,7 @@
 extern void udma_pci_irq_lost(struct ata_device *);
 extern int udma_pci_setup(struct ata_device *);
 
-extern int udma_new_table(struct ata_channel *, struct request *);
+extern int udma_new_table(struct ata_device *, struct request *);
 extern void udma_destroy_table(struct ata_channel *);
 extern void udma_print(struct ata_device *);
 
@@ -834,5 +838,6 @@
 extern int ata_irq_enable(struct ata_device *, int);
 extern void ata_reset(struct ata_channel *);
 extern void ata_out_regfile(struct ata_device *, struct hd_drive_task_hdr *);
+extern void ata_in_regfile(struct ata_device *, struct hd_drive_task_hdr *);
 
 #endif
diff -Nru a/include/linux/if_bonding.h b/include/linux/if_bonding.h
--- a/include/linux/if_bonding.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/if_bonding.h	Sat Jun  8 22:31:36 2002
@@ -51,7 +51,7 @@
 #define BOND_STATE_ACTIVE       0   /* link is active */
 #define BOND_STATE_BACKUP       1   /* link is backup */
 
-#define MAX_BONDS               1   /* Maximum number of devices to support */
+#define BOND_DEFAULT_MAX_BONDS  1   /* Default maximum number of devices to support */
 
 typedef struct ifbond {
 	__s32 bond_mode;
@@ -76,6 +76,7 @@
 	short  delay;
 	char   link;    /* one of BOND_LINK_XXXX */
 	char   state;   /* one of BOND_STATE_XXXX */
+	unsigned short original_flags;
 	u32 link_failure_count;
 } slave_t;
 
@@ -104,6 +105,8 @@
 #endif /* CONFIG_PROC_FS */
 	struct bonding *next_bond;
 	struct net_device *device;
+	struct dev_mc_list *mc_list;
+	unsigned short flags;
 } bonding_t;
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/init.h b/include/linux/init.h
--- a/include/linux/init.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/init.h	Sat Jun  8 22:31:35 2002
@@ -61,7 +61,7 @@
 	static initcall_t __initcall_##fn __attribute__ ((unused,__section__ (".initcall" level ".init"))) = fn
 
 #define core_initcall(fn)		__define_initcall("1",fn)
-#define unused_initcall(fn)		__define_initcall("2",fn)
+#define postcore_initcall(fn)		__define_initcall("2",fn)
 #define arch_initcall(fn)		__define_initcall("3",fn)
 #define subsys_initcall(fn)		__define_initcall("4",fn)
 #define fs_initcall(fn)			__define_initcall("5",fn)
@@ -160,7 +160,7 @@
 #define __setup(str,func) /* nothing */
 
 #define core_initcall(fn)		module_init(fn)
-#define unused_initcall(fn)		module_init(fn)
+#define postcore_initcall(fn)		module_init(fn)
 #define arch_initcall(fn)		module_init(fn)
 #define subsys_initcall(fn)		module_init(fn)
 #define fs_initcall(fn)			module_init(fn)
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/mmzone.h	Sat Jun  8 22:31:35 2002
@@ -142,8 +142,14 @@
 extern int numnodes;
 extern pg_data_t *pgdat_list;
 
-#define memclass(pgzone, classzone)	(((pgzone)->zone_pgdat == (classzone)->zone_pgdat) \
-			&& ((pgzone) <= (classzone)))
+static inline int memclass(zone_t *pgzone, zone_t *classzone)
+{
+	if (pgzone->zone_pgdat != classzone->zone_pgdat)
+		return 0;
+	if (pgzone > classzone)
+		return 0;
+	return 1;
+}
 
 /*
  * The following two are not meant for general usage. They are here as
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Sat Jun  8 22:31:37 2002
+++ b/include/linux/pci_ids.h	Sat Jun  8 22:31:37 2002
@@ -1054,6 +1054,7 @@
 #define PCI_DEVICE_ID_EICON_DIVA20PRO_U	0xe003
 #define PCI_DEVICE_ID_EICON_DIVA20_U	0xe004
 #define PCI_DEVICE_ID_EICON_DIVA201	0xe005
+#define PCI_DEVICE_ID_EICON_DIVA202	0xe00b
 #define PCI_DEVICE_ID_EICON_MAESTRA	0xe010
 #define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
 #define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/sched.h	Sat Jun  8 22:31:36 2002
@@ -392,8 +392,7 @@
 
 #define PF_FREEZE	0x00010000	/* this task should be frozen for suspend */
 #define PF_IOTHREAD	0x00020000	/* this thread is needed for doing I/O to swap */
-#define PF_KERNTHREAD	0x00040000	/* this thread is a kernel thread that cannot be sent signals to */
-#define PF_FROZEN	0x00080000	/* frozen for system suspend */
+#define PF_FROZEN	0x00040000	/* frozen for system suspend */
 
 /*
  * Ptrace flags
@@ -585,51 +584,12 @@
 extern void free_irq(unsigned int, void *);
 
 /*
- * This has now become a routine instead of a macro, it sets a flag if
- * it returns true (to do BSD-style accounting where the process is flagged
- * if it uses root privs). The implication of this is that you should do
- * normal permissions checks first, and check suser() last.
- *
- * [Dec 1997 -- Chris Evans]
- * For correctness, the above considerations need to be extended to
- * fsuser(). This is done, along with moving fsuser() checks to be
- * last.
- *
- * These will be removed, but in the mean time, when the SECURE_NOROOT 
- * flag is set, uids don't grant privilege.
+ * capable() checks for a particular capability.
+ * See include/linux/capability.h for defined capabilities.
  */
-static inline int suser(void)
-{
-	if (!issecure(SECURE_NOROOT) && current->euid == 0) { 
-		current->flags |= PF_SUPERPRIV;
-		return 1;
-	}
-	return 0;
-}
-
-static inline int fsuser(void)
-{
-	if (!issecure(SECURE_NOROOT) && current->fsuid == 0) {
-		current->flags |= PF_SUPERPRIV;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * capable() checks for a particular capability.  
- * New privilege checks should use this interface, rather than suser() or
- * fsuser(). See include/linux/capability.h for defined capabilities.
- */
-
 static inline int capable(int cap)
 {
-#if 1 /* ok now */
-	if (cap_raised(current->cap_effective, cap))
-#else
-	if (cap_is_fs_cap(cap) ? current->fsuid == 0 : current->euid == 0)
-#endif
-	{
+	if (cap_raised(current->cap_effective, cap)) {
 		current->flags |= PF_SUPERPRIV;
 		return 1;
 	}
diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h
--- a/include/linux/spinlock.h	Sat Jun  8 22:31:43 2002
+++ b/include/linux/spinlock.h	Sat Jun  8 22:31:43 2002
@@ -7,6 +7,8 @@
 #include <linux/thread_info.h>
 #include <linux/kernel.h>
 
+#include <asm/system.h>
+
 /*
  * These are the generic versions of the spinlocks and read-write
  * locks..
diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
--- a/include/linux/sunrpc/xdr.h	Sat Jun  8 22:31:52 2002
+++ b/include/linux/sunrpc/xdr.h	Sat Jun  8 22:31:52 2002
@@ -137,10 +137,9 @@
 /*
  * XDR buffer helper functions
  */
-extern int xdr_kmap(struct iovec *, struct xdr_buf *, unsigned int);
-extern void xdr_kunmap(struct xdr_buf *, unsigned int);
-extern void xdr_shift_buf(struct xdr_buf *, unsigned int);
-extern void xdr_zero_buf(struct xdr_buf *, unsigned int);
+extern int xdr_kmap(struct iovec *, struct xdr_buf *, size_t);
+extern void xdr_kunmap(struct xdr_buf *, size_t);
+extern void xdr_shift_buf(struct xdr_buf *, size_t);
 
 /*
  * Helper structure for copying from an sk_buff.
diff -Nru a/include/linux/suspend.h b/include/linux/suspend.h
--- a/include/linux/suspend.h	Sat Jun  8 22:31:36 2002
+++ b/include/linux/suspend.h	Sat Jun  8 22:31:36 2002
@@ -33,7 +33,7 @@
 	char version[20];
 	int num_cpus;
 	int page_size;
-	unsigned long suspend_pagedir;
+	suspend_pagedir_t *suspend_pagedir;
 	unsigned int num_pbes;
 	struct swap_location {
 		char filename[SWAP_FILENAME_MAXLENGTH];
@@ -50,11 +50,14 @@
 /* kernel/suspend.c */
 extern void software_suspend(void);
 extern void software_resume(void);
-extern int resume_setup(char *str);
 
 extern int register_suspend_notifier(struct notifier_block *);
 extern int unregister_suspend_notifier(struct notifier_block *);
 extern void refrigerator(unsigned long);
+
+extern unsigned int nr_copy_pages __nosavedata;
+extern suspend_pagedir_t *pagedir_nosave __nosavedata;
+
 
 #else
 #define software_suspend()		do { } while(0)
diff -Nru a/include/linux/swapops.h b/include/linux/swapops.h
--- a/include/linux/swapops.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/swapops.h	Sat Jun  8 22:31:35 2002
@@ -10,7 +10,7 @@
  * swp_entry_t's are *never* stored anywhere in their arch-dependent format.
  */
 #define SWP_TYPE_SHIFT(e)	(sizeof(e.val) * 8 - MAX_SWAPFILES_SHIFT)
-#define SWP_OFFSET_MASK(e)	((1 << SWP_TYPE_SHIFT(e)) - 1)
+#define SWP_OFFSET_MASK(e)	((1UL << SWP_TYPE_SHIFT(e)) - 1)
 
 /*
  * Store a type+offset into a swp_entry_t in an arch-independent format
@@ -19,7 +19,7 @@
 {
 	swp_entry_t ret;
 
-	ret.val = (type << SWP_TYPE_SHIFT(ret)) |
+	ret.val = ((unsigned long)type << SWP_TYPE_SHIFT(ret)) |
 			(offset & SWP_OFFSET_MASK(ret));
 	return ret;
 }
diff -Nru a/include/linux/vmalloc.h b/include/linux/vmalloc.h
--- a/include/linux/vmalloc.h	Sat Jun  8 22:31:52 2002
+++ b/include/linux/vmalloc.h	Sat Jun  8 22:31:52 2002
@@ -1,7 +1,6 @@
 #ifndef __LINUX_VMALLOC_H
 #define __LINUX_VMALLOC_H
 
-#include <linux/mm.h>
 #include <linux/spinlock.h>
 
 #include <asm/pgtable.h>
@@ -24,33 +23,13 @@
 extern void vmfree_area_pages(unsigned long address, unsigned long size);
 extern int vmalloc_area_pages(unsigned long address, unsigned long size,
                               int gfp_mask, pgprot_t prot);
-
-/*
- *	Allocate any pages
- */
- 
-static inline void * vmalloc (unsigned long size)
-{
-	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
-}
-
 /*
- *	Allocate ISA addressable pages for broke crap
+ * Various ways to allocate pages.
  */
 
-static inline void * vmalloc_dma (unsigned long size)
-{
-	return __vmalloc(size, GFP_KERNEL|GFP_DMA, PAGE_KERNEL);
-}
-
-/*
- *	vmalloc 32bit PA addressable pages - eg for PCI 32bit devices
- */
- 
-static inline void * vmalloc_32(unsigned long size)
-{
-	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
-}
+extern void * vmalloc(unsigned long size);
+extern void * vmalloc_dma(unsigned long size);
+extern void * vmalloc_32(unsigned long size);
 
 /*
  * vmlist_lock is a read-write spinlock that protects vmlist
diff -Nru a/include/linux/wait.h b/include/linux/wait.h
--- a/include/linux/wait.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/wait.h	Sat Jun  8 22:31:35 2002
@@ -27,42 +27,8 @@
 };
 typedef struct __wait_queue wait_queue_t;
 
-/*
- * 'dual' spinlock architecture. Can be switched between spinlock_t and
- * rwlock_t locks via changing this define. Since waitqueues are quite
- * decoupled in the new architecture, lightweight 'simple' spinlocks give
- * us slightly better latencies and smaller waitqueue structure size.
- */
-#define USE_RW_WAIT_QUEUE_SPINLOCK 0
-
-#if USE_RW_WAIT_QUEUE_SPINLOCK
-# define wq_lock_t rwlock_t
-# define WAITQUEUE_RW_LOCK_UNLOCKED RW_LOCK_UNLOCKED
-
-# define wq_read_lock read_lock
-# define wq_read_lock_irqsave read_lock_irqsave
-# define wq_read_unlock_irqrestore read_unlock_irqrestore
-# define wq_read_unlock read_unlock
-# define wq_write_lock_irq write_lock_irq
-# define wq_write_lock_irqsave write_lock_irqsave
-# define wq_write_unlock_irqrestore write_unlock_irqrestore
-# define wq_write_unlock write_unlock
-#else
-# define wq_lock_t spinlock_t
-# define WAITQUEUE_RW_LOCK_UNLOCKED SPIN_LOCK_UNLOCKED
-
-# define wq_read_lock spin_lock
-# define wq_read_lock_irqsave spin_lock_irqsave
-# define wq_read_unlock spin_unlock
-# define wq_read_unlock_irqrestore spin_unlock_irqrestore
-# define wq_write_lock_irq spin_lock_irq
-# define wq_write_lock_irqsave spin_lock_irqsave
-# define wq_write_unlock_irqrestore spin_unlock_irqrestore
-# define wq_write_unlock spin_unlock
-#endif
-
 struct __wait_queue_head {
-	wq_lock_t lock;
+	spinlock_t lock;
 	struct list_head task_list;
 };
 typedef struct __wait_queue_head wait_queue_head_t;
@@ -80,7 +46,7 @@
 	wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk)
 
 #define __WAIT_QUEUE_HEAD_INITIALIZER(name) {				\
-	lock:		WAITQUEUE_RW_LOCK_UNLOCKED,			\
+	lock:		SPIN_LOCK_UNLOCKED,			\
 	task_list:	{ &(name).task_list, &(name).task_list } }
 
 #define DECLARE_WAIT_QUEUE_HEAD(name) \
@@ -88,7 +54,7 @@
 
 static inline void init_waitqueue_head(wait_queue_head_t *q)
 {
-	q->lock = WAITQUEUE_RW_LOCK_UNLOCKED;
+	q->lock = SPIN_LOCK_UNLOCKED;
 	INIT_LIST_HEAD(&q->task_list);
 }
 
diff -Nru a/include/linux/zlib.h b/include/linux/zlib.h
--- a/include/linux/zlib.h	Sat Jun  8 22:31:35 2002
+++ b/include/linux/zlib.h	Sat Jun  8 22:31:35 2002
@@ -31,7 +31,7 @@
 #ifndef _ZLIB_H
 #define _ZLIB_H
 
-#include "zconf.h"
+#include <linux/zconf.h>
 
 #ifdef __cplusplus
 extern "C" {
diff -Nru a/include/net/pkt_sched.h b/include/net/pkt_sched.h
--- a/include/net/pkt_sched.h	Sat Jun  8 22:31:36 2002
+++ b/include/net/pkt_sched.h	Sat Jun  8 22:31:36 2002
@@ -8,6 +8,7 @@
 #define PSCHED_CLOCK_SOURCE	PSCHED_JIFFIES
 
 #include <linux/config.h>
+#include <linux/types.h>
 #include <linux/pkt_sched.h>
 #include <net/pkt_cls.h>
 
@@ -221,7 +222,7 @@
 
 #define PSCHED_EXPORTLIST_2
 
-#if ~0UL == 0xFFFFFFFF
+#if BITS_PER_LONG <= 32
 
 #define PSCHED_WATCHER unsigned long
 
diff -Nru a/include/video/neomagic.h b/include/video/neomagic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/video/neomagic.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,264 @@
+/*
+ * linux/include/video/neo_reg.h -- NeoMagic Framebuffer Driver
+ *
+ * Copyright (c) 2001  Denis Oliver Kropp <dok@convergence.de>
+ *
+ * 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.
+ */
+
+#define NEO_BS0_BLT_BUSY        0x00000001
+#define NEO_BS0_FIFO_AVAIL      0x00000002
+#define NEO_BS0_FIFO_PEND       0x00000004
+
+#define NEO_BC0_DST_Y_DEC       0x00000001
+#define NEO_BC0_X_DEC           0x00000002
+#define NEO_BC0_SRC_TRANS       0x00000004
+#define NEO_BC0_SRC_IS_FG       0x00000008
+#define NEO_BC0_SRC_Y_DEC       0x00000010
+#define NEO_BC0_FILL_PAT        0x00000020
+#define NEO_BC0_SRC_MONO        0x00000040
+#define NEO_BC0_SYS_TO_VID      0x00000080
+
+#define NEO_BC1_DEPTH8          0x00000100
+#define NEO_BC1_DEPTH16         0x00000200
+#define NEO_BC1_X_320           0x00000400
+#define NEO_BC1_X_640           0x00000800
+#define NEO_BC1_X_800           0x00000c00
+#define NEO_BC1_X_1024          0x00001000
+#define NEO_BC1_X_1152          0x00001400
+#define NEO_BC1_X_1280          0x00001800
+#define NEO_BC1_X_1600          0x00001c00
+#define NEO_BC1_DST_TRANS       0x00002000
+#define NEO_BC1_MSTR_BLT        0x00004000
+#define NEO_BC1_FILTER_Z        0x00008000
+
+#define NEO_BC2_WR_TR_DST       0x00800000
+
+#define NEO_BC3_SRC_XY_ADDR     0x01000000
+#define NEO_BC3_DST_XY_ADDR     0x02000000
+#define NEO_BC3_CLIP_ON         0x04000000
+#define NEO_BC3_FIFO_EN         0x08000000
+#define NEO_BC3_BLT_ON_ADDR     0x10000000
+#define NEO_BC3_SKIP_MAPPING    0x80000000
+
+#define NEO_MODE1_DEPTH8        0x0100
+#define NEO_MODE1_DEPTH16       0x0200
+#define NEO_MODE1_DEPTH24       0x0300
+#define NEO_MODE1_X_320         0x0400
+#define NEO_MODE1_X_640         0x0800
+#define NEO_MODE1_X_800         0x0c00
+#define NEO_MODE1_X_1024        0x1000
+#define NEO_MODE1_X_1152        0x1400
+#define NEO_MODE1_X_1280        0x1800
+#define NEO_MODE1_X_1600        0x1c00
+#define NEO_MODE1_BLT_ON_ADDR   0x2000
+
+#ifdef __KERNEL__
+
+#ifdef NEOFB_DEBUG
+# define DBG(x)		printk (KERN_DEBUG "neofb: %s\n", (x));
+#else
+# define DBG(x)
+#endif
+
+#define PCI_CHIP_NM2070 0x0001
+#define PCI_CHIP_NM2090 0x0002
+#define PCI_CHIP_NM2093 0x0003
+#define PCI_CHIP_NM2097 0x0083
+#define PCI_CHIP_NM2160 0x0004
+#define PCI_CHIP_NM2200 0x0005
+#define PCI_CHIP_NM2230 0x0025
+#define PCI_CHIP_NM2360 0x0006
+#define PCI_CHIP_NM2380 0x0016
+
+
+struct xtimings {
+  unsigned int pixclock;
+  unsigned int HDisplay;
+  unsigned int HSyncStart;
+  unsigned int HSyncEnd;
+  unsigned int HTotal;
+  unsigned int VDisplay;
+  unsigned int VSyncStart;
+  unsigned int VSyncEnd;
+  unsigned int VTotal;
+  unsigned int sync;
+  int	       dblscan;
+  int	       interlaced;
+};
+
+
+/* --------------------------------------------------------------------- */
+
+typedef volatile struct {
+  __u32 bltStat;
+  __u32 bltCntl;
+  __u32 xpColor;
+  __u32 fgColor;
+  __u32 bgColor;
+  __u32 pitch;
+  __u32 clipLT;
+  __u32 clipRB;
+  __u32 srcBitOffset;
+  __u32 srcStart;
+  __u32 reserved0;
+  __u32 dstStart;
+  __u32 xyExt;
+
+  __u32 reserved1[19];
+
+  __u32 pageCntl;
+  __u32 pageBase;
+  __u32 postBase;
+  __u32 postPtr;
+  __u32 dataPtr;
+} Neo2200;
+
+#define NR_PALETTE	256
+
+#define MMIO_SIZE 0x200000
+
+#define NEO_EXT_CR_MAX 0x85
+#define NEO_EXT_GR_MAX 0xC7
+
+struct neofb_par {
+  
+  unsigned char MiscOutReg;     /* Misc */
+  unsigned char CRTC[25];       /* Crtc Controller */
+  unsigned char Sequencer[5];   /* Video Sequencer */
+  unsigned char Graphics[9];    /* Video Graphics */
+  unsigned char Attribute[21];  /* Video Atribute */
+
+  unsigned char GeneralLockReg;
+  unsigned char ExtCRTDispAddr;
+  unsigned char ExtCRTOffset;
+  unsigned char SysIfaceCntl1;
+  unsigned char SysIfaceCntl2;
+  unsigned char ExtColorModeSelect;
+  unsigned char biosMode;
+
+  unsigned char PanelDispCntlReg1;
+  unsigned char PanelDispCntlReg2;
+  unsigned char PanelDispCntlReg3;
+  unsigned char PanelVertCenterReg1;
+  unsigned char PanelVertCenterReg2;
+  unsigned char PanelVertCenterReg3;
+  unsigned char PanelVertCenterReg4;
+  unsigned char PanelVertCenterReg5;
+  unsigned char PanelHorizCenterReg1;
+  unsigned char PanelHorizCenterReg2;
+  unsigned char PanelHorizCenterReg3;
+  unsigned char PanelHorizCenterReg4;
+  unsigned char PanelHorizCenterReg5;
+
+  int           ProgramVCLK;
+  unsigned char VCLK3NumeratorLow;
+  unsigned char VCLK3NumeratorHigh;
+  unsigned char VCLK3Denominator;
+  unsigned char VerticalExt;
+
+#ifdef CONFIG_MTRR
+  int    mtrr;
+#endif
+  u8    *mmio_vbase;
+
+  Neo2200 *neo2200;
+
+  /* Panels size */
+  int NeoPanelWidth;
+  int NeoPanelHeight;
+
+  int maxClock;
+
+  int pci_burst;
+  int lcd_stretch;
+  int internal_display;
+  int external_display;
+};
+
+typedef struct {
+    int x_res;
+    int y_res;
+    int mode;
+} biosMode;
+
+/* vga IO functions */
+static inline u8 VGArCR (u8 index)
+{
+  outb (index, 0x3d4);
+  return inb (0x3d5);
+}
+
+static inline void VGAwCR (u8 index, u8 val)
+{
+  outb (index, 0x3d4);
+  outb (val, 0x3d5);
+}
+
+static inline u8 VGArGR (u8 index)
+{
+  outb (index, 0x3ce);
+  return inb (0x3cf);
+}
+
+static inline void VGAwGR (u8 index, u8 val)
+{
+  outb (index, 0x3ce);
+  outb (val, 0x3cf);
+}
+
+static inline u8 VGArSEQ (u8 index)
+{
+  outb (index, 0x3c4);
+  return inb (0x3c5);
+}
+
+static inline void VGAwSEQ (u8 index, u8 val)
+{
+  outb (index, 0x3c4);
+  outb (val, 0x3c5);
+}
+
+
+static int paletteEnabled = 0;
+
+static inline void VGAenablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x00, 0x3c0);
+  paletteEnabled = 1;
+}
+
+static inline void VGAdisablePalette (void)
+{
+  u8 tmp;
+
+  tmp = inb (0x3da);
+  outb (0x20, 0x3c0);
+  paletteEnabled = 0;
+}
+
+static inline void VGAwATTR (u8 index, u8 value)
+{
+  u8 tmp;
+
+  if (paletteEnabled)
+    index &= ~0x20;
+  else
+    index |= 0x20;
+
+  tmp = inb (0x3da);
+  outb (index, 0x3c0);
+  outb (value, 0x3c0);
+}
+
+static inline void VGAwMISC (u8 value)
+{
+  outb (value, 0x3c2);
+}
+#endif
+
diff -Nru a/include/video/pm2fb.h b/include/video/pm2fb.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/video/pm2fb.h	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,222 @@
+/*
+ * Permedia2 framebuffer driver definitions.
+ * Copyright (c) 1998-2000 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
+ * --------------------------------------------------------------------------
+ * $Id: pm2fb.h,v 1.26 2000/09/19 00:11:53 illo Exp $
+ * --------------------------------------------------------------------------
+ * 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.
+ */
+
+#ifndef PM2FB_H
+#define PM2FB_H
+
+#define PM2_REFERENCE_CLOCK	14318			/* in KHz */
+#define PM2_MAX_PIXCLOCK	230000			/* in KHz */
+#define PM2_REGS_SIZE		0x10000
+
+#define PM2TAG(r) (u32 )(((r)-0x8000)>>3)
+
+/*****************************************************************************
+ * Permedia2 registers used in the framebuffer
+ *****************************************************************************/
+ 
+#define PM2R_RESET_STATUS				0x0000
+#define PM2R_IN_FIFO_SPACE				0x0018
+#define PM2R_OUT_FIFO_WORDS				0x0020
+#define PM2R_APERTURE_ONE				0x0050
+#define PM2R_APERTURE_TWO				0x0058
+#define PM2R_FIFO_DISCON				0x0068
+#define PM2R_CHIP_CONFIG				0x0070
+
+#define PM2R_REBOOT					0x1000
+#define PM2R_MEM_CONTROL				0x1040
+#define PM2R_BOOT_ADDRESS				0x1080
+#define PM2R_MEM_CONFIG					0x10c0
+#define PM2R_BYPASS_WRITE_MASK				0x1100
+#define PM2R_FRAMEBUFFER_WRITE_MASK			0x1140
+
+#define PM2R_OUT_FIFO					0x2000
+
+#define PM2R_SCREEN_BASE				0x3000
+#define PM2R_SCREEN_STRIDE				0x3008
+#define PM2R_H_TOTAL					0x3010
+#define PM2R_HG_END					0x3018
+#define PM2R_HB_END					0x3020
+#define PM2R_HS_START					0x3028
+#define PM2R_HS_END					0x3030
+#define PM2R_V_TOTAL					0x3038
+#define PM2R_VB_END					0x3040
+#define PM2R_VS_START					0x3048
+#define PM2R_VS_END					0x3050
+#define PM2R_VIDEO_CONTROL				0x3058
+#define PM2R_LINE_COUNT					0x3070
+#define PM2R_FIFO_CONTROL				0x3078
+
+#define PM2R_RD_PALETTE_WRITE_ADDRESS			0x4000
+#define PM2R_RD_PALETTE_DATA				0x4008
+#define PM2R_RD_PIXEL_MASK				0x4010
+#define PM2R_RD_PALETTE_READ_ADDRESS			0x4018
+#define PM2R_RD_INDEXED_DATA				0x4050
+
+#define PM2R_START_X_DOM				0x8000
+#define PM2R_D_X_DOM					0x8008
+#define PM2R_START_X_SUB				0x8010
+#define PM2R_D_X_SUB					0x8018
+#define PM2R_START_Y					0x8020
+#define PM2R_D_Y					0x8028
+#define PM2R_COUNT					0x8030
+#define PM2R_RENDER					0x8038
+#define PM2R_RASTERIZER_MODE				0x80a0
+#define PM2R_RECTANGLE_ORIGIN				0x80d0
+#define PM2R_RECTANGLE_SIZE				0x80d8
+#define PM2R_PACKED_DATA_LIMITS				0x8150
+#define PM2R_SCISSOR_MODE				0x8180
+#define PM2R_SCREEN_SIZE				0x8198
+#define PM2R_AREA_STIPPLE_MODE				0x81a0
+#define PM2R_WINDOW_ORIGIN				0x81c8
+#define PM2R_TEXTURE_ADDRESS_MODE			0x8380
+#define PM2R_TEXTURE_MAP_FORMAT				0x8588
+#define PM2R_TEXTURE_DATA_FORMAT			0x8590
+#define PM2R_TEXTURE_READ_MODE				0x8670
+#define PM2R_TEXEL_LUT_MODE				0x8678
+#define PM2R_TEXTURE_COLOR_MODE				0x8680
+#define PM2R_FOG_MODE					0x8690
+#define PM2R_COLOR_DDA_MODE				0x87e0
+#define PM2R_ALPHA_BLEND_MODE				0x8810
+#define PM2R_DITHER_MODE				0x8818
+#define PM2R_FB_SOFT_WRITE_MASK				0x8820
+#define PM2R_LOGICAL_OP_MODE				0x8828
+#define PM2R_LB_READ_MODE				0x8880
+#define PM2R_LB_READ_FORMAT				0x8888
+#define PM2R_LB_SOURCE_OFFSET				0x8890
+#define PM2R_LB_WINDOW_BASE				0x88b8
+#define PM2R_LB_WRITE_FORMAT				0x88c8
+#define PM2R_STENCIL_MODE				0x8988
+#define PM2R_DEPTH_MODE					0x89a0
+#define PM2R_FB_READ_MODE				0x8a80
+#define PM2R_FB_SOURCE_OFFSET				0x8a88
+#define PM2R_FB_PIXEL_OFFSET				0x8a90
+#define PM2R_FB_WINDOW_BASE				0x8ab0
+#define PM2R_FB_WRITE_MODE				0x8ab8
+#define PM2R_FB_HARD_WRITE_MASK				0x8ac0
+#define PM2R_FB_BLOCK_COLOR				0x8ac8
+#define PM2R_FB_READ_PIXEL				0x8ad0
+#define PM2R_FILTER_MODE				0x8c00
+#define PM2R_SYNC					0x8c40
+#define PM2R_YUV_MODE					0x8f00
+#define PM2R_STATISTICS_MODE				0x8c08
+#define PM2R_FB_SOURCE_DELTA				0x8d88
+#define PM2R_CONFIG					0x8d90
+#define PM2R_DELTA_MODE					0x9300
+
+/* Permedia2v */
+#define PM2VR_RD_INDEX_LOW				0x4020
+#define PM2VR_RD_INDEX_HIGH				0x4028
+#define PM2VR_RD_INDEXED_DATA				0x4030
+
+/* Permedia2 RAMDAC indexed registers */
+#define PM2I_RD_CURSOR_CONTROL				0x06
+#define PM2I_RD_COLOR_MODE				0x18
+#define PM2I_RD_MODE_CONTROL				0x19
+#define PM2I_RD_MISC_CONTROL				0x1e
+#define PM2I_RD_PIXEL_CLOCK_A1				0x20
+#define PM2I_RD_PIXEL_CLOCK_A2				0x21
+#define PM2I_RD_PIXEL_CLOCK_A3				0x22
+#define PM2I_RD_PIXEL_CLOCK_STATUS			0x29
+#define PM2I_RD_MEMORY_CLOCK_1				0x30
+#define PM2I_RD_MEMORY_CLOCK_2				0x31
+#define PM2I_RD_MEMORY_CLOCK_3				0x32
+#define PM2I_RD_MEMORY_CLOCK_STATUS			0x33
+#define PM2I_RD_COLOR_KEY_CONTROL			0x40
+#define PM2I_RD_OVERLAY_KEY				0x41
+#define PM2I_RD_RED_KEY					0x42
+#define PM2I_RD_GREEN_KEY				0x43
+#define PM2I_RD_BLUE_KEY				0x44
+
+/* Permedia2v extensions */
+#define PM2VI_RD_MISC_CONTROL				0x000
+#define PM2VI_RD_SYNC_CONTROL				0x001
+#define PM2VI_RD_DAC_CONTROL				0x002
+#define PM2VI_RD_PIXEL_SIZE				0x003
+#define PM2VI_RD_COLOR_FORMAT				0x004
+#define PM2VI_RD_CURSOR_MODE				0x005
+#define PM2VI_RD_CURSOR_X_LOW				0x007
+#define PM2VI_RD_CURSOR_X_HIGH				0x008
+#define PM2VI_RD_CURSOR_Y_LOW				0x009
+#define PM2VI_RD_CURSOR_Y_HIGH				0x00A
+#define PM2VI_RD_CURSOR_X_HOT				0x00B
+#define PM2VI_RD_CURSOR_Y_HOT				0x00C
+#define PM2VI_RD_CLK0_PRESCALE				0x201
+#define PM2VI_RD_CLK0_FEEDBACK				0x202
+#define PM2VI_RD_CLK0_POSTSCALE				0x203
+#define PM2VI_RD_CLK1_PRESCALE				0x204
+#define PM2VI_RD_CLK1_FEEDBACK				0x205
+#define PM2VI_RD_CLK1_POSTSCALE				0x206
+#define PM2VI_RD_CURSOR_PALETTE				0x303
+#define PM2VI_RD_CURSOR_PATTERN				0x400
+
+/* Fields and flags */
+#define PM2F_RENDER_AREASTIPPLE				(1L<<0)
+#define PM2F_RENDER_FASTFILL				(1L<<3)
+#define PM2F_RENDER_PRIMITIVE_MASK			(3L<<6)
+#define PM2F_RENDER_LINE				0
+#define PM2F_RENDER_TRAPEZOID				(1L<<6)
+#define PM2F_RENDER_POINT				(2L<<6)
+#define PM2F_RENDER_RECTANGLE				(3L<<6)
+#define PM2F_SYNCHRONIZATION				(1L<<10)
+#define PM2F_PLL_LOCKED					0x10
+#define PM2F_BEING_RESET				(1L<<31)
+#define PM2F_DATATYPE_COLOR				0x8000
+#define PM2F_VGA_ENABLE					0x02
+#define PM2F_VGA_FIXED					0x04
+#define PM2F_FB_WRITE_ENABLE				0x01
+#define PM2F_FB_READ_SOURCE_ENABLE			0x0200
+#define PM2F_RD_PALETTE_WIDTH_8				0x02
+#define PM2F_PART_PROD_MASK				0x01ff
+#define PM2F_SCREEN_SCISSOR_ENABLE			0x02
+#define PM2F_DATA_64_ENABLE				0x00010000
+#define PM2F_BLANK_LOW					0x02
+#define PM2F_HSYNC_MASK					0x18
+#define PM2F_VSYNC_MASK					0x60
+#define PM2F_HSYNC_ACT_HIGH				0x08
+#define PM2F_HSYNC_FORCED_LOW				0x10
+#define PM2F_HSYNC_ACT_LOW				0x18
+#define PM2F_VSYNC_ACT_HIGH				0x20
+#define PM2F_VSYNC_FORCED_LOW				0x40
+#define PM2F_VSYNC_ACT_LOW				0x60
+#define PM2F_LINE_DOUBLE				0x04
+#define PM2F_VIDEO_ENABLE				0x01
+#define PM2F_RD_GUI_ACTIVE				0x10
+#define PM2F_RD_COLOR_MODE_RGB				0x20
+#define PM2F_DELTA_ORDER_RGB				(1L<<18)
+#define PM2F_RD_TRUECOLOR				0x80
+#define PM2F_NO_ALPHA_BUFFER				0x10
+#define PM2F_TEXTEL_SIZE_16				0x00080000
+#define PM2F_TEXTEL_SIZE_32				0x00100000
+#define PM2F_TEXTEL_SIZE_4				0x00180000
+#define PM2F_TEXTEL_SIZE_24				0x00200000
+#define PM2F_INCREASE_X					(1L<<21)
+#define PM2F_INCREASE_Y					(1L<<22)
+#define PM2F_CONFIG_FB_WRITE_ENABLE			(1L<<3)
+#define PM2F_CONFIG_FB_PACKED_DATA			(1L<<2)
+#define PM2F_CONFIG_FB_READ_DEST_ENABLE			(1L<<1)
+#define PM2F_CONFIG_FB_READ_SOURCE_ENABLE		(1L<<0)
+#define PM2F_COLOR_KEY_TEST_OFF				(1L<<4)
+#define PM2F_MEM_CONFIG_RAM_MASK			(3L<<29)
+#define PM2F_MEM_BANKS_1				0L
+#define PM2F_MEM_BANKS_2				(1L<<29)
+#define PM2F_MEM_BANKS_3				(2L<<29)
+#define PM2F_MEM_BANKS_4				(3L<<29)
+
+typedef enum {
+	PM2_TYPE_PERMEDIA2,
+	PM2_TYPE_PERMEDIA2V
+} pm2type_t;
+
+#endif /* PM2FB_H */
+
+/*****************************************************************************
+ * That's all folks!
+ *****************************************************************************/
diff -Nru a/include/video/tx3912.h b/include/video/tx3912.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/video/tx3912.h	Sat Jun  8 22:31:35 2002
@@ -0,0 +1,62 @@
+/*
+ * linux/include/video/tx3912.h
+ *
+ * Copyright (C) 2001 Steven Hill (sjhill@realitydiluted.com)
+ *
+ * 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.
+ *
+ * Includes for TMPR3912/05 and PR31700 LCD controller registers
+ */
+#include <asm/tx3912.h>
+
+#define VidCtrl1        REG_AT(0x028)
+#define VidCtrl2        REG_AT(0x02C)
+#define VidCtrl3        REG_AT(0x030)
+#define VidCtrl4        REG_AT(0x034)
+#define VidCtrl5        REG_AT(0x038)
+#define VidCtrl6        REG_AT(0x03C)
+#define VidCtrl7        REG_AT(0x040)
+#define VidCtrl8        REG_AT(0x044)
+#define VidCtrl9        REG_AT(0x048)
+#define VidCtrl10       REG_AT(0x04C)
+#define VidCtrl11       REG_AT(0x050)
+#define VidCtrl12       REG_AT(0x054)
+#define VidCtrl13       REG_AT(0x058)
+#define VidCtrl14       REG_AT(0x05C)
+
+/* Video Control 1 Register */
+#define LINECNT         0xffc00000
+#define LINECNT_SHIFT   22
+#define LOADDLY         BIT(21)
+#define BAUDVAL         (BIT(20) | BIT(19) | BIT(18) | BIT(17) | BIT(16))
+#define BAUDVAL_SHIFT   16
+#define VIDDONEVAL      (BIT(15) | BIT(14) | BIT(13) | BIT(12) | BIT(11) | BIT(10) | BIT(9))
+#define VIDDONEVAL_SHIFT  9
+#define ENFREEZEFRAME   BIT(8)
+#define TX3912_VIDCTRL1_BITSEL_MASK	0x000000c0
+#define TX3912_VIDCTRL1_2BIT_GRAY	0x00000040
+#define TX3912_VIDCTRL1_4BIT_GRAY	0x00000080
+#define TX3912_VIDCTRL1_8BIT_COLOR	0x000000c0
+#define BITSEL_SHIFT    6
+#define DISPSPLIT       BIT(5)
+#define DISP8           BIT(4)
+#define DFMODE          BIT(3)
+#define INVVID          BIT(2)
+#define DISPON          BIT(1)
+#define ENVID           BIT(0)
+
+/* Video Control 2 Register */
+#define VIDRATE_MASK    0xffc00000
+#define VIDRATE_SHIFT   22
+#define HORZVAL_MASK    0x001ff000
+#define HORZVAL_SHIFT   12
+#define LINEVAL_MASK    0x000001ff
+
+/* Video Control 3 Register */
+#define TX3912_VIDCTRL3_VIDBANK_MASK    0xfff00000
+#define TX3912_VIDCTRL3_VIDBASEHI_MASK  0x000ffff0
+
+/* Video Control 4 Register */
+#define TX3912_VIDCTRL4_VIDBASELO_MASK  0x000ffff0
diff -Nru a/init/Makefile b/init/Makefile
--- a/init/Makefile	Sat Jun  8 22:31:37 2002
+++ b/init/Makefile	Sat Jun  8 22:31:37 2002
@@ -22,5 +22,5 @@
 # actual file if its content has changed.
 
 ../include/linux/compile.h: FORCE
-	@echo Generating $@
-	@. ../scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
+	@echo -n 'Generating $@'
+	@../scripts/mkcompile_h $@ "$(ARCH)" "$(CONFIG_SMP)" "$(CC) $(CFLAGS)"
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Sat Jun  8 22:31:36 2002
+++ b/init/main.c	Sat Jun  8 22:31:36 2002
@@ -51,7 +51,7 @@
  * To avoid associated bogus bug reports, we flatly refuse to compile
  * with a gcc that is known to be too old from the very beginning.
  */
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 91)
 #error Sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
diff -Nru a/kernel/Makefile b/kernel/Makefile
--- a/kernel/Makefile	Sat Jun  8 22:31:36 2002
+++ b/kernel/Makefile	Sat Jun  8 22:31:36 2002
@@ -13,7 +13,7 @@
 		printk.o platform.o suspend.o
 
 obj-y     = sched.o dma.o fork.o exec_domain.o panic.o printk.o \
-	    module.o exit.o itimer.o info.o time.o softirq.o resource.o \
+	    module.o exit.o itimer.o time.o softirq.o resource.o \
 	    sysctl.o capability.o ptrace.o timer.o user.o \
 	    signal.o sys.o kmod.o context.o futex.o platform.o
 
diff -Nru a/kernel/capability.c b/kernel/capability.c
--- a/kernel/capability.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/capability.c	Sat Jun  8 22:31:36 2002
@@ -2,17 +2,21 @@
  * linux/kernel/capability.c
  *
  * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
+ *
  * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@transmeta.com>
+ * 30 May 2002:	Cleanup, Robert M. Love <rml@tech9.net>
  */ 
 
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
 unsigned securebits = SECUREBITS_DEFAULT; /* systemwide security settings */
-
 kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
 
-/* Note: never hold tasklist_lock while spinning for this one */
+/*
+ * This global lock protects task->cap_* for all tasks including current.
+ * Locking rule: acquire this prior to tasklist_lock.
+ */
 spinlock_t task_capability_lock = SPIN_LOCK_UNLOCKED;
 
 /*
@@ -21,72 +25,65 @@
  * uninteresting and/or not to be changed.
  */
 
+/*
+ * sys_capget - get the capabilities of a given process.
+ */
 asmlinkage long sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
 {
-     int error, pid;
+     int ret = 0;
+     pid_t pid;
      __u32 version;
-     struct task_struct *target;
+     task_t *target;
      struct __user_cap_data_struct data;
 
      if (get_user(version, &header->version))
 	     return -EFAULT;
-	     
-     error = -EINVAL; 
+
      if (version != _LINUX_CAPABILITY_VERSION) {
-             version = _LINUX_CAPABILITY_VERSION;
-	     if (put_user(version, &header->version))
-		     error = -EFAULT; 
-             return error;
+	     if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
+		     return -EFAULT; 
+             return -EINVAL;
      }
 
      if (get_user(pid, &header->pid))
-	     return -EFAULT; 
+	     return -EFAULT;
 
      if (pid < 0) 
              return -EINVAL;
 
-     error = 0;
-
      spin_lock(&task_capability_lock);
+     read_lock(&tasklist_lock); 
 
-     if (pid && pid != current->pid) {
-	     read_lock(&tasklist_lock); 
-             target = find_task_by_pid(pid);  /* identify target of query */
-             if (!target) 
-                     error = -ESRCH;
-     } else {
-             target = current;
+     target = find_task_by_pid(pid);
+     if (!target) {
+          ret = -ESRCH;
+          goto out;
      }
 
-     if (!error) { 
-	     data.permitted = cap_t(target->cap_permitted);
-	     data.inheritable = cap_t(target->cap_inheritable); 
-	     data.effective = cap_t(target->cap_effective);
-     }
+     data.permitted = cap_t(target->cap_permitted);
+     data.inheritable = cap_t(target->cap_inheritable); 
+     data.effective = cap_t(target->cap_effective);
 
-     if (target != current)
-	     read_unlock(&tasklist_lock); 
+out:
+     read_unlock(&tasklist_lock); 
      spin_unlock(&task_capability_lock);
 
-     if (!error) {
-	     if (copy_to_user(dataptr, &data, sizeof data))
-		     return -EFAULT; 
-     }
+     if (!ret && copy_to_user(dataptr, &data, sizeof data))
+          return -EFAULT; 
 
-     return error;
+     return ret;
 }
 
-/* set capabilities for all processes in a given process group */
-
-static void cap_set_pg(int pgrp,
-                    kernel_cap_t *effective,
-                    kernel_cap_t *inheritable,
-                    kernel_cap_t *permitted)
+/*
+ * cap_set_pg - set capabilities for all processes in a given process
+ * group.  We call this holding task_capability_lock and tasklist_lock.
+ */
+static inline void cap_set_pg(int pgrp, kernel_cap_t *effective,
+			      kernel_cap_t *inheritable,
+			      kernel_cap_t *permitted)
 {
-     struct task_struct *target;
+     task_t *target;
 
-     /* FIXME: do we need to have a write lock here..? */
-     read_lock(&tasklist_lock);
      for_each_task(target) {
              if (target->pgrp != pgrp)
                      continue;
@@ -94,20 +91,18 @@
              target->cap_inheritable = *inheritable;
              target->cap_permitted   = *permitted;
      }
-     read_unlock(&tasklist_lock);
 }
 
-/* set capabilities for all processes other than 1 and self */
-
-static void cap_set_all(kernel_cap_t *effective,
-                     kernel_cap_t *inheritable,
-                     kernel_cap_t *permitted)
+/*
+ * cap_set_all - set capabilities for all processes other than init
+ * and self.  We call this holding task_capability_lock and tasklist_lock.
+ */
+static inline void cap_set_all(kernel_cap_t *effective,
+			       kernel_cap_t *inheritable,
+			       kernel_cap_t *permitted)
 {
-     struct task_struct *target;
+     task_t *target;
 
-     /* FIXME: do we need to have a write lock here..? */
-     read_lock(&tasklist_lock);
-     /* ALL means everyone other than self or 'init' */
      for_each_task(target) {
              if (target == current || target->pid == 1)
                      continue;
@@ -115,32 +110,33 @@
              target->cap_inheritable = *inheritable;
              target->cap_permitted   = *permitted;
      }
-     read_unlock(&tasklist_lock);
 }
 
 /*
+ * sys_capset - set capabilities for a given process, all processes, or all
+ * processes in a given process group.
+ *
  * The restrictions on setting capabilities are specified as:
  *
  * [pid is for the 'target' task.  'current' is the calling task.]
  *
- * I: any raised capabilities must be a subset of the (old current) Permitted
+ * I: any raised capabilities must be a subset of the (old current) permitted
  * P: any raised capabilities must be a subset of the (old current) permitted
- * E: must be set to a subset of (new target) Permitted
+ * E: must be set to a subset of (new target) permitted
  */
-
 asmlinkage long sys_capset(cap_user_header_t header, const cap_user_data_t data)
 {
      kernel_cap_t inheritable, permitted, effective;
      __u32 version;
-     struct task_struct *target;
-     int error, pid;
+     task_t *target;
+     int ret;
+     pid_t pid;
 
      if (get_user(version, &header->version))
 	     return -EFAULT; 
 
      if (version != _LINUX_CAPABILITY_VERSION) {
-             version = _LINUX_CAPABILITY_VERSION;
-	     if (put_user(version, &header->version))
+	     if (put_user(_LINUX_CAPABILITY_VERSION, &header->version))
 		     return -EFAULT; 
              return -EINVAL;
      }
@@ -156,43 +152,35 @@
 	 copy_from_user(&permitted, &data->permitted, sizeof(permitted)))
 	     return -EFAULT; 
 
-     error = -EPERM;
      spin_lock(&task_capability_lock);
+     read_lock(&tasklist_lock);
 
      if (pid > 0 && pid != current->pid) {
-             read_lock(&tasklist_lock);
-             target = find_task_by_pid(pid);  /* identify target of query */
-             if (!target) {
-                     error = -ESRCH;
-		     goto out;
-	     }
-     } else {
-             target = current;
-     }
+          target = find_task_by_pid(pid);
+          if (!target) {
+               ret = -ESRCH;
+               goto out;
+          }
+     } else
+               target = current;
 
+     ret = -EPERM;
 
      /* verify restrictions on target's new Inheritable set */
-     if (!cap_issubset(inheritable,
-                       cap_combine(target->cap_inheritable,
-                                   current->cap_permitted))) {
+     if (!cap_issubset(inheritable, cap_combine(target->cap_inheritable,
+                       current->cap_permitted)))
              goto out;
-     }
 
      /* verify restrictions on target's new Permitted set */
-     if (!cap_issubset(permitted,
-                       cap_combine(target->cap_permitted,
-                                   current->cap_permitted))) {
+     if (!cap_issubset(permitted, cap_combine(target->cap_permitted,
+                       current->cap_permitted)))
              goto out;
-     }
 
      /* verify the _new_Effective_ is a subset of the _new_Permitted_ */
-     if (!cap_issubset(effective, permitted)) {
+     if (!cap_issubset(effective, permitted))
              goto out;
-     }
 
-     /* having verified that the proposed changes are legal,
-           we now put them into effect. */
-     error = 0;
+     ret = 0;
 
      if (pid < 0) {
              if (pid == -1)  /* all procs other than current and init */
@@ -200,19 +188,15 @@
 
              else            /* all procs in process group */
                      cap_set_pg(-pid, &effective, &inheritable, &permitted);
-             goto spin_out;
      } else {
-             /* FIXME: do we need to have a write lock here..? */
              target->cap_effective   = effective;
              target->cap_inheritable = inheritable;
              target->cap_permitted   = permitted;
      }
 
 out:
-     if (target != current) {
-             read_unlock(&tasklist_lock);
-     }
-spin_out:
+     read_unlock(&tasklist_lock);
      spin_unlock(&task_capability_lock);
-     return error;
+
+     return ret;
 }
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/fork.c	Sat Jun  8 22:31:36 2002
@@ -53,9 +53,9 @@
 	unsigned long flags;
 
 	wait->flags &= ~WQ_FLAG_EXCLUSIVE;
-	wq_write_lock_irqsave(&q->lock, flags);
+	spin_lock_irqsave(&q->lock, flags);
 	__add_wait_queue(q, wait);
-	wq_write_unlock_irqrestore(&q->lock, flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
 void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)
@@ -63,18 +63,18 @@
 	unsigned long flags;
 
 	wait->flags |= WQ_FLAG_EXCLUSIVE;
-	wq_write_lock_irqsave(&q->lock, flags);
+	spin_lock_irqsave(&q->lock, flags);
 	__add_wait_queue_tail(q, wait);
-	wq_write_unlock_irqrestore(&q->lock, flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
 void remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)
 {
 	unsigned long flags;
 
-	wq_write_lock_irqsave(&q->lock, flags);
+	spin_lock_irqsave(&q->lock, flags);
 	__remove_wait_queue(q, wait);
-	wq_write_unlock_irqrestore(&q->lock, flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
 void __init fork_init(unsigned long mempages)
diff -Nru a/kernel/futex.c b/kernel/futex.c
--- a/kernel/futex.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/futex.c	Sat Jun  8 22:31:36 2002
@@ -33,14 +33,10 @@
 #include <linux/futex.h>
 #include <linux/highmem.h>
 #include <linux/time.h>
+#include <linux/pagemap.h>
 #include <asm/uaccess.h>
 
-/* These mutexes are a very simple counter: the winner is the one who
-   decrements from 1 to 0.  The counter starts at 1 when the lock is
-   free.  A value other than 0 or 1 means someone may be sleeping.
-   This is simple enough to work on all architectures, but has the
-   problem that if we never "up" the semaphore it could eventually
-   wrap around. */
+/* Simple "sleep if unchanged" interface. */
 
 /* FIXME: This may be way too small. --RR */
 #define FUTEX_HASHBITS 6
@@ -49,7 +45,7 @@
    the relevent ones (hashed queues may be shared) */
 struct futex_q {
 	struct list_head list;
-	struct task_struct *task;
+	wait_queue_head_t waiters;
 	/* Page struct and offset within it. */
 	struct page *page;
 	unsigned int offset;
@@ -69,6 +65,11 @@
 	return &futex_queues[hash_long(h, FUTEX_HASHBITS)];
 }
 
+static inline void tell_waiter(struct futex_q *q)
+{
+	wake_up_all(&q->waiters);
+}
+
 static int futex_wake(struct list_head *head,
 		      struct page *page,
 		      unsigned int offset,
@@ -83,7 +84,7 @@
 
 		if (this->page == page && this->offset == offset) {
 			list_del_init(i);
-			wake_up_process(this->task);
+			tell_waiter(this);
 			num_woken++;
 			if (num_woken >= num) break;
 		}
@@ -94,11 +95,12 @@
 
 /* Add at end to avoid starvation */
 static inline void queue_me(struct list_head *head,
+			    wait_queue_t *wait,
 			    struct futex_q *q,
 			    struct page *page,
 			    unsigned int offset)
 {
-	q->task = current;
+	add_wait_queue(&q->waiters, wait);
 	q->page = page;
 	q->offset = offset;
 
@@ -150,18 +152,20 @@
 {
 	int curval;
 	struct futex_q q;
+	DECLARE_WAITQUEUE(wait, current);
 	int ret = 0;
 
 	set_current_state(TASK_INTERRUPTIBLE);
-	queue_me(head, &q, page, offset);
+	queue_me(head, &wait, &q, page, offset);
 
-	/* Page is pinned, can't fail */
-	if (get_user(curval, uaddr) != 0)
-		BUG();
+	/* Page is pinned, but may no longer be in this address space. */
+	if (get_user(curval, uaddr) != 0) {
+		ret = -EFAULT;
+		goto out;
+	}
 
 	if (curval != val) {
 		ret = -EWOULDBLOCK;
-		set_current_state(TASK_RUNNING);
 		goto out;
 	}
 	time = schedule_timeout(time);
@@ -174,6 +178,7 @@
 		goto out;
 	}
  out:
+	set_current_state(TASK_RUNNING);
 	/* Were we woken up anyway? */
 	if (!unqueue_me(&q))
 		return 0;
@@ -218,7 +223,7 @@
 	default:
 		ret = -EINVAL;
 	}
-	put_page(page);
+	page_cache_release(page);
 
 	return ret;
 }
diff -Nru a/kernel/info.c b/kernel/info.c
--- a/kernel/info.c	Sat Jun  8 22:31:35 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,79 +0,0 @@
-/*
- * linux/kernel/info.c
- *
- * Copyright (C) 1992 Darren Senn
- */
-
-/* This implements the sysinfo() system call */
-
-#include <linux/mm.h>
-#include <linux/unistd.h>
-#include <linux/swap.h>
-#include <linux/smp_lock.h>
-
-#include <asm/uaccess.h>
-
-asmlinkage long sys_sysinfo(struct sysinfo *info)
-{
-	struct sysinfo val;
-
-	memset((char *)&val, 0, sizeof(struct sysinfo));
-
-	cli();
-	val.uptime = jiffies / HZ;
-
-	val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
-	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
-	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
-
-	val.procs = nr_threads;
-	sti();
-
-	si_meminfo(&val);
-	si_swapinfo(&val);
-
-	{
-		unsigned long mem_total, sav_total;
-		unsigned int mem_unit, bitcount;
-
-		/* If the sum of all the available memory (i.e. ram + swap)
-		 * is less than can be stored in a 32 bit unsigned long then
-		 * we can be binary compatible with 2.2.x kernels.  If not,
-		 * well, in that case 2.2.x was broken anyways...
-		 *
-		 *  -Erik Andersen <andersee@debian.org> */
-
-		mem_total = val.totalram + val.totalswap;
-		if (mem_total < val.totalram || mem_total < val.totalswap)
-			goto out;
-		bitcount = 0;
-		mem_unit = val.mem_unit;
-		while (mem_unit > 1) {
-			bitcount++;
-			mem_unit >>= 1;
-			sav_total = mem_total;
-			mem_total <<= 1;
-			if (mem_total < sav_total)
-				goto out;
-		}
-
-		/* If mem_total did not overflow, multiply all memory values by
-		 * val.mem_unit and set it to 1.  This leaves things compatible
-		 * with 2.2.x, and also retains compatibility with earlier 2.4.x
-		 * kernels...  */
-
-		val.mem_unit = 1;
-		val.totalram <<= bitcount;
-		val.freeram <<= bitcount;
-		val.sharedram <<= bitcount;
-		val.bufferram <<= bitcount;
-		val.totalswap <<= bitcount;
-		val.freeswap <<= bitcount;
-		val.totalhigh <<= bitcount;
-		val.freehigh <<= bitcount;
-	}
-out:
-	if (copy_to_user(info, &val, sizeof(struct sysinfo)))
-		return -EFAULT;
-	return 0;
-}
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Sat Jun  8 22:31:35 2002
+++ b/kernel/ksyms.c	Sat Jun  8 22:31:35 2002
@@ -140,7 +140,6 @@
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(inode_init_once);
-EXPORT_SYMBOL(force_delete);
 EXPORT_SYMBOL(follow_up);
 EXPORT_SYMBOL(follow_down);
 EXPORT_SYMBOL(lookup_mnt);
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/sched.c	Sat Jun  8 22:31:36 2002
@@ -605,7 +605,7 @@
 #define CAN_MIGRATE_TASK(p,rq,this_cpu)					\
 	((jiffies - (p)->sleep_timestamp > cache_decay_ticks) &&	\
 		((p) != (rq)->curr) &&					\
-			((p)->cpus_allowed & (1 << (this_cpu))))
+			((p)->cpus_allowed & (1UL << (this_cpu))))
 
 	if (!CAN_MIGRATE_TASK(tmp, busiest, this_cpu)) {
 		curr = curr->next;
@@ -777,12 +777,12 @@
 	spin_lock_irq(&rq->lock);
 
 	/*
-	 * if entering from preempt_schedule, off a kernel preemption,
-	 * go straight to picking the next task.
+	 * if entering off a kernel preemption go straight
+	 * to picking the next task.
 	 */
 	if (unlikely(preempt_get_count() & PREEMPT_ACTIVE))
 		goto pick_next_task;
-	
+
 	switch (prev->state) {
 	case TASK_INTERRUPTIBLE:
 		if (unlikely(signal_pending(prev))) {
@@ -854,7 +854,9 @@
 
 #ifdef CONFIG_PREEMPT
 /*
- * this is is the entry point to schedule() from in-kernel preemption.
+ * this is is the entry point to schedule() from in-kernel preemption
+ * off of preempt_enable.  Kernel preemptions off return from interrupt
+ * occur there and call schedule directly.
  */
 asmlinkage void preempt_schedule(void)
 {
@@ -866,7 +868,6 @@
 	ti->preempt_count = PREEMPT_ACTIVE;
 	schedule();
 	ti->preempt_count = 0;
-	barrier();
 }
 #endif /* CONFIG_PREEMPT */
 
@@ -903,9 +904,9 @@
 	if (unlikely(!q))
 		return;
 
-	wq_read_lock_irqsave(&q->lock, flags);
+	spin_lock_irqsave(&q->lock, flags);
 	__wake_up_common(q, mode, nr_exclusive);
-	wq_read_unlock_irqrestore(&q->lock, flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 }
 
 void complete(struct completion *x)
@@ -944,14 +945,14 @@
 	init_waitqueue_entry(&wait, current);
 
 #define	SLEEP_ON_HEAD					\
-	wq_write_lock_irqsave(&q->lock,flags);		\
+	spin_lock_irqsave(&q->lock,flags);		\
 	__add_wait_queue(q, &wait);			\
-	wq_write_unlock(&q->lock);
+	spin_unlock(&q->lock);
 
 #define	SLEEP_ON_TAIL						\
-	wq_write_lock_irq(&q->lock);				\
+	spin_lock_irq(&q->lock);				\
 	__remove_wait_queue(q, &wait);				\
-	wq_write_unlock_irqrestore(&q->lock,flags);
+	spin_unlock_irqrestore(&q->lock, flags);
 
 void interruptible_sleep_on(wait_queue_head_t *q)
 {
@@ -1143,7 +1144,7 @@
 				policy != SCHED_OTHER)
 			goto out_unlock;
 	}
-	
+
 	/*
 	 * Valid priorities for SCHED_FIFO and SCHED_RR are
 	 * 1..MAX_USER_RT_PRIO, valid priority for SCHED_OTHER is 0.
@@ -1376,6 +1377,7 @@
 
 	return 0;
 }
+
 asmlinkage long sys_sched_get_priority_max(int policy)
 {
 	int ret = -EINVAL;
@@ -1591,9 +1593,9 @@
 	int i, j, k;
 
 	for (i = 0; i < NR_CPUS; i++) {
-		runqueue_t *rq = cpu_rq(i);
 		prio_array_t *array;
 
+		rq = cpu_rq(i);
 		rq->active = rq->arrays;
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
@@ -1661,7 +1663,8 @@
  * is removed from the allowed bitmask.
  *
  * NOTE: the caller must have a valid reference to the task, the
- * task must not exit() & deallocate itself prematurely.
+ * task must not exit() & deallocate itself prematurely.  The
+ * call is not atomic; no spinlocks may be held.
  */
 void set_cpus_allowed(task_t *p, unsigned long new_mask)
 {
@@ -1681,16 +1684,6 @@
 	 * migrate the process off to a proper CPU.
 	 */
 	if (new_mask & (1UL << p->thread_info->cpu)) {
-		task_rq_unlock(rq, &flags);
-		goto out;
-	}
-
-	/*
-	 * If the task is not on a runqueue, then it is sufficient
-	 * to simply update the task's cpu field.
-	 */
-	if (!p->array) {
-		p->thread_info->cpu = __ffs(p->cpus_allowed);
 		task_rq_unlock(rq, &flags);
 		goto out;
 	}
diff -Nru a/kernel/suspend.c b/kernel/suspend.c
--- a/kernel/suspend.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/suspend.c	Sat Jun  8 22:31:36 2002
@@ -66,6 +66,8 @@
 #include <asm/io.h>
 #include <linux/swapops.h>
 
+extern void signal_wake_up(struct task_struct *t);
+
 unsigned char software_suspend_enabled = 0;
 
 /* #define SUSPEND_CONSOLE	(MAX_NR_CONSOLES-1) */
@@ -104,7 +106,7 @@
 static char resume_file[256] = "";			/* For resume= kernel option */
 static kdev_t resume_device;
 /* Local variables that should not be affected by save */
-static unsigned int nr_copy_pages __nosavedata = 0;
+unsigned int nr_copy_pages __nosavedata = 0;
 
 static int pm_suspend_state = 0;
 
@@ -117,8 +119,8 @@
    allocated at time of resume, that travels through memory not to
    collide with anything.
  */
-static suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
-static unsigned long pagedir_save;
+suspend_pagedir_t *pagedir_nosave __nosavedata = NULL;
+static suspend_pagedir_t *pagedir_save;
 static int pagedir_order __nosavedata = 0;
 
 struct link {
@@ -282,7 +284,7 @@
 	strncpy(sh->version, system_utsname.version, 20);
 	sh->num_cpus = smp_num_cpus;
 	sh->page_size = PAGE_SIZE;
-	sh->suspend_pagedir = (unsigned long)pagedir_nosave;
+	sh->suspend_pagedir = pagedir_nosave;
 	if (pagedir_save != pagedir_nosave)
 		panic("Must not happen");
 	sh->num_pbes = nr_copy_pages;
@@ -298,15 +300,10 @@
  * but that should not be a problem since tasks are stopped..
  */
 
-static void do_suspend_sync(void)
+static inline void do_suspend_sync(void)
 {
-	while (1) {
-		blk_run_queues();
-#error this is broken, FIXME
-		if (!TQ_ACTIVE(tq_disk))
-			break;
-		printk(KERN_ERR "Hm, tq_disk is not empty after run_task_queue\n");
-	}
+	blk_run_queues();
+#warning This might be broken. We need to somehow wait for data to reach the disk
 }
 
 /* We memorize in swapfile_used what swap devices are used for suspension */
@@ -412,7 +409,6 @@
 	int nr_pgdir_pages = SUSPEND_PD_PAGES(nr_copy_pages);
 	union diskpage *cur,  *buffer = (union diskpage *)get_free_page(GFP_ATOMIC);
 	unsigned long address;
-	kdev_t suspend_device;
 
 	PRINTS( "Writing data to swap (%d pages): ", nr_copy_pages );
 	for (i=0; i<nr_copy_pages; i++) {
@@ -427,8 +423,9 @@
 		address = (pagedir_nosave+i)->address;
 		lock_page(virt_to_page(address));
 		{
-			long dummy1, dummy2;
-			get_swaphandle_info(entry, &dummy1, &suspend_device);
+			long dummy1;
+			struct inode *suspend_file;
+			get_swaphandle_info(entry, &dummy1, &suspend_file);
 		}
 		rw_swap_page_nolock(WRITE, entry, (char *) address);
 		(pagedir_nosave+i)->swap_address = entry;
@@ -786,7 +783,7 @@
  * Magic happens here
  */
 
-static void do_magic_resume_1(void)
+void do_magic_resume_1(void)
 {
 	barrier();
 	mb();
@@ -798,7 +795,7 @@
 			   driver scheduled DMA, we have good chance for DMA to finish ;-). */
 }
 
-static void do_magic_resume_2(void)
+void do_magic_resume_2(void)
 {
 	if (nr_copy_pages_check != nr_copy_pages)
 		panic("nr_copy_pages changed?!");
@@ -806,7 +803,7 @@
 		panic("pagedir_order changed?!");
 
 	PRINTR( "Freeing prev allocated pagedir\n" );
-	free_suspend_pagedir(pagedir_save);
+	free_suspend_pagedir((unsigned long) pagedir_save);
 	__flush_tlb_global();		/* Even mappings of "global" things (vmalloc) need to be fixed */
 	drivers_resume(RESUME_ALL_PHASES);
 	spin_unlock_irq(&suspend_pagedir_lock);
@@ -820,14 +817,14 @@
 #endif
 }
 
-static void do_magic_suspend_1(void)
+void do_magic_suspend_1(void)
 {
 	mb();
 	barrier();
 	spin_lock_irq(&suspend_pagedir_lock);
 }
 
-static void do_magic_suspend_2(void)
+void do_magic_suspend_2(void)
 {
 	read_swapfiles();
 	if (!suspend_save_image())
@@ -1047,7 +1044,7 @@
 	return 0;
 } 
 
-extern kdev_t __init name_to_kdev_t(char *line);
+extern kdev_t __init name_to_kdev_t(const char *line);
 
 static int resume_try_to_read(const char * specialfile, int noresume)
 {
@@ -1064,7 +1061,7 @@
 		goto resume_read_error;
 	}
 
-	printk("Resuming from device %x\n", resume_device);
+	printk("Resuming from device %x\n", kdev_t_to_nr(resume_device));
 
 #define READTO(pos, ptr) \
 	if (bdev_read_page(resume_device, pos, ptr)) { error = -EIO; goto resume_read_error; }
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Sat Jun  8 22:31:36 2002
+++ b/kernel/sysctl.c	Sat Jun  8 22:31:36 2002
@@ -971,7 +971,7 @@
 	vleft = table->maxlen / sizeof(int);
 	left = *lenp;
 	
-	for (; left && vleft--; i++, first=0) {
+	for (; left && vleft--; i++, min++, max++, first=0) {
 		if (write) {
 			while (left) {
 				char c;
@@ -1007,9 +1007,7 @@
 			buffer += len;
 			left -= len;
 
-			if (min && val < *min++)
-				continue;
-			if (max && val > *max++)
+			if ((min && val < *min) || (max && val > *max))
 				continue;
 			*i = val;
 		} else {
@@ -1074,7 +1072,7 @@
 	vleft = table->maxlen / sizeof(unsigned long);
 	left = *lenp;
 	
-	for (; left && vleft--; i++, first=0) {
+	for (; left && vleft--; i++, min++, max++, first=0) {
 		if (write) {
 			while (left) {
 				char c;
@@ -1112,9 +1110,7 @@
 
 			if(neg)
 				continue;
-			if (min && val < *min++)
-				continue;
-			if (max && val > *max++)
+			if ((min && val < *min) || (max && val > *max))
 				continue;
 			*i = val;
 		} else {
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Sat Jun  8 22:31:37 2002
+++ b/kernel/timer.c	Sat Jun  8 22:31:37 2002
@@ -13,6 +13,7 @@
  *              serialize accesses to xtime/lost_ticks).
  *                              Copyright (C) 1998  Andrea Arcangeli
  *  1999-03-10  Improved NTP compatibility by Ulrich Windl
+ *  2002-05-31	Move sys_sysinfo here and make its locking sane, Robert Love
  */
 
 #include <linux/config.h>
@@ -605,9 +606,15 @@
  * imply that avenrun[] is the standard name for this kind of thing.
  * Nothing else seems to be standardized: the fractional size etc
  * all seem to differ on different machines.
+ *
+ * Requires xtime_lock to access.
  */
 unsigned long avenrun[3];
 
+/*
+ * calc_load - given tick count, update the avenrun load estimates.
+ * This is called while holding a write_lock on xtime_lock.
+ */
 static inline void calc_load(unsigned long ticks)
 {
 	unsigned long active_tasks; /* fixed-point */
@@ -627,7 +634,8 @@
 unsigned long wall_jiffies;
 
 /*
- * This spinlock protect us from races in SMP while playing with xtime. -arca
+ * This read-write spinlock protects us from races in SMP while
+ * playing with xtime and avenrun.
  */
 rwlock_t xtime_lock = RW_LOCK_UNLOCKED;
 unsigned long last_time_offset;
@@ -649,8 +657,8 @@
 		update_wall_time(ticks);
 	}
 	last_time_offset = 0;
-	write_unlock_irq(&xtime_lock);
 	calc_load(ticks);
+	write_unlock_irq(&xtime_lock);
 }
 
 void timer_bh(void)
@@ -912,3 +920,73 @@
 	return 0;
 }
 
+/*
+ * sys_sysinfo - fill in sysinfo struct
+ */ 
+asmlinkage long sys_sysinfo(struct sysinfo *info)
+{
+	struct sysinfo val;
+	unsigned long mem_total, sav_total;
+	unsigned int mem_unit, bitcount;
+
+	memset((char *)&val, 0, sizeof(struct sysinfo));
+
+	read_lock_irq(&xtime_lock);
+	val.uptime = jiffies / HZ;
+
+	val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
+	val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT);
+
+	val.procs = nr_threads;
+	read_unlock_irq(&xtime_lock);
+
+	si_meminfo(&val);
+	si_swapinfo(&val);
+
+	/*
+	 * If the sum of all the available memory (i.e. ram + swap)
+	 * is less than can be stored in a 32 bit unsigned long then
+	 * we can be binary compatible with 2.2.x kernels.  If not,
+	 * well, in that case 2.2.x was broken anyways...
+	 *
+	 *  -Erik Andersen <andersee@debian.org>
+	 */
+
+	mem_total = val.totalram + val.totalswap;
+	if (mem_total < val.totalram || mem_total < val.totalswap)
+		goto out;
+	bitcount = 0;
+	mem_unit = val.mem_unit;
+	while (mem_unit > 1) {
+		bitcount++;
+		mem_unit >>= 1;
+		sav_total = mem_total;
+		mem_total <<= 1;
+		if (mem_total < sav_total)
+			goto out;
+	}
+
+	/*
+	 * If mem_total did not overflow, multiply all memory values by
+	 * val.mem_unit and set it to 1.  This leaves things compatible
+	 * with 2.2.x, and also retains compatibility with earlier 2.4.x
+	 * kernels...
+	 */
+
+	val.mem_unit = 1;
+	val.totalram <<= bitcount;
+	val.freeram <<= bitcount;
+	val.sharedram <<= bitcount;
+	val.bufferram <<= bitcount;
+	val.totalswap <<= bitcount;
+	val.freeswap <<= bitcount;
+	val.totalhigh <<= bitcount;
+	val.freehigh <<= bitcount;
+
+out:
+	if (copy_to_user(info, &val, sizeof(struct sysinfo)))
+		return -EFAULT;
+
+	return 0;
+}
diff -Nru a/mm/bootmem.c b/mm/bootmem.c
--- a/mm/bootmem.c	Sat Jun  8 22:31:37 2002
+++ b/mm/bootmem.c	Sat Jun  8 22:31:37 2002
@@ -18,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/mmzone.h>
 #include <asm/dma.h>
+#include <asm/io.h>
 
 /*
  * Access to this subsystem has to be serialized externally. (this is
diff -Nru a/mm/highmem.c b/mm/highmem.c
--- a/mm/highmem.c	Sat Jun  8 22:31:35 2002
+++ b/mm/highmem.c	Sat Jun  8 22:31:35 2002
@@ -20,6 +20,7 @@
 #include <linux/pagemap.h>
 #include <linux/mempool.h>
 #include <linux/blkdev.h>
+#include <linux/init.h>
 #include <asm/pgalloc.h>
 
 static mempool_t *page_pool, *isa_page_pool;
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Sat Jun  8 22:31:35 2002
+++ b/mm/page_alloc.c	Sat Jun  8 22:31:35 2002
@@ -27,11 +27,14 @@
 unsigned long totalram_pages;
 unsigned long totalhigh_pages;
 int nr_swap_pages;
-struct list_head inactive_list;
-struct list_head active_list;
+LIST_HEAD(active_list);
+LIST_HEAD(inactive_list);
 pg_data_t *pgdat_list;
 
-/* Used to look up the address of the struct zone encoded in page->zone */
+/*
+ * Used by page_zone() to look up the address of the struct zone whose
+ * id is encoded in the upper bits of page->flags
+ */
 zone_t *zone_table[MAX_NR_ZONES*MAX_NR_NODES];
 EXPORT_SYMBOL(zone_table);
 
@@ -41,26 +44,6 @@
 static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, };
 
 /*
- * Free_page() adds the page to the free lists. This is optimized for
- * fast normal cases (no error jumps taken normally).
- *
- * The way to optimize jumps for gcc-2.2.2 is to:
- *  - select the "normal" case and put it inside the if () { XXX }
- *  - no else-statements if you can avoid them
- *
- * With the above two rules, you get a straight-line execution path
- * for the normal case, giving better asm-code.
- */
-
-#define memlist_init(x) INIT_LIST_HEAD(x)
-#define memlist_add_head list_add
-#define memlist_add_tail list_add_tail
-#define memlist_del list_del
-#define memlist_entry list_entry
-#define memlist_next(x) ((x)->next)
-#define memlist_prev(x) ((x)->prev)
-
-/*
  * Temporary debugging check.
  */
 #define BAD_RANGE(zone, page)						\
@@ -154,13 +137,13 @@
 		if (BAD_RANGE(zone,buddy2))
 			BUG();
 
-		memlist_del(&buddy1->list);
+		list_del(&buddy1->list);
 		mask <<= 1;
 		area++;
 		index >>= 1;
 		page_idx &= mask;
 	}
-	memlist_add_head(&(base + page_idx)->list, &area->free_list);
+	list_add(&(base + page_idx)->list, &area->free_list);
 
 	spin_unlock_irqrestore(&zone->lock, flags);
 	return;
@@ -190,7 +173,7 @@
 		area--;
 		high--;
 		size >>= 1;
-		memlist_add_head(&(page)->list, &(area)->free_list);
+		list_add(&(page)->list, &(area)->free_list);
 		MARK_USED(index, high, area);
 		index += size;
 		page += size;
@@ -212,15 +195,15 @@
 	spin_lock_irqsave(&zone->lock, flags);
 	do {
 		head = &area->free_list;
-		curr = memlist_next(head);
+		curr = head->next;
 
 		if (curr != head) {
 			unsigned int index;
 
-			page = memlist_entry(curr, struct page, list);
+			page = list_entry(curr, struct page, list);
 			if (BAD_RANGE(zone,page))
 				BUG();
-			memlist_del(curr);
+			list_del(curr);
 			index = page - zone->zone_mem_map;
 			if (curr_order != MAX_ORDER-1)
 				MARK_USED(index, curr_order, area);
@@ -682,7 +665,7 @@
 				curr = head;
 				nr = 0;
 				for (;;) {
-					curr = memlist_next(curr);
+					curr = curr->next;
 					if (curr == head)
 						break;
 					nr++;
@@ -827,9 +810,6 @@
 			
 	printk("On node %d totalpages: %lu\n", nid, realtotalpages);
 
-	INIT_LIST_HEAD(&active_list);
-	INIT_LIST_HEAD(&inactive_list);
-
 	/*
 	 * Some architectures (with lots of mem and discontinous memory
 	 * maps) have to search for a good mem_map area:
@@ -912,7 +892,7 @@
 			set_page_zone(page, nid * MAX_NR_ZONES + j);
 			set_page_count(page, 0);
 			SetPageReserved(page);
-			memlist_init(&page->list);
+			INIT_LIST_HEAD(&page->list);
 			if (j != ZONE_HIGHMEM)
 				set_page_address(page, __va(zone_start_paddr));
 			zone_start_paddr += PAGE_SIZE;
@@ -922,7 +902,7 @@
 		for (i = 0; ; i++) {
 			unsigned long bitmap_size;
 
-			memlist_init(&zone->free_area[i].free_list);
+			INIT_LIST_HEAD(&zone->free_area[i].free_list);
 			if (i == MAX_ORDER-1) {
 				zone->free_area[i].map = NULL;
 				break;
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Sat Jun  8 22:31:37 2002
+++ b/mm/shmem.c	Sat Jun  8 22:31:37 2002
@@ -1483,7 +1483,7 @@
 	remount_fs:	shmem_remount_fs,
 #endif
 	delete_inode:	shmem_delete_inode,
-	put_inode:	force_delete,	
+	drop_inode:	generic_delete_inode,
 	put_super:	shmem_put_super,
 };
 
diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c
--- a/mm/vmalloc.c	Sat Jun  8 22:31:35 2002
+++ b/mm/vmalloc.c	Sat Jun  8 22:31:35 2002
@@ -232,6 +232,33 @@
 	printk(KERN_ERR "Trying to vfree() nonexistent vm area (%p)\n", addr);
 }
 
+/*
+ *	Allocate any pages
+ */
+
+void * vmalloc (unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+/*
+ *	Allocate ISA addressable pages for broke crap
+ */
+
+void * vmalloc_dma (unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL|GFP_DMA, PAGE_KERNEL);
+}
+
+/*
+ *	vmalloc 32bit PA addressable pages - eg for PCI 32bit devices
+ */
+
+void * vmalloc_32(unsigned long size)
+{
+	return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL);
+}
+
 void * __vmalloc (unsigned long size, int gfp_mask, pgprot_t prot)
 {
 	void * addr;
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Sat Jun  8 22:31:43 2002
+++ b/net/core/dev.c	Sat Jun  8 22:31:43 2002
@@ -20,17 +20,18 @@
  *              Pekka Riikonen <priikone@poesidon.pspt.fi>
  *
  *	Changes:
- *              D.J. Barrow     :       Fixed bug where dev->refcnt gets set to 2
- *                                      if register_netdev gets called before
- *                                      net_dev_init & also removed a few lines
- *                                      of code in the process.
+ *              D.J. Barrow     :       Fixed bug where dev->refcnt gets set
+ *              			to 2 if register_netdev gets called
+ *              			before net_dev_init & also removed a
+ *              			few lines of code in the process.
  *		Alan Cox	:	device private ioctl copies fields back.
- *		Alan Cox	:	Transmit queue code does relevant stunts to
- *					keep the queue safe.
+ *		Alan Cox	:	Transmit queue code does relevant
+ *					stunts to keep the queue safe.
  *		Alan Cox	:	Fixed double lock.
  *		Alan Cox	:	Fixed promisc NULL pointer trap
  *		????????	:	Support the full private ioctl range
- *		Alan Cox	:	Moved ioctl permission check into drivers
+ *		Alan Cox	:	Moved ioctl permission check into
+ *					drivers
  *		Tim Kordas	:	SIOCADDMULTI/SIOCDELMULTI
  *		Alan Cox	:	100 backlog just doesn't cut it when
  *					you start doing multicast video 8)
@@ -38,16 +39,19 @@
  *		Alan Cox	: 	Fix ETH_P_ALL echoback lengths.
  *		Alan Cox	:	Took out transmit every packet pass
  *					Saved a few bytes in the ioctl handler
- *		Alan Cox	:	Network driver sets packet type before calling netif_rx. Saves
- *					a function call a packet.
+ *		Alan Cox	:	Network driver sets packet type before
+ *					calling netif_rx. Saves a function
+ *					call a packet.
  *		Alan Cox	:	Hashed net_bh()
  *		Richard Kooijman:	Timestamp fixes.
  *		Alan Cox	:	Wrong field in SIOCGIFDSTADDR
  *		Alan Cox	:	Device lock protection.
- *		Alan Cox	: 	Fixed nasty side effect of device close changes.
- *		Rudi Cilibrasi	:	Pass the right thing to set_mac_address()
- *		Dave Miller	:	32bit quantity for the device lock to make it work out
- *					on a Sparc.
+ *		Alan Cox	: 	Fixed nasty side effect of device close
+ *					changes.
+ *		Rudi Cilibrasi	:	Pass the right thing to
+ *					set_mac_address()
+ *		Dave Miller	:	32bit quantity for the device lock to
+ *					make it work out on a Sparc.
  *		Bjorn Ekwall	:	Added KERNELD hack.
  *		Alan Cox	:	Cleaned up the backlog initialise.
  *		Craig Metz	:	SIOCGIFCONF fix if space for under
@@ -62,9 +66,10 @@
  *					the backlog queue.
  *	Paul Rusty Russell	:	SIOCSIFNAME
  *              Pekka Riikonen  :	Netdev boot-time settings code
- *              Andrew Morton   :       Make unregister_netdevice wait indefinitely on dev->refcnt
+ *              Andrew Morton   :       Make unregister_netdevice wait
+ *              			indefinitely on dev->refcnt
  * 		J Hadi Salim	:	- Backlog queue sampling
- *				        - netif_rx() feedback	
+ *				        - netif_rx() feedback
  */
 
 #include <asm/uaccess.h>
@@ -162,8 +167,8 @@
  *		86DD	IPv6
  */
 
-static struct packet_type *ptype_base[16];		/* 16 way hashed list */
-static struct packet_type *ptype_all = NULL;		/* Taps */
+static struct packet_type *ptype_base[16];	/* 16 way hashed list */
+static struct packet_type *ptype_all;		/* Taps */
 
 #ifdef OFFLINE_SAMPLE
 static void sample_queue(unsigned long dummy);
@@ -179,8 +184,8 @@
 /*
  *	Our notifier list
  */
- 
-static struct notifier_block *netdev_chain=NULL;
+
+static struct notifier_block *netdev_chain;
 
 /*
  *	Device drivers call our routines to queue packets here. We empty the
@@ -194,17 +199,17 @@
 #endif
 
 
-/******************************************************************************************
+/*******************************************************************************
 
 		Protocol management and registration routines
 
-*******************************************************************************************/
+*******************************************************************************/
 
 /*
  *	For efficiency
  */
 
-int netdev_nit=0;
+int netdev_nit;
 
 /*
  *	Add a protocol ID to the list. Now that the input handler is
@@ -225,12 +230,12 @@
 /**
  *	dev_add_pack - add packet handler
  *	@pt: packet type declaration
- * 
+ *
  *	Add a protocol handler to the networking stack. The passed &packet_type
  *	is linked into kernel lists and may not be freed until it has been
  *	removed from the kernel lists.
  */
- 
+
 void dev_add_pack(struct packet_type *pt)
 {
 	int hash;
@@ -239,17 +244,17 @@
 
 #ifdef CONFIG_NET_FASTROUTE
 	/* Hack to detect packet socket */
-	if ((pt->data) && ((int)(pt->data)!=1)) {
+	if (pt->data && (long)(pt->data) != 1) {
 		netdev_fastroute_obstacles++;
 		dev_clear_fastroute(pt->dev);
 	}
 #endif
 	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit++;
-		pt->next=ptype_all;
-		ptype_all=pt;
+		pt->next  = ptype_all;
+		ptype_all = pt;
 	} else {
-		hash=ntohs(pt->type)&15;
+		hash = ntohs(pt->type) & 15;
 		pt->next = ptype_base[hash];
 		ptype_base[hash] = pt;
 	}
@@ -260,13 +265,12 @@
 /**
  *	dev_remove_pack	 - remove packet handler
  *	@pt: packet type declaration
- * 
+ *
  *	Remove a protocol handler that was previously added to the kernel
  *	protocol handlers by dev_add_pack(). The passed &packet_type is removed
  *	from the kernel lists and can be freed or reused once this function
  *	returns.
  */
- 
 void dev_remove_pack(struct packet_type *pt)
 {
 	struct packet_type **pt1;
@@ -275,24 +279,23 @@
 
 	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit--;
-		pt1=&ptype_all;
-	} else {
-		pt1=&ptype_base[ntohs(pt->type)&15];
-	}
+		pt1 = &ptype_all;
+	} else
+		pt1 = &ptype_base[ntohs(pt->type) & 15];
 
-	for (; (*pt1) != NULL; pt1 = &((*pt1)->next)) {
-		if (pt == (*pt1)) {
+	for (; *pt1; pt1 = &((*pt1)->next)) {
+		if (pt == *pt1) {
 			*pt1 = pt->next;
 #ifdef CONFIG_NET_FASTROUTE
 			if (pt->data)
 				netdev_fastroute_obstacles--;
 #endif
-			br_write_unlock_bh(BR_NETPROTO_LOCK);
-			return;
+			goto out;
 		}
 	}
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
 	printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
+out:
+	br_write_unlock_bh(BR_NETPROTO_LOCK);
 }
 
 /******************************************************************************
@@ -328,10 +331,7 @@
 		}
 	}
 
-	if (i >= NETDEV_BOOT_SETUP_MAX)
-		return 0;
-
-	return 1;
+	return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1;
 }
 
 /**
@@ -345,10 +345,9 @@
  */
 int netdev_boot_setup_check(struct net_device *dev)
 {
-	struct netdev_boot_setup *s;
+	struct netdev_boot_setup *s = dev_boot_setup;
 	int i;
 
-	s = dev_boot_setup;
 	for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) {
 		if (s[i].name[0] != '\0' && s[i].name[0] != ' ' &&
 		    !strncmp(dev->name, s[i].name, strlen(s[i].name))) {
@@ -385,20 +384,20 @@
 	if (ints[0] > 3)
 		map.mem_end = ints[4];
 
-	/* Add new entry to the list */	
+	/* Add new entry to the list */
 	return netdev_boot_setup_add(str, &map);
 }
 
 __setup("netdev=", netdev_boot_setup);
 
-/*****************************************************************************************
+/*******************************************************************************
 
 			    Device Interface Subroutines
 
-******************************************************************************************/
+*******************************************************************************/
 
 /**
- *	__dev_get_by_name	- find a device by its name 
+ *	__dev_get_by_name	- find a device by its name
  *	@name: name to find
  *
  *	Find an interface by name. Must be called under RTNL semaphore
@@ -407,24 +406,22 @@
  *	reference counters are not incremented so the caller must be
  *	careful with locks.
  */
- 
 
 struct net_device *__dev_get_by_name(const char *name)
 {
 	struct net_device *dev;
 
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		if (strncmp(dev->name, name, IFNAMSIZ) == 0)
-			return dev;
-	}
-	return NULL;
+	for (dev = dev_base; dev; dev = dev->next)
+		if (!strncmp(dev->name, name, IFNAMSIZ))
+			break;
+	return dev;
 }
 
 /**
  *	dev_get_by_name		- find a device by its name
  *	@name: name to find
  *
- *	Find an interface by name. This can be called from any 
+ *	Find an interface by name. This can be called from any
  *	context and does its own locking. The returned handle has
  *	the usage count incremented and the caller must use dev_put() to
  *	release it when it is no longer needed. %NULL is returned if no
@@ -443,7 +440,7 @@
 	return dev;
 }
 
-/* 
+/*
    Return value is changed to int to prevent illegal usage in future.
    It is still legal to use to check for device existence.
 
@@ -460,9 +457,8 @@
  *	caller must hold the rtnl semaphore.
  *
  *	This function primarily exists for back compatibility with older
- *	drivers. 
+ *	drivers.
  */
- 
 int dev_get(const char *name)
 {
 	struct net_device *dev;
@@ -484,15 +480,14 @@
  *	or @dev_base_lock.
  */
 
-struct net_device * __dev_get_by_index(int ifindex)
+struct net_device *__dev_get_by_index(int ifindex)
 {
 	struct net_device *dev;
 
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for (dev = dev_base; dev; dev = dev->next)
 		if (dev->ifindex == ifindex)
-			return dev;
-	}
-	return NULL;
+			break;
+	return dev;
 }
 
 
@@ -501,12 +496,12 @@
  *	@ifindex: index of device
  *
  *	Search for an interface by index. Returns NULL if the device
- *	is not found or a pointer to the device. The device returned has 
+ *	is not found or a pointer to the device. The device returned has
  *	had a reference added and the pointer is safe until the user calls
  *	dev_put to indicate they have finished with it.
  */
 
-struct net_device * dev_get_by_index(int ifindex)
+struct net_device *dev_get_by_index(int ifindex)
 {
 	struct net_device *dev;
 
@@ -538,17 +533,16 @@
 
 	ASSERT_RTNL();
 
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for (dev = dev_base; dev; dev = dev->next)
 		if (dev->type == type &&
-		    memcmp(dev->dev_addr, ha, dev->addr_len) == 0)
-			return dev;
-	}
-	return NULL;
+		    !memcmp(dev->dev_addr, ha, dev->addr_len))
+			break;
+	return dev;
 }
 
 /**
  *	dev_alloc_name - allocate a name for a device
- *	@dev: device 
+ *	@dev: device
  *	@name: name format string
  *
  *	Passed a format string - eg "lt%d" it will try and find a suitable
@@ -570,15 +564,15 @@
 	 * characters, or no "%" characters at all.
 	 */
 	p = strchr(name, '%');
-	if (p && (p[1] != 'd' || strchr(p+2, '%')))
+	if (p && (p[1] != 'd' || strchr(p + 2, '%')))
 		return -EINVAL;
 
 	/*
 	 * If you need over 100 please also fix the algorithm...
 	 */
 	for (i = 0; i < 100; i++) {
-		snprintf(buf,sizeof(buf),name,i);
-		if (__dev_get_by_name(buf) == NULL) {
+		snprintf(buf, sizeof(buf), name, i);
+		if (!__dev_get_by_name(buf)) {
 			strcpy(dev->name, buf);
 			return i;
 		}
@@ -593,7 +587,7 @@
  *
  *	Passed a format string, eg. "lt%d", it will allocate a network device
  *	and space for the name. %NULL is returned if no memory is available.
- *	If the allocation succeeds then the name is assigned and the 
+ *	If the allocation succeeds then the name is assigned and the
  *	device pointer returned. %NULL is returned if the name allocation
  *	failed. The cause of an error is returned as a negative errno code
  *	in the variable @err points to.
@@ -604,16 +598,17 @@
 
 struct net_device *dev_alloc(const char *name, int *err)
 {
-	struct net_device *dev=kmalloc(sizeof(struct net_device), GFP_KERNEL);
-	if (dev == NULL) {
+	struct net_device *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+
+	if (!dev)
 		*err = -ENOBUFS;
-		return NULL;
-	}
-	memset(dev, 0, sizeof(struct net_device));
-	*err = dev_alloc_name(dev, name);
-	if (*err < 0) {
-		kfree(dev);
-		return NULL;
+	else {
+		memset(dev, 0, sizeof(*dev));
+		*err = dev_alloc_name(dev, name);
+		if (*err < 0) {
+			kfree(dev);
+			dev = NULL;
+		}
 	}
 	return dev;
 }
@@ -626,10 +621,9 @@
  *	the notifier chains for netdev_chain and sends a NEWLINK message
  *	to the routing socket.
  */
- 
 void netdev_state_change(struct net_device *dev)
 {
-	if (dev->flags&IFF_UP) {
+	if (dev->flags & IFF_UP) {
 		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
 		rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
 	}
@@ -661,13 +655,14 @@
 
 static int default_rebuild_header(struct sk_buff *skb)
 {
-	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", skb->dev ? skb->dev->name : "NULL!!!");
+	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n",
+	       skb->dev ? skb->dev->name : "NULL!!!");
 	kfree_skb(skb);
 	return 1;
 }
 
 /**
- *	dev_open	- prepare an interface for use. 
+ *	dev_open	- prepare an interface for use.
  *	@dev:	device to open
  *
  *	Takes a device from down to up state. The device's private open
@@ -678,7 +673,6 @@
  *	Calling this function on an active interface is a nop. On a failure
  *	a negative errno code is returned.
  */
- 
 int dev_open(struct net_device *dev)
 {
 	int ret = 0;
@@ -687,7 +681,7 @@
 	 *	Is it already up?
 	 */
 
-	if (dev->flags&IFF_UP)
+	if (dev->flags & IFF_UP)
 		return 0;
 
 	/*
@@ -702,7 +696,7 @@
 	if (try_inc_mod_count(dev->owner)) {
 		if (dev->open) {
 			ret = dev->open(dev);
-			if (ret != 0 && dev->owner)
+			if (ret && dev->owner)
 				__MOD_DEC_USE_COUNT(dev->owner);
 		}
 	} else {
@@ -712,9 +706,8 @@
 	/*
 	 *	If it went open OK then:
 	 */
-	 
-	if (ret == 0) 
-	{
+
+	if (!ret) {
 		/*
 		 *	Set the flags.
 		 */
@@ -723,7 +716,7 @@
 		set_bit(__LINK_STATE_START, &dev->state);
 
 		/*
-		 *	Initialize multicasting status 
+		 *	Initialize multicasting status
 		 */
 		dev_mc_upload(dev);
 
@@ -737,7 +730,7 @@
 		 */
 		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
 	}
-	return(ret);
+	return ret;
 }
 
 #ifdef CONFIG_NET_FASTROUTE
@@ -747,7 +740,7 @@
 	if (dev->accept_fastpath) {
 		int i;
 
-		for (i=0; i<=NETDEV_FASTROUTE_HMASK; i++) {
+		for (i = 0; i <= NETDEV_FASTROUTE_HMASK; i++) {
 			struct dst_entry *dst;
 
 			write_lock_irq(&dev->fastpath_lock);
@@ -777,15 +770,14 @@
  *	dev_close - shutdown an interface.
  *	@dev: device to shutdown
  *
- *	This function moves an active device into down state. A 
+ *	This function moves an active device into down state. A
  *	%NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
  *	is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
  *	chain.
  */
- 
 int dev_close(struct net_device *dev)
 {
-	if (!(dev->flags&IFF_UP))
+	if (!(dev->flags & IFF_UP))
 		return 0;
 
 	/*
@@ -818,7 +810,6 @@
 	 *	We allow it to be called even after a DETACH hot-plug
 	 *	event.
 	 */
-	 
 	if (dev->stop)
 		dev->stop(dev);
 
@@ -842,7 +833,7 @@
 	if (dev->owner)
 		__MOD_DEC_USE_COUNT(dev->owner);
 
-	return(0);
+	return 0;
 }
 
 
@@ -850,7 +841,7 @@
  *	Device change register/unregister. These are not inline or static
  *	as we export them to the world.
  */
- 
+
 /**
  *	register_netdevice_notifier - register a network notifier block
  *	@nb: notifier
@@ -878,7 +869,7 @@
 
 int unregister_netdevice_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&netdev_chain,nb);
+	return notifier_chain_unregister(&netdev_chain, nb);
 }
 
 /*
@@ -892,16 +883,14 @@
 	do_gettimeofday(&skb->stamp);
 
 	br_read_lock(BR_NETPROTO_LOCK);
-	for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next) 
-	{
+	for (ptype = ptype_all; ptype; ptype = ptype->next) {
 		/* Never send packets back to the socket
 		 * they originated from - MvS (miquels@drinkel.ow.org)
 		 */
 		if ((ptype->dev == dev || !ptype->dev) &&
-			((struct sock *)ptype->data != skb->sk))
-		{
-			struct sk_buff *skb2;
-			if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL)
+		    (struct sock *)ptype->data != skb->sk) {
+			struct sk_buff *skb2= skb_clone(skb, GFP_ATOMIC);
+			if (!skb2)
 				break;
 
 			/* skb->nh should be correctly
@@ -910,9 +899,12 @@
 			 */
 			skb2->mac.raw = skb2->data;
 
-			if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) {
+			if (skb2->nh.raw < skb2->data ||
+			    skb2->nh.raw > skb2->tail) {
 				if (net_ratelimit())
-					printk(KERN_DEBUG "protocol %04x is buggy, dev %s\n", skb2->protocol, dev->name);
+					printk(KERN_DEBUG "protocol %04x is "
+							  "buggy, dev %s\n",
+					       skb2->protocol, dev->name);
 				skb2->nh.raw = skb2->data;
 			}
 
@@ -928,12 +920,11 @@
  * If it failed by some reason, ignore and send skb with wrong
  * checksum.
  */
-struct sk_buff * skb_checksum_help(struct sk_buff *skb)
+struct sk_buff *skb_checksum_help(struct sk_buff *skb)
 {
-	int offset;
 	unsigned int csum;
+	int offset = skb->h.raw - skb->data;
 
-	offset = skb->h.raw - skb->data;
 	if (offset > (int)skb->len)
 		BUG();
 	csum = skb_checksum(skb, offset, skb->len-offset, 0);
@@ -941,7 +932,7 @@
 	offset = skb->tail - skb->h.raw;
 	if (offset <= 0)
 		BUG();
-	if (skb->csum+2 > offset)
+	if (skb->csum + 2 > offset)
 		BUG();
 
 	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
@@ -955,15 +946,14 @@
  * 2. No high memory really exists on this machine.
  */
 
-static inline int
-illegal_highdma(struct net_device *dev, struct sk_buff *skb)
+static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
 {
 	int i;
 
-	if (dev->features&NETIF_F_HIGHDMA)
+	if (dev->features & NETIF_F_HIGHDMA)
 		return 0;
 
-	for (i=0; i<skb_shinfo(skb)->nr_frags; i++)
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
 		if (skb_shinfo(skb)->frags[i].page >= highmem_start_page)
 			return 1;
 
@@ -976,10 +966,10 @@
 /**
  *	dev_queue_xmit - transmit a buffer
  *	@skb: buffer to transmit
- *	
+ *
  *	Queue a buffer for transmission to a network device. The caller must
- *	have set the device and priority and built the buffer before calling this 
- *	function. The function can be called from an interrupt.
+ *	have set the device and priority and built the buffer before calling
+ *	this function. The function can be called from an interrupt.
  *
  *	A negative errno code is returned on a failure. A success does not
  *	guarantee the frame will be transmitted as it may be dropped due
@@ -989,61 +979,60 @@
 int dev_queue_xmit(struct sk_buff *skb)
 {
 	struct net_device *dev = skb->dev;
-	struct Qdisc  *q;
+	struct Qdisc *q;
+	int rc = -ENOMEM;
 
 	if (skb_shinfo(skb)->frag_list &&
-	    !(dev->features&NETIF_F_FRAGLIST) &&
-	    skb_linearize(skb, GFP_ATOMIC) != 0) {
-		kfree_skb(skb);
-		return -ENOMEM;
-	}
+	    !(dev->features & NETIF_F_FRAGLIST) &&
+	    skb_linearize(skb, GFP_ATOMIC))
+		goto out_kfree_skb;
 
 	/* Fragmented skb is linearized if device does not support SG,
 	 * or if at least one of fragments is in highmem and device
 	 * does not support DMA from it.
 	 */
 	if (skb_shinfo(skb)->nr_frags &&
-	    (!(dev->features&NETIF_F_SG) || illegal_highdma(dev, skb)) &&
-	    skb_linearize(skb, GFP_ATOMIC) != 0) {
-		kfree_skb(skb);
-		return -ENOMEM;
-	}
+	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
+	    skb_linearize(skb, GFP_ATOMIC))
+		goto out_kfree_skb;
 
 	/* If packet is not checksummed and device does not support
 	 * checksumming for this protocol, complete checksumming here.
 	 */
 	if (skb->ip_summed == CHECKSUM_HW &&
-	    (!(dev->features&(NETIF_F_HW_CSUM|NETIF_F_NO_CSUM)) &&
-	     (!(dev->features&NETIF_F_IP_CSUM) ||
+	    (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
+	     (!(dev->features & NETIF_F_IP_CSUM) ||
 	      skb->protocol != htons(ETH_P_IP)))) {
 		if ((skb = skb_checksum_help(skb)) == NULL)
-			return -ENOMEM;
+			goto out;
 	}
 
 	/* Grab device queue */
 	spin_lock_bh(&dev->queue_lock);
 	q = dev->qdisc;
 	if (q->enqueue) {
-		int ret = q->enqueue(skb, q);
+		rc = q->enqueue(skb, q);
 
 		qdisc_run(dev);
 
 		spin_unlock_bh(&dev->queue_lock);
-		return ret == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : ret;
+		rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
+		goto out;
 	}
 
 	/* The device has no queue. Common case for software devices:
 	   loopback, all the sorts of tunnels...
 
 	   Really, it is unlikely that xmit_lock protection is necessary here.
-	   (f.e. loopback and IP tunnels are clean ignoring statistics counters.)
+	   (f.e. loopback and IP tunnels are clean ignoring statistics
+	   counters.)
 	   However, it is possible, that they rely on protection
 	   made by us here.
 
 	   Check this and shot the lock. It is not prone from deadlocks.
 	   Either shot noqueue qdisc, it is even simpler 8)
 	 */
-	if (dev->flags&IFF_UP) {
+	if (dev->flags & IFF_UP) {
 		int cpu = smp_processor_id();
 
 		if (dev->xmit_lock_owner != cpu) {
@@ -1059,30 +1048,36 @@
 
 			if (!netif_queue_stopped(dev)) {
 				if (netdev_nit)
-					dev_queue_xmit_nit(skb,dev);
+					dev_queue_xmit_nit(skb, dev);
 
-				if (dev->hard_start_xmit(skb, dev) == 0) {
+				rc = 0;
+				if (!dev->hard_start_xmit(skb, dev)) {
 					dev->xmit_lock_owner = -1;
 					spin_unlock_bh(&dev->xmit_lock);
-					return 0;
+					goto out;
 				}
 			}
 			dev->xmit_lock_owner = -1;
 			spin_unlock_bh(&dev->xmit_lock);
 			if (net_ratelimit())
-				printk(KERN_DEBUG "Virtual device %s asks to queue packet!\n", dev->name);
-			kfree_skb(skb);
-			return -ENETDOWN;
+				printk(KERN_DEBUG "Virtual device %s asks to "
+				       "queue packet!\n", dev->name);
+			goto out_enetdown;
 		} else {
-			/* Recursion is detected! It is possible, unfortunately */
+			/* Recursion is detected! It is possible,
+			 * unfortunately */
 			if (net_ratelimit())
-				printk(KERN_DEBUG "Dead loop on virtual device %s, fix it urgently!\n", dev->name);
+				printk(KERN_DEBUG "Dead loop on virtual device "
+				       "%s, fix it urgently!\n", dev->name);
 		}
 	}
 	spin_unlock_bh(&dev->queue_lock);
-
+out_enetdown:
+	rc = -ENETDOWN;
+out_kfree_skb:
 	kfree_skb(skb);
-	return -ENETDOWN;
+out:
+	return rc;
 }
 
 
@@ -1107,7 +1102,7 @@
 #ifdef CONFIG_NET_HW_FLOWCONTROL
 atomic_t netdev_dropping = ATOMIC_INIT(0);
 static unsigned long netdev_fc_mask = 1;
-unsigned long netdev_fc_xoff = 0;
+unsigned long netdev_fc_xoff;
 spinlock_t netdev_fc_lock = SPIN_LOCK_UNLOCKED;
 
 static struct
@@ -1116,7 +1111,8 @@
 	struct net_device *dev;
 } netdev_fc_slots[BITS_PER_LONG];
 
-int netdev_register_fc(struct net_device *dev, void (*stimul)(struct net_device *dev))
+int netdev_register_fc(struct net_device *dev,
+		       void (*stimul)(struct net_device *dev))
 {
 	int bit = 0;
 	unsigned long flags;
@@ -1156,7 +1152,7 @@
 	netdev_fc_xoff = 0;
 	while (xoff) {
 		int i = ffz(~xoff);
-		xoff &= ~(1<<i);
+		xoff &= ~(1 << i);
 		netdev_fc_slots[i].stimul(netdev_fc_slots[i].dev);
 	}
 	spin_unlock(&netdev_fc_lock);
@@ -1172,7 +1168,7 @@
 	int blog = softnet_data[cpu].input_pkt_queue.qlen;
 	int avg_blog = softnet_data[cpu].avg_blog;
 
-	avg_blog = (avg_blog >> 1)+ (blog >> 1);
+	avg_blog = (avg_blog >> 1) + (blog >> 1);
 
 	if (avg_blog > mod_cong) {
 		/* Above moderate congestion levels. */
@@ -1191,7 +1187,7 @@
 			if (rq < avg_blog) /* unlucky bastard */
 				softnet_data[cpu].cng_level = NET_RX_CN_HIGH;
 #endif
-	} else if (avg_blog > no_cong) 
+	} else if (avg_blog > no_cong)
 		softnet_data[cpu].cng_level = NET_RX_CN_LOW;
 	else  /* no congestion */
 		softnet_data[cpu].cng_level = NET_RX_SUCCESS;
@@ -1219,17 +1215,16 @@
  *
  *	This function receives a packet from a device driver and queues it for
  *	the upper (protocol) levels to process.  It always succeeds. The buffer
- *	may be dropped during processing for congestion control or by the 
+ *	may be dropped during processing for congestion control or by the
  *	protocol layers.
- *      
+ *
  *	return values:
- *	NET_RX_SUCCESS	(no congestion)           
- *	NET_RX_CN_LOW     (low congestion) 
- *	NET_RX_CN_MOD     (moderate congestion)
- *	NET_RX_CN_HIGH    (high congestion) 
- *	NET_RX_DROP    (packet was dropped)
- *      
- *      
+ *	NET_RX_SUCCESS	(no congestion)
+ *	NET_RX_CN_LOW   (low congestion)
+ *	NET_RX_CN_MOD   (moderate congestion)
+ *	NET_RX_CN_HIGH  (high congestion)
+ *	NET_RX_DROP     (packet was dropped)
+ *
  */
 
 int netif_rx(struct sk_buff *skb)
@@ -1238,7 +1233,7 @@
 	struct softnet_data *queue;
 	unsigned long flags;
 
-	if (skb->stamp.tv_sec == 0)
+	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
 	/* The code is rearranged so that the path is the most
@@ -1256,7 +1251,7 @@
 
 enqueue:
 			dev_hold(skb->dev);
-			__skb_queue_tail(&queue->input_pkt_queue,skb);
+			__skb_queue_tail(&queue->input_pkt_queue, skb);
 			local_irq_restore(flags);
 #ifndef OFFLINE_SAMPLE
 			get_sample_stats(this_cpu);
@@ -1276,7 +1271,7 @@
 		goto enqueue;
 	}
 
-	if (queue->throttle == 0) {
+	if (!queue->throttle) {
 		queue->throttle = 1;
 		netdev_rx_stat[this_cpu].throttled++;
 #ifdef CONFIG_NET_HW_FLOWCONTROL
@@ -1295,21 +1290,19 @@
 /* Deliver skb to an old protocol, which is not threaded well
    or which do not understand shared skbs.
  */
-static int deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int last)
+static int deliver_to_old_ones(struct packet_type *pt,
+			       struct sk_buff *skb, int last)
 {
 	static spinlock_t net_bh_lock = SPIN_LOCK_UNLOCKED;
 	int ret = NET_RX_DROP;
 
-
 	if (!last) {
 		skb = skb_clone(skb, GFP_ATOMIC);
-		if (skb == NULL)
-			return ret;
-	}
-	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
-		kfree_skb(skb);
-		return ret;
+		if (!skb)
+			goto out;
 	}
+	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC))
+		goto out_kfree;
 
 	/* The assumption (correct one) is that old protocols
 	   did not depened on BHs different of NET_BH and TIMER_BH.
@@ -1325,7 +1318,11 @@
 
 	tasklet_hi_enable(bh_task_vec+TIMER_BH);
 	spin_unlock(&net_bh_lock);
+out:
 	return ret;
+out_kfree:
+	kfree_skb(skb);
+	goto out;
 }
 
 static __inline__ void skb_bond(struct sk_buff *skb)
@@ -1348,11 +1345,11 @@
 		softnet_data[cpu].completion_queue = NULL;
 		local_irq_enable();
 
-		while (clist != NULL) {
+		while (clist) {
 			struct sk_buff *skb = clist;
 			clist = clist->next;
 
-			BUG_TRAP(atomic_read(&skb->users) == 0);
+			BUG_TRAP(!atomic_read(&skb->users));
 			__kfree_skb(skb);
 		}
 	}
@@ -1365,7 +1362,7 @@
 		softnet_data[cpu].output_queue = NULL;
 		local_irq_enable();
 
-		while (head != NULL) {
+		while (head) {
 			struct net_device *dev = head;
 			head = head->next_sched;
 
@@ -1389,7 +1386,6 @@
  *	Make a function call that is atomic with respect to the protocol
  *	layers.
  */
- 
 void net_call_rx_atomic(void (*fn)(void))
 {
 	br_write_lock_bh(BR_NETPROTO_LOCK);
@@ -1421,11 +1417,12 @@
 
 
 #ifdef CONFIG_NET_DIVERT
-static inline void handle_diverter(struct sk_buff *skb)
+static inline int handle_diverter(struct sk_buff *skb)
 {
 	/* if diversion is supported on device, then divert */
 	if (skb->dev->divert && skb->dev->divert->divert)
 		divert_frame(skb);
+	return 0;
 }
 #endif   /* CONFIG_NET_DIVERT */
 
@@ -1435,7 +1432,7 @@
 	int ret = NET_RX_DROP;
 	unsigned short type = skb->protocol;
 
-	if (skb->stamp.tv_sec == 0)
+	if (!skb->stamp.tv_sec)
 		do_gettimeofday(&skb->stamp);
 
 	skb_bond(skb);
@@ -1456,10 +1453,12 @@
 		if (!ptype->dev || ptype->dev == skb->dev) {
 			if (pt_prev) {
 				if (!pt_prev->data) {
-					ret = deliver_to_old_ones(pt_prev, skb, 0);
+					ret = deliver_to_old_ones(pt_prev,
+								  skb, 0);
 				} else {
 					atomic_inc(&skb->users);
-					ret = pt_prev->func(skb, skb->dev, pt_prev);
+					ret = pt_prev->func(skb, skb->dev,
+							    pt_prev);
 				}
 			}
 			pt_prev = ptype;
@@ -1470,23 +1469,24 @@
 	if (skb->dev->divert && skb->dev->divert->divert)
 		ret = handle_diverter(skb);
 #endif /* CONFIG_NET_DIVERT */
-			
+
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-	if (skb->dev->br_port != NULL &&
-	    br_handle_frame_hook != NULL) {
+	if (skb->dev->br_port && br_handle_frame_hook) {
 		return handle_bridge(skb, pt_prev);
 	}
 #endif
 
-	for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) {
+	for (ptype = ptype_base[ntohs(type) & 15]; ptype; ptype = ptype->next) {
 		if (ptype->type == type &&
 		    (!ptype->dev || ptype->dev == skb->dev)) {
 			if (pt_prev) {
 				if (!pt_prev->data) {
-					ret = deliver_to_old_ones(pt_prev, skb, 0);
+					ret = deliver_to_old_ones(pt_prev,
+								  skb, 0);
 				} else {
 					atomic_inc(&skb->users);
-					ret = pt_prev->func(skb, skb->dev, pt_prev);
+					ret = pt_prev->func(skb, skb->dev,
+							    pt_prev);
 				}
 			}
 			pt_prev = ptype;
@@ -1524,7 +1524,7 @@
 
 		local_irq_disable();
 		skb = __skb_dequeue(&queue->input_pkt_queue);
-		if (skb == NULL)
+		if (!skb)
 			goto job_done;
 		local_irq_enable();
 
@@ -1540,7 +1540,8 @@
 			break;
 
 #ifdef CONFIG_NET_HW_FLOWCONTROL
-		if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) {
+		if (queue->throttle &&
+		    queue->input_pkt_queue.qlen < no_cong_thresh ) {
 			if (atomic_dec_and_test(&netdev_dropping)) {
 				queue->throttle = 0;
 				netdev_wakeup();
@@ -1590,7 +1591,8 @@
 
 		local_irq_enable();
 
-		dev = list_entry(queue->poll_list.next, struct net_device, poll_list);
+		dev = list_entry(queue->poll_list.next,
+				 struct net_device, poll_list);
 
 		if (dev->quota <= 0 || dev->poll(dev, &budget)) {
 			local_irq_disable();
@@ -1605,7 +1607,7 @@
 			local_irq_disable();
 		}
 	}
-
+out:
 	local_irq_enable();
 	br_read_unlock(BR_NETPROTO_LOCK);
 	return;
@@ -1613,9 +1615,7 @@
 softnet_break:
 	netdev_rx_stat[this_cpu].time_squeeze++;
 	__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
-
-	local_irq_enable();
-	br_read_unlock(BR_NETPROTO_LOCK);
+	goto out;
 }
 
 static gifconf_func_t * gifconf_list [NPROTO];
@@ -1629,10 +1629,9 @@
  *	that is passed must not be freed or reused until it has been replaced
  *	by another handler.
  */
- 
 int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
 {
-	if (family>=NPROTO)
+	if (family >= NPROTO)
 		return -EINVAL;
 	gifconf_list[family] = gifconf;
 	return 0;
@@ -1656,9 +1655,9 @@
 	struct ifreq ifr;
 
 	/*
-	 *	Fetch the caller's info block. 
+	 *	Fetch the caller's info block.
 	 */
-	
+
 	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
 		return -EFAULT;
 
@@ -1693,9 +1692,9 @@
 	int i;
 
 	/*
-	 *	Fetch the caller's info block. 
+	 *	Fetch the caller's info block.
 	 */
-	
+
 	if (copy_from_user(&ifc, arg, sizeof(struct ifconf)))
 		return -EFAULT;
 
@@ -1703,39 +1702,35 @@
 	len = ifc.ifc_len;
 
 	/*
-	 *	Loop over the interfaces, and write an info block for each. 
+	 *	Loop over the interfaces, and write an info block for each.
 	 */
 
 	total = 0;
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
-		for (i=0; i<NPROTO; i++) {
+	for (dev = dev_base; dev; dev = dev->next) {
+		for (i = 0; i < NPROTO; i++) {
 			if (gifconf_list[i]) {
 				int done;
-				if (pos==NULL) {
+				if (!pos)
 					done = gifconf_list[i](dev, NULL, 0);
-				} else {
-					done = gifconf_list[i](dev, pos+total, len-total);
-				}
-				if (done<0) {
+				else
+					done = gifconf_list[i](dev, pos + total,
+							       len - total);
+				if (done < 0)
 					return -EFAULT;
-				}
 				total += done;
 			}
 		}
   	}
 
 	/*
-	 *	All done.  Write the updated control block back to the caller. 
+	 *	All done.  Write the updated control block back to the caller.
 	 */
 	ifc.ifc_len = total;
 
-	if (copy_to_user(arg, &ifc, sizeof(struct ifconf)))
-		return -EFAULT; 
-
-	/* 
+	/*
 	 * 	Both BSD and Solaris return 0 here, so we do too.
 	 */
-	return 0;
+	return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0;
 }
 
 /*
@@ -1747,36 +1742,39 @@
 
 static int sprintf_stats(char *buffer, struct net_device *dev)
 {
-	struct net_device_stats *stats = (dev->get_stats ? dev->get_stats(dev): NULL);
+	struct net_device_stats *stats = dev->get_stats ? dev->get_stats(dev) :
+							  NULL;
 	int size;
-	
+
 	if (stats)
-		size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu %8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
+		size = sprintf(buffer, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu "
+				       "%10lu %9lu %8lu %7lu %4lu %4lu %4lu "
+				       "%5lu %7lu %10lu\n",
  		   dev->name,
 		   stats->rx_bytes,
 		   stats->rx_packets, stats->rx_errors,
 		   stats->rx_dropped + stats->rx_missed_errors,
 		   stats->rx_fifo_errors,
-		   stats->rx_length_errors + stats->rx_over_errors
-		   + stats->rx_crc_errors + stats->rx_frame_errors,
+		   stats->rx_length_errors + stats->rx_over_errors +
+		   	stats->rx_crc_errors + stats->rx_frame_errors,
 		   stats->rx_compressed, stats->multicast,
 		   stats->tx_bytes,
 		   stats->tx_packets, stats->tx_errors, stats->tx_dropped,
 		   stats->tx_fifo_errors, stats->collisions,
-		   stats->tx_carrier_errors + stats->tx_aborted_errors
-		   + stats->tx_window_errors + stats->tx_heartbeat_errors,
+		   stats->tx_carrier_errors + stats->tx_aborted_errors +
+		   	stats->tx_window_errors + stats->tx_heartbeat_errors,
 		   stats->tx_compressed);
 	else
-		size = sprintf(buffer, "%6s: No statistics available.\n", dev->name);
+		size = sprintf(buffer, "%6s: No statistics available.\n",
+			       dev->name);
 
 	return size;
 }
 
 /*
- *	Called from the PROCfs module. This now uses the new arbitrary sized /proc/net interface
- *	to create /proc/net/dev
+ *	Called from the PROCfs module. This now uses the new arbitrary sized
+ *	/proc/net interface to create /proc/net/dev
  */
- 
 static int dev_get_info(char *buffer, char **start, off_t offset, int length)
 {
 	int len = 0;
@@ -1785,21 +1783,19 @@
 	int size;
 	struct net_device *dev;
 
-
-	size = sprintf(buffer, 
+	size = sprintf(buffer,
 		"Inter-|   Receive                                                |  Transmit\n"
 		" face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\n");
-	
+
 	pos += size;
 	len += size;
-	
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for (dev = dev_base; dev; dev = dev->next) {
 		size = sprintf_stats(buffer+len, dev);
 		len += size;
 		pos = begin + len;
-				
+
 		if (pos < offset) {
 			len = 0;
 			begin = pos;
@@ -1810,7 +1806,7 @@
 	read_unlock(&dev_base_lock);
 
 	*start = buffer + (offset - begin);	/* Start of wanted data */
-	len -= (offset - begin);		/* Start slop */
+	len -= offset - begin;			/* Start slop */
 	if (len > length)
 		len = length;			/* Ending slop */
 	if (len < 0)
@@ -1822,11 +1818,12 @@
 			  int length, int *eof, void *data)
 {
 	int i, lcpu;
-	int len=0;
+	int len = 0;
 
-	for (lcpu=0; lcpu<smp_num_cpus; lcpu++) {
+	for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) {
 		i = cpu_logical_map(lcpu);
-		len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
+		len += sprintf(buffer + len, "%08x %08x %08x %08x %08x %08x "
+					     "%08x %08x %08x\n",
 			       netdev_rx_stat[i].total,
 			       netdev_rx_stat[i].dropped,
 			       netdev_rx_stat[i].time_squeeze,
@@ -1870,7 +1867,6 @@
  *	are adjusted, %RTM_NEWLINK is sent to the routing socket and the
  *	function returns zero.
  */
- 
 int netdev_set_master(struct net_device *slave, struct net_device *master)
 {
 	struct net_device *old = slave->master;
@@ -1909,7 +1905,6 @@
  *	the device reverts back to normal filtering operation. A negative inc
  *	value is used to drop promiscuity on the device.
  */
- 
 void dev_set_promiscuity(struct net_device *dev, int inc)
 {
 	unsigned short old_flags = dev->flags;
@@ -1917,9 +1912,9 @@
 	dev->flags |= IFF_PROMISC;
 	if ((dev->promiscuity += inc) == 0)
 		dev->flags &= ~IFF_PROMISC;
-	if (dev->flags^old_flags) {
+	if (dev->flags ^ old_flags) {
 #ifdef CONFIG_NET_FASTROUTE
-		if (dev->flags&IFF_PROMISC) {
+		if (dev->flags & IFF_PROMISC) {
 			netdev_fastroute_obstacles++;
 			dev_clear_fastroute(dev);
 		} else
@@ -1927,7 +1922,8 @@
 #endif
 		dev_mc_upload(dev);
 		printk(KERN_INFO "device %s %s promiscuous mode\n",
-		       dev->name, (dev->flags&IFF_PROMISC) ? "entered" : "left");
+		       dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
+		       					       "left");
 	}
 }
 
@@ -1950,7 +1946,7 @@
 	dev->flags |= IFF_ALLMULTI;
 	if ((dev->allmulti += inc) == 0)
 		dev->flags &= ~IFF_ALLMULTI;
-	if (dev->flags^old_flags)
+	if (dev->flags ^ old_flags)
 		dev_mc_upload(dev);
 }
 
@@ -1963,13 +1959,15 @@
 	 *	Set the flags on our device.
 	 */
 
-	dev->flags = (flags & (IFF_DEBUG|IFF_NOTRAILERS|IFF_NOARP|IFF_DYNAMIC|
-			       IFF_MULTICAST|IFF_PORTSEL|IFF_AUTOMEDIA)) |
-				       (dev->flags & (IFF_UP|IFF_VOLATILE|IFF_PROMISC|IFF_ALLMULTI));
+	dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP |
+			       IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL |
+			       IFF_AUTOMEDIA)) |
+		     (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC |
+				    IFF_ALLMULTI));
 
 	/*
 	 *	Load in the correct multicast list now the flags have changed.
-	 */				
+	 */
 
 	dev_mc_upload(dev);
 
@@ -1980,20 +1978,20 @@
 	 */
 
 	ret = 0;
-	if ((old_flags^flags)&IFF_UP)	/* Bit is different  ? */
-	{
+	if ((old_flags ^ flags) & IFF_UP) {	/* Bit is different  ? */
 		ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
 
-		if (ret == 0) 
+		if (!ret)
 			dev_mc_upload(dev);
 	}
 
-	if (dev->flags&IFF_UP &&
-	    ((old_flags^dev->flags)&~(IFF_UP|IFF_PROMISC|IFF_ALLMULTI|IFF_VOLATILE)))
+	if (dev->flags & IFF_UP &&
+	    ((old_flags ^ dev->flags) &~ (IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
+					  IFF_VOLATILE)))
 		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
 
-	if ((flags^dev->gflags)&IFF_PROMISC) {
-		int inc = (flags&IFF_PROMISC) ? +1 : -1;
+	if ((flags ^ dev->gflags) & IFF_PROMISC) {
+		int inc = (flags & IFF_PROMISC) ? +1 : -1;
 		dev->gflags ^= IFF_PROMISC;
 		dev_set_promiscuity(dev, inc);
 	}
@@ -2002,53 +2000,56 @@
 	   is important. Some (broken) drivers set IFF_PROMISC, when
 	   IFF_ALLMULTI is requested not asking us and not reporting.
 	 */
-	if ((flags^dev->gflags)&IFF_ALLMULTI) {
-		int inc = (flags&IFF_ALLMULTI) ? +1 : -1;
+	if ((flags ^ dev->gflags) & IFF_ALLMULTI) {
+		int inc = (flags & IFF_ALLMULTI) ? +1 : -1;
 		dev->gflags ^= IFF_ALLMULTI;
 		dev_set_allmulti(dev, inc);
 	}
 
-	if (old_flags^dev->flags)
-		rtmsg_ifinfo(RTM_NEWLINK, dev, old_flags^dev->flags);
+	if (old_flags ^ dev->flags)
+		rtmsg_ifinfo(RTM_NEWLINK, dev, old_flags ^ dev->flags);
 
 	return ret;
 }
 
 /*
- *	Perform the SIOCxIFxxx calls. 
+ *	Perform the SIOCxIFxxx calls.
  */
- 
 static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
 {
-	struct net_device *dev;
 	int err;
+	struct net_device *dev = __dev_get_by_name(ifr->ifr_name);
 
-	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL)
+	if (!dev)
 		return -ENODEV;
 
-	switch(cmd) 
-	{
+	switch (cmd) {
 		case SIOCGIFFLAGS:	/* Get interface flags */
-			ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING))
-				|(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
+			ifr->ifr_flags = (dev->flags & ~(IFF_PROMISC |
+							 IFF_ALLMULTI |
+							 IFF_RUNNING)) | 
+					 (dev->gflags & (IFF_PROMISC |
+							 IFF_ALLMULTI));
 			if (netif_running(dev) && netif_carrier_ok(dev))
 				ifr->ifr_flags |= IFF_RUNNING;
 			return 0;
 
 		case SIOCSIFFLAGS:	/* Set interface flags */
 			return dev_change_flags(dev, ifr->ifr_flags);
-		
-		case SIOCGIFMETRIC:	/* Get the metric on the interface (currently unused) */
+
+		case SIOCGIFMETRIC:	/* Get the metric on the interface
+					   (currently unused) */
 			ifr->ifr_metric = 0;
 			return 0;
-			
-		case SIOCSIFMETRIC:	/* Set the metric on the interface (currently unused) */
+
+		case SIOCSIFMETRIC:	/* Set the metric on the interface
+					   (currently unused) */
 			return -EOPNOTSUPP;
-	
+
 		case SIOCGIFMTU:	/* Get the MTU of a device */
 			ifr->ifr_mtu = dev->mtu;
 			return 0;
-	
+
 		case SIOCSIFMTU:	/* Set the MTU of a device */
 			if (ifr->ifr_mtu == dev->mtu)
 				return 0;
@@ -2056,80 +2057,85 @@
 			/*
 			 *	MTU must be positive.
 			 */
-			 
-			if (ifr->ifr_mtu<0)
+			if (ifr->ifr_mtu < 0)
 				return -EINVAL;
 
 			if (!netif_device_present(dev))
 				return -ENODEV;
 
+			err = 0;
 			if (dev->change_mtu)
 				err = dev->change_mtu(dev, ifr->ifr_mtu);
-			else {
+			else
 				dev->mtu = ifr->ifr_mtu;
-				err = 0;
-			}
-			if (!err && dev->flags&IFF_UP)
-				notifier_call_chain(&netdev_chain, NETDEV_CHANGEMTU, dev);
+			if (!err && dev->flags & IFF_UP)
+				notifier_call_chain(&netdev_chain,
+						    NETDEV_CHANGEMTU, dev);
 			return err;
 
 		case SIOCGIFHWADDR:
-			memcpy(ifr->ifr_hwaddr.sa_data,dev->dev_addr, MAX_ADDR_LEN);
-			ifr->ifr_hwaddr.sa_family=dev->type;
+			memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,
+			       MAX_ADDR_LEN);
+			ifr->ifr_hwaddr.sa_family = dev->type;
 			return 0;
-				
+
 		case SIOCSIFHWADDR:
-			if (dev->set_mac_address == NULL)
+			if (!dev->set_mac_address)
 				return -EOPNOTSUPP;
-			if (ifr->ifr_hwaddr.sa_family!=dev->type)
+			if (ifr->ifr_hwaddr.sa_family != dev->type)
 				return -EINVAL;
 			if (!netif_device_present(dev))
 				return -ENODEV;
 			err = dev->set_mac_address(dev, &ifr->ifr_hwaddr);
 			if (!err)
-				notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+				notifier_call_chain(&netdev_chain,
+						    NETDEV_CHANGEADDR, dev);
 			return err;
-			
+
 		case SIOCSIFHWBROADCAST:
-			if (ifr->ifr_hwaddr.sa_family!=dev->type)
+			if (ifr->ifr_hwaddr.sa_family != dev->type)
 				return -EINVAL;
-			memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, MAX_ADDR_LEN);
-			notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
+			memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data,
+			       MAX_ADDR_LEN);
+			notifier_call_chain(&netdev_chain,
+					    NETDEV_CHANGEADDR, dev);
 			return 0;
 
 		case SIOCGIFMAP:
-			ifr->ifr_map.mem_start=dev->mem_start;
-			ifr->ifr_map.mem_end=dev->mem_end;
-			ifr->ifr_map.base_addr=dev->base_addr;
-			ifr->ifr_map.irq=dev->irq;
-			ifr->ifr_map.dma=dev->dma;
-			ifr->ifr_map.port=dev->if_port;
+			ifr->ifr_map.mem_start = dev->mem_start;
+			ifr->ifr_map.mem_end   = dev->mem_end;
+			ifr->ifr_map.base_addr = dev->base_addr;
+			ifr->ifr_map.irq       = dev->irq;
+			ifr->ifr_map.dma       = dev->dma;
+			ifr->ifr_map.port      = dev->if_port;
 			return 0;
-			
+
 		case SIOCSIFMAP:
 			if (dev->set_config) {
 				if (!netif_device_present(dev))
 					return -ENODEV;
-				return dev->set_config(dev,&ifr->ifr_map);
+				return dev->set_config(dev, &ifr->ifr_map);
 			}
 			return -EOPNOTSUPP;
-			
+
 		case SIOCADDMULTI:
-			if (dev->set_multicast_list == NULL ||
+			if (!dev->set_multicast_list ||
 			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
 				return -EINVAL;
 			if (!netif_device_present(dev))
 				return -ENODEV;
-			dev_mc_add(dev,ifr->ifr_hwaddr.sa_data, dev->addr_len, 1);
+			dev_mc_add(dev, ifr->ifr_hwaddr.sa_data,
+				   dev->addr_len, 1);
 			return 0;
 
 		case SIOCDELMULTI:
-			if (dev->set_multicast_list == NULL ||
-			    ifr->ifr_hwaddr.sa_family!=AF_UNSPEC)
+			if (!dev->set_multicast_list ||
+			    ifr->ifr_hwaddr.sa_family != AF_UNSPEC)
 				return -EINVAL;
 			if (!netif_device_present(dev))
 				return -ENODEV;
-			dev_mc_delete(dev,ifr->ifr_hwaddr.sa_data,dev->addr_len, 1);
+			dev_mc_delete(dev, ifr->ifr_hwaddr.sa_data,
+				      dev->addr_len, 1);
 			return 0;
 
 		case SIOCGIFINDEX:
@@ -2141,19 +2147,20 @@
 			return 0;
 
 		case SIOCSIFTXQLEN:
-			if (ifr->ifr_qlen<0)
+			if (ifr->ifr_qlen < 0)
 				return -EINVAL;
 			dev->tx_queue_len = ifr->ifr_qlen;
 			return 0;
 
 		case SIOCSIFNAME:
-			if (dev->flags&IFF_UP)
+			if (dev->flags & IFF_UP)
 				return -EBUSY;
 			if (__dev_get_by_name(ifr->ifr_newname))
 				return -EEXIST;
 			memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
-			dev->name[IFNAMSIZ-1] = 0;
-			notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
+			dev->name[IFNAMSIZ - 1] = 0;
+			notifier_call_chain(&netdev_chain,
+					    NETDEV_CHANGENAME, dev);
 			return 0;
 
 		/*
@@ -2174,16 +2181,19 @@
 			    cmd == SIOCGMIIREG ||
 			    cmd == SIOCSMIIREG ||
 			    cmd == SIOCWANDEV) {
+				err = -EOPNOTSUPP;
 				if (dev->do_ioctl) {
-					if (!netif_device_present(dev))
-						return -ENODEV;
-					return dev->do_ioctl(dev, ifr, cmd);
+					if (netif_device_present(dev))
+						err = dev->do_ioctl(dev, ifr,
+								    cmd);
+					else
+						err = -ENODEV;
 				}
-				return -EOPNOTSUPP;
-			}
+			} else
+				err = -EINVAL;
 
 	}
-	return -EINVAL;
+	return err;
 }
 
 /*
@@ -2197,7 +2207,7 @@
  *	@arg: pointer to a struct ifreq in user space
  *
  *	Issue ioctl functions to devices. This is normally called by the
- *	user space syscall interfaces but can sometimes be useful for 
+ *	user space syscall interfaces but can sometimes be useful for
  *	other purposes. The return value is the return from the syscall if
  *	positive or a negative errno code on error.
  */
@@ -2212,16 +2222,15 @@
 	   and requires shared lock, because it sleeps writing
 	   to user space.
 	 */
-	   
+
 	if (cmd == SIOCGIFCONF) {
 		rtnl_shlock();
 		ret = dev_ifconf((char *) arg);
 		rtnl_shunlock();
 		return ret;
 	}
-	if (cmd == SIOCGIFNAME) {
+	if (cmd == SIOCGIFNAME)
 		return dev_ifname((struct ifreq *)arg);
-	}
 
 	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
 		return -EFAULT;
@@ -2233,18 +2242,16 @@
 		*colon = 0;
 
 	/*
-	 *	See which interface the caller is talking about. 
+	 *	See which interface the caller is talking about.
 	 */
-	 
-	switch(cmd) 
-	{
+
+	switch (cmd) {
 		/*
 		 *	These ioctl calls:
 		 *	- can be done by all.
 		 *	- atomic and do not require locking.
 		 *	- return a value
 		 */
-		 
 		case SIOCGIFFLAGS:
 		case SIOCGIFMETRIC:
 		case SIOCGIFMTU:
@@ -2260,8 +2267,9 @@
 			if (!ret) {
 				if (colon)
 					*colon = ':';
-				if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-					return -EFAULT;
+				if (copy_to_user(arg, &ifr,
+						 sizeof(struct ifreq)))
+					ret = -EFAULT;
 			}
 			return ret;
 
@@ -2271,7 +2279,6 @@
 		 *	- require strict serialization.
 		 *	- return a value
 		 */
-		 
 		case SIOCETHTOOL:
 		case SIOCGMIIPHY:
 		case SIOCGMIIREG:
@@ -2286,8 +2293,9 @@
 			if (!ret) {
 				if (colon)
 					*colon = ':';
-				if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-					return -EFAULT;
+				if (copy_to_user(arg, &ifr,
+						 sizeof(struct ifreq)))
+					ret = -EFAULT;
 			}
 			return ret;
 
@@ -2297,7 +2305,6 @@
 		 *	- require strict serialization.
 		 *	- do not return a value
 		 */
-		 
 		case SIOCSIFFLAGS:
 		case SIOCSIFMETRIC:
 		case SIOCSIFMTU:
@@ -2325,19 +2332,19 @@
 			rtnl_unlock();
 			dev_probe_unlock();
 			return ret;
-	
+
 		case SIOCGIFMEM:
-			/* Get the per device memory space. We can add this but currently
-			   do not support it */
+			/* Get the per device memory space. We can add this but
+			 * currently do not support it */
 		case SIOCSIFMEM:
-			/* Set the per device memory buffer space. Not applicable in our case */
+			/* Set the per device memory buffer space.
+			 * Not applicable in our case */
 		case SIOCSIFLINK:
 			return -EINVAL;
 
 		/*
 		 *	Unknown or private ioctl.
-		 */	
-		 
+		 */
 		default:
 			if (cmd == SIOCWANDEV ||
 			    (cmd >= SIOCDEVPRIVATE &&
@@ -2348,8 +2355,9 @@
 				ret = dev_ifsioc(&ifr, cmd);
 				rtnl_unlock();
 				dev_probe_unlock();
-				if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-					return -EFAULT;
+				if (!ret && copy_to_user(arg, &ifr,
+							 sizeof(struct ifreq)))
+					ret = -EFAULT;
 				return ret;
 			}
 #ifdef WIRELESS_EXT
@@ -2358,8 +2366,8 @@
 				/* If command is `set a parameter', or
 				 * `get the encoding parameters', check if
 				 * the user has the right to do it */
-				if (IW_IS_SET(cmd) || (cmd == SIOCGIWENCODE)) {
-					if(!capable(CAP_NET_ADMIN))
+				if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) {
+					if (!capable(CAP_NET_ADMIN))
 						return -EPERM;
 				}
 				dev_load(ifr.ifr_name);
@@ -2368,8 +2376,9 @@
 				ret = wireless_process_ioctl(&ifr, cmd);
 				rtnl_unlock();
 				if (!ret && IW_IS_GET(cmd) &&
-				    copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-					return -EFAULT;
+				    copy_to_user(arg, &ifr,
+					    	 sizeof(struct ifreq)))
+					ret = -EFAULT;
 				return ret;
 			}
 #endif	/* WIRELESS_EXT */
@@ -2385,14 +2394,13 @@
  *	number.  The caller must hold the rtnl semaphore or the
  *	dev_base_lock to be sure it remains unique.
  */
- 
 int dev_new_index(void)
 {
 	static int ifindex;
 	for (;;) {
 		if (++ifindex <= 0)
-			ifindex=1;
-		if (__dev_get_by_index(ifindex) == NULL)
+			ifindex = 1;
+		if (!__dev_get_by_index(ifindex))
 			return ifindex;
 	}
 }
@@ -2402,7 +2410,7 @@
 /**
  *	register_netdevice	- register a network device
  *	@dev: device to register
- *	
+ *
  *	Take a completed network device structure and add it to the kernel
  *	interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier
  *	chain. 0 is returned on success. A negative errno code is returned
@@ -2422,15 +2430,13 @@
 int register_netdevice(struct net_device *dev)
 {
 	struct net_device *d, **dp;
-#ifdef CONFIG_NET_DIVERT
 	int ret;
-#endif
 
 	spin_lock_init(&dev->queue_lock);
 	spin_lock_init(&dev->xmit_lock);
 	dev->xmit_lock_owner = -1;
 #ifdef CONFIG_NET_FASTROUTE
-	dev->fastpath_lock=RW_LOCK_UNLOCKED;
+	dev->fastpath_lock = RW_LOCK_UNLOCKED;
 #endif
 
 	if (dev_boot_phase)
@@ -2439,38 +2445,32 @@
 #ifdef CONFIG_NET_DIVERT
 	ret = alloc_divert_blk(dev);
 	if (ret)
-		return ret;
+		goto out;
 #endif /* CONFIG_NET_DIVERT */
-	
+
 	dev->iflink = -1;
 
 	/* Init, if this function is available */
-	if (dev->init && dev->init(dev) != 0) {
-#ifdef CONFIG_NET_DIVERT
-		free_divert_blk(dev);
-#endif
-		return -EIO;
-	}
+	ret = -EIO;
+	if (dev->init && dev->init(dev))
+		goto out_err;
 
 	dev->ifindex = dev_new_index();
 	if (dev->iflink == -1)
 		dev->iflink = dev->ifindex;
 
 	/* Check for existence, and append to tail of chain */
-	for (dp=&dev_base; (d=*dp) != NULL; dp=&d->next) {
-		if (d == dev || strcmp(d->name, dev->name) == 0) {
-#ifdef CONFIG_NET_DIVERT
-			free_divert_blk(dev);
-#endif
-			return -EEXIST;
-		}
+	ret = -EEXIST;
+	for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
+		if (d == dev || !strcmp(d->name, dev->name))
+			goto out_err;
 	}
 	/*
 	 *	nil rebuild_header routine,
 	 *	that should be never called and used as just bug trap.
 	 */
 
-	if (dev->rebuild_header == NULL)
+	if (!dev->rebuild_header)
 		dev->rebuild_header = default_rebuild_header;
 
 	/*
@@ -2492,8 +2492,15 @@
 	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
 	net_run_sbin_hotplug(dev, "register");
+	ret = 0;
 
-	return 0;
+out:
+	return ret;
+out_err:
+#ifdef CONFIG_NET_DIVERT
+	free_divert_blk(dev);
+#endif
+	goto out;
 }
 
 /**
@@ -2503,15 +2510,15 @@
  *	Destroy and free a dead device. A value of zero is returned on
  *	success.
  */
- 
 int netdev_finish_unregister(struct net_device *dev)
 {
-	BUG_TRAP(dev->ip_ptr==NULL);
-	BUG_TRAP(dev->ip6_ptr==NULL);
-	BUG_TRAP(dev->dn_ptr==NULL);
+	BUG_TRAP(!dev->ip_ptr);
+	BUG_TRAP(!dev->ip6_ptr);
+	BUG_TRAP(!dev->dn_ptr);
 
 	if (!dev->deadbeaf) {
-		printk(KERN_ERR "Freeing alive device %p, %s\n", dev, dev->name);
+		printk(KERN_ERR "Freeing alive device %p, %s\n",
+		       dev, dev->name);
 		return 0;
 	}
 #ifdef NET_REFCNT_DEBUG
@@ -2547,11 +2554,11 @@
 	if (dev->flags & IFF_UP)
 		dev_close(dev);
 
-	BUG_TRAP(dev->deadbeaf==0);
+	BUG_TRAP(!dev->deadbeaf);
 	dev->deadbeaf = 1;
 
 	/* And unlink it from device chain. */
-	for (dp = &dev_base; (d=*dp) != NULL; dp=&d->next) {
+	for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
 		if (d == dev) {
 			write_lock_bh(&dev_base_lock);
 			*dp = d->next;
@@ -2559,8 +2566,9 @@
 			break;
 		}
 	}
-	if (d == NULL) {
-		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never was registered\n", dev->name, dev);
+	if (!d) {
+		printk(KERN_DEBUG "unregister_netdevice: device %s/%p never "
+				  "was registered\n", dev->name, dev);
 		return -ENODEV;
 	}
 
@@ -2568,7 +2576,7 @@
 	br_write_lock_bh(BR_NETPROTO_LOCK);
 	br_write_unlock_bh(BR_NETPROTO_LOCK);
 
-	if (dev_boot_phase == 0) {
+	if (!dev_boot_phase) {
 #ifdef CONFIG_NET_FASTROUTE
 		dev_clear_fastroute(dev);
 #endif
@@ -2593,7 +2601,7 @@
 		dev->uninit(dev);
 
 	/* Notifier chain MUST detach us from master device. */
-	BUG_TRAP(dev->master==NULL);
+	BUG_TRAP(!dev->master);
 
 #ifdef CONFIG_NET_DIVERT
 	free_divert_blk(dev);
@@ -2602,20 +2610,20 @@
 	if (dev->features & NETIF_F_DYNALLOC) {
 #ifdef NET_REFCNT_DEBUG
 		if (atomic_read(&dev->refcnt) != 1)
-			printk(KERN_DEBUG "unregister_netdevice: holding %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)-1);
+			printk(KERN_DEBUG "unregister_netdevice: holding %s "
+					  "refcnt=%d\n",
+			       dev->name, atomic_read(&dev->refcnt) - 1);
 #endif
-		dev_put(dev);
-		return 0;
+		goto out;
 	}
 
 	/* Last reference is our one */
-	if (atomic_read(&dev->refcnt) == 1) {
-		dev_put(dev);
-		return 0;
-	}
+	if (atomic_read(&dev->refcnt) == 1)
+		goto out;
 
 #ifdef NET_REFCNT_DEBUG
-	printk("unregister_netdevice: waiting %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt));
+	printk(KERN_DEBUG "unregister_netdevice: waiting %s refcnt=%d\n",
+	       dev->name, atomic_read(&dev->refcnt));
 #endif
 
 	/* EXPLANATION. If dev->refcnt is not now 1 (our own reference)
@@ -2623,14 +2631,15 @@
 	   to this device and we cannot release it.
 
 	   "New style" devices have destructors, hence we can return from this
-	   function and destructor will do all the work later.  As of kernel 2.4.0
-	   there are very few "New Style" devices.
+	   function and destructor will do all the work later. As of kernel
+	   2.4.0 there are very few "New Style" devices.
 
 	   "Old style" devices expect that the device is free of any references
 	   upon exit from this function.
 	   We cannot return from this function until all such references have
-	   fallen away.  This is because the caller of this function will probably
-	   immediately kfree(*dev) and then be unloaded via sys_delete_module.
+	   fallen away. This is because the caller of this function will
+	   probably immediately kfree(*dev) and then be unloaded via
+	   sys_delete_module.
 
 	   So, we linger until all references fall away.  The duration of the
 	   linger is basically unbounded! It is driven by, for example, the
@@ -2643,20 +2652,22 @@
 
 	now = warning_time = jiffies;
 	while (atomic_read(&dev->refcnt) != 1) {
-		if ((jiffies - now) > 1*HZ) {
+		if ((jiffies - now) > 1 * HZ) {
 			/* Rebroadcast unregister notification */
-			notifier_call_chain(&netdev_chain, NETDEV_UNREGISTER, dev);
+			notifier_call_chain(&netdev_chain,
+					    NETDEV_UNREGISTER, dev);
 		}
 		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ/4);
+		schedule_timeout(HZ / 4);
 		current->state = TASK_RUNNING;
-		if ((jiffies - warning_time) > 10*HZ) {
-			printk(KERN_EMERG "unregister_netdevice: waiting for %s to "
-					"become free. Usage count = %d\n",
-					dev->name, atomic_read(&dev->refcnt));
+		if ((jiffies - warning_time) > 10 * HZ) {
+			printk(KERN_EMERG "unregister_netdevice: waiting for "
+			       "%s to become free. Usage count = %d\n",
+			       dev->name, atomic_read(&dev->refcnt));
 			warning_time = jiffies;
 		}
 	}
+out:
 	dev_put(dev);
 	return 0;
 }
@@ -2664,7 +2675,7 @@
 
 /*
  *	Initialize the DEV module. At boot time this walks the device list and
- *	unhooks any devices that fail to initialise (normally hardware not 
+ *	unhooks any devices that fail to initialise (normally hardware not
  *	present) and leaves us with a valid list of present and active devices.
  *
  */
@@ -2692,7 +2703,7 @@
 #ifdef CONFIG_NET_DIVERT
 	dv_init();
 #endif /* CONFIG_NET_DIVERT */
-	
+
 	/*
 	 *	Initialise the packet receive queues.
 	 */
@@ -2752,7 +2763,7 @@
 		if (strchr(dev->name, '%'))
 			dev_alloc_name(dev, dev->name);
 
-		/* 
+		/*
 		 * Check boot time settings for the device.
 		 */
 		netdev_boot_setup_check(dev);
@@ -2770,7 +2781,7 @@
 			dev->ifindex = dev_new_index();
 			if (dev->iflink == -1)
 				dev->iflink = dev->ifindex;
-			if (dev->rebuild_header == NULL)
+			if (!dev->rebuild_header)
 				dev->rebuild_header = default_rebuild_header;
 			dev_init_scheduler(dev);
 			set_bit(__LINK_STATE_PRESENT, &dev->state);
@@ -2815,7 +2826,7 @@
 	/*
 	 *	Initialise network devices
 	 */
-	 
+
 	net_device_init();
 
 	return 0;
@@ -2848,7 +2859,7 @@
 	envp [i++] = ifname;
 	envp [i++] = action_str;
 	envp [i] = 0;
-	
+
 	return call_usermodehelper(argv [0], argv, envp);
 }
 #endif
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Sat Jun  8 22:31:36 2002
+++ b/net/ipv4/af_inet.c	Sat Jun  8 22:31:36 2002
@@ -21,30 +21,34 @@
  *					so sockets that fail to connect
  *					don't return -EINPROGRESS.
  *		Alan Cox	:	Asynchronous I/O support
- *		Alan Cox	:	Keep correct socket pointer on sock structures
+ *		Alan Cox	:	Keep correct socket pointer on sock
+ *					structures
  *					when accept() ed
- *		Alan Cox	:	Semantics of SO_LINGER aren't state moved
- *					to close when you look carefully. With
- *					this fixed and the accept bug fixed 
+ *		Alan Cox	:	Semantics of SO_LINGER aren't state
+ *					moved to close when you look carefully.
+ *					With this fixed and the accept bug fixed
  *					some RPC stuff seems happier.
  *		Niibe Yutaka	:	4.4BSD style write async I/O
- *		Alan Cox, 
+ *		Alan Cox,
  *		Tony Gale 	:	Fixed reuse semantics.
  *		Alan Cox	:	bind() shouldn't abort existing but dead
  *					sockets. Stops FTP netin:.. I hope.
- *		Alan Cox	:	bind() works correctly for RAW sockets. Note
- *					that FreeBSD at least was broken in this respect
- *					so be careful with compatibility tests...
+ *		Alan Cox	:	bind() works correctly for RAW sockets.
+ *					Note that FreeBSD at least was broken
+ *					in this respect so be careful with
+ *					compatibility tests...
  *		Alan Cox	:	routing cache support
- *		Alan Cox	:	memzero the socket structure for compactness.
+ *		Alan Cox	:	memzero the socket structure for
+ *					compactness.
  *		Matt Day	:	nonblock connect error handler
  *		Alan Cox	:	Allow large numbers of pending sockets
  *					(eg for big web sites), but only if
  *					specifically application requested.
- *		Alan Cox	:	New buffering throughout IP. Used dumbly.
+ *		Alan Cox	:	New buffering throughout IP. Used
+ *					dumbly.
  *		Alan Cox	:	New buffering now used smartly.
- *		Alan Cox	:	BSD rather than common sense interpretation of
- *					listen.
+ *		Alan Cox	:	BSD rather than common sense
+ *					interpretation of listen.
  *		Germano Caronni	:	Assorted small races.
  *		Alan Cox	:	sendmsg/recvmsg basic support.
  *		Alan Cox	:	Only sendmsg/recvmsg now supported.
@@ -117,7 +121,7 @@
 #include <linux/wireless.h>		/* Note : will define WIRELESS_EXT */
 #endif	/* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */
 
-struct linux_mib net_statistics[NR_CPUS*2];
+struct linux_mib net_statistics[NR_CPUS * 2];
 
 #ifdef INET_REFCNT_DEBUG
 atomic_t inet_sock_nr;
@@ -132,7 +136,7 @@
 extern void ip_mc_drop_socket(struct sock *sk);
 
 #ifdef CONFIG_DLCI
-extern int dlci_ioctl(unsigned int, void*);
+extern int dlci_ioctl(unsigned int, void *);
 #endif
 
 #ifdef CONFIG_DLCI_MODULE
@@ -177,17 +181,18 @@
 		return;
 	}
 
-	BUG_TRAP(atomic_read(&sk->rmem_alloc) == 0);
-	BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0);
-	BUG_TRAP(sk->wmem_queued == 0);
-	BUG_TRAP(sk->forward_alloc == 0);
+	BUG_TRAP(!atomic_read(&sk->rmem_alloc));
+	BUG_TRAP(!atomic_read(&sk->wmem_alloc));
+	BUG_TRAP(!sk->wmem_queued);
+	BUG_TRAP(!sk->forward_alloc);
 
 	if (inet->opt)
 		kfree(inet->opt);
 	dst_release(sk->dst_cache);
 #ifdef INET_REFCNT_DEBUG
 	atomic_dec(&inet_sock_nr);
-	printk(KERN_DEBUG "INET socket %p released, %d are still alive\n", sk, atomic_read(&inet_sock_nr));
+	printk(KERN_DEBUG "INET socket %p released, %d are still alive\n",
+	       sk, atomic_read(&inet_sock_nr));
 #endif
 }
 
@@ -221,9 +226,9 @@
 	sock_orphan(sk);
 
 #ifdef INET_REFCNT_DEBUG
-	if (atomic_read(&sk->refcnt) != 1) {
-		printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n", sk, atomic_read(&sk->refcnt));
-	}
+	if (atomic_read(&sk->refcnt) != 1)
+		printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n",
+		       sk, atomic_read(&sk->refcnt));
 #endif
 	sock_put(sk);
 }
@@ -234,18 +239,16 @@
  *	socket object. Mostly it punts to the subprotocols of IP to do
  *	the work.
  */
- 
 
 /*
  *	Set socket options on an inet socket.
  */
- 
 int inet_setsockopt(struct socket *sock, int level, int optname,
 		    char *optval, int optlen)
 {
-	struct sock *sk=sock->sk;
+	struct sock *sk = sock->sk;
 
-	return sk->prot->setsockopt(sk,level,optname,optval,optlen);
+	return sk->prot->setsockopt(sk, level, optname, optval, optlen);
 }
 
 /*
@@ -259,9 +262,9 @@
 int inet_getsockopt(struct socket *sock, int level, int optname,
 		    char *optval, int *optlen)
 {
-	struct sock *sk=sock->sk;
+	struct sock *sk = sock->sk;
 
-	return sk->prot->getsockopt(sk,level,optname,optval,optlen);
+	return sk->prot->getsockopt(sk, level, optname, optval, optlen);
 }
 
 /*
@@ -270,11 +273,12 @@
 
 static int inet_autobind(struct sock *sk)
 {
-	struct inet_opt *inet = inet_sk(sk);
+	struct inet_opt *inet;
 	/* We may need to bind the socket. */
 	lock_sock(sk);
+	inet = inet_sk(sk);
 	if (!inet->num) {
-		if (sk->prot->get_port(sk, 0) != 0) {
+		if (sk->prot->get_port(sk, 0)) {
 			release_sock(sk);
 			return -EAGAIN;
 		}
@@ -287,7 +291,6 @@
 /*
  *	Move a socket into listening state.
  */
- 
 int inet_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
@@ -301,7 +304,7 @@
 		goto out;
 
 	old_state = sk->state;
-	if (!((1<<old_state)&(TCPF_CLOSE|TCPF_LISTEN)))
+	if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN)))
 		goto out;
 
 	/* Really, if the socket is already in listen state
@@ -349,16 +352,17 @@
 static int inet_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
-        struct list_head *p;
-        struct inet_protosw *answer;
+	struct list_head *p;
+	struct inet_protosw *answer;
 	struct inet_opt *inet;
+	int err = -ENOBUFS;
 
 	sock->state = SS_UNCONNECTED;
 	sk = sk_alloc(PF_INET, GFP_KERNEL, inet_sk_size(protocol),
 		      inet_sk_slab(protocol));
-	if (sk == NULL) 
-		goto do_oom;
-  
+	if (!sk)
+		goto out;
+
 	/* Look for the requested type/protocol pair. */
 	answer = NULL;
 	br_read_lock_bh(BR_NETPROTO_LOCK);
@@ -382,13 +386,16 @@
 	}
 	br_read_unlock_bh(BR_NETPROTO_LOCK);
 
+	err = -ESOCKTNOSUPPORT;
 	if (!answer)
-		goto free_and_badtype;
+		goto out_sk_free;
+	err = -EPERM;
 	if (answer->capability > 0 && !capable(answer->capability))
-		goto free_and_badperm;
+		goto out_sk_free;
+	err = -EPROTONOSUPPORT;
 	if (!protocol)
-		goto free_and_noproto;
-
+		goto out_sk_free;
+	err = 0;
 	sock->ops = answer->ops;
 	sk->prot = answer->prot;
 	sk->no_check = answer->no_check;
@@ -410,18 +417,15 @@
 
 	inet->id = 0;
 
-	sock_init_data(sock,sk);
+	sock_init_data(sock, sk);
 
 	sk->destruct = inet_sock_destruct;
-
 	sk->zapped	= 0;
 	sk->family	= PF_INET;
 	sk->protocol	= protocol;
-
 	sk->backlog_rcv = sk->prot->backlog_rcv;
 
 	inet->ttl	= sysctl_ip_default_ttl;
-
 	inet->mc_loop	= 1;
 	inet->mc_ttl	= 1;
 	inet->mc_index	= 0;
@@ -438,34 +442,20 @@
 		 * shares.
 		 */
 		inet->sport = htons(inet->num);
-
 		/* Add to protocol hash chains. */
 		sk->prot->hash(sk);
 	}
 
 	if (sk->prot->init) {
-		int err = sk->prot->init(sk);
-		if (err != 0) {
+		err = sk->prot->init(sk);
+		if (err)
 			inet_sock_release(sk);
-			return err;
-		}
 	}
-	return 0;
-
-free_and_badtype:
-	sk_free(sk);
-	return -ESOCKTNOSUPPORT;
-
-free_and_badperm:
-	sk_free(sk);
-	return -EPERM;
-
-free_and_noproto:
+out:
+	return err;
+out_sk_free:
 	sk_free(sk);
-	return -EPROTONOSUPPORT;
-
-do_oom:
-	return -ENOBUFS;
+	goto out;
 }
 
 
@@ -474,7 +464,6 @@
  *	function we are destroying the object and from then on nobody
  *	should refer to it.
  */
- 
 int inet_release(struct socket *sock)
 {
 	struct sock *sk = sock->sk;
@@ -498,7 +487,7 @@
 		sock->sk = NULL;
 		sk->prot->close(sk, timeout);
 	}
-	return(0);
+	return 0;
 }
 
 /* It is off by default, see below. */
@@ -506,19 +495,21 @@
 
 static int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
-	struct sockaddr_in *addr=(struct sockaddr_in *)uaddr;
-	struct sock *sk=sock->sk;
+	struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
+	struct sock *sk = sock->sk;
 	struct inet_opt *inet = inet_sk(sk);
 	unsigned short snum;
 	int chk_addr_ret;
 	int err;
 
 	/* If the socket has its own bind function then use it. (RAW) */
-	if(sk->prot->bind)
-		return sk->prot->bind(sk, uaddr, addr_len);
-
+	if (sk->prot->bind) {
+		err = sk->prot->bind(sk, uaddr, addr_len);
+		goto out;
+	}
+	err = -EINVAL;
 	if (addr_len < sizeof(struct sockaddr_in))
-		return -EINVAL;
+		goto out;
 
 	chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr);
 
@@ -529,17 +520,19 @@
 	 * (ie. your servers still start up even if your ISDN link
 	 *  is temporarily down)
 	 */
-	if (sysctl_ip_nonlocal_bind == 0 && 
-	    inet->freebind == 0 &&
+	err = -EADDRNOTAVAIL;
+	if (!sysctl_ip_nonlocal_bind &&
+	    !inet->freebind &&
 	    addr->sin_addr.s_addr != INADDR_ANY &&
 	    chk_addr_ret != RTN_LOCAL &&
 	    chk_addr_ret != RTN_MULTICAST &&
 	    chk_addr_ret != RTN_BROADCAST)
-		return -EADDRNOTAVAIL;
+		goto out;
 
 	snum = ntohs(addr->sin_port);
+	err = -EACCES;
 	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
-		return -EACCES;
+		goto out;
 
 	/*      We keep a pair of addresses. rcv_saddr is the one
 	 *      used by hash lookups, and saddr is used for transmit.
@@ -553,17 +546,17 @@
 	/* Check these errors (active socket, double bind). */
 	err = -EINVAL;
 	if (sk->state != TCP_CLOSE || inet->num)
-		goto out;
+		goto out_release_sock;
 
 	inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;
 	if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)
 		inet->saddr = 0;  /* Use device */
 
 	/* Make sure we are allowed to bind here. */
-	if (sk->prot->get_port(sk, snum) != 0) {
+	if (sk->prot->get_port(sk, snum)) {
 		inet->saddr = inet->rcv_saddr = 0;
 		err = -EADDRINUSE;
-		goto out;
+		goto out_release_sock;
 	}
 
 	if (inet->rcv_saddr)
@@ -575,15 +568,16 @@
 	inet->dport = 0;
 	sk_dst_reset(sk);
 	err = 0;
-out:
+out_release_sock:
 	release_sock(sk);
+out:
 	return err;
 }
 
 int inet_dgram_connect(struct socket *sock, struct sockaddr * uaddr,
 		       int addr_len, int flags)
 {
-	struct sock *sk=sock->sk;
+	struct sock *sk = sock->sk;
 
 	if (uaddr->sa_family == AF_UNSPEC)
 		return sk->prot->disconnect(sk, flags);
@@ -605,7 +599,7 @@
 	 * Connect() does not allow to get error notifications
 	 * without closing the socket.
 	 */
-	while ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
+	while ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 		release_sock(sk);
 		timeo = schedule_timeout(timeo);
 		lock_sock(sk);
@@ -622,11 +616,10 @@
  *	Connect to a remote host. There is regrettably still a little
  *	TCP 'magic' in here.
  */
- 
-int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr,
+int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr,
 			int addr_len, int flags)
 {
-	struct sock *sk=sock->sk;
+	struct sock *sk = sock->sk;
 	int err;
 	long timeo;
 
@@ -651,7 +644,7 @@
 		break;
 	case SS_UNCONNECTED:
 		err = -EISCONN;
-		if (sk->state != TCP_CLOSE) 
+		if (sk->state != TCP_CLOSE)
 			goto out;
 
 		err = sk->prot->connect(sk, uaddr, addr_len);
@@ -668,9 +661,9 @@
 		break;
 	}
 
-	timeo = sock_sndtimeo(sk, flags&O_NONBLOCK);
+	timeo = sock_sndtimeo(sk, flags & O_NONBLOCK);
 
-	if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {
+	if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) {
 		/* Error code is set above */
 		if (!timeo || !inet_wait_for_connect(sk, timeo))
 			goto out;
@@ -712,22 +705,22 @@
 int inet_accept(struct socket *sock, struct socket *newsock, int flags)
 {
 	struct sock *sk1 = sock->sk;
-	struct sock *sk2;
 	int err = -EINVAL;
+	struct sock *sk2 = sk1->prot->accept(sk1, flags, &err);
 
-	if((sk2 = sk1->prot->accept(sk1,flags,&err)) == NULL)
+	if (!sk2)
 		goto do_err;
 
 	lock_sock(sk2);
 
-	BUG_TRAP((1<<sk2->state)&(TCPF_ESTABLISHED|TCPF_CLOSE_WAIT|TCPF_CLOSE));
+	BUG_TRAP((1 << sk2->state) &
+		 (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE));
 
 	sock_graft(sk2, newsock);
 
 	newsock->state = SS_CONNECTED;
+	err = 0;
 	release_sock(sk2);
-	return 0;
-
 do_err:
 	return err;
 }
@@ -736,19 +729,18 @@
 /*
  *	This does both peername and sockname.
  */
- 
 static int inet_getname(struct socket *sock, struct sockaddr *uaddr,
-		 int *uaddr_len, int peer)
+			int *uaddr_len, int peer)
 {
 	struct sock *sk		= sock->sk;
 	struct inet_opt *inet	= inet_sk(sk);
 	struct sockaddr_in *sin	= (struct sockaddr_in *)uaddr;
-  
+
 	sin->sin_family = AF_INET;
 	if (peer) {
-		if (!inet->dport)
-			return -ENOTCONN;
-		if (((1<<sk->state)&(TCPF_CLOSE|TCPF_SYN_SENT)) && peer == 1)
+		if (!inet->dport ||
+		    (((1 << sk->state) & (TCPF_CLOSE | TCPF_SYN_SENT)) &&
+		     peer == 1))
 			return -ENOTCONN;
 		sin->sin_port = inet->dport;
 		sin->sin_addr.s_addr = inet->daddr;
@@ -760,7 +752,7 @@
 		sin->sin_addr.s_addr = addr;
 	}
 	*uaddr_len = sizeof(*sin);
-	return(0);
+	return 0;
 }
 
 
@@ -770,10 +762,8 @@
 {
 	struct sock *sk = sock->sk;
 	int addr_len = 0;
-	int err;
-
-	err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT,
-				flags&~MSG_DONTWAIT, &addr_len);
+	int err = sk->prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT,
+				    flags & ~MSG_DONTWAIT, &addr_len);
 	if (err >= 0)
 		msg->msg_namelen = addr_len;
 	return err;
@@ -803,12 +793,13 @@
 	how++; /* maps 0->1 has the advantage of making bit 1 rcvs and
 		       1->2 bit 2 snds.
 		       2->3 */
-	if ((how & ~SHUTDOWN_MASK) || how==0)	/* MAXINT->0 */
+	if ((how & ~SHUTDOWN_MASK) || !how)	/* MAXINT->0 */
 		return -EINVAL;
 
 	lock_sock(sk);
 	if (sock->state == SS_CONNECTING) {
-		if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE))
+		if ((1 << sk->state) &
+		    (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE))
 			sock->state = SS_DISCONNECTING;
 		else
 			sock->state = SS_CONNECTED;
@@ -858,38 +849,42 @@
 static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
 	struct sock *sk = sock->sk;
-	int err;
+	int err = 0;
 	int pid;
 
-	switch(cmd) {
+	switch (cmd) {
 		case FIOSETOWN:
 		case SIOCSPGRP:
-			err = get_user(pid, (int *) arg);
-			if (err)
-				return err; 
-			if (current->pid != pid && current->pgrp != -pid && 
-			    !capable(CAP_NET_ADMIN))
-				return -EPERM;
-			sk->proc = pid;
-			return(0);
+			if (get_user(pid, (int *)arg))
+				err = -EFAULT;
+			else if (current->pid != pid &&
+				 current->pgrp != -pid &&
+				!capable(CAP_NET_ADMIN))
+				err = -EPERM;
+			else
+				sk->proc = pid;
+			break;
 		case FIOGETOWN:
 		case SIOCGPGRP:
-			return put_user(sk->proc, (int *)arg);
+			err = put_user(sk->proc, (int *)arg);
+			break;
 		case SIOCGSTAMP:
-			if(sk->stamp.tv_sec==0)
-				return -ENOENT;
-			err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
-			if (err)
+			if (!sk->stamp.tv_sec)
+				err = -ENOENT;
+			else if (copy_to_user((void *)arg, &sk->stamp,
+					      sizeof(struct timeval)))
 				err = -EFAULT;
-			return err;
+			break;
 		case SIOCADDRT:
 		case SIOCDELRT:
 		case SIOCRTMSG:
-			return(ip_rt_ioctl(cmd,(void *) arg));
+			err = ip_rt_ioctl(cmd, (void *)arg);
+			break;
 		case SIOCDARP:
 		case SIOCGARP:
 		case SIOCSARP:
-			return(arp_ioctl(cmd,(void *) arg));
+			err = arp_ioctl(cmd, (void *)arg);
+			break;
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFBRDADDR:
@@ -898,83 +893,82 @@
 		case SIOCSIFNETMASK:
 		case SIOCGIFDSTADDR:
 		case SIOCSIFDSTADDR:
-		case SIOCSIFPFLAGS:	
-		case SIOCGIFPFLAGS:	
+		case SIOCSIFPFLAGS:
+		case SIOCGIFPFLAGS:
 		case SIOCSIFFLAGS:
-			return(devinet_ioctl(cmd,(void *) arg));
+			err = devinet_ioctl(cmd, (void *)arg);
+			break;
 		case SIOCGIFBR:
 		case SIOCSIFBR:
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 #ifdef CONFIG_KMOD
-			if (br_ioctl_hook == NULL)
+			if (!br_ioctl_hook)
 				request_module("bridge");
 #endif
-			if (br_ioctl_hook != NULL)
-				return br_ioctl_hook(arg);
+			if (br_ioctl_hook)
+				err = br_ioctl_hook(arg);
+			else
 #endif
-			return -ENOPKG;
-
+			err = -ENOPKG;
+			break;
 		case SIOCGIFVLAN:
 		case SIOCSIFVLAN:
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 #ifdef CONFIG_KMOD
-			if (vlan_ioctl_hook == NULL)
+			if (!vlan_ioctl_hook)
 				request_module("8021q");
 #endif
-			if (vlan_ioctl_hook != NULL)
-				return vlan_ioctl_hook(arg);
+			if (vlan_ioctl_hook)
+				err = vlan_ioctl_hook(arg);
+			else
 #endif
-			return -ENOPKG;
-
+			err = -ENOPKG;
+			break;
 		case SIOCGIFDIVERT:
 		case SIOCSIFDIVERT:
 #ifdef CONFIG_NET_DIVERT
-			return divert_ioctl(cmd, (struct divert_cf *) arg);
+			err = divert_ioctl(cmd, (struct divert_cf *)arg);
 #else
-			return -ENOPKG;
+			err = -ENOPKG;
 #endif	/* CONFIG_NET_DIVERT */
-			
+			break;
 		case SIOCADDDLCI:
 		case SIOCDELDLCI:
 #ifdef CONFIG_DLCI
 			lock_kernel();
-			err = dlci_ioctl(cmd, (void *) arg);
+			err = dlci_ioctl(cmd, (void *)arg);
 			unlock_kernel();
-			return err;
-#endif
-
-#ifdef CONFIG_DLCI_MODULE
-
+			break;
+#elif CONFIG_DLCI_MODULE
 #ifdef CONFIG_KMOD
-			if (dlci_ioctl_hook == NULL)
+			if (!dlci_ioctl_hook)
 				request_module("dlci");
 #endif
-
 			if (dlci_ioctl_hook) {
 				lock_kernel();
-				err = (*dlci_ioctl_hook)(cmd, (void *) arg);
+				err = (*dlci_ioctl_hook)(cmd, (void *)arg);
 				unlock_kernel();
-				return err;
-			}
+			} else
 #endif
-			return -ENOPKG;
-
+			err = -ENOPKG;
+			break;
 		default:
-			if ((cmd >= SIOCDEVPRIVATE) &&
-			    (cmd <= (SIOCDEVPRIVATE + 15)))
-				return(dev_ioctl(cmd,(void *) arg));
-
+			if (cmd >= SIOCDEVPRIVATE &&
+			    cmd <= (SIOCDEVPRIVATE + 15))
+				err = dev_ioctl(cmd, (void *)arg);
+			else
 #ifdef WIRELESS_EXT
-			if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST))
-				return(dev_ioctl(cmd,(void *) arg));
+			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+				err = dev_ioctl(cmd, (void *)arg);
+			else
 #endif	/* WIRELESS_EXT */
-
-			if (sk->prot->ioctl==NULL || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD)
-				return(dev_ioctl(cmd,(void *) arg));		
-			return err;
+			if (!sk->prot->ioctl ||
+			    (err = sk->prot->ioctl(sk, cmd, arg)) ==
+			    					-ENOIOCTLCMD)
+				err = dev_ioctl(cmd, (void *)arg);
+			break;
 	}
-	/*NOTREACHED*/
-	return(0);
+	return err;
 }
 
 struct proto_ops inet_stream_ops = {
@@ -985,7 +979,7 @@
 	connect:	inet_stream_connect,
 	socketpair:	sock_no_socketpair,
 	accept:		inet_accept,
-	getname:	inet_getname, 
+	getname:	inet_getname,
 	poll:		tcp_poll,
 	ioctl:		inet_ioctl,
 	listen:		inet_listen,
@@ -1006,7 +1000,7 @@
 	connect:	inet_dgram_connect,
 	socketpair:	sock_no_socketpair,
 	accept:		sock_no_accept,
-	getname:	inet_getname, 
+	getname:	inet_getname,
 	poll:		datagram_poll,
 	ioctl:		inet_ioctl,
 	listen:		sock_no_listen,
@@ -1067,8 +1061,7 @@
 
 #define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))
 
-void
-inet_register_protosw(struct inet_protosw *p)
+void inet_register_protosw(struct inet_protosw *p)
 {
 	struct list_head *lh;
 	struct inet_protosw *answer;
@@ -1115,8 +1108,7 @@
 	goto out;
 }
 
-void
-inet_unregister_protosw(struct inet_protosw *p)
+void inet_unregister_protosw(struct inet_protosw *p)
 {
 	if (INET_PROTOSW_PERMANENT & p->flags) {
 		printk(KERN_ERR
@@ -1133,7 +1125,7 @@
 /*
  *	Called by socket.c on kernel startup.  
  */
- 
+
 static int __init inet_init(void)
 {
 	struct sk_buff *dummy_skb;
@@ -1157,32 +1149,32 @@
 	raw4_sk_cachep = kmem_cache_create("raw4_sock",
 					   sizeof(struct raw_sock), 0,
 					   SLAB_HWCACHE_ALIGN, 0, 0);
-        if (!tcp_sk_cachep || !udp_sk_cachep || !raw4_sk_cachep)
+	if (!tcp_sk_cachep || !udp_sk_cachep || !raw4_sk_cachep)
 		printk(KERN_CRIT
 		       "inet_init: Can't create protocol sock SLAB caches!\n");
 	/*
 	 *	Tell SOCKET that we are alive... 
 	 */
-   
-  	(void) sock_register(&inet_family_ops);
+
+  	(void)sock_register(&inet_family_ops);
 
 	/*
 	 *	Add all the protocols. 
 	 */
 
 	printk(KERN_INFO "IP Protocols: ");
-	for (p = inet_protocol_base; p != NULL;) {
-		struct inet_protocol *tmp = (struct inet_protocol *) p->next;
+	for (p = inet_protocol_base; p;) {
+		struct inet_protocol *tmp = (struct inet_protocol *)p->next;
 		inet_add_protocol(p);
-		printk("%s%s",p->name,tmp?", ":"\n");
+		printk("%s%s", p->name, tmp ? ", " : "\n");
 		p = tmp;
 	}
 
 	/* Register the socket-side information for inet_create. */
-	for(r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
+	for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
 		INIT_LIST_HEAD(r);
 
-	for(q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
+	for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
 		inet_register_protosw(q);
 
 	/*
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Sat Jun  8 22:31:36 2002
+++ b/net/ipv4/devinet.c	Sat Jun  8 22:31:36 2002
@@ -18,16 +18,17 @@
  *		Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  *
  *	Changes:
- *	        Alexey Kuznetsov:	pa_* fields are replaced with ifaddr lists.
+ *		Alexey Kuznetsov:	pa_* fields are replaced with ifaddr
+ *					lists.
  *		Cyrus Durgin:		updated for kmod
- *		Matthias Andree:	in devinet_ioctl, compare label and 
+ *		Matthias Andree:	in devinet_ioctl, compare label and
  *					address (4.4BSD alias style support),
  *					fall back to comparing just the label
  *					if no match found.
  */
 
 #include <linux/config.h>
- 
+
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -60,15 +61,29 @@
 #include <net/route.h>
 #include <net/ip_fib.h>
 
-struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, };
-static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, };
+struct ipv4_devconf ipv4_devconf = {
+	accept_redirects: 1,
+	send_redirects:	  1,
+	secure_redirects: 1,
+	shared_media:	  1,
+};
+
+static struct ipv4_devconf ipv4_devconf_dflt = {
+	accept_redirects:    1,
+	send_redirects:      1,
+	secure_redirects:    1,
+	shared_media:	     1,
+	accept_source_route: 1,
+};
 
 static void rtmsg_ifa(int event, struct in_ifaddr *);
 
 static struct notifier_block *inetaddr_chain;
-static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy);
+static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+			 int destroy);
 #ifdef CONFIG_SYSCTL
-static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p);
+static void devinet_sysctl_register(struct in_device *in_dev,
+				    struct ipv4_devconf *p);
 static void devinet_sysctl_unregister(struct ipv4_devconf *p);
 #endif
 
@@ -79,12 +94,10 @@
 
 rwlock_t inetdev_lock = RW_LOCK_UNLOCKED;
 
-
-static struct in_ifaddr * inet_alloc_ifa(void)
+static struct in_ifaddr *inet_alloc_ifa(void)
 {
-	struct in_ifaddr *ifa;
+	struct in_ifaddr *ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
 
-	ifa = kmalloc(sizeof(*ifa), GFP_KERNEL);
 	if (ifa) {
 		memset(ifa, 0, sizeof(*ifa));
 		inet_ifa_count++;
@@ -105,18 +118,19 @@
 {
 	struct net_device *dev = idev->dev;
 
-	BUG_TRAP(idev->ifa_list==NULL);
-	BUG_TRAP(idev->mc_list==NULL);
+	BUG_TRAP(!idev->ifa_list);
+	BUG_TRAP(!idev->mc_list);
 #ifdef NET_REFCNT_DEBUG
-	printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n", idev, dev ? dev->name : "NIL");
+	printk(KERN_DEBUG "in_dev_finish_destroy: %p=%s\n",
+	       idev, dev ? dev->name : "NIL");
 #endif
 	dev_put(dev);
-	if (!idev->dead) {
+	if (!idev->dead)
 		printk("Freeing alive in_device %p\n", idev);
-		return;
+	else {
+		inet_dev_count--;
+		kfree(idev);
 	}
-	inet_dev_count--;
-	kfree(idev);
 }
 
 struct in_device *inetdev_init(struct net_device *dev)
@@ -127,21 +141,20 @@
 
 	in_dev = kmalloc(sizeof(*in_dev), GFP_KERNEL);
 	if (!in_dev)
-		return NULL;
+		goto out;
 	memset(in_dev, 0, sizeof(*in_dev));
 	in_dev->lock = RW_LOCK_UNLOCKED;
 	memcpy(&in_dev->cnf, &ipv4_devconf_dflt, sizeof(in_dev->cnf));
 	in_dev->cnf.sysctl = NULL;
 	in_dev->dev = dev;
-	if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL) {
-		kfree(in_dev);
-		return NULL;
-	}
+	if ((in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl)) == NULL)
+		goto out_kfree;
 	inet_dev_count++;
 	/* Reference in_dev->dev */
 	dev_hold(dev);
 #ifdef CONFIG_SYSCTL
-	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
+	neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
+			      NET_IPV4_NEIGH, "ipv4");
 #endif
 	write_lock_bh(&inetdev_lock);
 	dev->ip_ptr = in_dev;
@@ -151,9 +164,14 @@
 #ifdef CONFIG_SYSCTL
 	devinet_sysctl_register(in_dev, &in_dev->cnf);
 #endif
-	if (dev->flags&IFF_UP)
+	if (dev->flags & IFF_UP)
 		ip_mc_up(in_dev);
+out:
 	return in_dev;
+out_kfree:
+	kfree(in_dev);
+	in_dev = NULL;
+	goto out;
 }
 
 static void inetdev_destroy(struct in_device *in_dev)
@@ -197,10 +215,10 @@
 	} endfor_ifa(in_dev);
 	read_unlock(&in_dev->lock);
 	return 0;
-} 
+}
 
-static void
-inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
+static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
+			 int destroy)
 {
 	struct in_ifaddr *ifa1 = *ifap;
 
@@ -208,12 +226,12 @@
 
 	/* 1. Deleting primary ifaddr forces deletion all secondaries */
 
-	if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) {
+	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
 		struct in_ifaddr *ifa;
 		struct in_ifaddr **ifap1 = &ifa1->ifa_next;
 
-		while ((ifa=*ifap1) != NULL) {
-			if (!(ifa->ifa_flags&IFA_F_SECONDARY) ||
+		while ((ifa = *ifap1) != NULL) {
+			if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
 			    ifa1->ifa_mask != ifa->ifa_mask ||
 			    !inet_ifa_match(ifa1->ifa_address, ifa)) {
 				ifap1 = &ifa->ifa_next;
@@ -250,20 +268,19 @@
 	if (destroy) {
 		inet_free_ifa(ifa1);
 
-		if (in_dev->ifa_list == NULL)
+		if (!in_dev->ifa_list)
 			inetdev_destroy(in_dev);
 	}
 }
 
-static int
-inet_insert_ifa(struct in_ifaddr *ifa)
+static int inet_insert_ifa(struct in_ifaddr *ifa)
 {
 	struct in_device *in_dev = ifa->ifa_dev;
 	struct in_ifaddr *ifa1, **ifap, **last_primary;
 
 	ASSERT_RTNL();
 
-	if (ifa->ifa_local == 0) {
+	if (!ifa->ifa_local) {
 		inet_free_ifa(ifa);
 		return 0;
 	}
@@ -271,10 +288,13 @@
 	ifa->ifa_flags &= ~IFA_F_SECONDARY;
 	last_primary = &in_dev->ifa_list;
 
-	for (ifap=&in_dev->ifa_list; (ifa1=*ifap)!=NULL; ifap=&ifa1->ifa_next) {
-		if (!(ifa1->ifa_flags&IFA_F_SECONDARY) && ifa->ifa_scope <= ifa1->ifa_scope)
+	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
+	     ifap = &ifa1->ifa_next) {
+		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
+		    ifa->ifa_scope <= ifa1->ifa_scope)
 			last_primary = &ifa1->ifa_next;
-		if (ifa1->ifa_mask == ifa->ifa_mask && inet_ifa_match(ifa1->ifa_address, ifa)) {
+		if (ifa1->ifa_mask == ifa->ifa_mask &&
+		    inet_ifa_match(ifa1->ifa_address, ifa)) {
 			if (ifa1->ifa_local == ifa->ifa_local) {
 				inet_free_ifa(ifa);
 				return -EEXIST;
@@ -287,7 +307,7 @@
 		}
 	}
 
-	if (!(ifa->ifa_flags&IFA_F_SECONDARY)) {
+	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
 		net_srandom(ifa->ifa_local);
 		ifap = last_primary;
 	}
@@ -306,24 +326,23 @@
 	return 0;
 }
 
-static int
-inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
+static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
 {
 	struct in_device *in_dev = __in_dev_get(dev);
 
 	ASSERT_RTNL();
 
-	if (in_dev == NULL) {
+	if (!in_dev) {
 		in_dev = inetdev_init(dev);
-		if (in_dev == NULL) {
+		if (!in_dev) {
 			inet_free_ifa(ifa);
 			return -ENOBUFS;
 		}
 	}
 	if (ifa->ifa_dev != in_dev) {
-		BUG_TRAP(ifa->ifa_dev==NULL);
+		BUG_TRAP(!ifa->ifa_dev);
 		in_dev_hold(in_dev);
-		ifa->ifa_dev=in_dev;
+		ifa->ifa_dev = in_dev;
 	}
 	if (LOOPBACK(ifa->ifa_local))
 		ifa->ifa_scope = RT_SCOPE_HOST;
@@ -344,7 +363,8 @@
 
 /* Called only from RTNL semaphored context. No locks. */
 
-struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask)
+struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
+				    u32 mask)
 {
 	ASSERT_RTNL();
 
@@ -355,10 +375,9 @@
 	return NULL;
 }
 
-int
-inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
-	struct rtattr  **rta = arg;
+	struct rtattr **rta = arg;
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in_ifaddr *ifa, **ifap;
@@ -366,93 +385,103 @@
 	ASSERT_RTNL();
 
 	if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
-		return -EADDRNOTAVAIL;
+		goto out;
 	__in_dev_put(in_dev);
 
-	for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) {
-		if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
-		    (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)) ||
-		    (rta[IFA_ADDRESS-1] &&
+	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+	     ifap = &ifa->ifa_next) {
+		if ((rta[IFA_LOCAL - 1] &&
+		     memcmp(RTA_DATA(rta[IFA_LOCAL - 1]),
+			    &ifa->ifa_local, 4)) ||
+		    (rta[IFA_LABEL - 1] &&
+		     strcmp(RTA_DATA(rta[IFA_LABEL - 1]), ifa->ifa_label)) ||
+		    (rta[IFA_ADDRESS - 1] &&
 		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
-		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS-1]), ifa))))
+		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS - 1]),
+			      	      ifa))))
 			continue;
 		inet_del_ifa(in_dev, ifap, 1);
 		return 0;
 	}
-
+out:
 	return -EADDRNOTAVAIL;
 }
 
-int
-inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
 	struct rtattr **rta = arg;
 	struct net_device *dev;
 	struct in_device *in_dev;
 	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
 	struct in_ifaddr *ifa;
+	int rc = -EINVAL;
 
 	ASSERT_RTNL();
 
-	if (ifm->ifa_prefixlen > 32 || rta[IFA_LOCAL-1] == NULL)
-		return -EINVAL;
+	if (ifm->ifa_prefixlen > 32 || !rta[IFA_LOCAL - 1])
+		goto out;
 
+	rc = -ENODEV;
 	if ((dev = __dev_get_by_index(ifm->ifa_index)) == NULL)
-		return -ENODEV;
+		goto out;
 
+	rc = -ENOBUFS;
 	if ((in_dev = __in_dev_get(dev)) == NULL) {
 		in_dev = inetdev_init(dev);
 		if (!in_dev)
-			return -ENOBUFS;
+			goto out;
 	}
 
 	if ((ifa = inet_alloc_ifa()) == NULL)
-		return -ENOBUFS;
+		goto out;
 
-	if (rta[IFA_ADDRESS-1] == NULL)
-		rta[IFA_ADDRESS-1] = rta[IFA_LOCAL-1];
-	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL-1]), 4);
-	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS-1]), 4);
+	if (!rta[IFA_ADDRESS - 1])
+		rta[IFA_ADDRESS - 1] = rta[IFA_LOCAL - 1];
+	memcpy(&ifa->ifa_local, RTA_DATA(rta[IFA_LOCAL - 1]), 4);
+	memcpy(&ifa->ifa_address, RTA_DATA(rta[IFA_ADDRESS - 1]), 4);
 	ifa->ifa_prefixlen = ifm->ifa_prefixlen;
 	ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen);
-	if (rta[IFA_BROADCAST-1])
-		memcpy(&ifa->ifa_broadcast, RTA_DATA(rta[IFA_BROADCAST-1]), 4);
-	if (rta[IFA_ANYCAST-1])
-		memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST-1]), 4);
+	if (rta[IFA_BROADCAST - 1])
+		memcpy(&ifa->ifa_broadcast,
+		       RTA_DATA(rta[IFA_BROADCAST - 1]), 4);
+	if (rta[IFA_ANYCAST - 1])
+		memcpy(&ifa->ifa_anycast, RTA_DATA(rta[IFA_ANYCAST - 1]), 4);
 	ifa->ifa_flags = ifm->ifa_flags;
 	ifa->ifa_scope = ifm->ifa_scope;
 	in_dev_hold(in_dev);
-	ifa->ifa_dev = in_dev;
-	if (rta[IFA_LABEL-1])
-		memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
+	ifa->ifa_dev   = in_dev;
+	if (rta[IFA_LABEL - 1])
+		memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL - 1]), IFNAMSIZ);
 	else
 		memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
-	return inet_insert_ifa(ifa);
+	rc = inet_insert_ifa(ifa);
+out:
+	return rc;
 }
 
-/* 
- *	Determine a default network mask, based on the IP address. 
+/*
+ *	Determine a default network mask, based on the IP address.
  */
 
 static __inline__ int inet_abc_len(u32 addr)
 {
-  	if (ZERONET(addr))
-  		return 0;
+	int rc = -1;	/* Something else, probably a multicast. */
 
-  	addr = ntohl(addr);
-  	if (IN_CLASSA(addr)) 
-  		return 8;
-  	if (IN_CLASSB(addr)) 
-  		return 16;
-  	if (IN_CLASSC(addr)) 
-  		return 24;
+  	if (ZERONET(addr))
+  		rc = 0;
+	else {
+		addr = ntohl(addr);
+
+		if (IN_CLASSA(addr))
+			rc = 8;
+		else if (IN_CLASSB(addr))
+			rc = 16;
+		else if (IN_CLASSC(addr))
+			rc = 24;
+	}
 
-	/*
-	 *	Something else, probably a multicast. 
-	 */
-  	 
-  	return -1;
+  	return rc;
 }
 
 
@@ -466,7 +495,7 @@
 	struct in_ifaddr *ifa = NULL;
 	struct net_device *dev;
 	char *colon;
-	int ret = 0;
+	int ret = -EFAULT;
 	int tryaddrmatch = 0;
 
 	/*
@@ -474,8 +503,8 @@
 	 */
 
 	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
-		return -EFAULT;
-	ifr.ifr_name[IFNAMSIZ-1] = 0;
+		goto out;
+	ifr.ifr_name[IFNAMSIZ - 1] = 0;
 
 	/* save original address for comparison */
 	memcpy(&sin_orig, sin, sizeof(*sin));
@@ -503,215 +532,222 @@
 		break;
 
 	case SIOCSIFFLAGS:
+		ret = -EACCES;
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			goto out;
 		break;
 	case SIOCSIFADDR:	/* Set interface address (and family) */
 	case SIOCSIFBRDADDR:	/* Set the broadcast address */
 	case SIOCSIFDSTADDR:	/* Set the destination address */
 	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
+		ret = -EACCES;
 		if (!capable(CAP_NET_ADMIN))
-			return -EACCES;
+			goto out;
+		ret = -EINVAL;
 		if (sin->sin_family != AF_INET)
-			return -EINVAL;
+			goto out;
 		break;
 	default:
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	dev_probe_lock();
 	rtnl_lock();
 
-	if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
-		ret = -ENODEV;
+	ret = -ENODEV;
+	if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL)
 		goto done;
-	}
 
 	if (colon)
 		*colon = ':';
 
-	if ((in_dev=__in_dev_get(dev)) != NULL) {
+	if ((in_dev = __in_dev_get(dev)) != NULL) {
 		if (tryaddrmatch) {
 			/* Matthias Andree */
 			/* compare label and address (4.4BSD style) */
 			/* note: we only do this for a limited set of ioctls
 			   and only if the original address family was AF_INET.
 			   This is checked above. */
-			for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next) {
-				if ((strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
-				    && (sin_orig.sin_addr.s_addr == ifa->ifa_address)) {
+			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+			     ifap = &ifa->ifa_next) {
+				if (!strcmp(ifr.ifr_name, ifa->ifa_label) &&
+				    sin_orig.sin_addr.s_addr ==
+							ifa->ifa_address) {
 					break; /* found */
 				}
 			}
 		}
 		/* we didn't get a match, maybe the application is
-		   4.3BSD-style and passed in junk so we fall back to 
+		   4.3BSD-style and passed in junk so we fall back to
 		   comparing just the label */
-		if (ifa == NULL) {
-			for (ifap=&in_dev->ifa_list; (ifa=*ifap) != NULL; ifap=&ifa->ifa_next)
-				if (strcmp(ifr.ifr_name, ifa->ifa_label) == 0)
+		if (!ifa) {
+			for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
+			     ifap = &ifa->ifa_next)
+				if (!strcmp(ifr.ifr_name, ifa->ifa_label))
 					break;
 		}
 	}
 
-	if (ifa == NULL && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) {
-		ret = -EADDRNOTAVAIL;
+	ret = -EADDRNOTAVAIL;
+	if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
 		goto done;
-	}
 
 	switch(cmd) {
-		case SIOCGIFADDR:	/* Get interface address */
-			sin->sin_addr.s_addr = ifa->ifa_local;
-			goto rarok;
-
-		case SIOCGIFBRDADDR:	/* Get the broadcast address */
-			sin->sin_addr.s_addr = ifa->ifa_broadcast;
-			goto rarok;
-
-		case SIOCGIFDSTADDR:	/* Get the destination address */
-			sin->sin_addr.s_addr = ifa->ifa_address;
-			goto rarok;
-
-		case SIOCGIFNETMASK:	/* Get the netmask for the interface */
-			sin->sin_addr.s_addr = ifa->ifa_mask;
-			goto rarok;
-
-		case SIOCSIFFLAGS:
-			if (colon) {
-				if (ifa == NULL) {
-					ret = -EADDRNOTAVAIL;
-					break;
-				}
-				if (!(ifr.ifr_flags&IFF_UP))
-					inet_del_ifa(in_dev, ifap, 1);
+	case SIOCGIFADDR:	/* Get interface address */
+		sin->sin_addr.s_addr = ifa->ifa_local;
+		goto rarok;
+
+	case SIOCGIFBRDADDR:	/* Get the broadcast address */
+		sin->sin_addr.s_addr = ifa->ifa_broadcast;
+		goto rarok;
+
+	case SIOCGIFDSTADDR:	/* Get the destination address */
+		sin->sin_addr.s_addr = ifa->ifa_address;
+		goto rarok;
+
+	case SIOCGIFNETMASK:	/* Get the netmask for the interface */
+		sin->sin_addr.s_addr = ifa->ifa_mask;
+		goto rarok;
+
+	case SIOCSIFFLAGS:
+		if (colon) {
+			ret = -EADDRNOTAVAIL;
+			if (!ifa)
 				break;
-			}
-			ret = dev_change_flags(dev, ifr.ifr_flags);
+			ret = 0;
+			if (!(ifr.ifr_flags & IFF_UP))
+				inet_del_ifa(in_dev, ifap, 1);
 			break;
-	
-		case SIOCSIFADDR:	/* Set interface address (and family) */
-			if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
-				ret = -EINVAL;
+		}
+		ret = dev_change_flags(dev, ifr.ifr_flags);
+		break;
+
+	case SIOCSIFADDR:	/* Set interface address (and family) */
+		ret = -EINVAL;
+		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
+			break;
+
+		if (!ifa) {
+			ret = -ENOBUFS;
+			if ((ifa = inet_alloc_ifa()) == NULL)
 				break;
-			}
+			if (colon)
+				memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
+			else
+				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
+		} else {
+			ret = 0;
+			if (ifa->ifa_local == sin->sin_addr.s_addr)
+				break;
+			inet_del_ifa(in_dev, ifap, 0);
+			ifa->ifa_broadcast = 0;
+			ifa->ifa_anycast = 0;
+		}
 
-			if (!ifa) {
-				if ((ifa = inet_alloc_ifa()) == NULL) {
-					ret = -ENOBUFS;
-					break;
-				}
-				if (colon)
-					memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ);
-				else
-					memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
-			} else {
-				ret = 0;
-				if (ifa->ifa_local == sin->sin_addr.s_addr)
-					break;
-				inet_del_ifa(in_dev, ifap, 0);
-				ifa->ifa_broadcast = 0;
-				ifa->ifa_anycast = 0;
-			}
+		ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr;
 
-			ifa->ifa_address =
-			ifa->ifa_local = sin->sin_addr.s_addr;
+		if (!(dev->flags & IFF_POINTOPOINT)) {
+			ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
+			ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
+			if ((dev->flags & IFF_BROADCAST) &&
+			    ifa->ifa_prefixlen < 31)
+				ifa->ifa_broadcast = ifa->ifa_address |
+						     ~ifa->ifa_mask;
+		} else {
+			ifa->ifa_prefixlen = 32;
+			ifa->ifa_mask = inet_make_mask(32);
+		}
+		ret = inet_set_ifa(dev, ifa);
+		break;
 
-			if (!(dev->flags&IFF_POINTOPOINT)) {
-				ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address);
-				ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen);
-				if ((dev->flags&IFF_BROADCAST) && ifa->ifa_prefixlen < 31)
-					ifa->ifa_broadcast = ifa->ifa_address|~ifa->ifa_mask;
-			} else {
-				ifa->ifa_prefixlen = 32;
-				ifa->ifa_mask = inet_make_mask(32);
-			}
-			ret = inet_set_ifa(dev, ifa);
-			break;
+	case SIOCSIFBRDADDR:	/* Set the broadcast address */
+		ret = 0;
+		if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
+			inet_del_ifa(in_dev, ifap, 0);
+			ifa->ifa_broadcast = sin->sin_addr.s_addr;
+			inet_insert_ifa(ifa);
+		}
+		break;
 
-		case SIOCSIFBRDADDR:	/* Set the broadcast address */
-			if (ifa->ifa_broadcast != sin->sin_addr.s_addr) {
-				inet_del_ifa(in_dev, ifap, 0);
-				ifa->ifa_broadcast = sin->sin_addr.s_addr;
-				inet_insert_ifa(ifa);
-			}
+	case SIOCSIFDSTADDR:	/* Set the destination address */
+		ret = 0;
+		if (ifa->ifa_address == sin->sin_addr.s_addr)
 			break;
-	
-		case SIOCSIFDSTADDR:	/* Set the destination address */
-			if (ifa->ifa_address != sin->sin_addr.s_addr) {
-				if (inet_abc_len(sin->sin_addr.s_addr) < 0) {
-					ret = -EINVAL;
-					break;
-				}
-				inet_del_ifa(in_dev, ifap, 0);
-				ifa->ifa_address = sin->sin_addr.s_addr;
-				inet_insert_ifa(ifa);
-			}
+		ret = -EINVAL;
+		if (inet_abc_len(sin->sin_addr.s_addr) < 0)
 			break;
+		ret = 0;
+		inet_del_ifa(in_dev, ifap, 0);
+		ifa->ifa_address = sin->sin_addr.s_addr;
+		inet_insert_ifa(ifa);
+		break;
 
-		case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
-
-			/*
-			 *	The mask we set must be legal.
-			 */
-			if (bad_mask(sin->sin_addr.s_addr, 0)) {
-				ret = -EINVAL;
-				break;
-			}
+	case SIOCSIFNETMASK: 	/* Set the netmask for the interface */
 
-			if (ifa->ifa_mask != sin->sin_addr.s_addr) {
-				inet_del_ifa(in_dev, ifap, 0);
-				ifa->ifa_mask = sin->sin_addr.s_addr;
-				ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
-				inet_insert_ifa(ifa);
-			}
+		/*
+		 *	The mask we set must be legal.
+		 */
+		ret = -EINVAL;
+		if (bad_mask(sin->sin_addr.s_addr, 0))
 			break;
+		ret = 0;
+		if (ifa->ifa_mask != sin->sin_addr.s_addr) {
+			inet_del_ifa(in_dev, ifap, 0);
+			ifa->ifa_mask = sin->sin_addr.s_addr;
+			ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
+			inet_insert_ifa(ifa);
+		}
+		break;
 	}
 done:
 	rtnl_unlock();
 	dev_probe_unlock();
+out:
 	return ret;
-
 rarok:
 	rtnl_unlock();
 	dev_probe_unlock();
-	if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-		return -EFAULT;
-	return 0;
+	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
+	goto out;
 }
 
-static int
-inet_gifconf(struct net_device *dev, char *buf, int len)
+static int inet_gifconf(struct net_device *dev, char *buf, int len)
 {
 	struct in_device *in_dev = __in_dev_get(dev);
 	struct in_ifaddr *ifa;
 	struct ifreq ifr;
-	int done=0;
+	int done = 0;
 
-	if (in_dev==NULL || (ifa=in_dev->ifa_list)==NULL)
-		return 0;
+	if (!in_dev || (ifa = in_dev->ifa_list) == NULL)
+		goto out;
 
-	for ( ; ifa; ifa = ifa->ifa_next) {
+	for (; ifa; ifa = ifa->ifa_next) {
 		if (!buf) {
 			done += sizeof(ifr);
 			continue;
 		}
 		if (len < (int) sizeof(ifr))
-			return done;
+			break;
 		memset(&ifr, 0, sizeof(struct ifreq));
 		if (ifa->ifa_label)
 			strcpy(ifr.ifr_name, ifa->ifa_label);
 		else
 			strcpy(ifr.ifr_name, dev->name);
 
-		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = AF_INET;
-		(*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = ifa->ifa_local;
+		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET;
+		(*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr =
+								ifa->ifa_local;
 
-		if (copy_to_user(buf, &ifr, sizeof(struct ifreq)))
-			return -EFAULT;
-		buf += sizeof(struct ifreq);
-		len -= sizeof(struct ifreq);
+		if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) {
+			done = -EFAULT;
+			break;
+		}
+		buf  += sizeof(struct ifreq);
+		len  -= sizeof(struct ifreq);
 		done += sizeof(struct ifreq);
 	}
+out:
 	return done;
 }
 
@@ -722,10 +758,8 @@
 
 	read_lock(&inetdev_lock);
 	in_dev = __in_dev_get(dev);
-	if (in_dev == NULL) {
-		read_unlock(&inetdev_lock);
-		return 0;
-	}
+	if (!in_dev)
+		goto out_unlock_inetdev;
 
 	read_lock(&in_dev->lock);
 	for_primary_ifa(in_dev) {
@@ -742,7 +776,7 @@
 	read_unlock(&inetdev_lock);
 
 	if (addr)
-		return addr;
+		goto out;
 
 	/* Not loopback addresses on loopback should be preferred
 	   in this case. It is importnat that lo is the first interface
@@ -750,8 +784,8 @@
 	 */
 	read_lock(&dev_base_lock);
 	read_lock(&inetdev_lock);
-	for (dev=dev_base; dev; dev=dev->next) {
-		if ((in_dev=__in_dev_get(dev)) == NULL)
+	for (dev = dev_base; dev; dev = dev->next) {
+		if ((in_dev = __in_dev_get(dev)) == NULL)
 			continue;
 
 		read_lock(&in_dev->lock);
@@ -759,17 +793,20 @@
 			if (ifa->ifa_scope != RT_SCOPE_LINK &&
 			    ifa->ifa_scope <= scope) {
 				read_unlock(&in_dev->lock);
-				read_unlock(&inetdev_lock);
-				read_unlock(&dev_base_lock);
-				return ifa->ifa_local;
+				addr = ifa->ifa_local;
+				goto out_unlock_both;
 			}
 		} endfor_ifa(in_dev);
 		read_unlock(&in_dev->lock);
 	}
+out_unlock_both:
 	read_unlock(&inetdev_lock);
 	read_unlock(&dev_base_lock);
-
-	return 0;
+out:
+	return addr;
+out_unlock_inetdev:
+	read_unlock(&inetdev_lock);
+	goto out;
 }
 
 /*
@@ -783,20 +820,21 @@
 
 int unregister_inetaddr_notifier(struct notifier_block *nb)
 {
-	return notifier_chain_unregister(&inetaddr_chain,nb);
+	return notifier_chain_unregister(&inetaddr_chain, nb);
 }
 
 /* Called only under RTNL semaphore */
 
-static int inetdev_event(struct notifier_block *this, unsigned long event, void *ptr)
+static int inetdev_event(struct notifier_block *this, unsigned long event,
+			 void *ptr)
 {
 	struct net_device *dev = ptr;
 	struct in_device *in_dev = __in_dev_get(dev);
 
 	ASSERT_RTNL();
 
-	if (in_dev == NULL)
-		return NOTIFY_DONE;
+	if (!in_dev)
+		goto out;
 
 	switch (event) {
 	case NETDEV_REGISTER:
@@ -810,7 +848,7 @@
 			struct in_ifaddr *ifa;
 			if ((ifa = inet_alloc_ifa()) != NULL) {
 				ifa->ifa_local =
-				ifa->ifa_address = htonl(INADDR_LOOPBACK);
+				  ifa->ifa_address = htonl(INADDR_LOOPBACK);
 				ifa->ifa_prefixlen = 8;
 				ifa->ifa_mask = inet_make_mask(8);
 				in_dev_hold(in_dev);
@@ -843,7 +881,7 @@
 		}
 		break;
 	}
-
+out:
 	return NOTIFY_DONE;
 }
 
@@ -887,15 +925,14 @@
 static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
 {
 	int idx, ip_idx;
-	int s_idx, s_ip_idx;
 	struct net_device *dev;
 	struct in_device *in_dev;
 	struct in_ifaddr *ifa;
+	int s_ip_idx, s_idx = cb->args[0];
 
-	s_idx = cb->args[0];
 	s_ip_idx = ip_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
 		if (idx < s_idx)
 			continue;
 		if (idx > s_idx)
@@ -911,7 +948,8 @@
 			if (ip_idx < s_ip_idx)
 				continue;
 			if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
-					     cb->nlh->nlmsg_seq, RTM_NEWADDR) <= 0) {
+					     cb->nlh->nlmsg_seq,
+					     RTM_NEWADDR) <= 0) {
 				read_unlock(&in_dev->lock);
 				read_unlock(&inetdev_lock);
 				goto done;
@@ -929,65 +967,39 @@
 	return skb->len;
 }
 
-static void rtmsg_ifa(int event, struct in_ifaddr * ifa)
+static void rtmsg_ifa(int event, struct in_ifaddr* ifa)
 {
-	struct sk_buff *skb;
-	int size = NLMSG_SPACE(sizeof(struct ifaddrmsg)+128);
+	int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + 128);
+	struct sk_buff *skb = alloc_skb(size, GFP_KERNEL);
 
-	skb = alloc_skb(size, GFP_KERNEL);
-	if (!skb) {
+	if (!skb)
 		netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, ENOBUFS);
-		return;
-	}
-	if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
+	else if (inet_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
 		kfree_skb(skb);
 		netlink_set_err(rtnl, 0, RTMGRP_IPV4_IFADDR, EINVAL);
-		return;
+	} else {
+		NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR;
+		netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);
 	}
-	NETLINK_CB(skb).dst_groups = RTMGRP_IPV4_IFADDR;
-	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV4_IFADDR, GFP_KERNEL);
 }
 
-
-static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
-{
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-
-	{ inet_rtm_newaddr,	NULL,			},
-	{ inet_rtm_deladdr,	NULL,			},
-	{ NULL,			inet_dump_ifaddr,	},
-	{ NULL,			NULL,			},
-
-	{ inet_rtm_newroute,	NULL,			},
-	{ inet_rtm_delroute,	NULL,			},
-	{ inet_rtm_getroute,	inet_dump_fib,		},
-	{ NULL,			NULL,			},
-
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-
+static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
+	 [4] = { doit:	 inet_rtm_newaddr,  },
+	 [5] = { doit:	 inet_rtm_deladdr,  },
+	 [6] = { dumpit: inet_dump_ifaddr,  },
+	 [8] = { doit:	 inet_rtm_newroute, },
+	 [9] = { doit:	 inet_rtm_delroute, },
+	[10] = { doit:	 inet_rtm_getroute, dumpit: inet_dump_fib, },
 #ifdef CONFIG_IP_MULTIPLE_TABLES
-	{ inet_rtm_newrule,	NULL,			},
-	{ inet_rtm_delrule,	NULL,			},
-	{ NULL,			inet_dump_rules,	},
-	{ NULL,			NULL,			},
-#else
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
+	[16] = { doit:	 inet_rtm_newrule, },
+	[17] = { doit:	 inet_rtm_delrule, },
+	[18] = { dumpit: inet_dump_rules,  },
 #endif
 };
 
-
 #ifdef CONFIG_SYSCTL
 
-void inet_forward_change()
+void inet_forward_change(void)
 {
 	struct net_device *dev;
 	int on = ipv4_devconf.forwarding;
@@ -1009,15 +1021,13 @@
 	rt_cache_flush(0);
 }
 
-static
-int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
-			   void *buffer, size_t *lenp)
+static int devinet_sysctl_forward(ctl_table *ctl, int write,
+				  struct file* filp, void *buffer,
+				  size_t *lenp)
 {
 	int *valp = ctl->data;
 	int val = *valp;
-	int ret;
-
-	ret = proc_dointvec(ctl, write, filp, buffer, lenp);
+	int ret = proc_dointvec(ctl, write, filp, buffer, lenp);
 
 	if (write && *valp != val) {
 		if (valp == &ipv4_devconf.forwarding)
@@ -1026,81 +1036,179 @@
 			rt_cache_flush(0);
 	}
 
-        return ret;
+	return ret;
 }
 
-static struct devinet_sysctl_table
-{
+static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table devinet_vars[15];
-	ctl_table devinet_dev[2];
-	ctl_table devinet_conf_dir[2];
-	ctl_table devinet_proto_dir[2];
-	ctl_table devinet_root_dir[2];
+	ctl_table		devinet_vars[15];
+	ctl_table		devinet_dev[2];
+	ctl_table		devinet_conf_dir[2];
+	ctl_table		devinet_proto_dir[2];
+	ctl_table		devinet_root_dir[2];
 } devinet_sysctl = {
-	NULL,
-	{{NET_IPV4_CONF_FORWARDING, "forwarding",
-         &ipv4_devconf.forwarding, sizeof(int), 0644, NULL,
-         &devinet_sysctl_forward},
-	{NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding",
-         &ipv4_devconf.mc_forwarding, sizeof(int), 0444, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects",
-         &ipv4_devconf.accept_redirects, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects",
-         &ipv4_devconf.secure_redirects, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_SHARED_MEDIA, "shared_media",
-         &ipv4_devconf.shared_media, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_RP_FILTER, "rp_filter",
-         &ipv4_devconf.rp_filter, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects",
-         &ipv4_devconf.send_redirects, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route",
-         &ipv4_devconf.accept_source_route, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_PROXY_ARP, "proxy_arp",
-         &ipv4_devconf.proxy_arp, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_MEDIUM_ID, "medium_id",
-         &ipv4_devconf.medium_id, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay",
-         &ipv4_devconf.bootp_relay, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-        {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",
-         &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,
-         &proc_dointvec},
-	{NET_IPV4_CONF_TAG, "tag",
-	 &ipv4_devconf.tag, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-	{NET_IPV4_CONF_ARPFILTER, "arp_filter",
-	 &ipv4_devconf.arp_filter, sizeof(int), 0644, NULL,
-	 &proc_dointvec},
-	 {0}},
-
-	{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
-	{{NET_IPV4_CONF, "conf", NULL, 0, 0555, devinet_sysctl.devinet_dev},{0}},
-	{{NET_IPV4, "ipv4", NULL, 0, 0555, devinet_sysctl.devinet_conf_dir},{0}},
-	{{CTL_NET, "net", NULL, 0, 0555, devinet_sysctl.devinet_proto_dir},{0}}
+	devinet_vars: {
+		{
+			ctl_name:	NET_IPV4_CONF_FORWARDING,
+			procname:	"forwarding",
+			data:		&ipv4_devconf.forwarding,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&devinet_sysctl_forward,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_MC_FORWARDING,
+			procname:	"mc_forwarding",
+			data:		&ipv4_devconf.mc_forwarding,
+			maxlen:		sizeof(int),
+			mode:		0444,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_ACCEPT_REDIRECTS,
+			procname:	"accept_redirects",
+			data:		&ipv4_devconf.accept_redirects,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_SECURE_REDIRECTS,
+			procname:	"secure_redirects",
+			data:		&ipv4_devconf.secure_redirects,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_SHARED_MEDIA,
+			procname:	"shared_media",
+			data:		&ipv4_devconf.shared_media,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_RP_FILTER,
+			procname:	"rp_filter",
+			data:		&ipv4_devconf.rp_filter,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_SEND_REDIRECTS,
+			procname:	"send_redirects",
+			data:		&ipv4_devconf.send_redirects,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,
+			procname:	"accept_source_route",
+			data:		&ipv4_devconf.accept_source_route,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_PROXY_ARP,
+			procname:	"proxy_arp",
+			data:		&ipv4_devconf.proxy_arp,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_MEDIUM_ID,
+			procname:	"medium_id",
+			data:		&ipv4_devconf.medium_id,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_BOOTP_RELAY,
+			procname:	"bootp_relay",
+			data:		&ipv4_devconf.bootp_relay,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_LOG_MARTIANS,
+			procname:	"log_martians",
+			data:		&ipv4_devconf.log_martians,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_TAG,
+			procname:	"tag",
+			data:		&ipv4_devconf.tag,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+		{
+			ctl_name:	NET_IPV4_CONF_ARPFILTER,
+			procname:	"arp_filter",
+			data:		&ipv4_devconf.arp_filter,
+			maxlen:		sizeof(int),
+			mode:		0644,
+			proc_handler:	&proc_dointvec,
+		},
+	},
+	devinet_dev: {
+		{
+			ctl_name:	NET_PROTO_CONF_ALL,
+			procname:	"all",
+			mode:		0555,
+			child:		devinet_sysctl.devinet_vars,
+		},
+	},
+	devinet_conf_dir: {
+	        {
+			ctl_name:	NET_IPV4_CONF,
+			procname:	"conf",
+			mode:		0555,
+			child:		devinet_sysctl.devinet_dev,
+		},
+	},
+	devinet_proto_dir: {
+		{
+			ctl_name:	NET_IPV4,
+			procname:	"ipv4",
+			mode:		0555,
+			child:		devinet_sysctl.devinet_conf_dir,
+		},
+	},
+	devinet_root_dir: {
+		{
+			ctl_name:	CTL_NET,
+			procname:	"net",
+			mode:		0555,
+			child:		devinet_sysctl.devinet_proto_dir,
+		},
+	},
 };
 
-static void devinet_sysctl_register(struct in_device *in_dev, struct ipv4_devconf *p)
+static void devinet_sysctl_register(struct in_device *in_dev,
+				    struct ipv4_devconf *p)
 {
 	int i;
 	struct net_device *dev = in_dev ? in_dev->dev : NULL;
-	struct devinet_sysctl_table *t;
+	struct devinet_sysctl_table *t = kmalloc(sizeof(*t), GFP_KERNEL);
 
-	t = kmalloc(sizeof(*t), GFP_KERNEL);
-	if (t == NULL)
+	if (!t)
 		return;
 	memcpy(t, &devinet_sysctl, sizeof(*t));
-	for (i=0; i<sizeof(t->devinet_vars)/sizeof(t->devinet_vars[0])-1; i++) {
-		t->devinet_vars[i].data += (char*)p - (char*)&ipv4_devconf;
+	for (i = 0;
+	     i < sizeof(t->devinet_vars) / sizeof(t->devinet_vars[0]) - 1;
+	     i++) {
+		t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
 		t->devinet_vars[i].de = NULL;
 	}
 	if (dev) {
@@ -1110,17 +1218,17 @@
 		t->devinet_dev[0].procname = "default";
 		t->devinet_dev[0].ctl_name = NET_PROTO_CONF_DEFAULT;
 	}
-	t->devinet_dev[0].child = t->devinet_vars;
-	t->devinet_dev[0].de = NULL;
-	t->devinet_conf_dir[0].child = t->devinet_dev;
-	t->devinet_conf_dir[0].de = NULL;
+	t->devinet_dev[0].child	      = t->devinet_vars;
+	t->devinet_dev[0].de	      = NULL;
+	t->devinet_conf_dir[0].child  = t->devinet_dev;
+	t->devinet_conf_dir[0].de     = NULL;
 	t->devinet_proto_dir[0].child = t->devinet_conf_dir;
-	t->devinet_proto_dir[0].de = NULL;
-	t->devinet_root_dir[0].child = t->devinet_proto_dir;
-	t->devinet_root_dir[0].de = NULL;
+	t->devinet_proto_dir[0].de    = NULL;
+	t->devinet_root_dir[0].child  = t->devinet_proto_dir;
+	t->devinet_root_dir[0].de     = NULL;
 
 	t->sysctl_header = register_sysctl_table(t->devinet_root_dir, 0);
-	if (t->sysctl_header == NULL)
+	if (!t->sysctl_header)
 		kfree(t);
 	else
 		p->sysctl = t;
diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Sat Jun  8 22:31:37 2002
+++ b/net/ipv4/icmp.c	Sat Jun  8 22:31:37 2002
@@ -1,6 +1,6 @@
 /*
- *	NET3:	Implementation of the ICMP protocol layer. 
- *	
+ *	NET3:	Implementation of the ICMP protocol layer.
+ *
  *		Alan Cox, <alan@redhat.com>
  *
  *	Version: $Id: icmp.c,v 1.85 2002/02/01 22:01:03 davem Exp $
@@ -21,25 +21,25 @@
  *					of broken per type icmp timeouts.
  *		Mike Shaver	:	RFC1122 checks.
  *		Alan Cox	:	Multicast ping reply as self.
- *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit 
+ *		Alan Cox	:	Fix atomicity lockup in ip_build_xmit
  *					call.
- *		Alan Cox	:	Added 216,128 byte paths to the MTU 
+ *		Alan Cox	:	Added 216,128 byte paths to the MTU
  *					code.
  *		Martin Mares	:	RFC1812 checks.
- *		Martin Mares	:	Can be configured to follow redirects 
+ *		Martin Mares	:	Can be configured to follow redirects
  *					if acting as a router _without_ a
  *					routing protocol (RFC 1812).
- *		Martin Mares	:	Echo requests may be configured to 
+ *		Martin Mares	:	Echo requests may be configured to
  *					be ignored (RFC 1812).
- *		Martin Mares	:	Limitation of ICMP error message 
+ *		Martin Mares	:	Limitation of ICMP error message
  *					transmit rate (RFC 1812).
- *		Martin Mares	:	TOS and Precedence set correctly 
+ *		Martin Mares	:	TOS and Precedence set correctly
  *					(RFC 1812).
- *		Martin Mares	:	Now copying as much data from the 
+ *		Martin Mares	:	Now copying as much data from the
  *					original packet as we can without
  *					exceeding 576 bytes (RFC 1812).
  *	Willy Konynenberg	:	Transparent proxying support.
- *		Keith Owens	:	RFC1191 correction for 4.2BSD based 
+ *		Keith Owens	:	RFC1191 correction for 4.2BSD based
  *					path MTU bug.
  *		Thomas Quinot	:	ICMP Dest Unreach codes up to 15 are
  *					valid (RFC 1812).
@@ -52,9 +52,10 @@
  *					the rates sysctl configurable.
  *		Yu Tianli	:	Fixed two ugly bugs in icmp_send
  *					- IP option length was accounted wrongly
- *					- ICMP header length was not accounted at all.
- *              Tristan Greaves :       Added sysctl option to ignore bogus broadcast
- *                                      responses from broken routers.
+ *					- ICMP header length was not accounted
+ *					  at all.
+ *              Tristan Greaves :       Added sysctl option to ignore bogus
+ *              			broadcast responses from broken routers.
  *
  * To Fix:
  *
@@ -95,8 +96,7 @@
  *	Build xmit assembly blocks
  */
 
-struct icmp_bxm
-{
+struct icmp_bxm {
 	struct sk_buff *skb;
 	int offset;
 	int data_len;
@@ -114,29 +114,76 @@
 /*
  *	Statistics
  */
- 
-struct icmp_mib icmp_statistics[NR_CPUS*2];
+struct icmp_mib icmp_statistics[NR_CPUS * 2];
 
 /* An array of errno for error messages from dest unreach. */
 /* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOS_UNREACH and SR_FAIELD MUST be considered 'transient errs'. */
 
 struct icmp_err icmp_err_convert[] = {
-  { ENETUNREACH,	0 },	/*	ICMP_NET_UNREACH	*/
-  { EHOSTUNREACH,	0 },	/*	ICMP_HOST_UNREACH	*/
-  { ENOPROTOOPT,	1 },	/*	ICMP_PROT_UNREACH	*/
-  { ECONNREFUSED,	1 },	/*	ICMP_PORT_UNREACH	*/
-  { EMSGSIZE,		0 },	/*	ICMP_FRAG_NEEDED	*/
-  { EOPNOTSUPP,		0 },	/*	ICMP_SR_FAILED		*/
-  { ENETUNREACH,	1 },	/* 	ICMP_NET_UNKNOWN	*/
-  { EHOSTDOWN,		1 },	/*	ICMP_HOST_UNKNOWN	*/
-  { ENONET,		1 },	/*	ICMP_HOST_ISOLATED	*/
-  { ENETUNREACH,	1 },	/*	ICMP_NET_ANO		*/
-  { EHOSTUNREACH,	1 },	/*	ICMP_HOST_ANO		*/
-  { ENETUNREACH,	0 },	/*	ICMP_NET_UNR_TOS	*/
-  { EHOSTUNREACH,	0 },	/*	ICMP_HOST_UNR_TOS	*/
-  { EHOSTUNREACH,	1 },	/*	ICMP_PKT_FILTERED	*/
-  { EHOSTUNREACH,	1 },	/*	ICMP_PREC_VIOLATION	*/
-  { EHOSTUNREACH,	1 }	/*	ICMP_PREC_CUTOFF	*/
+	{
+		errno:	ENETUNREACH,	/* ICMP_NET_UNREACH */
+		fatal:	0,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_HOST_UNREACH */
+		fatal:	0,
+	},
+	{
+		errno:	ENOPROTOOPT	/* ICMP_PROT_UNREACH */,
+		fatal:	1,
+	},
+	{
+		errno:	ECONNREFUSED,	/* ICMP_PORT_UNREACH */
+		fatal:	1,
+	},
+	{
+		errno:	EMSGSIZE,	/* ICMP_FRAG_NEEDED */
+		fatal:	0,
+	},
+	{
+		errno:	EOPNOTSUPP,	/* ICMP_SR_FAILED */
+		fatal:	0,
+	},
+	{
+		errno:	ENETUNREACH,	/* ICMP_NET_UNKNOWN */
+		fatal:	1,
+	},
+	{
+		errno:	EHOSTDOWN,	/* ICMP_HOST_UNKNOWN */
+		fatal:	1,
+	},
+	{
+		errno:	ENONET,		/* ICMP_HOST_ISOLATED */
+		fatal:	1,
+	},
+	{
+		errno:	ENETUNREACH,	/* ICMP_NET_ANO	*/
+		fatal:	1,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_HOST_ANO */
+		fatal:	1,
+	},
+	{
+		errno:	ENETUNREACH,	/* ICMP_NET_UNR_TOS */
+		fatal:	0,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_HOST_UNR_TOS */
+		fatal:	0,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_PKT_FILTERED */
+		fatal:	1,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_PREC_VIOLATION */
+		fatal:	1,
+	},
+	{
+		errno:	EHOSTUNREACH,	/* ICMP_PREC_CUTOFF */
+		fatal:	1,
+	},
 };
 
 extern int sysctl_ip_default_ttl;
@@ -148,19 +195,19 @@
 /* Control parameter - ignore bogus broadcast responses? */
 int sysctl_icmp_ignore_bogus_error_responses;
 
-/* 
+/*
  * 	Configurable global rate limit.
  *
  *	ratelimit defines tokens/packet consumed for dst->rate_token bucket
  *	ratemask defines which icmp types are ratelimited by setting
  * 	it's bit position.
  *
- *	default: 
+ *	default:
  *	dest unreachable (3), source quench (4),
  *	time exceeded (11), parameter problem (12)
  */
 
-int sysctl_icmp_ratelimit = 1*HZ;
+int sysctl_icmp_ratelimit = 1 * HZ;
 int sysctl_icmp_ratemask = 0x1818;
 
 /*
@@ -182,7 +229,6 @@
  *	our ICMP output as well as maintain a clean interface throughout
  *	all layers. All Socketless IP sends will soon be gone.
  */
-	
 struct socket *icmp_socket;
 
 /* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
@@ -194,13 +240,17 @@
 
 static int icmp_xmit_lock_bh(void)
 {
+	int rc;
 	if (!spin_trylock(&icmp_socket->sk->lock.slock)) {
+		rc = -EAGAIN;
 		if (icmp_xmit_holder == smp_processor_id())
-			return -EAGAIN;
+			goto out;
 		spin_lock(&icmp_socket->sk->lock.slock);
 	}
+	rc = 0;
 	icmp_xmit_holder = smp_processor_id();
-	return 0;
+out:
+	return rc;
 }
 
 static __inline__ int icmp_xmit_lock(void)
@@ -236,14 +286,14 @@
  *	This function is generic and could be used for other purposes
  *	too. It uses a Token bucket filter as suggested by Alexey Kuznetsov.
  *
- *	Note that the same dst_entry fields are modified by functions in 
+ *	Note that the same dst_entry fields are modified by functions in
  *	route.c too, but these work for packet destinations while xrlim_allow
  *	works for icmp destinations. This means the rate limiting information
  *	for one "ip object" is shared - and these ICMPs are twice limited:
  *	by source and by destination.
  *
  *	RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate
- *			  SHOULD allow setting of rate limits 
+ *			  SHOULD allow setting of rate limits
  *
  * 	Shared between ICMPv4 and ICMPv6.
  */
@@ -251,68 +301,75 @@
 int xrlim_allow(struct dst_entry *dst, int timeout)
 {
 	unsigned long now;
+	int rc = 0;
 
 	now = jiffies;
 	dst->rate_tokens += now - dst->rate_last;
 	dst->rate_last = now;
-	if (dst->rate_tokens > XRLIM_BURST_FACTOR*timeout)
-        	dst->rate_tokens = XRLIM_BURST_FACTOR*timeout;
+	if (dst->rate_tokens > XRLIM_BURST_FACTOR * timeout)
+		dst->rate_tokens = XRLIM_BURST_FACTOR * timeout;
 	if (dst->rate_tokens >= timeout) {
 		dst->rate_tokens -= timeout;
-		return 1;
+		rc = 1;
 	}
-	return 0; 
+	return rc;
 }
 
 static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code)
 {
-	struct dst_entry *dst = &rt->u.dst; 
+	struct dst_entry *dst = &rt->u.dst;
+	int rc = 1;
 
 	if (type > NR_ICMP_TYPES)
-		return 1;
+		goto out;
 
 	/* Don't limit PMTU discovery. */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
-		return 1;
+		goto out;
 
 	/* No rate limit on loopback */
 	if (dst->dev && (dst->dev->flags&IFF_LOOPBACK))
- 		return 1;
+ 		goto out;
 
 	/* Limit if icmp type is enabled in ratemask. */
-	if((1 << type) & sysctl_icmp_ratemask)
-		return xrlim_allow(dst, sysctl_icmp_ratelimit);
-	else
-		return 1;
+	if ((1 << type) & sysctl_icmp_ratemask)
+		rc = xrlim_allow(dst, sysctl_icmp_ratelimit);
+out:
+	return rc;
 }
 
 /*
  *	Maintain the counters used in the SNMP statistics for outgoing ICMP
  */
- 
 static void icmp_out_count(int type)
 {
-	if (type>NR_ICMP_TYPES)
-		return;
-	(icmp_pointers[type].output)[(smp_processor_id()*2+!in_softirq())*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
-	ICMP_INC_STATS(IcmpOutMsgs);
+	if (type <= NR_ICMP_TYPES) {
+		(icmp_pointers[type].output)[(smp_processor_id() * 2 +
+					      !in_softirq()) *
+					     sizeof(struct icmp_mib) /
+					     sizeof(unsigned long)]++;
+		ICMP_INC_STATS(IcmpOutMsgs);
+	}
 }
- 
+
 /*
- *	Checksum each fragment, and on the first include the headers and final checksum.
+ *	Checksum each fragment, and on the first include the headers and final
+ *	checksum.
  */
- 
-static int icmp_glue_bits(const void *p, char *to, unsigned int offset, unsigned int fraglen)
+static int icmp_glue_bits(const void *p, char *to, unsigned int offset,
+			  unsigned int fraglen)
 {
 	struct icmp_bxm *icmp_param = (struct icmp_bxm *)p;
 	struct icmphdr *icmph;
 	unsigned int csum;
 
 	if (offset) {
-		icmp_param->csum=skb_copy_and_csum_bits(icmp_param->skb,
-							icmp_param->offset+(offset-icmp_param->head_len), 
-							to, fraglen,icmp_param->csum);
-		return 0;
+		icmp_param->csum =
+			skb_copy_and_csum_bits(icmp_param->skb,
+					       icmp_param->offset +
+					       (offset - icmp_param->head_len),
+						to, fraglen, icmp_param->csum);
+		goto out;
 	}
 
 	/*
@@ -321,15 +378,14 @@
 	 *	for the whole packet here.
 	 */
 	csum = csum_partial_copy_nocheck((void *)&icmp_param->data,
-		to, icmp_param->head_len,
-		icmp_param->csum);
-	csum=skb_copy_and_csum_bits(icmp_param->skb,
-				    icmp_param->offset, 
-				    to+icmp_param->head_len,
-				    fraglen-icmp_param->head_len,
-				    csum);
-	icmph=(struct icmphdr *)to;
+					 to, icmp_param->head_len,
+					 icmp_param->csum);
+	csum = skb_copy_and_csum_bits(icmp_param->skb, icmp_param->offset,
+				      to + icmp_param->head_len,
+				      fraglen - icmp_param->head_len, csum);
+	icmph = (struct icmphdr *)to;
 	icmph->checksum = csum_fold(csum);
+out:
 	return 0;
 }
 
@@ -339,20 +395,18 @@
 
 static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
 {
-	struct sock *sk=icmp_socket->sk;
+	struct sock *sk = icmp_socket->sk;
 	struct inet_opt *inet = inet_sk(sk);
 	struct ipcm_cookie ipc;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = (struct rtable *)skb->dst;
 	u32 daddr;
 
-	if (ip_options_echo(&icmp_param->replyopts, skb))
-		return;
-
-	if (icmp_xmit_lock_bh())
-		return;
+	if (ip_options_echo(&icmp_param->replyopts, skb) ||
+	    icmp_xmit_lock_bh())
+		goto out;
 
-	icmp_param->data.icmph.checksum=0;
-	icmp_param->csum=0;
+	icmp_param->data.icmph.checksum = 0;
+	icmp_param->csum = 0;
 	icmp_out_count(icmp_param->data.icmph.type);
 
 	inet->tos = skb->nh.iph->tos;
@@ -364,24 +418,27 @@
 		if (ipc.opt->srr)
 			daddr = icmp_param->replyopts.faddr;
 	}
-	if (ip_route_output(&rt, daddr, rt->rt_spec_dst, RT_TOS(skb->nh.iph->tos), 0))
-		goto out;
-	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, 
-			       icmp_param->data.icmph.code)) { 
-		ip_build_xmit(sk, icmp_glue_bits, icmp_param, 
+	if (ip_route_output(&rt, daddr, rt->rt_spec_dst,
+			    RT_TOS(skb->nh.iph->tos), 0))
+		goto out_unlock;
+	if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type,
+			       icmp_param->data.icmph.code)) {
+		ip_build_xmit(sk, icmp_glue_bits, icmp_param,
 			      icmp_param->data_len+icmp_param->head_len,
 			      &ipc, rt, MSG_DONTWAIT);
 	}
 	ip_rt_put(rt);
-out:
+out_unlock:
 	icmp_xmit_unlock_bh();
+out:;
 }
 
 
 /*
  *	Send an ICMP message in response to a situation
  *
- *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
+ *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header.
+ *		  MAY send more (we do).
  *			MUST NOT change this header information.
  *			MUST NOT reply to a multicast/broadcast IP address.
  *			MUST NOT reply to a multicast/broadcast MAC address.
@@ -393,13 +450,13 @@
 	struct iphdr *iph;
 	int room;
 	struct icmp_bxm icmp_param;
-	struct rtable *rt = (struct rtable*)skb_in->dst;
+	struct rtable *rt = (struct rtable *)skb_in->dst;
 	struct ipcm_cookie ipc;
 	u32 saddr;
 	u8  tos;
 
 	if (!rt)
-		return;
+		goto out;
 
 	/*
 	 *	Find the original header. It is expected to be valid, of course.
@@ -408,66 +465,67 @@
 	 */
 	iph = skb_in->nh.iph;
 
-	if ((u8*)iph < skb_in->head || (u8*)(iph+1) > skb_in->tail)
-		return;
+	if ((u8 *)iph < skb_in->head || (u8 *)(iph + 1) > skb_in->tail)
+		goto out;
 
 	/*
 	 *	No replies to physical multicast/broadcast
 	 */
-	if (skb_in->pkt_type!=PACKET_HOST)
-		return;
+	if (skb_in->pkt_type != PACKET_HOST)
+		goto out;
 
 	/*
 	 *	Now check at the protocol level
 	 */
-	if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
-		return;
+	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+		goto out;
 
 	/*
 	 *	Only reply to fragment 0. We byte re-order the constant
 	 *	mask for efficiency.
 	 */
-	if (iph->frag_off&htons(IP_OFFSET))
-		return;
+	if (iph->frag_off & htons(IP_OFFSET))
+		goto out;
 
-	/* 
+	/*
 	 *	If we send an ICMP error to an ICMP error a mess would result..
 	 */
 	if (icmp_pointers[type].error) {
 		/*
-		 *	We are an error, check if we are replying to an ICMP error
+		 *	We are an error, check if we are replying to an
+		 *	ICMP error
 		 */
-		if (iph->protocol==IPPROTO_ICMP) {
+		if (iph->protocol == IPPROTO_ICMP) {
 			u8 inner_type;
 
 			if (skb_copy_bits(skb_in,
-					  skb_in->nh.raw + (iph->ihl<<2)
-					  + offsetof(struct icmphdr, type)
-					  - skb_in->data,
-					  &inner_type, 1))
-				return;
+					  skb_in->nh.raw + (iph->ihl << 2) +
+					  offsetof(struct icmphdr, type) -
+					  skb_in->data, &inner_type, 1))
+				goto out;
 
 			/*
-			 *	Assume any unknown ICMP type is an error. This isn't
-			 *	specified by the RFC, but think about it..
+			 *	Assume any unknown ICMP type is an error. This
+			 *	isn't specified by the RFC, but think about it..
 			 */
-			if (inner_type>NR_ICMP_TYPES || icmp_pointers[inner_type].error)
-				return;
+			if (inner_type > NR_ICMP_TYPES ||
+			    icmp_pointers[inner_type].error)
+				goto out;
 		}
 	}
 
 	if (icmp_xmit_lock())
-		return;
+		goto out;
 
 	/*
 	 *	Construct source address and options.
 	 */
 
-#ifdef CONFIG_IP_ROUTE_NAT	
+#ifdef CONFIG_IP_ROUTE_NAT
 	/*
 	 *	Restore original addresses if packet has been translated.
 	 */
-	if (rt->rt_flags&RTCF_NAT && IPCB(skb_in)->flags&IPSKB_TRANSLATED) {
+	if (rt->rt_flags & RTCF_NAT && IPCB(skb_in)->flags & IPSKB_TRANSLATED) {
 		iph->daddr = rt->key.dst;
 		iph->saddr = rt->key.src;
 	}
@@ -477,14 +535,14 @@
 	if (!(rt->rt_flags & RTCF_LOCAL))
 		saddr = 0;
 
-	tos = icmp_pointers[type].error ?
-		((iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL) :
-			iph->tos;
+	tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) |
+					   IPTOS_PREC_INTERNETCONTROL) :
+					  iph->tos;
 
 	if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
-		goto out;
+		goto out_unlock;
 
-	if (ip_options_echo(&icmp_param.replyopts, skb_in)) 
+	if (ip_options_echo(&icmp_param.replyopts, skb_in))
 		goto ende;
 
 
@@ -492,13 +550,13 @@
 	 *	Prepare data for ICMP header.
 	 */
 
-	icmp_param.data.icmph.type=type;
-	icmp_param.data.icmph.code=code;
+	icmp_param.data.icmph.type	 = type;
+	icmp_param.data.icmph.code	 = code;
 	icmp_param.data.icmph.un.gateway = info;
-	icmp_param.data.icmph.checksum=0;
-	icmp_param.csum=0;
-	icmp_param.skb=skb_in;
-	icmp_param.offset=skb_in->nh.raw - skb_in->data;
+	icmp_param.data.icmph.checksum	 = 0;
+	icmp_param.csum	  = 0;
+	icmp_param.skb	  = skb_in;
+	icmp_param.offset = skb_in->nh.raw - skb_in->data;
 	icmp_out_count(icmp_param.data.icmph.type);
 	inet_sk(icmp_socket->sk)->tos = tos;
 	inet_sk(icmp_socket->sk)->ttl = sysctl_ip_default_ttl;
@@ -506,8 +564,9 @@
 	ipc.opt = &icmp_param.replyopts;
 	if (icmp_param.replyopts.srr) {
 		ip_rt_put(rt);
-		if (ip_route_output(&rt, icmp_param.replyopts.faddr, saddr, RT_TOS(tos), 0))
-			goto out;
+		if (ip_route_output(&rt, icmp_param.replyopts.faddr,
+				    saddr, RT_TOS(tos), 0))
+			goto out_unlock;
 	}
 
 	if (!icmpv4_xrlim_allow(rt, type, code))
@@ -521,24 +580,24 @@
 	room -= sizeof(struct iphdr) + icmp_param.replyopts.optlen;
 	room -= sizeof(struct icmphdr);
 
-	icmp_param.data_len=skb_in->len-icmp_param.offset;
+	icmp_param.data_len = skb_in->len - icmp_param.offset;
 	if (icmp_param.data_len > room)
 		icmp_param.data_len = room;
 	icmp_param.head_len = sizeof(struct icmphdr);
 
-	ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param, 
-		icmp_param.data_len+sizeof(struct icmphdr),
-		&ipc, rt, MSG_DONTWAIT);
-
+	ip_build_xmit(icmp_socket->sk, icmp_glue_bits, &icmp_param,
+		      icmp_param.data_len + sizeof(struct icmphdr),
+		      &ipc, rt, MSG_DONTWAIT);
 ende:
 	ip_rt_put(rt);
-out:
+out_unlock:
 	icmp_xmit_unlock();
+out:;
 }
 
 
-/* 
- *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH. 
+/*
+ *	Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, and ICMP_QUENCH.
  */
 
 static void icmp_unreach(struct sk_buff *skb)
@@ -556,60 +615,59 @@
 	 *	additional check for longer headers in upper levels.
 	 */
 
-	if (!pskb_may_pull(skb, sizeof(struct iphdr))) {
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return;
-	}
+	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+		goto out_err;
 
 	icmph = skb->h.icmph;
-	iph = (struct iphdr *) skb->data;
+	iph   = (struct iphdr *)skb->data;
 
-	if (iph->ihl<5) {
-		/* Mangled header, drop. */
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return;
-	}
+	if (iph->ihl < 5) /* Mangled header, drop. */
+		goto out_err;
 
-	if(icmph->type==ICMP_DEST_UNREACH) {
-		switch(icmph->code & 15) {
-			case ICMP_NET_UNREACH:
-				break;
-			case ICMP_HOST_UNREACH:
-				break;
-			case ICMP_PROT_UNREACH:
-				break;
-			case ICMP_PORT_UNREACH:
-				break;
-			case ICMP_FRAG_NEEDED:
-				if (ipv4_config.no_pmtu_disc) {
-					if (net_ratelimit())
-						printk(KERN_INFO "ICMP: %u.%u.%u.%u: fragmentation needed and DF set.\n",
-						       NIPQUAD(iph->daddr));
-				} else {
-					info = ip_rt_frag_needed(iph, ntohs(icmph->un.frag.mtu));
-					if (!info) 
-						goto out;
-				}
-				break;
-			case ICMP_SR_FAILED:
+	if (icmph->type == ICMP_DEST_UNREACH) {
+		switch (icmph->code & 15) {
+		case ICMP_NET_UNREACH:
+		case ICMP_HOST_UNREACH:
+		case ICMP_PROT_UNREACH:
+		case ICMP_PORT_UNREACH:
+			break;
+		case ICMP_FRAG_NEEDED:
+			if (ipv4_config.no_pmtu_disc) {
 				if (net_ratelimit())
-					printk(KERN_INFO "ICMP: %u.%u.%u.%u: Source Route Failed.\n", NIPQUAD(iph->daddr));
-				break;
-			default:
-				break;
+					printk(KERN_INFO "ICMP: %u.%u.%u.%u: "
+							 "fragmentation needed "
+							 "and DF set.\n",
+					       NIPQUAD(iph->daddr));
+			} else {
+				info = ip_rt_frag_needed(iph,
+						     ntohs(icmph->un.frag.mtu));
+				if (!info)
+					goto out;
+			}
+			break;
+		case ICMP_SR_FAILED:
+			if (net_ratelimit())
+				printk(KERN_INFO "ICMP: %u.%u.%u.%u: Source "
+						 "Route Failed.\n",
+				       NIPQUAD(iph->daddr));
+			break;
+		default:
+			break;
 		}
-		if (icmph->code>NR_ICMP_UNREACH)
+		if (icmph->code > NR_ICMP_UNREACH)
 			goto out;
-	} else if (icmph->type == ICMP_PARAMETERPROB) {
-		info = ntohl(icmph->un.gateway)>>24;
-	}
+	} else if (icmph->type == ICMP_PARAMETERPROB)
+		info = ntohl(icmph->un.gateway) >> 24;
 
 	/*
 	 *	Throw it at our lower layers
 	 *
-	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed header.
-	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the transport layer.
-	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to transport layer.
+	 *	RFC 1122: 3.2.2 MUST extract the protocol ID from the passed
+	 *		  header.
+	 *	RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the
+	 *		  transport layer.
+	 *	RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to
+	 *		  transport layer.
 	 */
 
 	/*
@@ -619,25 +677,22 @@
 	 *	get the other vendor to fix their kit.
 	 */
 
-	if (!sysctl_icmp_ignore_bogus_error_responses)
-	{
-	
-		if (inet_addr_type(iph->daddr) == RTN_BROADCAST)
-		{
-			if (net_ratelimit())
-				printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP error to a broadcast.\n",
-			       	NIPQUAD(skb->nh.iph->saddr));
-			goto out;
-		}
+	if (!sysctl_icmp_ignore_bogus_error_responses &&
+	    inet_addr_type(iph->daddr) == RTN_BROADCAST) {
+		if (net_ratelimit())
+			printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP "
+					    "error to a broadcast.\n",
+			       NIPQUAD(skb->nh.iph->saddr));
+		goto out;
 	}
 
 	/* Checkin full IP header plus 8 bytes of protocol to
 	 * avoid additional coding at protocol handlers.
 	 */
-	if (!pskb_may_pull(skb, iph->ihl*4+8))
+	if (!pskb_may_pull(skb, iph->ihl * 4 + 8))
 		goto out;
 
-	iph = (struct iphdr *) skb->data;
+	iph = (struct iphdr *)skb->data;
 	protocol = iph->protocol;
 
 	/*
@@ -647,10 +702,10 @@
 	/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
 	hash = protocol & (MAX_INET_PROTOS - 1);
 	read_lock(&raw_v4_lock);
-	if ((raw_sk = raw_v4_htable[hash]) != NULL) 
-	{
+	if ((raw_sk = raw_v4_htable[hash]) != NULL) {
 		while ((raw_sk = __raw_v4_lookup(raw_sk, protocol, iph->daddr,
-						 iph->saddr, skb->dev->ifindex)) != NULL) {
+						 iph->saddr,
+						 skb->dev->ifindex)) != NULL) {
 			raw_err(raw_sk, skb, info);
 			raw_sk = raw_sk->next;
 			iph = (struct iphdr *)skb->data;
@@ -659,19 +714,18 @@
 	read_unlock(&raw_v4_lock);
 
 	/*
-	 *	This can't change while we are doing it. 
+	 *	This can't change while we are doing it.
 	 *	Callers have obtained BR_NETPROTO_LOCK so
 	 *	we are OK.
 	 */
 
-	ipprot = (struct inet_protocol *) inet_protos[hash];
+	ipprot = (struct inet_protocol *)inet_protos[hash];
 	while (ipprot) {
 		struct inet_protocol *nextip;
 
-		nextip = (struct inet_protocol *) ipprot->next;
-	
-		/* 
-		 *	Pass it off to everyone who wants it. 
+		nextip = (struct inet_protocol *)ipprot->next;
+		/*
+		 *	Pass it off to everyone who wants it.
 		 */
 
 		/* RFC1122: OK. Passes appropriate ICMP errors to the */
@@ -682,12 +736,16 @@
 
 		ipprot = nextip;
   	}
-out:;
+out:
+	return;
+out_err:
+	ICMP_INC_STATS_BH(IcmpInErrors);
+	goto out;
 }
 
 
 /*
- *	Handle ICMP_REDIRECT. 
+ *	Handle ICMP_REDIRECT.
  */
 
 static void icmp_redirect(struct sk_buff *skb)
@@ -695,18 +753,16 @@
 	struct iphdr *iph;
 	unsigned long ip;
 
-	if (skb->len < sizeof(struct iphdr)) {
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return; 
-	}
+	if (skb->len < sizeof(struct iphdr))
+		goto out_err;
 
 	/*
 	 *	Get the copied header of the packet that caused the redirect
 	 */
 	if (!pskb_may_pull(skb, sizeof(struct iphdr)))
-		return;
+		goto out;
 
-	iph = (struct iphdr *) skb->data;
+	iph = (struct iphdr *)skb->data;
 	ip = iph->daddr;
 
 	switch (skb->h.icmph->code & 7) {
@@ -716,22 +772,31 @@
 			 *	As per RFC recommendations now handle it as
 			 *	a host redirect.
 			 */
-			 
 		case ICMP_REDIR_HOST:
 		case ICMP_REDIR_HOSTTOS:
-			ip_rt_redirect(skb->nh.iph->saddr, ip, skb->h.icmph->un.gateway, iph->saddr, iph->tos, skb->dev);
+			ip_rt_redirect(skb->nh.iph->saddr,
+				       ip, skb->h.icmph->un.gateway,
+				       iph->saddr, iph->tos, skb->dev);
 			break;
 		default:
 			break;
   	}
+out:
+	return;
+out_err:
+	ICMP_INC_STATS_BH(IcmpInErrors);
+	goto out;
 }
 
 /*
- *	Handle ICMP_ECHO ("ping") requests. 
+ *	Handle ICMP_ECHO ("ping") requests.
  *
- *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests.
- *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply.
- *	RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT.
+ *	RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo
+ *		  requests.
+ *	RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be
+ *		  included in the reply.
+ *	RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring
+ *		  echo requests, MUST have default=NOT.
  *	See also WRT handling of options once they are done and working.
  */
 
@@ -740,65 +805,66 @@
 	if (!sysctl_icmp_echo_ignore_all) {
 		struct icmp_bxm icmp_param;
 
-		icmp_param.data.icmph=*skb->h.icmph;
-		icmp_param.data.icmph.type=ICMP_ECHOREPLY;
-		icmp_param.skb=skb;
-		icmp_param.offset=0;
-		icmp_param.data_len=skb->len;
-		icmp_param.head_len=sizeof(struct icmphdr);
+		icmp_param.data.icmph	   = *skb->h.icmph;
+		icmp_param.data.icmph.type = ICMP_ECHOREPLY;
+		icmp_param.skb		   = skb;
+		icmp_param.offset	   = 0;
+		icmp_param.data_len	   = skb->len;
+		icmp_param.head_len	   = sizeof(struct icmphdr);
 		icmp_reply(&icmp_param, skb);
 	}
 }
 
 /*
- *	Handle ICMP Timestamp requests. 
+ *	Handle ICMP Timestamp requests.
  *	RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests.
  *		  SHOULD be in the kernel for minimum random latency.
  *		  MUST be accurate to a few minutes.
  *		  MUST be updated at least at 15Hz.
  */
- 
 static void icmp_timestamp(struct sk_buff *skb)
 {
 	struct timeval tv;
 	struct icmp_bxm icmp_param;
-	
 	/*
 	 *	Too short.
 	 */
-	 
-	if (skb->len < 4) {
-		ICMP_INC_STATS_BH(IcmpInErrors);
-		return;
-	}
+	if (skb->len < 4)
+		goto out_err;
 
 	/*
-	 *	Fill in the current time as ms since midnight UT: 
+	 *	Fill in the current time as ms since midnight UT:
 	 */
 	do_gettimeofday(&tv);
-	icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
+	icmp_param.data.times[1] = htonl((tv.tv_sec % 86400) * 1000 +
+					 tv.tv_usec / 1000);
 	icmp_param.data.times[2] = icmp_param.data.times[1];
 	if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4))
 		BUG();
-	icmp_param.data.icmph=*skb->h.icmph;
-	icmp_param.data.icmph.type=ICMP_TIMESTAMPREPLY;
-	icmp_param.data.icmph.code=0;
-	icmp_param.skb=skb;
-	icmp_param.offset=0;
-	icmp_param.data_len=0;
-	icmp_param.head_len=sizeof(struct icmphdr)+12;
+	icmp_param.data.icmph	   = *skb->h.icmph;
+	icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY;
+	icmp_param.data.icmph.code = 0;
+	icmp_param.skb		   = skb;
+	icmp_param.offset	   = 0;
+	icmp_param.data_len	   = 0;
+	icmp_param.head_len	   = sizeof(struct icmphdr) + 12;
 	icmp_reply(&icmp_param, skb);
+out:
+	return;
+out_err:
+	ICMP_INC_STATS_BH(IcmpInErrors);
+	goto out;
 }
 
 
-/* 
+/*
  *	Handle ICMP_ADDRESS_MASK requests.  (RFC950)
  *
- * RFC1122 (3.2.2.9).  A host MUST only send replies to 
- * ADDRESS_MASK requests if it's been configured as an address mask 
- * agent.  Receiving a request doesn't constitute implicit permission to 
- * act as one. Of course, implementing this correctly requires (SHOULD) 
- * a way to turn the functionality on and off.  Another one for sysctl(), 
+ * RFC1122 (3.2.2.9).  A host MUST only send replies to
+ * ADDRESS_MASK requests if it's been configured as an address mask
+ * agent.  Receiving a request doesn't constitute implicit permission to
+ * act as one. Of course, implementing this correctly requires (SHOULD)
+ * a way to turn the functionality on and off.  Another one for sysctl(),
  * I guess. -- MS
  *
  * RFC1812 (4.3.3.9).	A router MUST implement it.
@@ -829,7 +895,7 @@
 #if 0
 	if (net_ratelimit())
 		printk(KERN_DEBUG "a guy asks for address mask. Who is it?\n");
-#endif		
+#endif
 }
 
 /*
@@ -839,57 +905,60 @@
 
 static void icmp_address_reply(struct sk_buff *skb)
 {
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = (struct rtable *)skb->dst;
 	struct net_device *dev = skb->dev;
 	struct in_device *in_dev;
 	struct in_ifaddr *ifa;
 	u32 mask;
 
 	if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
-		return;
+		goto out;
 
 	in_dev = in_dev_get(dev);
 	if (!in_dev)
-		return;
+		goto out;
 	read_lock(&in_dev->lock);
 	if (in_dev->ifa_list &&
 	    IN_DEV_LOG_MARTIANS(in_dev) &&
 	    IN_DEV_FORWARD(in_dev)) {
 		if (skb_copy_bits(skb, 0, &mask, 4))
 			BUG();
-		for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
-			if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
+		for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
+			if (mask == ifa->ifa_mask &&
+			    inet_ifa_match(rt->rt_src, ifa))
 				break;
 		}
 		if (!ifa && net_ratelimit()) {
-			printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from %s/%u.%u.%u.%u\n",
+			printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from "
+					 "%s/%u.%u.%u.%u\n",
 			       NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src));
 		}
 	}
 	read_unlock(&in_dev->lock);
 	in_dev_put(in_dev);
+out:;
 }
 
 static void icmp_discard(struct sk_buff *skb)
 {
 }
 
-/* 
+/*
  *	Deal with incoming ICMP packets.
  */
- 
 int icmp_rcv(struct sk_buff *skb)
 {
 	struct icmphdr *icmph;
-	struct rtable *rt = (struct rtable*)skb->dst;
+	struct rtable *rt = (struct rtable *)skb->dst;
 
 	ICMP_INC_STATS_BH(IcmpInMsgs);
 
 	switch (skb->ip_summed) {
 	case CHECKSUM_HW:
-		if ((u16)csum_fold(skb->csum) == 0)
+		if (!(u16)csum_fold(skb->csum))
 			break;
-		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "icmp v4 hw csum failure\n"));
+		NETDEBUG(if (net_ratelimit())
+				printk(KERN_DEBUG "icmp v4 hw csum failure\n"));
 	case CHECKSUM_NONE:
 		if ((u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))
 			goto error;
@@ -904,17 +973,18 @@
 	/*
 	 *	18 is the highest 'known' ICMP type. Anything else is a mystery
 	 *
-	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently discarded.
+	 *	RFC 1122: 3.2.2  Unknown ICMP messages types MUST be silently
+	 *		  discarded.
 	 */
 	if (icmph->type > NR_ICMP_TYPES)
 		goto error;
 
 
 	/*
-	 *	Parse the ICMP message 
+	 *	Parse the ICMP message
 	 */
 
- 	if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) {
+ 	if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) {
 		/*
 		 *	RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be
 		 *	  silently ignored (we let user decide with a sysctl).
@@ -933,7 +1003,9 @@
   		}
 	}
 
-	icmp_pointers[icmph->type].input[smp_processor_id()*2*sizeof(struct icmp_mib)/sizeof(unsigned long)]++;
+	icmp_pointers[icmph->type].input[smp_processor_id() * 2 *
+					 sizeof(struct icmp_mib) /
+					 sizeof(unsigned long)]++;
 	(icmp_pointers[icmph->type].handler)(skb);
 
 drop:
@@ -947,40 +1019,127 @@
 /*
  *	This table is the definition of how we handle ICMP.
  */
- 
-static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1] = {
-/* ECHO REPLY (0) */
- { &icmp_statistics[0].IcmpOutEchoReps, &icmp_statistics[0].IcmpInEchoReps, icmp_discard, 0 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
-/* DEST UNREACH (3) */
- { &icmp_statistics[0].IcmpOutDestUnreachs, &icmp_statistics[0].IcmpInDestUnreachs, icmp_unreach, 1 },
-/* SOURCE QUENCH (4) */
- { &icmp_statistics[0].IcmpOutSrcQuenchs, &icmp_statistics[0].IcmpInSrcQuenchs, icmp_unreach, 1 },
-/* REDIRECT (5) */
- { &icmp_statistics[0].IcmpOutRedirects, &icmp_statistics[0].IcmpInRedirects, icmp_redirect, 1 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
-/* ECHO (8) */
- { &icmp_statistics[0].IcmpOutEchos, &icmp_statistics[0].IcmpInEchos, icmp_echo, 0 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
- { &icmp_statistics[0].dummy, &icmp_statistics[0].IcmpInErrors, icmp_discard, 1 },
-/* TIME EXCEEDED (11) */
- { &icmp_statistics[0].IcmpOutTimeExcds, &icmp_statistics[0].IcmpInTimeExcds, icmp_unreach, 1 },
-/* PARAMETER PROBLEM (12) */
- { &icmp_statistics[0].IcmpOutParmProbs, &icmp_statistics[0].IcmpInParmProbs, icmp_unreach, 1 },
-/* TIMESTAMP (13) */
- { &icmp_statistics[0].IcmpOutTimestamps, &icmp_statistics[0].IcmpInTimestamps, icmp_timestamp, 0  },
-/* TIMESTAMP REPLY (14) */
- { &icmp_statistics[0].IcmpOutTimestampReps, &icmp_statistics[0].IcmpInTimestampReps, icmp_discard, 0 },
-/* INFO (15) */
- { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0 },
-/* INFO REPLY (16) */
- { &icmp_statistics[0].dummy, &icmp_statistics[0].dummy, icmp_discard, 0 },
-/* ADDR MASK (17) */
- { &icmp_statistics[0].IcmpOutAddrMasks, &icmp_statistics[0].IcmpInAddrMasks, icmp_address, 0  },
-/* ADDR MASK REPLY (18) */
- { &icmp_statistics[0].IcmpOutAddrMaskReps, &icmp_statistics[0].IcmpInAddrMaskReps, icmp_address_reply, 0 }
+static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
+	/* ECHO REPLY (0) */
+	[0] = {
+		output:	 &icmp_statistics[0].IcmpOutEchoReps,
+		input:	 &icmp_statistics[0].IcmpInEchoReps,
+		handler: icmp_discard,
+	},
+	[1] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	[2] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	/* DEST UNREACH (3) */
+	[3] = {
+		output:	 &icmp_statistics[0].IcmpOutDestUnreachs,
+		input:	 &icmp_statistics[0].IcmpInDestUnreachs,
+		handler: icmp_unreach,
+		error:	 1,
+	},
+	/* SOURCE QUENCH (4) */
+	[4] = {
+		output:	 &icmp_statistics[0].IcmpOutSrcQuenchs,
+		input:	 &icmp_statistics[0].IcmpInSrcQuenchs,
+		icmp_unreach,
+		error:	 1,
+	},
+	/* REDIRECT (5) */
+	[5] = {
+		output:	 &icmp_statistics[0].IcmpOutRedirects,
+		input:	 &icmp_statistics[0].IcmpInRedirects,
+		handler: icmp_redirect,
+		error:	 1,
+	},
+	[6] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	[7] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	/* ECHO (8) */
+	[8] = {
+		output:	 &icmp_statistics[0].IcmpOutEchos,
+		input:	 &icmp_statistics[0].IcmpInEchos,
+		handler: icmp_echo,
+		error:	 0,
+	},
+	[9] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	[10] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].IcmpInErrors,
+		handler: icmp_discard,
+		error:	 1,
+	},
+	/* TIME EXCEEDED (11) */
+	[11] = {
+		output:	 &icmp_statistics[0].IcmpOutTimeExcds,
+		input:	 &icmp_statistics[0].IcmpInTimeExcds,
+		handler: icmp_unreach,
+		error:	 1,
+	},
+	/* PARAMETER PROBLEM (12) */
+	[12] = {
+		output:	 &icmp_statistics[0].IcmpOutParmProbs,
+		input:	 &icmp_statistics[0].IcmpInParmProbs,
+		handler: icmp_unreach,
+		error:	 1,
+	},
+	/* TIMESTAMP (13) */
+	[13] = {
+		output:	 &icmp_statistics[0].IcmpOutTimestamps,
+		input:	 &icmp_statistics[0].IcmpInTimestamps,
+		handler: icmp_timestamp,
+	},
+	/* TIMESTAMP REPLY (14) */
+	[14] = {
+		output:	 &icmp_statistics[0].IcmpOutTimestampReps,
+		input:	 &icmp_statistics[0].IcmpInTimestampReps,
+		handler: icmp_discard,
+	},
+	/* INFO (15) */
+	[15] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].dummy,
+		handler: icmp_discard,
+	},
+	/* INFO REPLY (16) */
+ 	[16] = {
+		output:	 &icmp_statistics[0].dummy,
+		input:	 &icmp_statistics[0].dummy,
+		handler: icmp_discard,
+	},
+	/* ADDR MASK (17) */
+	[17] = {
+		output:	 &icmp_statistics[0].IcmpOutAddrMasks,
+		input:	 &icmp_statistics[0].IcmpInAddrMasks,
+		handler: icmp_address,
+	},
+	/* ADDR MASK REPLY (18) */
+	[18] = {
+		output:	 &icmp_statistics[0].IcmpOutAddrMaskReps,
+		input:	 &icmp_statistics[0].IcmpInAddrMaskReps,
+		handler: icmp_address_reply,
+	}
 };
 
 void __init icmp_init(struct net_proto_family *ops)
@@ -990,8 +1149,8 @@
 
 	if (err < 0)
 		panic("Failed to create the ICMP control socket.\n");
-	icmp_socket->sk->allocation=GFP_ATOMIC;
-	icmp_socket->sk->sndbuf = SK_WMEM_MAX*2;
+	icmp_socket->sk->allocation = GFP_ATOMIC;
+	icmp_socket->sk->sndbuf	    = SK_WMEM_MAX * 2;
 	inet	       = inet_sk(icmp_socket->sk);
 	inet->ttl      = MAXTTL;
 	inet->pmtudisc = IP_PMTUDISC_DONT;
diff -Nru a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c
--- a/net/ipv4/netfilter/ipchains_core.c	Sat Jun  8 22:31:37 2002
+++ b/net/ipv4/netfilter/ipchains_core.c	Sat Jun  8 22:31:37 2002
@@ -549,7 +549,7 @@
 			strcpy(outskb->data+sizeof(__u32)*2, rif);
 			memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip,
 			       len-(sizeof(__u32)*2+IFNAMSIZ));
-			netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_KERNEL);
+			netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC);
 		}
 		else {
 #endif
@@ -723,6 +723,7 @@
 						      src_port, dst_port,
 						      count, tcpsyn)) {
 					ret = FW_BLOCK;
+					cleanup(chain, 0, slot);
 					goto out;
 				}
 				break;
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Sat Jun  8 22:31:37 2002
+++ b/net/ipv4/tcp_ipv4.c	Sat Jun  8 22:31:37 2002
@@ -32,7 +32,8 @@
  *					and the rest go in the other half.
  *		Andi Kleen :		Add support for syncookies and fixed
  *					some bugs: ip options weren't passed to
- *					the TCP layer, missed a check for an ACK bit.
+ *					the TCP layer, missed a check for an
+ *					ACK bit.
  *		Andi Kleen :		Implemented fast path mtu discovery.
  *	     				Fixed many serious bugs in the
  *					open_request handling and moved
@@ -42,7 +43,8 @@
  *		Mike McLagan	:	Routing by source
  *	Juan Jose Ciarlante:		ip_dynaddr bits
  *		Andi Kleen:		various fixes.
- *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
+ *	Vitaly E. Lavrov	:	Transparent proxy revived after year
+ *					coma.
  *	Andi Kleen		:	Fix new listen.
  *	Andi Kleen		:	Fix accept error reporting.
  */
@@ -65,26 +67,18 @@
 
 extern int sysctl_ip_dynaddr;
 extern int sysctl_ip_default_ttl;
-int sysctl_tcp_tw_reuse = 0;
+int sysctl_tcp_tw_reuse;
 
 /* Check TCP sequence numbers in ICMP packets. */
 #define ICMP_MIN_LENGTH 8
 
-/* Socket used for sending RSTs */ 	
+/* Socket used for sending RSTs */
 static struct socket *tcp_socket;
 
-void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
+void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
 		       struct sk_buff *skb);
 
-/*
- * ALL members must be initialised to prevent gcc-2.7.2.3 miscompilation
- */
 struct tcp_hashinfo __cacheline_aligned tcp_hashinfo = {
-	__tcp_ehash:          NULL,
-	__tcp_bhash:          NULL,
-	__tcp_bhash_size:     0,
-	__tcp_ehash_size:     0,
-	__tcp_listening_hash: { NULL, },
 	__tcp_lhash_lock:     RW_LOCK_UNLOCKED,
 	__tcp_lhash_users:    ATOMIC_INIT(0),
 	__tcp_lhash_wait:
@@ -98,14 +92,14 @@
  * 32768-61000
  */
 int sysctl_local_port_range[2] = { 1024, 4999 };
-int tcp_port_rover = (1024 - 1);
+int tcp_port_rover = 1024 - 1;
 
 static __inline__ int tcp_hashfn(__u32 laddr, __u16 lport,
 				 __u32 faddr, __u16 fport)
 {
-	int h = ((laddr ^ lport) ^ (faddr ^ fport));
-	h ^= h>>16;
-	h ^= h>>8;
+	int h = (laddr ^ lport) ^ (faddr ^ fport);
+	h ^= h >> 16;
+	h ^= h >> 8;
 	return h & (tcp_ehash_size - 1);
 }
 
@@ -126,14 +120,13 @@
 struct tcp_bind_bucket *tcp_bucket_create(struct tcp_bind_hashbucket *head,
 					  unsigned short snum)
 {
-	struct tcp_bind_bucket *tb;
-
-	tb = kmem_cache_alloc(tcp_bucket_cachep, SLAB_ATOMIC);
-	if(tb != NULL) {
+	struct tcp_bind_bucket *tb = kmem_cache_alloc(tcp_bucket_cachep,
+						      SLAB_ATOMIC);
+	if (tb) {
 		tb->port = snum;
 		tb->fastreuse = 0;
 		tb->owners = NULL;
-		if((tb->next = head->chain) != NULL)
+		if ((tb->next = head->chain) != NULL)
 			tb->next->pprev = &tb->next;
 		head->chain = tb;
 		tb->pprev = &head->chain;
@@ -152,9 +145,9 @@
 	tb = (struct tcp_bind_bucket *)sk->prev;
 	if ((child->bind_next = tb->owners) != NULL)
 		tb->owners->bind_pprev = &child->bind_next;
-	tb->owners = child;
+	tb->owners	  = child;
 	child->bind_pprev = &tb->owners;
-	child->prev = (struct sock *) tb;
+	child->prev	  = (struct sock *)tb;
 	spin_unlock(&head->lock);
 }
 
@@ -165,14 +158,15 @@
 	local_bh_enable();
 }
 
-static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb, unsigned short snum)
+static inline void tcp_bind_hash(struct sock *sk, struct tcp_bind_bucket *tb,
+				 unsigned short snum)
 {
 	inet_sk(sk)->num = snum;
 	if ((sk->bind_next = tb->owners) != NULL)
 		tb->owners->bind_pprev = &sk->bind_next;
-	tb->owners = sk;
+	tb->owners     = sk;
 	sk->bind_pprev = &tb->owners;
-	sk->prev = (struct sock *) tb;
+	sk->prev       = (struct sock *)tb;
 }
 
 static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb)
@@ -180,17 +174,14 @@
 	struct inet_opt *inet = inet_sk(sk);
 	struct sock *sk2 = tb->owners;
 	int sk_reuse = sk->reuse;
-	
-	for( ; sk2 != NULL; sk2 = sk2->bind_next) {
-		if (sk != sk2 &&
-		    sk->bound_dev_if == sk2->bound_dev_if) {
-			if (!sk_reuse	||
-			    !sk2->reuse	||
+
+	for ( ; sk2; sk2 = sk2->bind_next) {
+		if (sk != sk2 && sk->bound_dev_if == sk2->bound_dev_if) {
+			if (!sk_reuse || !sk2->reuse ||
 			    sk2->state == TCP_LISTEN) {
 				struct inet_opt *inet2 = inet_sk(sk2);
-				if (!inet2->rcv_saddr	||
-				    !inet->rcv_saddr	||
-				    (inet2->rcv_saddr == inet->rcv_saddr))
+				if (!inet2->rcv_saddr || !inet->rcv_saddr ||
+				    inet2->rcv_saddr == inet->rcv_saddr)
 					break;
 			}
 		}
@@ -208,7 +199,7 @@
 	int ret;
 
 	local_bh_disable();
-	if (snum == 0) {
+	if (!snum) {
 		int low = sysctl_local_port_range[0];
 		int high = sysctl_local_port_range[1];
 		int remaining = (high - low) + 1;
@@ -216,8 +207,9 @@
 
 		spin_lock(&tcp_portalloc_lock);
 		rover = tcp_port_rover;
-		do {	rover++;
-			if ((rover < low) || (rover > high))
+		do {
+			rover++;
+			if (rover < low || rover > high)
 				rover = low;
 			head = &tcp_bhash[tcp_bhashfn(rover)];
 			spin_lock(&head->lock);
@@ -244,14 +236,14 @@
 	} else {
 		head = &tcp_bhash[tcp_bhashfn(snum)];
 		spin_lock(&head->lock);
-		for (tb = head->chain; tb != NULL; tb = tb->next)
+		for (tb = head->chain; tb; tb = tb->next)
 			if (tb->port == snum)
 				break;
 	}
-	if (tb != NULL && tb->owners != NULL) {
+	if (tb && tb->owners) {
 		if (sk->reuse > 1)
 			goto success;
-		if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) {
+		if (tb->fastreuse > 0 && sk->reuse && sk->state != TCP_LISTEN) {
 			goto success;
 		} else {
 			ret = 1;
@@ -260,21 +252,19 @@
 		}
 	}
 	ret = 1;
-	if (tb == NULL &&
-	    (tb = tcp_bucket_create(head, snum)) == NULL)
-			goto fail_unlock;
-	if (tb->owners == NULL) {
+	if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL)
+		goto fail_unlock;
+	if (!tb->owners) {
 		if (sk->reuse && sk->state != TCP_LISTEN)
 			tb->fastreuse = 1;
 		else
 			tb->fastreuse = 0;
-	} else if (tb->fastreuse &&
-		   ((sk->reuse == 0) || (sk->state == TCP_LISTEN)))
+	} else if (tb->fastreuse && (!sk->reuse || sk->state == TCP_LISTEN))
 		tb->fastreuse = 0;
 success:
-	if (sk->prev == NULL)
+	if (!sk->prev)
 		tcp_bind_hash(sk, tb, snum);
-	BUG_TRAP(sk->prev == (struct sock *) tb);
+	BUG_TRAP(sk->prev == (struct sock *)tb);
  	ret = 0;
 
 fail_unlock:
@@ -298,9 +288,9 @@
 	if (sk->bind_next)
 		sk->bind_next->bind_pprev = sk->bind_pprev;
 	*(sk->bind_pprev) = sk->bind_next;
-	sk->prev = NULL;
+	sk->prev  = NULL;
 	inet->num = 0;
-	if (tb->owners == NULL) {
+	if (!tb->owners) {
 		if (tb->next)
 			tb->next->pprev = tb->pprev;
 		*(tb->pprev) = tb->next;
@@ -333,7 +323,7 @@
 		add_wait_queue_exclusive(&tcp_lhash_wait, &wait);
 		for (;;) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
-			if (atomic_read(&tcp_lhash_users) == 0)
+			if (!atomic_read(&tcp_lhash_users))
 				break;
 			write_unlock_bh(&tcp_lhash_lock);
 			schedule();
@@ -350,8 +340,8 @@
 	struct sock **skp;
 	rwlock_t *lock;
 
-	BUG_TRAP(sk->pprev==NULL);
-	if(listen_possible && sk->state == TCP_LISTEN) {
+	BUG_TRAP(!sk->pprev);
+	if (listen_possible && sk->state == TCP_LISTEN) {
 		skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)];
 		lock = &tcp_lhash_lock;
 		tcp_listen_wlock();
@@ -360,7 +350,7 @@
 		lock = &tcp_ehash[sk->hashent].lock;
 		write_lock(lock);
 	}
-	if((sk->next = *skp) != NULL)
+	if ((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
 	*skp = sk;
 	sk->pprev = skp;
@@ -396,8 +386,8 @@
 		write_lock_bh(&head->lock);
 	}
 
-	if(sk->pprev) {
-		if(sk->next)
+	if (sk->pprev) {
+		if (sk->next)
 			sk->next->pprev = sk->pprev;
 		*sk->pprev = sk->next;
 		sk->pprev = NULL;
@@ -416,20 +406,21 @@
  * connection.  So always assume those are both wildcarded
  * during the search since they can never be otherwise.
  */
-static struct sock *__tcp_v4_lookup_listener(struct sock *sk, u32 daddr, unsigned short hnum, int dif)
+static struct sock *__tcp_v4_lookup_listener(struct sock *sk, u32 daddr,
+					     unsigned short hnum, int dif)
 {
 	struct sock *result = NULL;
 	int score, hiscore;
 
 	hiscore=0;
-	for(; sk; sk = sk->next) {
+	for (; sk; sk = sk->next) {
 		struct inet_opt *inet = inet_sk(sk);
 
-		if(inet->num == hnum) {
+		if (inet->num == hnum) {
 			__u32 rcv_saddr = inet->rcv_saddr;
 
 			score = 1;
-			if(rcv_saddr) {
+			if (rcv_saddr) {
 				if (rcv_saddr != daddr)
 					continue;
 				score++;
@@ -451,7 +442,8 @@
 }
 
 /* Optimize the common listener case. */
-__inline__ struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum, int dif)
+__inline__ struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum,
+					       int dif)
 {
 	struct sock *sk;
 
@@ -460,8 +452,7 @@
 	if (sk) {
 		struct inet_opt *inet = inet_sk(sk);
 
-		if (inet->num == hnum &&
-		    sk->next == NULL &&
+		if (inet->num == hnum && !sk->next &&
 		    (!inet->rcv_saddr || inet->rcv_saddr == daddr) &&
 		    !sk->bound_dev_if)
 			goto sherry_cache;
@@ -482,53 +473,47 @@
  */
 
 static inline struct sock *__tcp_v4_lookup_established(u32 saddr, u16 sport,
-						       u32 daddr, u16 hnum, int dif)
+						       u32 daddr, u16 hnum,
+						       int dif)
 {
 	struct tcp_ehash_bucket *head;
 	TCP_V4_ADDR_COOKIE(acookie, saddr, daddr)
 	__u32 ports = TCP_COMBINED_PORTS(sport, hnum);
 	struct sock *sk;
-	int hash;
-
 	/* Optimize here for direct hit, only listening connections can
 	 * have wildcards anyways.
 	 */
-	hash = tcp_hashfn(daddr, hnum, saddr, sport);
+	int hash = tcp_hashfn(daddr, hnum, saddr, sport);
 	head = &tcp_ehash[hash];
 	read_lock(&head->lock);
-	for(sk = head->chain; sk; sk = sk->next) {
-		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
+	for (sk = head->chain; sk; sk = sk->next) {
+		if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit; /* You sunk my battleship! */
 	}
 
 	/* Must check for a TIME_WAIT'er before going to listener hash. */
-	for(sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next)
-		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
+	for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next)
+		if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
 			goto hit;
+out:
 	read_unlock(&head->lock);
-
-	return NULL;
-
+	return sk;
 hit:
 	sock_hold(sk);
-	read_unlock(&head->lock);
-	return sk;
+	goto out;
 }
 
 static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport,
 					   u32 daddr, u16 hnum, int dif)
 {
-	struct sock *sk;
+	struct sock *sk = __tcp_v4_lookup_established(saddr, sport,
+						      daddr, hnum, dif);
 
-	sk = __tcp_v4_lookup_established(saddr, sport, daddr, hnum, dif);
-
-	if (sk)
-		return sk;
-		
-	return tcp_v4_lookup_listener(daddr, hnum, dif);
+	return sk ? : tcp_v4_lookup_listener(daddr, hnum, dif);
 }
 
-__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif)
+__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
+				      u16 dport, int dif)
 {
 	struct sock *sk;
 
@@ -565,11 +550,11 @@
 	write_lock(&head->lock);
 
 	/* Check TIME-WAIT sockets first. */
-	for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp) != NULL;
-	    skp = &sk2->next) {
-		tw = (struct tcp_tw_bucket*)sk2;
+	for (skp = &(head + tcp_ehash_size)->chain; (sk2 = *skp) != NULL;
+	     skp = &sk2->next) {
+		tw = (struct tcp_tw_bucket *)sk2;
 
-		if(TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
+		if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) {
 			struct tcp_opt *tp = tcp_sk(sk);
 
 			/* With PAWS, it is safe from the viewpoint
@@ -588,7 +573,8 @@
 			 */
 			if (tw->ts_recent_stamp &&
 			    (!twp || (sysctl_tcp_tw_reuse &&
-				      xtime.tv_sec - tw->ts_recent_stamp > 1))) {
+				      xtime.tv_sec -
+				      tw->ts_recent_stamp > 1))) {
 				if ((tp->write_seq =
 						tw->snd_nxt + 65535 + 2) == 0)
 					tp->write_seq = 1;
@@ -604,8 +590,8 @@
 	tw = NULL;
 
 	/* And established part... */
-	for(skp = &head->chain; (sk2=*skp)!=NULL; skp = &sk2->next) {
-		if(TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif))
+	for (skp = &head->chain; (sk2 = *skp) != NULL; skp = &sk2->next) {
+		if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif))
 			goto not_unique;
 	}
 
@@ -614,7 +600,7 @@
 	 * in hash table socket with a funny identity. */
 	inet->num = lport;
 	inet->sport = htons(lport);
-	BUG_TRAP(sk->pprev==NULL);
+	BUG_TRAP(!sk->pprev);
 	if ((sk->next = *skp) != NULL)
 		(*skp)->pprev = &sk->next;
 
@@ -651,16 +637,17 @@
 	unsigned short snum = inet_sk(sk)->num;
  	struct tcp_bind_hashbucket *head;
  	struct tcp_bind_bucket *tb;
- 
- 	if (snum == 0) {
+	int ret;
+
+ 	if (!snum) {
  		int rover;
  		int low = sysctl_local_port_range[0];
  		int high = sysctl_local_port_range[1];
  		int remaining = (high - low) + 1;
  		struct tcp_tw_bucket *tw = NULL;
- 
+
  		local_bh_disable();
- 
+
  		/* TODO. Actually it is not so bad idea to remove
  		 * tcp_portalloc_lock before next submission to Linus.
  		 * As soon as we touch this place at all it is time to think.
@@ -676,29 +663,31 @@
  		 */
  		spin_lock(&tcp_portalloc_lock);
  		rover = tcp_port_rover;
- 
+
  		do {
  			rover++;
  			if ((rover < low) || (rover > high))
  				rover = low;
  			head = &tcp_bhash[tcp_bhashfn(rover)];
- 			spin_lock(&head->lock);		
- 
+ 			spin_lock(&head->lock);
+
  			/* Does not bother with rcv_saddr checks,
  			 * because the established check is already
  			 * unique enough.
  			 */
  			for (tb = head->chain; tb; tb = tb->next) {
  				if (tb->port == rover) {
- 					BUG_TRAP(tb->owners != NULL);
+ 					BUG_TRAP(tb->owners);
  					if (tb->fastreuse >= 0)
  						goto next_port;
- 					if (!__tcp_v4_check_established(sk, rover, &tw))
+ 					if (!__tcp_v4_check_established(sk,
+									rover,
+									&tw))
  						goto ok;
  					goto next_port;
  				}
  			}
- 
+
  			tb = tcp_bucket_create(head, rover);
  			if (!tb) {
  				spin_unlock(&head->lock);
@@ -706,22 +695,22 @@
  			}
  			tb->fastreuse = -1;
  			goto ok;
- 
+
  		next_port:
  			spin_unlock(&head->lock);
  		} while (--remaining > 0);
  		tcp_port_rover = rover;
  		spin_unlock(&tcp_portalloc_lock);
- 
+
  		local_bh_enable();
- 
+
  		return -EADDRNOTAVAIL;
- 
- 	ok:
+
+ok:
  		/* All locks still held and bhs disabled */
  		tcp_port_rover = rover;
  		spin_unlock(&tcp_portalloc_lock);
- 
+
  		tcp_bind_hash(sk, tb, rover);
  		if (!sk->pprev) {
  			inet_sk(sk)->sport = htons(rover);
@@ -734,23 +723,23 @@
  			tcp_timewait_kill(tw);
  			tcp_tw_put(tw);
  		}
- 
- 		local_bh_enable();
- 		return 0;
+
+		ret = 0;
+		goto out;
  	}
- 
+
  	head  = &tcp_bhash[tcp_bhashfn(snum)];
  	tb  = (struct tcp_bind_bucket *)sk->prev;
 	spin_lock_bh(&head->lock);
-	if (tb->owners == sk && sk->bind_next == NULL) {
+	if (tb->owners == sk && !sk->bind_next) {
 		__tcp_v4_hash(sk, 0);
 		spin_unlock_bh(&head->lock);
 		return 0;
 	} else {
-		int ret;
 		spin_unlock(&head->lock);
 		/* No definite answer... Walk to established hash table */
 		ret = __tcp_v4_check_established(sk, snum, NULL);
+out:
 		local_bh_enable();
 		return ret;
 	}
@@ -761,21 +750,21 @@
 {
 	struct inet_opt *inet = inet_sk(sk);
 	struct tcp_opt *tp = tcp_sk(sk);
-	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+	struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
 	struct rtable *rt;
 	u32 daddr, nexthop;
 	int tmp;
 	int err;
 
 	if (addr_len < sizeof(struct sockaddr_in))
-		return(-EINVAL);
+		return -EINVAL;
 
 	if (usin->sin_family != AF_INET)
-		return(-EAFNOSUPPORT);
+		return -EAFNOSUPPORT;
 
 	nexthop = daddr = usin->sin_addr.s_addr;
 	if (inet->opt && inet->opt->srr) {
-		if (daddr == 0)
+		if (!daddr)
 			return -EINVAL;
 		nexthop = inet->opt->faddr;
 	}
@@ -785,7 +774,7 @@
 	if (tmp < 0)
 		return tmp;
 
-	if (rt->rt_flags&(RTCF_MULTICAST|RTCF_BROADCAST)) {
+	if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) {
 		ip_rt_put(rt);
 		return -ENETUNREACH;
 	}
@@ -808,8 +797,7 @@
 	}
 
 	if (sysctl_tcp_tw_recycle &&
-	    !tp->ts_recent_stamp &&
-	    rt->rt_dst == daddr) {
+	    !tp->ts_recent_stamp && rt->rt_dst == daddr) {
 		struct inet_peer *peer = rt_get_peer(rt);
 
 		/* VJ's idea. We save last timestamp seen from
@@ -866,24 +854,24 @@
 
 static __inline__ int tcp_v4_iif(struct sk_buff *skb)
 {
-	return ((struct rtable*)skb->dst)->rt_iif;
+	return ((struct rtable *)skb->dst)->rt_iif;
 }
 
 static __inline__ unsigned tcp_v4_synq_hash(u32 raddr, u16 rport)
 {
 	unsigned h = raddr ^ rport;
-	h ^= h>>16;
-	h ^= h>>8;
-	return h&(TCP_SYNQ_HSIZE-1);
+	h ^= h >> 16;
+	h ^= h >> 8;
+	return h & (TCP_SYNQ_HSIZE - 1);
 }
 
-static struct open_request *tcp_v4_search_req(struct tcp_opt *tp, 
+static struct open_request *tcp_v4_search_req(struct tcp_opt *tp,
 					      struct open_request ***prevp,
 					      __u16 rport,
 					      __u32 raddr, __u32 laddr)
 {
 	struct tcp_listen_opt *lopt = tp->listen_opt;
-	struct open_request *req, **prev;  
+	struct open_request *req, **prev;
 
 	for (prev = &lopt->syn_table[tcp_v4_synq_hash(raddr, rport)];
 	     (req = *prev) != NULL;
@@ -892,13 +880,13 @@
 		    req->af.v4_req.rmt_addr == raddr &&
 		    req->af.v4_req.loc_addr == laddr &&
 		    TCP_INET_FAMILY(req->class->family)) {
-			BUG_TRAP(req->sk == NULL);
+			BUG_TRAP(!req->sk);
 			*prevp = prev;
-			return req; 
+			break;
 		}
 	}
 
-	return NULL;
+	return req;
 }
 
 static void tcp_v4_synq_add(struct sock *sk, struct open_request *req)
@@ -920,7 +908,7 @@
 }
 
 
-/* 
+/*
  * This routine does path mtu discovery as defined in RFC1191.
  */
 static inline void do_pmtu_discovery(struct sock *sk, struct iphdr *iph,
@@ -935,7 +923,7 @@
 	 * unfragmented).
 	 */
 	if (sk->state == TCP_LISTEN)
-		return; 
+		return;
 
 	/* We don't check in the destentry if pmtu discovery is forbidden
 	 * on this route. We just assume that no packet_to_big packets
@@ -958,7 +946,7 @@
 	    tp->pmtu_cookie > dst->pmtu) {
 		tcp_sync_mss(sk, dst->pmtu);
 
-		/* Resend the TCP packet because it's  
+		/* Resend the TCP packet because it's
 		 * clear that the old packet has been
 		 * dropped. This is the new "fast" path mtu
 		 * discovery.
@@ -985,8 +973,8 @@
 
 void tcp_v4_err(struct sk_buff *skb, u32 info)
 {
-	struct iphdr *iph = (struct iphdr*)skb->data;
-	struct tcphdr *th = (struct tcphdr*)(skb->data+(iph->ihl<<2));
+	struct iphdr *iph = (struct iphdr *)skb->data;
+	struct tcphdr *th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
 	struct tcp_opt *tp;
 	struct inet_opt *inet;
 	int type = skb->h.icmph->type;
@@ -996,17 +984,18 @@
 	int err;
 
 	if (skb->len < (iph->ihl << 2) + 8) {
-		ICMP_INC_STATS_BH(IcmpInErrors); 
+		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
 
-	sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, th->source, tcp_v4_iif(skb));
-	if (sk == NULL) {
+	sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr,
+			   th->source, tcp_v4_iif(skb));
+	if (!sk) {
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
 	if (sk->state == TCP_TIME_WAIT) {
-		tcp_tw_put((struct tcp_tw_bucket*)sk);
+		tcp_tw_put((struct tcp_tw_bucket *)sk);
 		return;
 	}
 
@@ -1014,7 +1003,7 @@
 	/* If too many ICMPs get dropped on busy
 	 * servers this needs to be solved differently.
 	 */
-	if (sk->lock.users != 0)
+	if (sk->lock.users)
 		NET_INC_STATS_BH(LockDroppedIcmps);
 
 	if (sk->state == TCP_CLOSE)
@@ -1033,18 +1022,18 @@
 		/* This is deprecated, but if someone generated it,
 		 * we have no reasons to ignore it.
 		 */
-		if (sk->lock.users == 0)
+		if (!sk->lock.users)
 			tcp_enter_cwr(tp);
 		goto out;
 	case ICMP_PARAMETERPROB:
 		err = EPROTO;
-		break; 
+		break;
 	case ICMP_DEST_UNREACH:
 		if (code > NR_ICMP_UNREACH)
 			goto out;
 
 		if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */
-			if (sk->lock.users == 0)
+			if (!sk->lock.users)
 				do_pmtu_discovery(sk, iph, info);
 			goto out;
 		}
@@ -1061,39 +1050,38 @@
 	switch (sk->state) {
 		struct open_request *req, **prev;
 	case TCP_LISTEN:
-		if (sk->lock.users != 0)
+		if (sk->lock.users)
 			goto out;
 
-		req = tcp_v4_search_req(tp, &prev,
-					th->dest,
-					iph->daddr, iph->saddr); 
+		req = tcp_v4_search_req(tp, &prev, th->dest,
+					iph->daddr, iph->saddr);
 		if (!req)
 			goto out;
 
 		/* ICMPs are not backlogged, hence we cannot get
 		   an established socket here.
 		 */
-		BUG_TRAP(req->sk == NULL);
+		BUG_TRAP(!req->sk);
 
 		if (seq != req->snt_isn) {
 			NET_INC_STATS_BH(OutOfWindowIcmps);
 			goto out;
 		}
 
-		/* 
+		/*
 		 * Still in SYN_RECV, just remove it silently.
 		 * There is no good way to pass the error to the newly
 		 * created socket, and POSIX does not want network
-		 * errors returned from accept(). 
-		 */ 
+		 * errors returned from accept().
+		 */
 		tcp_synq_drop(sk, req, prev);
 		goto out;
 
 	case TCP_SYN_SENT:
 	case TCP_SYN_RECV:  /* Cannot happen.
 			       It can f.e. if SYNs crossed.
-			     */ 
-		if (sk->lock.users == 0) {
+			     */
+		if (!sk->lock.users) {
 			TCP_INC_STATS_BH(TcpAttemptFails);
 			sk->err = err;
 
@@ -1123,7 +1111,7 @@
 	 */
 
 	inet = inet_sk(sk);
-	if (sk->lock.users == 0 && inet->recverr) {
+	if (!sk->lock.users && inet->recverr) {
 		sk->err = err;
 		sk->error_report(sk);
 	} else	{ /* Only an error on timeout */
@@ -1136,7 +1124,7 @@
 }
 
 /* This routine computes an IPv4 TCP checksum. */
-void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
+void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len,
 		       struct sk_buff *skb)
 {
 	struct inet_opt *inet = inet_sk(sk);
@@ -1146,7 +1134,9 @@
 		skb->csum = offsetof(struct tcphdr, check);
 	} else {
 		th->check = tcp_v4_check(th, len, inet->saddr, inet->daddr,
-					 csum_partial((char *)th, th->doff<<2, skb->csum));
+					 csum_partial((char *)th,
+						      th->doff << 2,
+						      skb->csum));
 	}
 }
 
@@ -1173,34 +1163,32 @@
 	if (th->rst)
 		return;
 
-	if (((struct rtable*)skb->dst)->rt_type != RTN_LOCAL)
+	if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL)
 		return;
 
 	/* Swap the send and the receive. */
-	memset(&rth, 0, sizeof(struct tcphdr)); 
-	rth.dest = th->source;
-	rth.source = th->dest; 
-	rth.doff = sizeof(struct tcphdr)/4;
-	rth.rst = 1;
+	memset(&rth, 0, sizeof(struct tcphdr));
+	rth.dest   = th->source;
+	rth.source = th->dest;
+	rth.doff   = sizeof(struct tcphdr) / 4;
+	rth.rst    = 1;
 
 	if (th->ack) {
 		rth.seq = th->ack_seq;
 	} else {
 		rth.ack = 1;
-		rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin
-				    + skb->len - (th->doff<<2));
+		rth.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin +
+				    skb->len - (th->doff << 2));
 	}
 
-	memset(&arg, 0, sizeof arg); 
-	arg.iov[0].iov_base = (unsigned char *)&rth; 
+	memset(&arg, 0, sizeof arg);
+	arg.iov[0].iov_base = (unsigned char *)&rth;
 	arg.iov[0].iov_len  = sizeof rth;
-	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, 
+	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
 				      skb->nh.iph->saddr, /*XXX*/
-				      sizeof(struct tcphdr),
-				      IPPROTO_TCP,
-				      0); 
+				      sizeof(struct tcphdr), IPPROTO_TCP, 0);
 	arg.n_iov = 1;
-	arg.csumoffset = offsetof(struct tcphdr, check) / 2; 
+	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 
 	inet_sk(tcp_socket->sk)->ttl = sysctl_ip_default_ttl;
 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
@@ -1213,7 +1201,8 @@
    outside socket context is ugly, certainly. What can I do?
  */
 
-static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts)
+static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
+			    u32 win, u32 ts)
 {
 	struct tcphdr *th = skb->h.th;
 	struct {
@@ -1225,34 +1214,31 @@
 	memset(&rep.th, 0, sizeof(struct tcphdr));
 	memset(&arg, 0, sizeof arg);
 
-	arg.iov[0].iov_base = (unsigned char *)&rep; 
+	arg.iov[0].iov_base = (unsigned char *)&rep;
 	arg.iov[0].iov_len  = sizeof(rep.th);
 	arg.n_iov = 1;
 	if (ts) {
-		rep.tsopt[0] = __constant_htonl((TCPOPT_NOP << 24) |
-						(TCPOPT_NOP << 16) |
-						(TCPOPT_TIMESTAMP << 8) |
-						TCPOLEN_TIMESTAMP);
+		rep.tsopt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+				     (TCPOPT_TIMESTAMP << 8) |
+				     TCPOLEN_TIMESTAMP);
 		rep.tsopt[1] = htonl(tcp_time_stamp);
 		rep.tsopt[2] = htonl(ts);
 		arg.iov[0].iov_len = sizeof(rep);
 	}
 
 	/* Swap the send and the receive. */
-	rep.th.dest = th->source;
-	rep.th.source = th->dest; 
-	rep.th.doff = arg.iov[0].iov_len/4;
-	rep.th.seq = htonl(seq);
+	rep.th.dest    = th->source;
+	rep.th.source  = th->dest;
+	rep.th.doff    = arg.iov[0].iov_len / 4;
+	rep.th.seq     = htonl(seq);
 	rep.th.ack_seq = htonl(ack);
-	rep.th.ack = 1;
-	rep.th.window = htons(win);
+	rep.th.ack     = 1;
+	rep.th.window  = htons(win);
 
-	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr, 
+	arg.csum = csum_tcpudp_nofold(skb->nh.iph->daddr,
 				      skb->nh.iph->saddr, /*XXX*/
-				      arg.iov[0].iov_len,
-				      IPPROTO_TCP,
-				      0);
-	arg.csumoffset = offsetof(struct tcphdr, check) / 2; 
+				      arg.iov[0].iov_len, IPPROTO_TCP, 0);
+	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 
 	ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len);
 
@@ -1264,26 +1250,25 @@
 	struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk;
 
 	tcp_v4_send_ack(skb, tw->snd_nxt, tw->rcv_nxt,
-			tw->rcv_wnd>>tw->rcv_wscale, tw->ts_recent);
+			tw->rcv_wnd >> tw->rcv_wscale, tw->ts_recent);
 
 	tcp_tw_put(tw);
 }
 
 static void tcp_v4_or_send_ack(struct sk_buff *skb, struct open_request *req)
 {
-	tcp_v4_send_ack(skb, req->snt_isn+1, req->rcv_isn+1, req->rcv_wnd,
+	tcp_v4_send_ack(skb, req->snt_isn + 1, req->rcv_isn + 1, req->rcv_wnd,
 			req->ts_recent);
 }
 
-static struct dst_entry* tcp_v4_route_req(struct sock *sk, struct open_request *req)
+static struct dst_entry* tcp_v4_route_req(struct sock *sk,
+					  struct open_request *req)
 {
 	struct rtable *rt;
-	struct ip_options *opt;
+	struct ip_options *opt = req->af.v4_req.opt;
 
-	opt = req->af.v4_req.opt;
-	if(ip_route_output(&rt, ((opt && opt->srr) ?
-				 opt->faddr :
-				 req->af.v4_req.rmt_addr),
+	if (ip_route_output(&rt, ((opt && opt->srr) ? opt->faddr :
+						      req->af.v4_req.rmt_addr),
 			   req->af.v4_req.loc_addr,
 			   RT_CONN_FLAGS(sk), sk->bound_dev_if)) {
 		IP_INC_STATS_BH(IpOutNoRoutes);
@@ -1298,10 +1283,10 @@
 }
 
 /*
- *	Send a SYN-ACK after having received an ACK. 
+ *	Send a SYN-ACK after having received an ACK.
  *	This still operates on a open_request only, not on a big
  *	socket.
- */ 
+ */
 static int tcp_v4_send_synack(struct sock *sk, struct open_request *req,
 			      struct dst_entry *dst)
 {
@@ -1309,8 +1294,7 @@
 	struct sk_buff * skb;
 
 	/* First, grab a route. */
-	if (dst == NULL &&
-	    (dst = tcp_v4_route_req(sk, req)) == NULL)
+	if (!dst && (dst = tcp_v4_route_req(sk, req)) == NULL)
 		goto out;
 
 	skb = tcp_make_synack(sk, dst, req);
@@ -1319,11 +1303,14 @@
 		struct tcphdr *th = skb->h.th;
 
 		th->check = tcp_v4_check(th, skb->len,
-					 req->af.v4_req.loc_addr, req->af.v4_req.rmt_addr,
-					 csum_partial((char *)th, skb->len, skb->csum));
+					 req->af.v4_req.loc_addr,
+					 req->af.v4_req.rmt_addr,
+					 csum_partial((char *)th, skb->len,
+						      skb->csum));
 
 		err = ip_build_and_send_pkt(skb, sk, req->af.v4_req.loc_addr,
-					    req->af.v4_req.rmt_addr, req->af.v4_req.opt);
+					    req->af.v4_req.rmt_addr,
+					    req->af.v4_req.opt);
 		if (err == NET_XMIT_CN)
 			err = 0;
 	}
@@ -1335,7 +1322,7 @@
 
 /*
  *	IPv4 open_request destructor.
- */ 
+ */
 static void tcp_v4_or_free(struct open_request *req)
 {
 	if (req->af.v4_req.opt)
@@ -1345,26 +1332,26 @@
 static inline void syn_flood_warning(struct sk_buff *skb)
 {
 	static unsigned long warntime;
-	
-	if (jiffies - warntime > HZ*60) {
+
+	if (jiffies - warntime > HZ * 60) {
 		warntime = jiffies;
-		printk(KERN_INFO 
-		       "possible SYN flooding on port %d. Sending cookies.\n",  
+		printk(KERN_INFO
+		       "possible SYN flooding on port %d. Sending cookies.\n",
 		       ntohs(skb->h.th->dest));
 	}
 }
 
-/* 
- * Save and compile IPv4 options into the open_request if needed. 
+/*
+ * Save and compile IPv4 options into the open_request if needed.
  */
-static inline struct ip_options * 
-tcp_v4_save_options(struct sock *sk, struct sk_buff *skb)
+static inline struct ip_options *tcp_v4_save_options(struct sock *sk,
+						     struct sk_buff *skb)
 {
 	struct ip_options *opt = &(IPCB(skb)->opt);
-	struct ip_options *dopt = NULL; 
+	struct ip_options *dopt = NULL;
 
 	if (opt && opt->optlen) {
-		int opt_size = optlength(opt); 
+		int opt_size = optlength(opt);
 		dopt = kmalloc(opt_size, GFP_ATOMIC);
 		if (dopt) {
 			if (ip_options_echo(dopt, skb)) {
@@ -1376,7 +1363,7 @@
 	return dopt;
 }
 
-/* 
+/*
  * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
  * One SYN_RECV socket costs about 80bytes on a 32bit machine.
  * It would be better to replace it with a global counter for all sockets
@@ -1389,14 +1376,14 @@
  * (<=32Mb of memory) and to 1024 on normal or better ones (>=256Mb).
  * Further increasing requires to change hash table size.
  */
-int sysctl_max_syn_backlog = 256; 
+int sysctl_max_syn_backlog = 256;
 
 struct or_calltable or_ipv4 = {
-	PF_INET,
-	tcp_v4_send_synack,
-	tcp_v4_or_send_ack,
-	tcp_v4_or_free,
-	tcp_v4_send_reset
+	family:		PF_INET,
+	rtx_syn_ack:	tcp_v4_send_synack,
+	send_ack:	tcp_v4_or_send_ack,
+	destructor:	tcp_v4_or_free,
+	send_reset:	tcp_v4_send_reset,
 };
 
 int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
@@ -1414,9 +1401,9 @@
 #endif
 
 	/* Never answer to SYNs send to broadcast or multicast */
-	if (((struct rtable *)skb->dst)->rt_flags & 
-	    (RTCF_BROADCAST|RTCF_MULTICAST))
-		goto drop; 
+	if (((struct rtable *)skb->dst)->rt_flags &
+	    (RTCF_BROADCAST | RTCF_MULTICAST))
+		goto drop;
 
 	/* TW buckets are converted to open requests without
 	 * limitations, they conserve resources and peer is
@@ -1425,7 +1412,7 @@
 	if (tcp_synq_is_full(sk) && !isn) {
 #ifdef CONFIG_SYN_COOKIES
 		if (sysctl_tcp_syncookies) {
-			want_cookie = 1; 
+			want_cookie = 1;
 		} else
 #endif
 		goto drop;
@@ -1440,12 +1427,12 @@
 		goto drop;
 
 	req = tcp_openreq_alloc();
-	if (req == NULL)
+	if (!req)
 		goto drop;
 
 	tcp_clear_options(&tp);
 	tp.mss_clamp = 536;
-	tp.user_mss = tcp_sk(sk)->user_mss;
+	tp.user_mss  = tcp_sk(sk)->user_mss;
 
 	tcp_parse_options(skb, &tp, 0);
 
@@ -1454,14 +1441,14 @@
 		tp.saw_tstamp = 0;
 	}
 
-	if (tp.saw_tstamp && tp.rcv_tsval == 0) {
+	if (tp.saw_tstamp && !tp.rcv_tsval) {
 		/* Some OSes (unknown ones, but I see them on web server, which
 		 * contains information interesting only for windows'
 		 * users) do not send their stamp in SYN. It is easy case.
 		 * We simply do not advertise TS support.
 		 */
 		tp.saw_tstamp = 0;
-		tp.tstamp_ok = 0;
+		tp.tstamp_ok  = 0;
 	}
 	tp.tstamp_ok = tp.saw_tstamp;
 
@@ -1479,7 +1466,7 @@
 		syn_flood_warning(skb);
 #endif
 		isn = cookie_v4_init_sequence(sk, skb, &req->mss);
-	} else if (isn == 0) {
+	} else if (!isn) {
 		struct inet_peer *peer = NULL;
 
 		/* VJ's idea. We save last timestamp seen
@@ -1494,10 +1481,11 @@
 		if (tp.saw_tstamp &&
 		    sysctl_tcp_tw_recycle &&
 		    (dst = tcp_v4_route_req(sk, req)) != NULL &&
-		    (peer = rt_get_peer((struct rtable*)dst)) != NULL &&
+		    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
 		    peer->v4daddr == saddr) {
 			if (xtime.tv_sec < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
-			    (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) {
+			    (s32)(peer->tcp_ts - req->ts_recent) >
+							TCP_PAWS_WINDOW) {
 				NET_INC_STATS_BH(PAWSPassiveRejected);
 				dst_release(dst);
 				goto drop_and_free;
@@ -1505,19 +1493,23 @@
 		}
 		/* Kill the following clause, if you dislike this way. */
 		else if (!sysctl_tcp_syncookies &&
-			 (sysctl_max_syn_backlog - tcp_synq_len(sk)
-			  < (sysctl_max_syn_backlog>>2)) &&
+			 (sysctl_max_syn_backlog - tcp_synq_len(sk) <
+			  (sysctl_max_syn_backlog >> 2)) &&
 			 (!peer || !peer->tcp_ts_stamp) &&
 			 (!dst || !dst->rtt)) {
 			/* Without syncookies last quarter of
-			 * backlog is filled with destinations, proven to be alive.
+			 * backlog is filled with destinations,
+			 * proven to be alive.
 			 * It means that we continue to communicate
 			 * to destinations, already remembered
 			 * to the moment of synflood.
 			 */
 			NETDEBUG(if (net_ratelimit()) \
-				printk(KERN_DEBUG "TCP: drop open request from %u.%u.%u.%u/%u\n", \
-					NIPQUAD(saddr), ntohs(skb->h.th->source)));
+					printk(KERN_DEBUG "TCP: drop open "
+							  "request from %u.%u."
+							  "%u.%u/%u\n", \
+					       NIPQUAD(saddr),
+					       ntohs(skb->h.th->source)));
 			dst_release(dst);
 			goto drop_and_free;
 		}
@@ -1530,27 +1522,27 @@
 		goto drop_and_free;
 
 	if (want_cookie) {
-	   	tcp_openreq_free(req); 
+	   	tcp_openreq_free(req);
 	} else {
 		tcp_v4_synq_add(sk, req);
 	}
 	return 0;
 
 drop_and_free:
-	tcp_openreq_free(req); 
+	tcp_openreq_free(req);
 drop:
 	TCP_INC_STATS_BH(TcpAttemptFails);
 	return 0;
 }
 
 
-/* 
- * The three way handshake has completed - we got a valid synack - 
- * now create the new socket. 
- */
-struct sock * tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
-				   struct open_request *req,
-				   struct dst_entry *dst)
+/*
+ * The three way handshake has completed - we got a valid synack -
+ * now create the new socket.
+ */
+struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
+				  struct open_request *req,
+				  struct dst_entry *dst)
 {
 	struct inet_opt *newinet;
 	struct tcp_opt *newtp;
@@ -1559,8 +1551,7 @@
 	if (tcp_acceptq_is_full(sk))
 		goto exit_overflow;
 
-	if (dst == NULL &&
-	    (dst = tcp_v4_route_req(sk, req)) == NULL)
+	if (!dst && (dst = tcp_v4_route_req(sk, req)) == NULL)
 		goto exit;
 
 	newsk = tcp_create_openreq_child(sk, req, skb);
@@ -1570,15 +1561,15 @@
 	newsk->dst_cache = dst;
 	newsk->route_caps = dst->dev->features;
 
-	newtp = tcp_sk(newsk);
-	newinet = inet_sk(newsk);
-	newinet->daddr = req->af.v4_req.rmt_addr;
-	newinet->rcv_saddr = req->af.v4_req.loc_addr;
-	newinet->saddr = req->af.v4_req.loc_addr;
-	newinet->opt = req->af.v4_req.opt;
-	req->af.v4_req.opt = NULL;
-	newinet->mc_index = tcp_v4_iif(skb);
-	newinet->mc_ttl = skb->nh.iph->ttl;
+	newtp		      = tcp_sk(newsk);
+	newinet		      = inet_sk(newsk);
+	newinet->daddr	      = req->af.v4_req.rmt_addr;
+	newinet->rcv_saddr    = req->af.v4_req.loc_addr;
+	newinet->saddr	      = req->af.v4_req.loc_addr;
+	newinet->opt	      = req->af.v4_req.opt;
+	req->af.v4_req.opt    = NULL;
+	newinet->mc_index     = tcp_v4_iif(skb);
+	newinet->mc_ttl	      = skb->nh.iph->ttl;
 	newtp->ext_header_len = 0;
 	if (newinet->opt)
 		newtp->ext_header_len = newinet->opt->optlen;
@@ -1601,18 +1592,16 @@
 	return NULL;
 }
 
-static struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb)
+static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
 {
-	struct open_request *req, **prev;
 	struct tcphdr *th = skb->h.th;
 	struct iphdr *iph = skb->nh.iph;
 	struct tcp_opt *tp = tcp_sk(sk);
 	struct sock *nsk;
-
+	struct open_request **prev;
 	/* Find possible connection requests. */
-	req = tcp_v4_search_req(tp, &prev,
-				th->source,
-				iph->saddr, iph->daddr);
+	struct open_request *req = tcp_v4_search_req(tp, &prev, th->source,
+						     iph->saddr, iph->daddr);
 	if (req)
 		return tcp_check_req(sk, skb, req, prev);
 
@@ -1627,7 +1616,7 @@
 			bh_lock_sock(nsk);
 			return nsk;
 		}
-		tcp_tw_put((struct tcp_tw_bucket*)nsk);
+		tcp_tw_put((struct tcp_tw_bucket *)nsk);
 		return NULL;
 	}
 
@@ -1642,22 +1631,24 @@
 {
 	if (skb->ip_summed == CHECKSUM_HW) {
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
-		if (!tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
-				  skb->nh.iph->daddr,skb->csum))
+		if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
+				  skb->nh.iph->daddr, skb->csum))
 			return 0;
 
-		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "hw tcp v4 csum failed\n"));
+		NETDEBUG(if (net_ratelimit())
+				printk(KERN_DEBUG "hw tcp v4 csum failed\n"));
 		skb->ip_summed = CHECKSUM_NONE;
 	}
 	if (skb->len <= 76) {
-		if (tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
+		if (tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr,
 				 skb->nh.iph->daddr,
 				 skb_checksum(skb, 0, skb->len, 0)))
 			return -1;
 		skb->ip_summed = CHECKSUM_UNNECESSARY;
 	} else {
-		skb->csum = ~tcp_v4_check(skb->h.th,skb->len,skb->nh.iph->saddr,
-					  skb->nh.iph->daddr,0);
+		skb->csum = ~tcp_v4_check(skb->h.th, skb->len,
+					  skb->nh.iph->saddr,
+					  skb->nh.iph->daddr, 0);
 	}
 	return 0;
 }
@@ -1686,13 +1677,13 @@
 		if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
 			goto reset;
 		TCP_CHECK_TIMER(sk);
-		return 0; 
+		return 0;
 	}
 
-	if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb))
+	if (skb->len < (skb->h.th->doff << 2) || tcp_checksum_complete(skb))
 		goto csum_err;
 
-	if (sk->state == TCP_LISTEN) { 
+	if (sk->state == TCP_LISTEN) {
 		struct sock *nsk = tcp_v4_hnd_req(sk, skb);
 		if (!nsk)
 			goto discard;
@@ -1715,7 +1706,7 @@
 discard:
 	kfree_skb(skb);
 	/* Be careful here. If this function gets more complicated and
-	 * gcc suffers from register pressure on the x86, sk (in %ebx) 
+	 * gcc suffers from register pressure on the x86, sk (in %ebx)
 	 * might be destroyed here. This current version compiles correctly,
 	 * but you have been warned.
 	 */
@@ -1736,7 +1727,7 @@
 	struct sock *sk;
 	int ret;
 
-	if (skb->pkt_type!=PACKET_HOST)
+	if (skb->pkt_type != PACKET_HOST)
 		goto discard_it;
 
 	/* Count it even if it's bad */
@@ -1747,9 +1738,9 @@
 
 	th = skb->h.th;
 
-	if (th->doff < sizeof(struct tcphdr)/4)
+	if (th->doff < sizeof(struct tcphdr) / 4)
 		goto bad_packet;
-	if (!pskb_may_pull(skb, th->doff*4))
+	if (!pskb_may_pull(skb, th->doff * 4))
 		goto discard_it;
 
 	/* An explanation is required here, I think.
@@ -1763,20 +1754,21 @@
 	th = skb->h.th;
 	TCP_SKB_CB(skb)->seq = ntohl(th->seq);
 	TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin +
-				    skb->len - th->doff*4);
+				    skb->len - th->doff * 4);
 	TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq);
-	TCP_SKB_CB(skb)->when = 0;
-	TCP_SKB_CB(skb)->flags = skb->nh.iph->tos;
-	TCP_SKB_CB(skb)->sacked = 0;
+	TCP_SKB_CB(skb)->when	 = 0;
+	TCP_SKB_CB(skb)->flags	 = skb->nh.iph->tos;
+	TCP_SKB_CB(skb)->sacked	 = 0;
 
 	sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source,
-			     skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb));
+			     skb->nh.iph->daddr, ntohs(th->dest),
+			     tcp_v4_iif(skb));
 
 	if (!sk)
 		goto no_tcp_socket;
 
 process:
-	if(!ipsec_sk_policy(sk,skb))
+	if (!ipsec_sk_policy(sk, skb))
 		goto discard_and_relse;
 
 	if (sk->state == TCP_TIME_WAIT)
@@ -1798,7 +1790,7 @@
 	return ret;
 
 no_tcp_socket:
-	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
 bad_packet:
 		TCP_INC_STATS_BH(TcpInErrs);
 	} else {
@@ -1815,18 +1807,17 @@
 	goto discard_it;
 
 do_time_wait:
-	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
+	if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
 		goto discard_and_relse;
 	}
-	switch(tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
-					  skb, th, skb->len)) {
-	case TCP_TW_SYN:
-	{
-		struct sock *sk2;
-
-		sk2 = tcp_v4_lookup_listener(skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb));
-		if (sk2 != NULL) {
+	switch (tcp_timewait_state_process((struct tcp_tw_bucket *)sk,
+					   skb, th, skb->len)) {
+	case TCP_TW_SYN: {
+		struct sock *sk2 = tcp_v4_lookup_listener(skb->nh.iph->daddr,
+							  ntohs(th->dest),
+							  tcp_v4_iif(skb));
+		if (sk2) {
 			tcp_tw_deschedule((struct tcp_tw_bucket *)sk);
 			tcp_timewait_kill((struct tcp_tw_bucket *)sk);
 			tcp_tw_put((struct tcp_tw_bucket *)sk);
@@ -1884,7 +1875,7 @@
 	if (sysctl_ip_dynaddr > 1) {
 		printk(KERN_INFO "tcp_v4_rebuild_header(): shifting inet->"
 				 "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n",
-		       NIPQUAD(old_saddr), 
+		       NIPQUAD(old_saddr),
 		       NIPQUAD(new_saddr));
 	}
 
@@ -1910,7 +1901,7 @@
 	int err;
 
 	/* Route is OK, nothing to do. */
-	if (rt != NULL)
+	if (rt)
 		return 0;
 
 	/* Reroute. */
@@ -1958,15 +1949,15 @@
 {
 	struct inet_opt *inet = inet_sk(sk);
 	struct tcp_opt *tp = tcp_sk(sk);
-	struct rtable *rt = (struct rtable*)__sk_dst_get(sk);
+	struct rtable *rt = (struct rtable *)__sk_dst_get(sk);
 	struct inet_peer *peer = NULL;
 	int release_it = 0;
 
-	if (rt == NULL || rt->rt_dst != inet->daddr) {
+	if (!rt || rt->rt_dst != inet->daddr) {
 		peer = inet_getpeer(inet->daddr, 1);
 		release_it = 1;
 	} else {
-		if (rt->peer == NULL)
+		if (!rt->peer)
 			rt_bind_peer(rt, 1);
 		peer = rt->peer;
 	}
@@ -2007,18 +1998,17 @@
 }
 
 struct tcp_func ipv4_specific = {
-	ip_queue_xmit,
-	tcp_v4_send_check,
-	tcp_v4_rebuild_header,
-	tcp_v4_conn_request,
-	tcp_v4_syn_recv_sock,
-	tcp_v4_remember_stamp,
-	sizeof(struct iphdr),
-
-	ip_setsockopt,
-	ip_getsockopt,
-	v4_addr2sockaddr,
-	sizeof(struct sockaddr_in)
+	queue_xmit:	ip_queue_xmit,
+	send_check:	tcp_v4_send_check,
+	rebuild_header:	tcp_v4_rebuild_header,
+	conn_request:	tcp_v4_conn_request,
+	syn_recv_sock:	tcp_v4_syn_recv_sock,
+	remember_stamp:	tcp_v4_remember_stamp,
+	net_header_len:	sizeof(struct iphdr),
+	setsockopt:	ip_setsockopt,
+	getsockopt:	ip_getsockopt,
+	addr2sockaddr:	v4_addr2sockaddr,
+	sockaddr_len:	sizeof(struct sockaddr_in),
 };
 
 /* NOTE: A lot of things set to zero explicitly by call to
@@ -2034,7 +2024,7 @@
 
 	tp->rto  = TCP_TIMEOUT_INIT;
 	tp->mdev = TCP_TIMEOUT_INIT;
-      
+
 	/* So many TCP implementations out there (incorrectly) count the
 	 * initial SYN frame in their delayed-ACK and congestion control
 	 * algorithms that we must have the following bandaid to talk
@@ -2082,7 +2072,7 @@
 	__skb_queue_purge(&tp->ucopy.prequeue);
 
 	/* Clean up a referenced TCP bind bucket. */
-	if(sk->prev != NULL)
+	if (sk->prev)
 		tcp_put_port(sk);
 
 	/* If sendmsg cached page exists, toss it. */
@@ -2095,7 +2085,8 @@
 }
 
 /* Proc filesystem TCP sock list dumping. */
-static void get_openreq(struct sock *sk, struct open_request *req, char *tmpbuf, int i, int uid)
+static void get_openreq(struct sock *sk, struct open_request *req,
+			char *tmpbuf, int i, int uid)
 {
 	int ttd = req->expires - jiffies;
 
@@ -2107,31 +2098,28 @@
 		req->af.v4_req.rmt_addr,
 		ntohs(req->rmt_port),
 		TCP_SYN_RECV,
-		0,0, /* could print option size, but that is af dependent. */
-		1,   /* timers active (only the expire timer) */  
-		ttd, 
+		0, 0, /* could print option size, but that is af dependent. */
+		1,    /* timers active (only the expire timer) */
+		ttd,
 		req->retrans,
 		uid,
-		0,  /* non standard timer */  
+		0,  /* non standard timer */
 		0, /* open_requests have no inode */
 		atomic_read(&sk->refcnt),
-		req
-		); 
+		req);
 }
 
 static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
 {
-	unsigned int dest, src;
-	__u16 destp, srcp;
 	int timer_active;
 	unsigned long timer_expires;
 	struct tcp_opt *tp = tcp_sk(sp);
 	struct inet_opt *inet = inet_sk(sp);
+	unsigned int dest = inet->daddr;
+	unsigned int src = inet->rcv_saddr;
+	__u16 destp = ntohs(inet->dport);
+	__u16 srcp = ntohs(inet->sport);
 
-	dest  = inet->daddr;
-	src   = inet->rcv_saddr;
-	destp = ntohs(inet->dport);
-	srcp  = ntohs(inet->sport);
 	if (tp->pending == TCP_TIME_RETRANS) {
 		timer_active	= 1;
 		timer_expires	= tp->timeout;
@@ -2146,19 +2134,19 @@
 		timer_expires = jiffies;
 	}
 
-	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X"
-		" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %u %u %u %u %d",
-		i, src, srcp, dest, destp, sp->state, 
-		tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq,
-		timer_active, timer_expires-jiffies,
+	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
+			"%08X %5d %8d %lu %d %p %u %u %u %u %d",
+		i, src, srcp, dest, destp, sp->state,
+		tp->write_seq - tp->snd_una, tp->rcv_nxt - tp->copied_seq,
+		timer_active, timer_expires - jiffies,
 		tp->retransmits,
 		sock_i_uid(sp),
 		tp->probes_out,
 		sock_i_ino(sp),
 		atomic_read(&sp->refcnt), sp,
-		tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong,
-		tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh
-		);
+		tp->rto, tp->ack.ato, (tp->ack.quick << 1) | tp->ack.pingpong,
+		tp->snd_cwnd,
+		tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh);
 }
 
 static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
@@ -2188,18 +2176,19 @@
 {
 	int len = 0, num = 0, i;
 	off_t begin, pos = 0;
-	char tmpbuf[TMPSZ+1];
+	char tmpbuf[TMPSZ + 1];
 
 	if (offset < TMPSZ)
-		len += sprintf(buffer, "%-*s\n", TMPSZ-1,
+		len += sprintf(buffer, "%-*s\n", TMPSZ - 1,
 			       "  sl  local_address rem_address   st tx_queue "
-			       "rx_queue tr tm->when retrnsmt   uid  timeout inode");
+			       "rx_queue tr tm->when retrnsmt   uid  timeout "
+			       "inode");
 
 	pos = TMPSZ;
 
 	/* First, walk listening socket table. */
 	tcp_listen_lock();
-	for(i = 0; i < TCP_LHTABLE_SIZE; i++) {
+	for (i = 0; i < TCP_LHTABLE_SIZE; i++) {
 		struct sock *sk;
 		struct tcp_listen_opt *lopt;
 		int k;
@@ -2215,7 +2204,8 @@
 			pos += TMPSZ;
 			if (pos >= offset) {
 				get_tcp_sock(sk, tmpbuf, num);
-				len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
+				len += sprintf(buffer + len, "%-*s\n",
+					       TMPSZ - 1, tmpbuf);
 				if (pos >= offset + length) {
 					tcp_listen_unlock();
 					goto out_no_bh;
@@ -2226,17 +2216,22 @@
 			uid = sock_i_uid(sk);
 			read_lock_bh(&tp->syn_wait_lock);
 			lopt = tp->listen_opt;
-			if (lopt && lopt->qlen != 0) {
-				for (k=0; k<TCP_SYNQ_HSIZE; k++) {
-					for (req = lopt->syn_table[k]; req; req = req->dl_next, num++) {
+			if (lopt && lopt->qlen) {
+				for (k = 0; k < TCP_SYNQ_HSIZE; k++) {
+					for (req = lopt->syn_table[k];
+					     req; req = req->dl_next, num++) {
 						if (!TCP_INET_FAMILY(req->class->family))
 							continue;
 
 						pos += TMPSZ;
 						if (pos <= offset)
 							continue;
-						get_openreq(sk, req, tmpbuf, num, uid);
-						len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
+						get_openreq(sk, req, tmpbuf,
+							    num, uid);
+						len += sprintf(buffer + len,
+							       "%-*s\n",
+							       TMPSZ - 1,
+							       tmpbuf);
 						if (pos >= offset + length) {
 							read_unlock_bh(&tp->syn_wait_lock);
 							tcp_listen_unlock();
@@ -2261,21 +2256,23 @@
 		struct tcp_tw_bucket *tw;
 
 		read_lock(&head->lock);
-		for(sk = head->chain; sk; sk = sk->next, num++) {
+		for (sk = head->chain; sk; sk = sk->next, num++) {
 			if (!TCP_INET_FAMILY(sk->family))
 				continue;
 			pos += TMPSZ;
 			if (pos <= offset)
 				continue;
 			get_tcp_sock(sk, tmpbuf, num);
-			len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
+			len += sprintf(buffer + len, "%-*s\n",
+				       TMPSZ - 1, tmpbuf);
 			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
 			}
 		}
-		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i+tcp_ehash_size].chain;
-		     tw != NULL;
+		for (tw = (struct tcp_tw_bucket *)tcp_ehash[i +
+							  tcp_ehash_size].chain;
+		     tw;
 		     tw = (struct tcp_tw_bucket *)tw->next, num++) {
 			if (!TCP_INET_FAMILY(tw->family))
 				continue;
@@ -2283,7 +2280,8 @@
 			if (pos <= offset)
 				continue;
 			get_timewait_sock(tw, tmpbuf, num);
-			len += sprintf(buffer+len, "%-*s\n", TMPSZ-1, tmpbuf);
+			len += sprintf(buffer + len, "%-*s\n",
+				       TMPSZ - 1, tmpbuf);
 			if (pos >= offset + length) {
 				read_unlock(&head->lock);
 				goto out;
@@ -2302,7 +2300,7 @@
 	if (len > length)
 		len = length;
 	if (len < 0)
-		len = 0; 
+		len = 0;
 	return len;
 }
 
@@ -2333,7 +2331,7 @@
 	int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket);
 	if (err < 0)
 		panic("Failed to create the TCP control socket.\n");
-	tcp_socket->sk->allocation=GFP_ATOMIC;
+	tcp_socket->sk->allocation   = GFP_ATOMIC;
 	inet_sk(tcp_socket->sk)->ttl = MAXTTL;
 
 	/* Unhash it so that IP input processing does not even
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Sat Jun  8 22:31:37 2002
+++ b/net/ipv6/raw.c	Sat Jun  8 22:31:37 2002
@@ -11,6 +11,7 @@
  *
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
+ *	YOSHIFUJI,H.@USAGI	:	raw checksum (RFC2292(bis) compliance) 
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -487,11 +488,18 @@
 		hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,
 					     hdr->proto, hdr->cksum);
 		
-		if (opt->offset < len) {
+		if (opt->offset + 1 < len) {
 			__u16 *csum;
 
 			csum = (__u16 *) (buff + opt->offset);
-			*csum = hdr->cksum;
+			if (*csum) {
+				/* in case cksum was not initialized */
+				__u32 sum = hdr->cksum;
+				sum += *csum;
+				*csum = hdr->cksum = (sum + (sum>>16));
+			} else {
+				*csum = hdr->cksum;
+			}
 		} else {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "icmp: cksum offset too big\n");
@@ -720,6 +728,10 @@
 
 	switch (optname) {
 		case IPV6_CHECKSUM:
+			/* You may get strange result with a positive odd offset;
+			   RFC2292bis agrees with me. */
+			if (val > 0 && (val&1))
+				return(-EINVAL);
 			if (val < 0) {
 				opt->checksum = 0;
 			} else {
@@ -817,6 +829,11 @@
 
 static int rawv6_init_sk(struct sock *sk)
 {
+	if (inet_sk(sk)->num == IPPROTO_ICMPV6) {
+		struct raw6_opt *opt = raw6_sk(sk);
+		opt->checksum = 1;
+		opt->offset = 2;
+	}
 	return(0);
 }
 
diff -Nru a/net/khttpd/Makefile b/net/khttpd/Makefile
--- a/net/khttpd/Makefile	Sat Jun  8 22:31:51 2002
+++ b/net/khttpd/Makefile	Sat Jun  8 22:31:51 2002
@@ -8,12 +8,11 @@
 		rfc_time.o security.o sockets.o sysctl.o userspace.o \
 		waitheaders.o
 
+host-progs := make_times_h
+
 include $(TOPDIR)/Rules.make
 
 rfc_time.o: times.h
-
-make_times_h: make_times_h.c
-	$(HOSTCC) $(HOSTCFLAGS) -o make_times_h make_times_h.c
 
 times.h: make_times_h
 	./make_times_h
diff -Nru a/net/sched/sch_api.c b/net/sched/sch_api.c
--- a/net/sched/sch_api.c	Sat Jun  8 22:31:37 2002
+++ b/net/sched/sch_api.c	Sat Jun  8 22:31:37 2002
@@ -1117,7 +1117,7 @@
 	psched_timer.expires = jiffies + 1*HZ;
 #else
 	unsigned long now = jiffies;
-	psched_time_base = ((u64)now)<<PSCHED_JSCALE;
+	psched_time_base += ((u64)(now-psched_time_mark))<<PSCHED_JSCALE;
 	psched_time_mark = now;
 	psched_timer.expires = now + 60*60*HZ;
 #endif
diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Sat Jun  8 22:31:51 2002
+++ b/net/sunrpc/xdr.c	Sat Jun  8 22:31:51 2002
@@ -176,7 +176,7 @@
 /*
  * Map a struct xdr_buf into an iovec array.
  */
-int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, unsigned int base)
+int xdr_kmap(struct iovec *iov_base, struct xdr_buf *xdr, size_t base)
 {
 	struct iovec	*iov = iov_base;
 	struct page	**ppage = xdr->pages;
@@ -226,7 +226,7 @@
 	return (iov - iov_base);
 }
 
-void xdr_kunmap(struct xdr_buf *xdr, unsigned int base)
+void xdr_kunmap(struct xdr_buf *xdr, size_t base)
 {
 	struct page	**ppage = xdr->pages;
 	unsigned int	pglen = xdr->page_len;
@@ -290,7 +290,7 @@
 		char *kaddr;
 
 		len = PAGE_CACHE_SIZE;
-		kaddr = kmap_atomic(*ppage, KM_USER0);
+		kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
 		if (base) {
 			len -= base;
 			if (pglen < len)
@@ -302,7 +302,7 @@
 				len = pglen;
 			ret = copy_actor(desc, kaddr, len);
 		}
-		kunmap_atomic(kaddr, KM_USER0);
+		kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
 		if (ret != len || !desc->count)
 			return;
 		ppage++;
diff -Nru a/scripts/Configure b/scripts/Configure
--- a/scripts/Configure	Sat Jun  8 22:31:36 2002
+++ b/scripts/Configure	Sat Jun  8 22:31:36 2002
@@ -48,6 +48,10 @@
 #
 # 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
 # - Improve the exit message (Jeff Ronne).
+#
+# 7 October 2000, Ghozlane Toumi, <gtoumi@messel.emse.fr>
+# added switches for "random" , "all yes" and "all modules"
+#
 
 #
 # Make sure we're really running bash.
@@ -76,6 +80,43 @@
 }
 
 #
+# returns a random number between 1 and $1
+#
+function rnd () {
+	rnd=$[ $RANDOM  %  $1 + 1 ]
+}
+
+#
+# randomly chose a number in a config list (LIST_CONFIG_NAME)
+# or in a range ( MIN_CONFIG_NAME MAX_CONFIG_NAME )
+# ONLY if there is no forced default (and we are in an "auto" mode)
+# we are limited by the range of values taken by  "$RANDOM"
+#
+#       rndval CONFIG_NAME
+#
+
+function rndval () {
+	[ "$AUTO" != "yes" -o -n "$old" ] && return
+	def_list=$(eval echo "\${LIST_$1}")
+	def_min=$(eval echo "\${MIN_$1}")
+	def_max=$(eval echo "\${MAX_$1}")
+
+	if [ -n "$def_list" ]; then
+	  set -- $(echo $def_list | sed 's/,/ /g')
+	  rnd $#
+	  while [ $rnd -le $# ] ; do
+	    def=$1
+	    shift
+	  done
+	  return
+	fi
+	if [ -n "$def_min" -a -n "$def_max" ]; then
+	  rnd $[ $def_max - $def_min ]
+	  def=$[ $def_min + $rnd ]
+	fi
+}
+
+#
 # help prints the corresponding help text from Configure.help to stdout
 #
 #       help variable
@@ -109,7 +150,11 @@
 #	readln prompt default oldval
 #
 function readln () {
-	if [ "$DEFAULT" = "-d" -a -n "$3" ]; then
+	if [ "$AUTO" = "yes" ]; then 
+		echo -n "$1"
+		ans=$2
+		echo $ans
+	elif [ "$DEFAULT" = "-d" -a -n "$3" ]; then
 		echo "$1"
 		ans=$2
 	else
@@ -169,6 +214,17 @@
 function bool () {
 	old=$(eval echo "\${$2}")
 	def=${old:-'n'}
+	if [ "$AUTO" = "yes" -a -z "$old" ]; then
+	  if [ "$RND" = "-r" ]; then
+	    rnd 2
+	    case $rnd in
+	      "1") def="y" ;;
+	      "2") def="n" ;;
+	    esac
+	  else
+	    def=$DEF_ANS;
+	  fi
+	fi
 	case "$def" in
 	 "y" | "m") defprompt="Y/n/?"
 	      def="y"
@@ -200,6 +256,18 @@
 	else 
 	  old=$(eval echo "\${$2}")
 	  def=${old:-'n'}
+	  if [ "$AUTO" = "yes" -a -z "$old" ]; then
+	     if [ "$RND" = "-r" ]; then 
+	      rnd 3
+	      case $rnd in
+	        "1") def="y" ;;
+	        "2") def="n" ;;
+	        "3") def="m" ;;
+	      esac
+	    else
+	      def=$DEF_ANS
+	    fi
+	  fi
 	  case "$def" in
 	   "y") defprompt="Y/m/n/?"
 		;;
@@ -256,6 +324,17 @@
 
 	if [ $need_module = 1 ]; then
 	   if [ "$CONFIG_MODULES" = "y" ]; then
+		if [ "$AUTO" = "yes" -a -z "$old" ]; then
+		   if [ "$RND" = "-r" ]; then
+		      rnd 2
+		      case $rnd in
+			"1") def="m" ;;
+			"2") def="n" ;;
+		      esac
+		   else
+		      def=$DEF_ANS
+		   fi
+		fi
 		case "$def" in
 		 "y" | "m") defprompt="M/n/?"
 		      def="m"
@@ -351,6 +430,7 @@
 	else
 	  max=10000000     # !!
 	fi
+	rndval $2
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
 	  if expr \( \( $ans + 0 \) \>= $min \) \& \( $ans \<= $max \) >/dev/null 2>&1 ; then
@@ -382,6 +462,7 @@
 	old=$(eval echo "\${$2}")
 	def=${old:-$3}
 	def=${def#*[x,X]}
+	rndval $2
 	while :; do
 	  readln "$1 ($2) [$def] " "$def" "$old"
 	  ans=${ans#*[x,X]}
@@ -464,6 +545,15 @@
 		shift; shift
 	done
 
+	if [ "$RND" = "-r" -a -z "$old" ] ; then 
+	  set -- $choices
+	  rnd $#
+	  while [ $rnd -le $# ] ; do 
+	    def=$1
+	    shift ; shift
+	  done
+	fi
+
 	val=""
 	while [ -z "$val" ]; do
 		ambg=n
@@ -512,6 +602,7 @@
 
 CONFIG=.tmpconfig
 CONFIG_H=.tmpconfig.h
+FORCE_DEFAULT=.force_default
 trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
 
 #
@@ -532,34 +623,57 @@
 	shift
 fi
 
+RND=""
+DEF_ANS=""
+AUTO=""
+case "$1" in 
+	-r) RND="-r" ; AUTO="yes" ; shift ;;
+	-y) DEF_ANS="y" ; AUTO="yes" ; shift ;;
+	-m) DEF_ANS="m" ; AUTO="yes" ; shift ;;
+	-n) DEF_ANS="n" ; AUTO="yes" ; shift ;;
+esac
+
 CONFIG_IN=./config.in
 if [ "$1" != "" ] ; then
 	CONFIG_IN=$1
 fi
 
-DEFAULTS=.config
-if [ ! -f .config ]; then
-  DEFAULTS=/etc/kernel-config
-  if [ ! -f $DEFAULTS ]; then
-    DEFAULTS=/boot/config-`uname -r`
-    if [ ! -f $DEFAULTS ]; then
-      DEFAULTS=arch/$ARCH/defconfig
-    fi
+for DEFAULTS in .config /lib/modules/`uname -r`/.config /etc/kernel-config /boot/config-`uname -r` arch/$ARCH/defconfig
+do
+  [ -r $DEFAULTS ] && break
+done
+
+if [ "$AUTO" != "yes" ]; then
+  if [ -f $DEFAULTS ]; then
+    echo "#"
+    echo "# Using defaults found in" $DEFAULTS
+    echo "#"
+    . $DEFAULTS
+    sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
+    . .config-is-not.$$
+    rm .config-is-not.$$
+  else
+    echo "#"
+    echo "# No defaults found"
+    echo "#"
   fi
-fi
-
-if [ -f $DEFAULTS ]; then
-  echo "#"
-  echo "# Using defaults found in" $DEFAULTS
-  echo "#"
-  . $DEFAULTS
-  sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
-  . .config-is-not.$$
-  rm .config-is-not.$$
 else
-  echo "#"
-  echo "# No defaults found"
-  echo "#"
+  if [ -f $FORCE_DEFAULT ]; then
+    echo "#"
+    echo "# Forcing defaults found in $FORCE_DEFAULT"
+    echo "#"
+    sed -e '
+s/# \(CONFIG_[^ ]*\) is not.*/\1=n/;
+s/# range \(CONFIG_[^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\)/MIN_\1=\2; MAX_\1=\3/;
+s/# list \(CONFIG_[^ ]*\) \([^ ][^ ]*\)/LIST_\1=\2/
+' <$FORCE_DEFAULT >.default_val.$$
+    . .default_val.$$
+    rm .default_val.$$
+  else
+    echo "#"
+    echo "# No defaults found"
+    echo "#"
+  fi 
 fi
 
 . $CONFIG_IN
diff -Nru a/scripts/Makefile b/scripts/Makefile
--- a/scripts/Makefile	Sat Jun  8 22:31:49 2002
+++ b/scripts/Makefile	Sat Jun  8 22:31:49 2002
@@ -2,13 +2,15 @@
 # always needed
 # ---------------------------------------------------------------------------
 
-all: mkdep split-include
+# The following temporary rule will make sure that people's
+# trees get updated to the right permissions, since patch(1)
+# can't do it
+CHMOD_FILES := docgen gen-all-syms kernel-doc mkcompile_h makelst
 
-mkdep: mkdep.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+all: fixdep split-include $(CHMOD_FILES)
 
-split-include: split-include.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+$(CHMOD_FILES): FORCE
+	@chmod a+x $@
 
 # xconfig
 # ---------------------------------------------------------------------------
@@ -35,27 +37,27 @@
 	) > $@
 	chmod 755 $@
 
-tkparse: tkparse.o tkcond.o tkgen.o
-	$(HOSTCC) -o $@ $^
+# DocBook stuff
+# ---------------------------------------------------------------------------
 
-tkparse.o tkcond.o tkgen.o: %.o: %.c
-	$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
+doc-progs: docproc
 
-# DocBook stuff
 # ---------------------------------------------------------------------------
 
-doc-progs: docproc docgen gen-all-syms kernel-doc
+.PHONY: lxdialog
 
-docproc: docproc.c
-	$(HOSTCC) $(HOSTCFLAGS) -o $@ $<
+lxdialog:
+	$(MAKE) -C lxdialog all
 
-docgen gen-all-syms kernel-doc: FORCE
-	chmod 755 $@
+# ---------------------------------------------------------------------------
 
+host-progs := fixdep split-include docproc tkparse
 
-include $(TOPDIR)/Rules.make
+tkparse-objs := tkparse.o tkcond.o tkgen.o
 
-# we don't have automatic deps for host programs
+# fixdep is needed to compile other host programs
 
-tkparse.o tkcond.o tkgen.o: tkparse.h
+split-include docproc $(tkparse-objs) lxdialog: fixdep
 
+
+include $(TOPDIR)/Rules.make
diff -Nru a/scripts/fixdep.c b/scripts/fixdep.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/scripts/fixdep.c	Sat Jun  8 22:31:52 2002
@@ -0,0 +1,388 @@
+/*
+ * "Optimize" a list of dependencies as spit out by gcc -MD 
+ * for the kernel build
+ * ===========================================================================
+ *
+ * Author       Kai Germaschewski
+ * Copyright    2002 by Kai Germaschewski  <kai.germaschewski@gmx.de>
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU General Public License, incorporated herein by reference.
+ *
+ *
+ * Introduction:
+ * 
+ * gcc produces a very nice and correct list of dependencies which
+ * tells make when to remake a file.
+ *
+ * To use this list as-is however has the drawback that virtually
+ * every file in the kernel includes <linux/config.h> which then again
+ * includes <linux/autoconf.h>
+ *
+ * If the user re-runs make *config, linux/autoconf.h will be
+ * regenerated.  make notices that and will rebuild every file which
+ * includes autconf.h, i.e. basically all files. This is extremely
+ * annoying if the user just changed CONFIG_HIS_DRIVER from n to m.
+ * 
+ * So we play the same trick that "mkdep" played before. We replace
+ * the dependency on linux/autoconf.h by a dependency on every config
+ * option which is mentioned in any of the listed prequisites.
+ *  
+ * To be exact, split-include populates a tree in include/config/,
+ * e.g. include/config/his/driver.h, which contains the #define/#undef
+ * for the CONFIG_HIS_DRIVER option.
+ *
+ * So if the user changes his CONFIG_HIS_DRIVER option, only the objects
+ * which depend on "include/linux/config/his/driver.h" will be rebuilt,
+ * so most likely only his driver ;-) 
+ *
+ * The idea above dates, by the way, back to Michael E Chastain, AFAIK.
+ * 
+ * So to get dependencies right, there two issues:
+ * o if any of the files the compiler read changed, we need to rebuild
+ * o if the command line given to the compile the file changed, we
+ *   better rebuild as well.
+ *
+ * The former is handled by using the -MD output, the later by saving
+ * the command line used to compile the old object and comparing it
+ * to the one we would now use.
+ *
+ * Again, also this idea is pretty old and has been discussed on
+ * kbuild-devel a long time ago. I don't have a sensibly working
+ * internet connection right now, so I rather don't mention names
+ * without double checking.
+ *
+ * This code here has been based partially based on mkdep.c, which
+ * says the following about its history:
+ *
+ *   Copyright abandoned, Michael Chastain, <mailto:mec@shout.net>.
+ *   This is a C version of syncdep.pl by Werner Almesberger.
+ *
+ *
+ * It is invoked as
+ *
+ *   fixdep <target> <topdir> <cmdline>
+ *
+ * and will read the dependency file ".<target>.d".
+ *
+ * The transformed dependency snipped is written to stdout.
+ *
+ * It first generates a line
+ *
+ *   cmd_<target> = <cmdline>
+ *
+ * and then basically copies the .<target>.d file to stdout, in the
+ * process filtering out the dependency on linux/autconf.h and adding
+ * dependencies on include/config/my/option.h for every
+ * CONFIG_MY_OPTION encountered in any of the prequisites.
+ *
+ * It will also filter out all the dependencies on *.ver. We need
+ * to make sure that the generated version checksum are globally up
+ * to date before even starting the recursive build, so it's too late
+ * at this point anyway.
+ *
+ * The algorithm to grep for "CONFIG_..." is bit unusual, but should
+ * be fast ;-) We don't even try to really parse the header files, but
+ * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will
+ * be picked up as well. It's not a problem with respect to
+ * correctness, since that can only give too many dependencies, thus
+ * we cannot miss a rebuild. Since people tend to not mention totally
+ * unrelated CONFIG_ options all over the place, it's not an
+ * efficiency problem either.
+ * 
+ * (Note: it'd be easy to port over the complete mkdep state machine,
+ *  but I don't think the added complexity is worth it)
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <netinet/in.h>
+
+#define INT_CONF ntohl(0x434f4e46)
+#define INT_ONFI ntohl(0x4f4e4649)
+#define INT_NFIG ntohl(0x4e464947)
+#define INT_FIG_ ntohl(0x4649475f)
+
+char *topdir;
+
+void usage(void)
+
+{
+	fprintf(stderr, "Usage: fixdep <target> <topdir> <cmdline>\n");
+	exit(1);
+}
+
+void print_cmdline(char *target, char *cmdline)
+{
+	char *s = strdup(target);
+	char *p = s;
+
+	if (!s) {
+		fprintf(stderr, "no mem!\n");
+		exit(2);
+	}
+	while ((p = strchr(p,'/')))
+		*p = '_';
+
+	printf("cmd_%s := %s\n\n", s, cmdline);
+
+	free(s);
+}
+
+char * str_config  = NULL;
+int    size_config = 0;
+int    len_config  = 0;
+
+/*
+ * Grow the configuration string to a desired length.
+ * Usually the first growth is plenty.
+ */
+void grow_config(int len)
+{
+	while (len_config + len > size_config) {
+		if (size_config == 0)
+			size_config = 2048;
+		str_config = realloc(str_config, size_config *= 2);
+		if (str_config == NULL)
+			{ perror("malloc"); exit(1); }
+	}
+}
+
+
+
+/*
+ * Lookup a value in the configuration string.
+ */
+int is_defined_config(const char * name, int len)
+{
+	const char * pconfig;
+	const char * plast = str_config + len_config - len;
+	for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
+		if (pconfig[ -1] == '\n'
+		&&  pconfig[len] == '\n'
+		&&  !memcmp(pconfig, name, len))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Add a new value to the configuration string.
+ */
+void define_config(const char * name, int len)
+{
+	grow_config(len + 1);
+
+	memcpy(str_config+len_config, name, len);
+	len_config += len;
+	str_config[len_config++] = '\n';
+}
+
+/*
+ * Clear the set of configuration strings.
+ */
+void clear_config(void)
+{
+	len_config = 0;
+	define_config("", 0);
+}
+
+/*
+ * Record the use of a CONFIG_* word.
+ */
+void use_config(char *m, int slen)
+{
+	char s[PATH_MAX];
+	char *p;
+
+	if (is_defined_config(m, slen))
+	    return;
+
+	define_config(m, slen);
+
+	memcpy(s, m, slen); s[slen] = 0;
+
+	for (p = s; p < s + slen; p++) {
+		if (*p == '_')
+			*p = '/';
+		else
+			*p = tolower((unsigned char)*p);
+	}
+	printf("    $(wildcard %s/include/config/%s.h) \\\n", topdir, s);
+}
+
+void parse_config_file(char *map, size_t len)
+{
+	int *end = (int *) (map + len);
+	// start at +1, so that p can never be < map
+	int *m   = (int *) map + 1;
+	char *p, *q;
+
+	for (; m < end; m++) {
+		if (*m == INT_CONF) { p = (char *) m  ; goto conf; }
+		if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+		if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+		if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
+		continue;
+	conf:
+		if (p > map + len - 7)
+			continue;
+		if (memcmp(p, "CONFIG_", 7))
+			continue;
+		for (q = p + 7; q < map + len; q++) {
+			if (!(isalnum(*q) || *q == '_'))
+				goto found;
+		}
+		continue;
+
+	found: 
+		use_config(p+7, q-p-7);
+	}
+}
+
+/* test is s ends in sub */
+int strrcmp(char *s, char *sub)
+{
+	int slen = strlen(s);
+	int sublen = strlen(sub);
+  
+	if (sublen > slen)
+		return 1;
+	
+	return memcmp(s + slen - sublen, sub, sublen);
+}
+
+void do_config_file(char *filename)
+{
+	struct stat st;
+	int fd;
+	void *map;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		perror(filename);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (st.st_size == 0) {
+		close(fd);
+		return;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if ((long) map == -1) {
+		perror("mmap");
+		close(fd);
+		return;
+	}
+	
+	parse_config_file(map, st.st_size);
+
+	munmap(map, st.st_size);
+}
+
+void parse_dep_file(void *map, size_t len)
+{
+	char *m = map;
+	char *end = map + len;
+	char *p;
+	char s[PATH_MAX];
+
+	p = strchr(m, ':');
+	if (!p) {
+		fprintf(stderr, "parse error at %d", __LINE__);
+		exit(1);
+	}
+	memcpy(s, m, p-m); s[p-m] = 0;
+	printf("%s: \\\n", s);
+	m = p+1;
+
+	clear_config();
+
+	while (m < end) {
+		while (m < end && (*m == ' ' || *m == '\\' || *m == '\n'))
+			m++;
+		p = m;
+		while (p < end && *p != ' ') p++;
+		if (p == end) {
+			do p--; while (!isalnum(*p));
+			p++;
+		}
+		memcpy(s, m, p-m); s[p-m] = 0;
+		if (strrcmp(s, "include/linux/autoconf.h") &&
+		    strrcmp(s, ".ver")) {
+			printf("  %s \\\n", s);
+			do_config_file(s);
+		}
+		m = p + 1;
+	}
+	printf("\n");
+}
+
+void print_deps(char *target)
+{
+	char filename[PATH_MAX];
+	struct stat st;
+	int fd;
+	void *map;
+
+	sprintf(filename, ".%s.d", target);
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		perror(filename);
+		exit(2);
+	}
+	fstat(fd, &st);
+	if (st.st_size == 0) {
+		fprintf(stderr,"%s is empty\n",filename);
+		close(fd);
+		return;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if ((long) map == -1) {
+		perror("mmap");
+		close(fd);
+		return;
+	}
+	
+	parse_dep_file(map, st.st_size);
+
+	munmap(map, st.st_size);
+}
+
+void traps(void)
+{
+	char *test = "CONF";
+
+	if (*(int *)test != INT_CONF) {
+		fprintf(stderr, "sizeof(int) != 4 or wrong endianess? %#x\n",
+			*(int *)test);
+		exit(2);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	char *target, *cmdline;
+	
+	traps();
+
+	if (argc != 4)
+		usage();
+		
+	target = argv[1];
+	topdir = argv[2];
+	cmdline = argv[3];
+
+	print_cmdline(target, cmdline);
+	print_deps(target);
+
+	return 0;
+}
diff -Nru a/scripts/lxdialog/Makefile b/scripts/lxdialog/Makefile
--- a/scripts/lxdialog/Makefile	Sat Jun  8 22:31:37 2002
+++ b/scripts/lxdialog/Makefile	Sat Jun  8 22:31:37 2002
@@ -1,35 +1,32 @@
-HOSTCFLAGS += -DLOCALE 
-LIBS = -lncurses
+HOST_EXTRACFLAGS := -DLOCALE 
+HOST_LOADLIBES   := -lncurses
 
 ifeq (/usr/include/ncurses/ncurses.h, $(wildcard /usr/include/ncurses/ncurses.h))
-        HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
+        HOST_EXTRACFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses.h>"
 else
 ifeq (/usr/include/ncurses/curses.h, $(wildcard /usr/include/ncurses/curses.h))
-        HOSTCFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
+        HOST_EXTRACFLAGS += -I/usr/include/ncurses -DCURSES_LOC="<ncurses/curses.h>"
 else
 ifeq (/usr/include/ncurses.h, $(wildcard /usr/include/ncurses.h))
-        HOSTCFLAGS += -DCURSES_LOC="<ncurses.h>"
+        HOST_EXTRACFLAGS += -DCURSES_LOC="<ncurses.h>"
 else
-	HOSTCFLAGS += -DCURSES_LOC="<curses.h>"
+	HOST_EXTRACFLAGS += -DCURSES_LOC="<curses.h>"
 endif
 endif
 endif
 
+host-progs := lxdialog
 
-OBJS = checklist.o menubox.o textbox.o yesno.o inputbox.o \
-       util.o lxdialog.o msgbox.o
-
-%.o: %.c
-	$(HOSTCC) $(HOSTCFLAGS) -c -o $@ $<
+lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \
+		 util.o lxdialog.o msgbox.o
 
 all: ncurses lxdialog
 
-lxdialog: $(OBJS)
-	$(HOSTCC) -o lxdialog $(OBJS) $(LIBS)
+include $(TOPDIR)/Rules.make
 
 ncurses:
 	@echo "main() {}" > lxtemp.c
-	@if $(HOSTCC) -lncurses lxtemp.c ; then \
+	@if $(HOSTCC) lxtemp.c  $(HOST_LOADLIBES); then \
 		rm -f lxtemp.c a.out; \
 	else \
 		rm -f lxtemp.c; \
diff -Nru a/scripts/makelst b/scripts/makelst
--- a/scripts/makelst	Sat Jun  8 22:31:52 2002
+++ b/scripts/makelst	Sat Jun  8 22:31:52 2002
@@ -6,17 +6,26 @@
 #            William Stearns <wstearns@pobox.com>
 #%.lst: %.c
 #	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
-#	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
+#	$(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP)
 #
 #    Copyright (C) 2000 IBM Corporation
 #    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
 #
 
-t1=`$3 --syms $2/$1.o | grep .text | grep " F " | head -n 1`
-t2=`echo $t1 | gawk '{ print $6 }'`
-t3=`grep $t2 $2/System.map`
-t4=`echo $t3 | gawk '{ print $1 }'`
-t5=`echo $t1 | gawk '{ print $1 }'`
-t6=`echo $t4 - $t5 | sed -e s/a/A/g -e s/b/B/g -e s/c/C/g -e s/d/D/g -e s/e/E/g -e s/f/F/g`
-t7=`( echo  ibase=16 ; echo $t6 ) | bc`
-$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
+t1=`$3 --syms $1 | grep .text | grep " F " | head -n 1`
+if [ -n "$t1" ]; then
+  t2=`echo $t1 | gawk '{ print $6 }'`
+  if [ ! -r $2 ]; then
+    echo "No System.map" >&2
+    t7=0
+  else
+    t3=`grep $t2 $2`
+    t4=`echo $t3 | gawk '{ print $1 }'`
+    t5=`echo $t1 | gawk '{ print $1 }'`
+    t6=`echo $t4 - $t5 | tr a-f A-F`
+    t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+  fi
+else
+  t7=0
+fi
+$3 --source --adjust-vma=$t7 $1
diff -Nru a/scripts/mkcompile_h b/scripts/mkcompile_h
--- a/scripts/mkcompile_h	Sat Jun  8 22:31:49 2002
+++ b/scripts/mkcompile_h	Sat Jun  8 22:31:49 2002
@@ -10,24 +10,32 @@
   echo 0 > ../.version
 fi
 
+
+UTS_VERSION="#$VERSION"
+if [ -n "$SMP" ] ; then UTS_VERSION="$UTS_VERSION SMP"; fi
+UTS_VERSION="$UTS_VERSION `LANG=C date`"
+
+# Truncate to maximum length
+
+UTS_LEN=64
+UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
+
 # Generate a temporary compile.h
 
 ( echo /\* This file is auto generated, version $VERSION \*/
 
   echo \#define UTS_MACHINE \"$ARCH\"
 
-  echo -n \#define UTS_VERSION \"\#$VERSION
-  if [ -n "$SMP" ] ; then echo -n " SMP"; fi
-  echo ' '`date`'"'
+  echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
 
-  echo \#define LINUX_COMPILE_TIME \"`date +%T`\"
+  echo \#define LINUX_COMPILE_TIME \"`LANG=C date +%T`\"
   echo \#define LINUX_COMPILE_BY \"`whoami`\"
-  echo \#define LINUX_COMPILE_HOST \"`hostname`\"
+  echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
 
   if [ -x /bin/dnsdomainname ]; then
-    echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname`\"
+    echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
   elif [ -x /bin/domainname ]; then
-    echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\"
+    echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
   else
     echo \#define LINUX_COMPILE_DOMAIN
   fi
@@ -48,9 +56,10 @@
       grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' $TARGET > .tmpver.1 && \
       grep -v 'UTS_VERSION\|LINUX_COMPILE_TIME' .tmpcompile > .tmpver.2 && \
       cmp -s .tmpver.1 .tmpver.2; then
-   echo $TARGET is unchanged;
+   echo ' (unchanged)'
    rm -f .tmpcompile
 else
+   echo ' (updated)'
    mv -f .tmpcompile $TARGET
 fi
 rm -f .tmpver.1 .tmpver.2
diff -Nru a/scripts/mkdep.c b/scripts/mkdep.c
--- a/scripts/mkdep.c	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,628 +0,0 @@
-/*
- * Originally by Linus Torvalds.
- * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
- *
- * Usage: mkdep cflags -- file ...
- * 
- * Read source files and output makefile dependency lines for them.
- * I make simple dependency lines for #include <*.h> and #include "*.h".
- * I also find instances of CONFIG_FOO and generate dependencies
- *    like include/config/foo.h.
- *
- * 1 August 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Keith Owens reported a bug in smart config processing.  There used
- *   to be an optimization for "#define CONFIG_FOO ... #ifdef CONFIG_FOO",
- *   so that the file would not depend on CONFIG_FOO because the file defines
- *   this symbol itself.  But this optimization is bogus!  Consider this code:
- *   "#if 0 \n #define CONFIG_FOO \n #endif ... #ifdef CONFIG_FOO".  Here
- *   the definition is inactivated, but I still used it.  It turns out this
- *   actually happens a few times in the kernel source.  The simple way to
- *   fix this problem is to remove this particular optimization.
- *
- * 2.3.99-pre1, Andrew Morton <andrewm@uow.edu.au>
- * - Changed so that 'filename.o' depends upon 'filename.[cS]'.  This is so that
- *   missing source files are noticed, rather than silently ignored.
- *
- * 2.4.2-pre3, Keith Owens <kaos@ocs.com.au>
- * - Accept cflags followed by '--' followed by filenames.  mkdep extracts -I
- *   options from cflags and looks in the specified directories as well as the
- *   defaults.   Only -I is supported, no attempt is made to handle -idirafter,
- *   -isystem, -I- etc.
- */
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/fcntl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-
-
-char __depname[512] = "\n\t@touch ";
-#define depname (__depname+9)
-int hasdep;
-
-struct path_struct {
-	int len;
-	char *buffer;
-};
-struct path_struct *path_array;
-int paths;
-
-
-/* Current input file */
-static const char *g_filename;
-
-/*
- * This records all the configuration options seen.
- * In perl this would be a hash, but here it's a long string
- * of values separated by newlines.  This is simple and
- * extremely fast.
- */
-char * str_config  = NULL;
-int    size_config = 0;
-int    len_config  = 0;
-
-static void
-do_depname(void)
-{
-	if (!hasdep) {
-		hasdep = 1;
-		printf("%s:", depname);
-		if (g_filename)
-			printf(" %s", g_filename);
-	}
-}
-
-/*
- * Grow the configuration string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_config(int len)
-{
-	while (len_config + len > size_config) {
-		if (size_config == 0)
-			size_config = 2048;
-		str_config = realloc(str_config, size_config *= 2);
-		if (str_config == NULL)
-			{ perror("malloc config"); exit(1); }
-	}
-}
-
-
-
-/*
- * Lookup a value in the configuration string.
- */
-int is_defined_config(const char * name, int len)
-{
-	const char * pconfig;
-	const char * plast = str_config + len_config - len;
-	for ( pconfig = str_config + 1; pconfig < plast; pconfig++ ) {
-		if (pconfig[ -1] == '\n'
-		&&  pconfig[len] == '\n'
-		&&  !memcmp(pconfig, name, len))
-			return 1;
-	}
-	return 0;
-}
-
-
-
-/*
- * Add a new value to the configuration string.
- */
-void define_config(const char * name, int len)
-{
-	grow_config(len + 1);
-
-	memcpy(str_config+len_config, name, len);
-	len_config += len;
-	str_config[len_config++] = '\n';
-}
-
-
-
-/*
- * Clear the set of configuration strings.
- */
-void clear_config(void)
-{
-	len_config = 0;
-	define_config("", 0);
-}
-
-
-
-/*
- * This records all the precious .h filenames.  No need for a hash,
- * it's a long string of values enclosed in tab and newline.
- */
-char * str_precious  = NULL;
-int    size_precious = 0;
-int    len_precious  = 0;
-
-
-
-/*
- * Grow the precious string to a desired length.
- * Usually the first growth is plenty.
- */
-void grow_precious(int len)
-{
-	while (len_precious + len > size_precious) {
-		if (size_precious == 0)
-			size_precious = 2048;
-		str_precious = realloc(str_precious, size_precious *= 2);
-		if (str_precious == NULL)
-			{ perror("malloc"); exit(1); }
-	}
-}
-
-
-
-/*
- * Add a new value to the precious string.
- */
-void define_precious(const char * filename)
-{
-	int len = strlen(filename);
-	grow_precious(len + 4);
-	*(str_precious+len_precious++) = '\t';
-	memcpy(str_precious+len_precious, filename, len);
-	len_precious += len;
-	memcpy(str_precious+len_precious, " \\\n", 3);
-	len_precious += 3;
-}
-
-
-
-/*
- * Handle an #include line.
- */
-void handle_include(int start, const char * name, int len)
-{
-	struct path_struct *path;
-	int i;
-
-	if (len == 14 && !memcmp(name, "linux/config.h", len))
-		return;
-
-	if (len >= 7 && !memcmp(name, "config/", 7))
-		define_config(name+7, len-7-2);
-
-	for (i = start, path = path_array+start; i < paths; ++i, ++path) {
-		memcpy(path->buffer+path->len, name, len);
-		path->buffer[path->len+len] = '\0';
-		if (access(path->buffer, F_OK) == 0) {
-			do_depname();
-			printf(" \\\n   %s", path->buffer);
-			return;
-		}
-	}
-
-}
-
-
-
-/*
- * Add a path to the list of include paths.
- */
-void add_path(const char * name)
-{
-	struct path_struct *path;
-	char resolved_path[PATH_MAX+1];
-	const char *name2;
-
-	if (strcmp(name, ".")) {
-		name2 = realpath(name, resolved_path);
-		if (!name2) {
-			fprintf(stderr, "realpath(%s) failed, %m\n", name);
-			exit(1);
-		}
-	}
-	else {
-		name2 = "";
-	}
-
-	path_array = realloc(path_array, (++paths)*sizeof(*path_array));
-	if (!path_array) {
-		fprintf(stderr, "cannot expand path_arry\n");
-		exit(1);
-	}
-
-	path = path_array+paths-1;
-	path->len = strlen(name2);
-	path->buffer = malloc(path->len+1+256+1);
-	if (!path->buffer) {
-		fprintf(stderr, "cannot allocate path buffer\n");
-		exit(1);
-	}
-	strcpy(path->buffer, name2);
-	if (path->len && *(path->buffer+path->len-1) != '/') {
-		*(path->buffer+path->len) = '/';
-		*(path->buffer+(++(path->len))) = '\0';
-	}
-}
-
-
-
-/*
- * Record the use of a CONFIG_* word.
- */
-void use_config(const char * name, int len)
-{
-	char *pc;
-	int i;
-
-	pc = path_array[paths-1].buffer + path_array[paths-1].len;
-	memcpy(pc, "config/", 7);
-	pc += 7;
-
-	for (i = 0; i < len; i++) {
-	    int c = (unsigned char) name[i];
-	    if (isupper(c)) c = tolower(c);
-	    if (c == '_')   c = '/';
-	    pc[i] = c;
-	}
-	pc[len] = '\0';
-
-	if (is_defined_config(pc, len))
-	    return;
-
-	define_config(pc, len);
-
-	do_depname();
-	printf(" \\\n   $(wildcard %s.h)", path_array[paths-1].buffer);
-}
-
-
-
-/*
- * Macros for stunningly fast map-based character access.
- * __buf is a register which holds the current word of the input.
- * Thus, there is one memory access per sizeof(unsigned long) characters.
- */
-
-#if defined(__alpha__) || defined(__i386__) || defined(__ia64__)  || defined(__x86_64__) || defined(__MIPSEL__)	\
-    || defined(__arm__)
-#define LE_MACHINE
-#endif
-
-#ifdef LE_MACHINE
-#define next_byte(x) (x >>= 8)
-#define current ((unsigned char) __buf)
-#else
-#define next_byte(x) (x <<= 8)
-#define current (__buf >> 8*(sizeof(unsigned long)-1))
-#endif
-
-#define GETNEXT { \
-	next_byte(__buf); \
-	if ((unsigned long) next % sizeof(unsigned long) == 0) { \
-		if (next >= end) \
-			break; \
-		__buf = * (unsigned long *) next; \
-	} \
-	next++; \
-}
-
-/*
- * State machine macros.
- */
-#define CASE(c,label) if (current == c) goto label
-#define NOTCASE(c,label) if (current != c) goto label
-
-/*
- * Yet another state machine speedup.
- */
-#define MAX2(a,b) ((a)>(b)?(a):(b))
-#define MIN2(a,b) ((a)<(b)?(a):(b))
-#define MAX5(a,b,c,d,e) (MAX2(a,MAX2(b,MAX2(c,MAX2(d,e)))))
-#define MIN5(a,b,c,d,e) (MIN2(a,MIN2(b,MIN2(c,MIN2(d,e)))))
-
-
-
-/*
- * The state machine looks for (approximately) these Perl regular expressions:
- *
- *    m|\/\*.*?\*\/|
- *    m|\/\/.*|
- *    m|'.*?'|
- *    m|".*?"|
- *    m|#\s*include\s*"(.*?)"|
- *    m|#\s*include\s*<(.*?>"|
- *    m|#\s*(?define|undef)\s*CONFIG_(\w*)|
- *    m|(?!\w)CONFIG_|
- *
- * About 98% of the CPU time is spent here, and most of that is in
- * the 'start' paragraph.  Because the current characters are
- * in a register, the start loop usually eats 4 or 8 characters
- * per memory read.  The MAX5 and MIN5 tests dispose of most
- * input characters with 1 or 2 comparisons.
- */
-void state_machine(const char * map, const char * end)
-{
-	const char * next = map;
-	const char * map_dot;
-	unsigned long __buf = 0;
-
-	for (;;) {
-start:
-	GETNEXT
-__start:
-	if (current > MAX5('/','\'','"','#','C')) goto start;
-	if (current < MIN5('/','\'','"','#','C')) goto start;
-	CASE('/',  slash);
-	CASE('\'', squote);
-	CASE('"',  dquote);
-	CASE('#',  pound);
-	CASE('C',  cee);
-	goto start;
-
-/* // */
-slash_slash:
-	GETNEXT
-	CASE('\n', start);
-	NOTCASE('\\', slash_slash);
-	GETNEXT
-	goto slash_slash;
-
-/* / */
-slash:
-	GETNEXT
-	CASE('/',  slash_slash);
-	NOTCASE('*', __start);
-slash_star_dot_star:
-	GETNEXT
-__slash_star_dot_star:
-	NOTCASE('*', slash_star_dot_star);
-	GETNEXT
-	NOTCASE('/', __slash_star_dot_star);
-	goto start;
-
-/* '.*?' */
-squote:
-	GETNEXT
-	CASE('\'', start);
-	NOTCASE('\\', squote);
-	GETNEXT
-	goto squote;
-
-/* ".*?" */
-dquote:
-	GETNEXT
-	CASE('"', start);
-	NOTCASE('\\', dquote);
-	GETNEXT
-	goto dquote;
-
-/* #\s* */
-pound:
-	GETNEXT
-	CASE(' ',  pound);
-	CASE('\t', pound);
-	CASE('i',  pound_i);
-	CASE('d',  pound_d);
-	CASE('u',  pound_u);
-	goto __start;
-
-/* #\s*i */
-pound_i:
-	GETNEXT NOTCASE('n', __start);
-	GETNEXT NOTCASE('c', __start);
-	GETNEXT NOTCASE('l', __start);
-	GETNEXT NOTCASE('u', __start);
-	GETNEXT NOTCASE('d', __start);
-	GETNEXT NOTCASE('e', __start);
-	goto pound_include;
-
-/* #\s*include\s* */
-pound_include:
-	GETNEXT
-	CASE(' ',  pound_include);
-	CASE('\t', pound_include);
-	map_dot = next;
-	CASE('"',  pound_include_dquote);
-	CASE('<',  pound_include_langle);
-	goto __start;
-
-/* #\s*include\s*"(.*)" */
-pound_include_dquote:
-	GETNEXT
-	CASE('\n', start);
-	NOTCASE('"', pound_include_dquote);
-	handle_include(0, map_dot, next - map_dot - 1);
-	goto start;
-
-/* #\s*include\s*<(.*)> */
-pound_include_langle:
-	GETNEXT
-	CASE('\n', start);
-	NOTCASE('>', pound_include_langle);
-	handle_include(1, map_dot, next - map_dot - 1);
-	goto start;
-
-/* #\s*d */
-pound_d:
-	GETNEXT NOTCASE('e', __start);
-	GETNEXT NOTCASE('f', __start);
-	GETNEXT NOTCASE('i', __start);
-	GETNEXT NOTCASE('n', __start);
-	GETNEXT NOTCASE('e', __start);
-	goto pound_define_undef;
-
-/* #\s*u */
-pound_u:
-	GETNEXT NOTCASE('n', __start);
-	GETNEXT NOTCASE('d', __start);
-	GETNEXT NOTCASE('e', __start);
-	GETNEXT NOTCASE('f', __start);
-	goto pound_define_undef;
-
-/*
- * #\s*(define|undef)\s*CONFIG_(\w*)
- *
- * this does not define the word, because it could be inside another
- * conditional (#if 0).  But I do parse the word so that this instance
- * does not count as a use.  -- mec
- */
-pound_define_undef:
-	GETNEXT
-	CASE(' ',  pound_define_undef);
-	CASE('\t', pound_define_undef);
-
-	        NOTCASE('C', __start);
-	GETNEXT NOTCASE('O', __start);
-	GETNEXT NOTCASE('N', __start);
-	GETNEXT NOTCASE('F', __start);
-	GETNEXT NOTCASE('I', __start);
-	GETNEXT NOTCASE('G', __start);
-	GETNEXT NOTCASE('_', __start);
-
-	map_dot = next;
-pound_define_undef_CONFIG_word:
-	GETNEXT
-	if (isalnum(current) || current == '_')
-		goto pound_define_undef_CONFIG_word;
-	goto __start;
-
-/* \<CONFIG_(\w*) */
-cee:
-	if (next >= map+2 && (isalnum(next[-2]) || next[-2] == '_'))
-		goto start;
-	GETNEXT NOTCASE('O', __start);
-	GETNEXT NOTCASE('N', __start);
-	GETNEXT NOTCASE('F', __start);
-	GETNEXT NOTCASE('I', __start);
-	GETNEXT NOTCASE('G', __start);
-	GETNEXT NOTCASE('_', __start);
-
-	map_dot = next;
-cee_CONFIG_word:
-	GETNEXT
-	if (isalnum(current) || current == '_')
-		goto cee_CONFIG_word;
-	use_config(map_dot, next - map_dot - 1);
-	goto __start;
-    }
-}
-
-
-
-/*
- * Generate dependencies for one file.
- */
-void do_depend(const char * filename, const char * command)
-{
-	int mapsize;
-	int pagesizem1 = getpagesize()-1;
-	int fd;
-	struct stat st;
-	char * map;
-
-	fd = open(filename, O_RDONLY);
-	if (fd < 0) {
-		perror(filename);
-		return;
-	}
-
-	fstat(fd, &st);
-	if (st.st_size == 0) {
-		fprintf(stderr,"%s is empty\n",filename);
-		close(fd);
-		return;
-	}
-
-	mapsize = st.st_size;
-	mapsize = (mapsize+pagesizem1) & ~pagesizem1;
-	map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
-	if ((long) map == -1) {
-		perror("mkdep: mmap");
-		close(fd);
-		return;
-	}
-	if ((unsigned long) map % sizeof(unsigned long) != 0)
-	{
-		fprintf(stderr, "do_depend: map not aligned\n");
-		exit(1);
-	}
-
-	hasdep = 0;
-	clear_config();
-	state_machine(map, map+st.st_size);
-	if (hasdep) {
-		puts(command);
-		if (*command)
-			define_precious(filename);
-	}
-
-	munmap(map, mapsize);
-	close(fd);
-}
-
-
-
-/*
- * Generate dependencies for all files.
- */
-int main(int argc, char **argv)
-{
-	int len;
-	const char *hpath;
-
-	hpath = getenv("HPATH");
-	if (!hpath) {
-		fputs("mkdep: HPATH not set in environment.  "
-		      "Don't bypass the top level Makefile.\n", stderr);
-		return 1;
-	}
-
-	add_path(".");		/* for #include "..." */
-
-	while (++argv, --argc > 0) {
-		if (strncmp(*argv, "-I", 2) == 0) {
-			if (*((*argv)+2)) {
-				add_path((*argv)+2);
-			}
-			else {
-				++argv;
-				--argc;
-				add_path(*argv);
-			}
-		}
-		else if (strcmp(*argv, "--") == 0) {
-			break;
-		}
-	}
-
-	add_path(hpath);	/* must be last entry, for config files */
-
-	while (--argc > 0) {
-		const char * filename = *++argv;
-		const char * command  = __depname;
-		g_filename = 0;
-		len = strlen(filename);
-		memcpy(depname, filename, len+1);
-		if (len > 2 && filename[len-2] == '.') {
-			if (filename[len-1] == 'c' || filename[len-1] == 'S') {
-			    depname[len-1] = 'o';
-			    g_filename = filename;
-			    command = "";
-			}
-		}
-		do_depend(filename, command);
-	}
-	if (len_precious) {
-		*(str_precious+len_precious) = '\0';
-		printf(".PRECIOUS:%s\n", str_precious);
-	}
-	return 0;
-}
diff -Nru a/scripts/mkversion_h b/scripts/mkversion_h
--- a/scripts/mkversion_h	Sat Jun  8 22:31:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,24 +0,0 @@
-TARGET=$1
-KERNELRELEASE=$2
-VERSION=$3
-PATCHLEVEL=$4
-SUBLEVEL=$5
-
-# Generate a temporary version.h
-
-( echo \#define UTS_RELEASE \"$KERNELRELEASE\"
-  echo \#define LINUX_VERSION_CODE `expr $VERSION \\* 65536 + $PATCHLEVEL \\* 256 + $SUBLEVEL`
-  echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'
-) > .tmpversion
-
-# Only replace the real version.h if the new one is different
-# in order to preserve the timestamp and avoid unnecessary
-# recompilations.
-
-if [ -r $TARGET ] && \
-      cmp -s $TARGET .tmpversion; then
-   echo $TARGET is unchanged;
-   rm -f .tmpversion
-else
-   mv -f .tmpversion $TARGET
-fi
diff -Nru a/scripts/tkparse.c b/scripts/tkparse.c
--- a/scripts/tkparse.c	Sat Jun  8 22:31:35 2002
+++ b/scripts/tkparse.c	Sat Jun  8 22:31:35 2002
@@ -74,12 +74,12 @@
 
 
 /*
- * Find index of a specyfic variable in the symbol table.
+ * Find index of a specific variable in the symbol table.
  * Create a new entry if it does not exist yet.
  */
-#define VARTABLE_SIZE 4096
-struct variable vartable[VARTABLE_SIZE];
+struct variable *vartable;
 int max_varnum = 0;
+static int vartable_size = 0;
 
 int get_varnum( char * name )
 {
@@ -88,8 +88,13 @@
     for ( i = 1; i <= max_varnum; i++ )
 	if ( strcmp( vartable[i].name, name ) == 0 )
 	    return i;
-    if (max_varnum > VARTABLE_SIZE-1)
-	syntax_error( "Too many variables defined." );
+    while (max_varnum+1 >= vartable_size) {
+	vartable = realloc(vartable, (vartable_size += 1000)*sizeof(*vartable));
+	if (!vartable) {
+	    fprintf(stderr, "tkparse realloc vartable failed\n");
+	    exit(1);
+	}
+    }
     vartable[++max_varnum].name = malloc( strlen( name )+1 );
     strcpy( vartable[max_varnum].name, name );
     return max_varnum;
@@ -818,5 +823,6 @@
     do_source        ( "-"         );
     fix_conditionals ( config_list );
     dump_tk_script   ( config_list );
+    free(vartable);
     return 0;
 }
diff -Nru a/scripts/tkparse.h b/scripts/tkparse.h
--- a/scripts/tkparse.h	Sat Jun  8 22:31:36 2002
+++ b/scripts/tkparse.h	Sat Jun  8 22:31:36 2002
@@ -115,7 +115,7 @@
     char	global_written;
 };
 
-extern struct variable vartable[];
+extern struct variable *vartable;
 extern int max_varnum;
 
 /*
diff -Nru a/sound/last.c b/sound/last.c
--- a/sound/last.c	Sat Jun  8 22:31:36 2002
+++ b/sound/last.c	Sat Jun  8 22:31:36 2002
@@ -19,6 +19,8 @@
  *
  */
 
+#include <linux/init.h>
+
 #define SNDRV_MAIN_OBJECT_FILE
 #include <sound/driver.h>
 #include <sound/core.h>
diff -Nru a/sound/oss/Makefile b/sound/oss/Makefile
--- a/sound/oss/Makefile	Sat Jun  8 22:31:37 2002
+++ b/sound/oss/Makefile	Sat Jun  8 22:31:37 2002
@@ -95,6 +95,7 @@
 vidc_mod-objs	:= vidc.o vidc_fill.o
 wavefront-objs  := wavfront.o wf_midi.o yss225.o
 
+host-progs	:= bin2hex hex2hex
 
 include $(TOPDIR)/Rules.make
 
@@ -104,16 +105,6 @@
 # of what name was used to build them.  If the name changes, they
 # will be forced to be remade.
 #
-# First make the utilities.
-
-bin2hex: bin2hex.c
-	$(HOSTCC) $(HOSTCFLAGS) -o bin2hex bin2hex.c
-
-hex2hex: hex2hex.c
-	$(HOSTCC) $(HOSTCFLAGS) -o hex2hex hex2hex.c
-
-
-
 
 # Turtle Beach Maui / Tropez
 
