## Automatically generated incremental diff
## From:   linux-2.2.17-pre12
## To:     linux-2.2.17-pre13
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.2.17-pre12/CREDITS linux/CREDITS
--- linux-2.2.17-pre12/CREDITS	Mon Dec  3 22:09:38 2001
+++ linux/CREDITS	Mon Dec  3 22:09:50 2001
@@ -2124,7 +2124,7 @@
 
 N: Geert Uytterhoeven
 E: geert@linux-m68k.org
-W: http://www.cs.kuleuven.ac.be/~geert/
+W: http://home.tvd.be/cr26864/
 P: 1024/EC4A1EE1 8B 88 38 35 88 1E 95 A1  CD 9E AE DC 4B 4A 2F 41
 D: m68k/Amiga and PPC/CHRP Longtrail coordinator
 D: Frame buffer device and XF68_FBDev maintainer
diff -urN linux-2.2.17-pre12/Documentation/Changes linux/Documentation/Changes
--- linux-2.2.17-pre12/Documentation/Changes	Wed Jun  7 14:26:42 2000
+++ linux/Documentation/Changes	Mon Dec  3 22:09:50 2001
@@ -753,7 +753,7 @@
 =====
 
 The 2.1 release:
-http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.1.tar.gz
+http://home.tvd.be/cr26864/Linux/fbdev/
 
 PCI utils
 =========
diff -urN linux-2.2.17-pre12/Documentation/Debugging390.txt linux/Documentation/Debugging390.txt
--- linux-2.2.17-pre12/Documentation/Debugging390.txt	Wed May  3 17:16:30 2000
+++ linux/Documentation/Debugging390.txt	Mon Dec  3 22:09:50 2001
@@ -520,9 +520,46 @@
 }
 
 
+New compiler changes
+====================
+
+main(int argc,char *argv[])
+{
+  4004fc:	90 7f f0 1c       	stm	%r7,%r15,28(%r15)
+  400500:	a7 d5 00 04       	bras	%r13,400508 <main+0xc>
+  400504:	00 40 04 f4       	.long	0x004004f4 
+  # compiler now puts constant pool in code to so it saves an instruction 
+  400508:	18 0f             	lr	%r0,%r15
+  40050a:	a7 fa ff a0       	ahi	%r15,-96
+  40050e:	50 00 f0 00       	st	%r0,0(%r15)
+	return(test(5));
+  400512:	58 10 d0 00       	l	%r1,0(%r13)
+  400516:	a7 28 00 05       	lhi	%r2,5
+  40051a:	0d e1             	basr	%r14,%r1
+  # compiler adds 1 extra instruction to epilogue this is done to
+  # avoid processor pipeline stalls owing to data dependencies on g5 &
+  # above as register 14 in the old code was needed directly after being loaded 
+  # by the lm	%r11,%r15,140(%r15) for the br %14.
+  40051c:	58 40 f0 98       	l	%r4,152(%r15)
+  400520:	98 7f f0 7c       	lm	%r7,%r15,124(%r15)
+  400524:	07 f4             	br	%r4
+}
+
+Hartmut ( our compiler developer ) also has been threatening to take out the
+stack backchain in optimised code as this also causes pipeline stalls, you
+have been warned.
+
+
+
 Compiling programs for debugging on Linux for S390
 ==================================================
-Make sure that the gcc is compiling & linking with the -g flag on.
+Make sure that the gcc is compiling & linking with the -g flag on
+this generates plain old gnu stabs, don't use
+-ggdb, -gxcoff+ or any other silly option these other options more than
+likely don't work ( we haven't tested them ), -gstabs is supposed to add
+extra extensions to the debugging info for debugging c++ we haven't got
+round to testing this yet.
+
 This is typically done adding/appending the flags -g to the 
 CFLAGS & LDFLAGS variables Makefile of the program concerned.
 
@@ -695,6 +732,39 @@
 6) If debugging under VM go down to that section in the document for more info.
 
 
+I now have a tool which takes the pain out of --adjust-vma
+& you are able to do something like
+make /arch/s390/kernel/traps.lst
+& it automatically generates the correctly relocated entries for
+the text segment in traps.lst.
+
+Add the following lines to you Rules.make
+%.lst: %.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
+
+Copy the code snippet below into the scripts directory in a file called makelst
+it is'nt very pretty but it works & dont forget to chmod 755 makelst
+to make it an executable.
+#	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+#	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(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 s/a/A/ | sed s/b/B/ | sed s/c/C/ | sed s/d/D/ | sed s/e/E/ | sed s/f/F/`
+t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
+
+
+
+
 strace:
 -------
 Q. What is it ?
@@ -941,6 +1011,9 @@
 e.g.
 TR BR INTO 0 is often quite useful if a program is getting awkward & deciding
 to branch to 0 & crashing as this will stop at the address before in jumps to 0.
+TR I R <address range> RUN cmd d g
+single steps a range of addresses but stays running &
+displays the gprs on each step.
 
 
 
@@ -992,6 +1065,9 @@
 because there are thousands of these routines & VM can only set 255 breakpoints
 at a time so you nearly had to spend as long pruning the file down as you would 
 entering the msg's by hand ),however, the trick might be useful for a single object file.
+On linux'es 3270 emulator x3270 there is a very useful option under the file ment
+Save Screens In File this is very good of keeping a copy of traces. 
+
 
 
 Tracing Program Exceptions
@@ -1436,9 +1512,9 @@
 VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you
  a look at the output.
 
-1) Spool stdout to VM guest linux4's reader
-SP PRT TO * 
-2) Fill linux4's reader with the trace
+1) Spool stdout to VM reader
+SP PRT TO (another vm guest ) or * for the local vm guest
+2) Fill the reader with the trace
 TR IO 7c08-7c09 INST INT CCW PRT RUN
 3) Start up linux 
 i 00c  
@@ -1775,7 +1851,9 @@
 
 LDD
 ===
-This is a program which lists the shared libraries which a library needs.
+This is a program which lists the shared libraries which a library needs,
+Note you also get the relocations of the shared library text segments which
+help when using objdump --source.
 e.g.
  ldd ./gdb
 outputs
@@ -1783,6 +1861,21 @@
 libm.so.6 => /lib/libm.so.6 (0x4005e000)
 libc.so.6 => /lib/libc.so.6 (0x40084000)
 /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
+
+
+Debugging shared libraries
+==========================
+Most programs use shared libraries, however it can be very painful
+when you single step instruction into a function like printf for the 
+first time & you end up in functions like _dl_runtime_resolve this is
+the ld.so doing lazy binding, lazy binding is a concept in ELF where 
+shared library functions are not loaded into memory unless they are 
+actually used, great for saving memory but a pain to debug.
+To get around this either relink the program -static or exit gdb type 
+export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing 
+the program in question.
+ 
+
 
 Debugging modules
 =================
diff -urN linux-2.2.17-pre12/Documentation/fb/00-INDEX linux/Documentation/fb/00-INDEX
--- linux-2.2.17-pre12/Documentation/fb/00-INDEX	Wed Jun 24 14:44:00 1998
+++ linux/Documentation/fb/00-INDEX	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 Index of files in Documentation/fb.  If you think something about frame
 buffer devices needs an entry here, needs correction or you've written one
 please mail me.
-				    Geert Uytterhoeven
-				    <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+				Geert Uytterhoeven <geert@linux-m68k.org>
 
 00-INDEX
 	- this file
diff -urN linux-2.2.17-pre12/Documentation/fb/framebuffer.txt linux/Documentation/fb/framebuffer.txt
--- linux-2.2.17-pre12/Documentation/fb/framebuffer.txt	Wed Nov 25 14:53:51 1998
+++ linux/Documentation/fb/framebuffer.txt	Mon Dec  3 22:09:50 2001
@@ -1,7 +1,7 @@
 			The Frame Buffer Device
 			-----------------------
 
-Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Maintained by Geert Uytterhoeven <geert@linux-m68k.org>
 Last revised: November 7, 1998
 
 
diff -urN linux-2.2.17-pre12/Documentation/fb/internals.txt linux/Documentation/fb/internals.txt
--- linux-2.2.17-pre12/Documentation/fb/internals.txt	Mon Oct  5 13:39:20 1998
+++ linux/Documentation/fb/internals.txt	Mon Dec  3 22:09:50 2001
@@ -2,7 +2,7 @@
 This is a first start for some documentation about frame buffer device
 internals.
 
-Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>, 21 July 1998
+Geert Uytterhoeven <geert@linux-m68k.org>, 21 July 1998
 
 --------------------------------------------------------------------------------
 
diff -urN linux-2.2.17-pre12/Documentation/i386/boot.txt linux/Documentation/i386/boot.txt
--- linux-2.2.17-pre12/Documentation/i386/boot.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/i386/boot.txt	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,381 @@
+		     THE LINUX/I386 BOOT PROTOCOL
+		     ----------------------------
+
+		    H. Peter Anvin <hpa@zytor.com>
+		 Updated as of protocol version 2.02
+
+On the i386 platform, the Linux kernel uses a rather complicated boot
+convention.  This has evolved partially due to historical aspects, as
+well as the desire in the early days to have the kernel itself be a
+bootable image, the complicated PC memory model and due to changed
+expectations in the PC industry caused by the effective demise of
+real-mode DOS as a mainstream operating system.
+
+Currently, four versions of the Linux/i386 boot protocol exist.
+
+Old kernels:	zImage/Image support only.  Some very early kernels
+		may not even support a command line.
+
+Protocol 2.00:	Added bzImage and initrd support, as well as a
+		formalized way to communicate between the boot loader
+		and the kernel.
+
+Protocol 2.01:	Added a heap overrun warning.
+
+Protocol 2.02:	New command line protocol.  Lower the
+		conventional-memory ceiling.  zImage deprecated but
+		still supported.
+
+
+**** MEMORY LAYOUT
+
+The traditional memory map for the kernel loader, used for Image or
+zImage kernels, typically looks like:
+
+	|			 |
+0A0000	+------------------------+
+	|  Reserved for BIOS	 |	Do not use.  Reserved for BIOS EBDA.
+09A000	+------------------------+
+	|  Stack/heap/cmdline	 |	For use by the kernel real-mode code.
+098000	+------------------------+	
+	|  Kernel setup		 |	The kernel real-mode code.
+090200	+------------------------+
+	|  Kernel boot sector    |	The kernel legacy boot sector.
+090000	+------------------------+
+	|  Protected-mode kernel |	The bulk of the kernel image.
+010000	+------------------------+
+	|  Boot loader		 |	<- Boot sector entry point 0000:7C00
+001000	+------------------------+
+	|  Reserved for MBR/BIOS |
+000800	+------------------------+
+	|  Typically used by MBR |
+000600	+------------------------+ 
+	|  BIOS use only	 |
+000000	+------------------------+
+
+
+When using bzImage, the protected-mode kernel was relocated to
+0x100000 ("high memory"), and the kernel real-mode block (boot sector,
+setup, and stack/heap) was made relocatable to any address between
+0x10000 and end of low memory.  Unfortunately, in protocols 2.00 and
+2.01 the command line is still required to live in the 0x9XXXX memory
+range, and that memory range is still overwritten by the early kernel.
+The 2.02 protocol fixes that.
+
+It is desirable to keep the "memory ceiling" -- the highest point in
+low memory touched by the boot loader -- as low as possible, since
+some newer BIOSes have begun to allocate some rather large amounts of
+memory, called the Extended BIOS Data Area, near the top of low
+memory.  The boot loader should use the "INT 12h" BIOS call to verify
+how much low memory is available.
+
+Unfortunately, if INT 12h reports that the amount of memory is too
+low, there is usually nothing the boot loader can do but to report an
+error to the user.  The boot loader should therefore be designed to
+take up as little space in low memory as it reasonably can.  For
+zImage or old bzImage kernels, which need data written into the
+0x90000 segment, the boot loader should make sure not to use memory
+above the 0x9A000 point; too many BIOSes will break above that point.
+
+
+**** THE REAL-MODE KERNEL HEADER
+
+In the following text, and anywhere in the kernel boot sequence, "a
+sector" refers to 512 bytes.  It is independent of the actual sector
+size of the underlying medium.
+
+The first step in loading a Linux kernel should be to load the
+real-mode code (boot sector and setup code) and then examine the
+following header at offset 0x01f1.  The real-mode code can total up to
+32K, although the boot loader may choose to load only the first two
+sectors (1K) and then examine the bootup sector size.
+
+The header looks like:
+
+Offset	Proto	Name		Meaning
+Size
+
+01F1/1	ALL	setup_sects	The size of the setup in sectors
+01F2/2	ALL	root_flags	If set, the root is mounted readonly
+01F4/2	ALL	syssize		DO NOT USE - for bootsect.S use only
+01F6/2	ALL	swap_dev	DO NOT USE - obsolete
+01F8/2	ALL	ram_size	DO NOT USE - for bootsect.S use only
+01FA/2	ALL	vid_mode	Video mode control
+01FC/2	ALL	root_dev	Default root device number
+01FE/2	ALL	boot_flag	0xAA55 magic number
+0200/2	2.00+	jump		Jump instruction
+0202/4	2.00+	header		Magic signature "HdrS"
+0206/2	2.00+	version		Boot protocol version supported
+0208/4	2.00+	realmode_swtch	Boot loader hook (see below)
+020C/4	2.00+	start_sys	Points to kernel version string
+0210/1	2.00+	type_of_loader	Boot loader identifier
+0211/1	2.00+	loadflags	Boot protocol option flags
+0212/2	2.00+	setup_move_size	Move to high memory size (used with hooks)
+0214/4	2.00+	code32_start	Boot loader hook (see below)
+0218/4	2.00+	ramdisk_image	initrd load address (set by boot loader)
+021C/4	2.00+	ramdisk_size	initrd size (set by boot loader)
+0220/4	2.00+	bootsect_kludge	DO NOT USE - for bootsect.S use only
+0224/4	2.01+	heap_end_ptr	Free memory after setup end
+0226/2	N/A	pad1		Unused
+0228/4	2.02+	cmd_line_ptr	32-bit pointer to the kernel command line
+
+For backwards compatibility, if the setup_sects field contains 0, the
+real value is 4.
+
+If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
+the boot protocol version is "old".  Loading an old kernel, the
+following parameters should be assumed:
+
+	Image type = zImage
+	initrd not supported
+	Real-mode kernel must be located at 0x90000.
+
+Otherwise, the "version" field contains the protocol version,
+e.g. protocol version 2.01 will contain 0x0201 in this field.  When
+setting fields in the header, you must make sure only to set fields
+supported by the protocol version in use.
+
+Most boot loaders will simply load the kernel at its target address
+directly.  Such a boot loader do not need to worry about filling in
+most of the fields in the header.  The following fields should be
+filled out, however:
+
+  type_of_loader:
+	If your boot loader has an identifier assigned in
+	arch/i386/boot/setup.S, enter that value.  Otherwise, enter
+	0xFF here.
+
+  loadflags, heap_end_ptr:
+	If the protocol version is 2.01 or higher, enter the
+	offset limit of the setup heap into heap_end_ptr and set the
+	0x80 bit (CAN_USE_HEAP) of loadflags.  heap_end_ptr appears to
+	be relative to the start of setup (offset 0x0200).
+
+  setup_move_size: 
+	When using protocol 2.00 or 2.01, if the real mode
+	kernel is not loaded at 0x90000, it gets moved there later in
+	the loading sequence.  Fill in this field if you want
+	additional data (such as the kernel command line) moved in
+	addition to the real-mode kernel itself.
+
+  ramdisk_image, ramdisk_size:
+	If your boot loader has loaded an initial ramdisk (initrd),
+	set ramdisk_image to the 32-bit pointer to the ramdisk data
+	and the ramdisk_size to the size of the ramdisk data.
+
+	The initrd should typically be located as high in memory as
+	possible, as it may otherwise get overwritten by the early
+	kernel initialization sequence.  However, it must never be
+	located above address 0x3C000000 if you want all kernels to
+	read it.
+
+  cmd_line_ptr:
+	If the protocol version is 2.02 or higher, this is a 32-bit
+	pointer to the kernel command line.  The kernel command line
+	can be located anywhere between the end of setup and 0xA0000.
+	Fill in this field even if your boot loader does not support a
+	command line, in which case you can point this to an empty
+	string (or better yet, to the string "auto".)  If this field
+	is left at zero, the kernel will assume that your boot loader
+	does not support the 2.02 protocol.
+
+
+**** THE KERNEL COMMAND LINE
+
+The kernel command line has become an important way for the boot
+loader to communicate with the kernel.  Some of its options are also
+relevant to the boot loader itself, see "special command line options"
+below.
+
+The kernel command line is a null-terminated string up to 255
+characters long, plus the final null.
+
+If the boot protocol version is 2.02 or later, the address of the
+kernel command line is given by the header field cmd_line_ptr (see
+above.)
+
+If the protocol version is *not* 2.02 or higher, the kernel
+command line is entered using the following protocol:
+
+	At offset 0x0020 (word), "cmd_line_magic", enter the magic
+	number 0xA33F.
+
+	At offset 0x0022 (word), "cmd_line_offset", enter the offset
+	of the kernel command line (relative to the start of the
+	real-mode kernel).
+	
+	The kernel command line *must* be within the memory region
+	covered by setup_move_size, so you may need to adjust this
+	field.
+
+
+**** SAMPLE BOOT CONFIGURATION
+
+As a sample configuration, assume the following layout of the real
+mode segment:
+
+	0x0000-0x7FFF	Real mode kernel
+	0x8000-0x8FFF	Stack and heap
+	0x9000-0x90FF	Kernel command line
+
+Such a boot loader should enter the following fields in the header:
+
+	unsigned long base_ptr;	/* base address for real-mode segment */
+
+	if ( setup_sects == 0 ) {
+		setup_sects = 4;
+	}
+
+	if ( protocol >= 0x0200 ) {
+		type_of_loader = <type code>;
+		if ( loading_initrd ) {
+			ramdisk_image = <initrd_address>;
+			ramdisk_size = <initrd_size>;
+		}
+		if ( protocol >= 0x0201 ) {
+			heap_end_ptr = 0x9000 - 0x200;
+			loadflags |= 0x80; /* CAN_USE_HEAP */
+		}
+		if ( protocol >= 0x0202 ) {
+			cmd_line_ptr = base_ptr + 0x9000;
+		} else {
+			cmd_line_magic  = 0xA33F;
+			cmd_line_offset = 0x9000;
+			setup_move_size = 0x9100;
+		}
+	} else {
+		/* Very old kernel */
+
+		cmd_line_magic  = 0xA33F;
+		cmd_line_offset = 0x9000;
+
+		/* A very old kernel MUST have its real-mode code
+		   loaded at 0x90000 */
+
+		if ( base_ptr != 0x90000 ) {
+			/* Copy the real-mode kernel */
+			memcpy(0x90000, base_ptr, (setup_sects+1)*512);
+			/* Copy the command line */
+			memcpy(0x99000, base_ptr+0x9000, 256);
+		}
+
+		/* It is recommended to clear memory up to the 32K mark */
+		memset(0x90000 + (setup_sects-1)*512, 0,
+		       (64-setup_sects-1)*512);
+	}
+
+
+**** LOADING THE REST OF THE KERNEL
+
+The non-real-mode kernel starts at offset (setup_sects+1)*512 in the
+kernel file (again, if setup_sects == 0 the real value is 4.)  It
+should be loaded at address 0x10000 for Image/zImage kernels and
+0x100000 for bzImage kernels.
+
+The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
+bit (LOAD_HIGH) in the loadflags field is set:
+
+	is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
+	load_address = is_bzImage ? 0x100000 : 0x10000;
+
+Note that Image/zImage kernels can be up to 512K in size, and thus use
+the entire 0x10000-0x90000 range of memory.  This means it is pretty
+much a requirement for these kernels to load the real-mode part at
+0x90000.  bzImage kernels allow much more flexibility.
+
+
+**** SPECIAL COMMAND LINE OPTIONS
+
+If the command line provided by the boot loader is entered by the
+user, the user may expect the following command line options to work.
+They should normally not be deleted from the kernel command line even
+though not all of them are actually meaningful to the kernel.
+
+  vga=<mode>
+	<mode> here is either an integer (in C notation, either
+	decimal, octal, or hexadecimal) or one of the strings
+	"normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
+	(meaning 0xFFFD).  This value should be entered into the
+	vid_mode field, as it is used by the kernel before the command
+	line is parsed.
+
+  mem=<size>
+	<size> is an integer in C notation optionally followed by K, M
+	or G (meaning << 10, << 20 or << 30).  This specifies to the
+	kernel the memory size.  This affects the possible placement
+	of an initrd, since an initrd should be placed near end of
+	memory.
+
+  initrd=<file>
+	An initrd should be loaded.  The meaning of <file> is
+	obviously bootloader-dependent.
+
+In addition, some boot loaders add the following options to the
+user-specified command line:
+
+  BOOT_IMAGE=<file>
+	The boot image which was loaded.  Again, the meaning of <file>
+	is obviously bootloader-dependent.
+
+  auto
+	The kernel was booted without explicit user intervention.
+
+If these options are added by the boot loader, it is highly
+recommended that they are located *first*, before the user-specified
+or configuration-specified command line.  Otherwise, "init=/bin/sh"
+gets confused by the "auto" option.
+
+
+**** RUNNING THE KERNEL
+
+The kernel is started by jumping to the kernel entry point, which is
+located at *segment* offset 0x20 from the start of the real mode
+kernel.  This means that if you loaded your real-mode kernel code at
+0x90000, the kernel entry point is 9020:0000.
+
+At entry, ds = es = ss = fs = gs should point to the start of the
+real-mode kernel code (0x9000 if the code is loaded at 0x90000), and
+sp should be set up properly, normally pointing to the top of the
+heap.  In our example from above, we would do:
+
+	seg = base_ptr >> 4;
+
+	cli();	/* Enter with interrupts disabled! */
+
+	_SS = seg;
+	_SP = 0x9000;	/* Load SP right after loading SS! */
+	_DS = _ES = _FS = _GS = seg;
+	jmp_far(seg+0x20, 0);	/* Run the kernel */
+
+If your boot sector accesses a floppy drive, it is recommended to
+switch off the floppy motor before running the kernel, since the
+kernel boot leaves interrupts off and thus the motor will not be
+switched off.
+
+
+**** ADVANCED BOOT TIME HOOKS
+
+If the boot loader runs in a particularly hostile environment (such as
+LOADLIN, which runs under DOS) it may be impossible to follow the
+standard memory location requirements.  Such a boot loader may use the
+following hooks that, if set, are invoked by the kernel at the
+appropriate time.  The use of these hooks should probably be
+considered an absolutely last resort!
+
+IMPORTANT: All the hooks are required to preserve %ebp, %esi and %edi
+across invocation.
+
+  realmode_swtch:
+	A 16-bit real mode far subroutine invoked immediately before
+	entering protected mode.  The default routine disables NMI, so
+	your routine should probably do so, too.
+
+  code32_start:
+	A 32-bit flat-mode routine *jumped* to immediately after the
+	transition to protected mode, but before the kernel is
+	uncompressed.  No segments, except CS, are set up; you should
+	set them up to KERNEL_DS (0x18) yourself.
+
+	After completing your hook, you should jump to the address
+	that was in this field before your boot loader overwrote it.
+
diff -urN linux-2.2.17-pre12/Documentation/serial-console.txt linux/Documentation/serial-console.txt
--- linux-2.2.17-pre12/Documentation/serial-console.txt	Wed Apr  1 14:58:54 1998
+++ linux/Documentation/serial-console.txt	Mon Dec  3 22:09:50 2001
@@ -87,8 +87,8 @@
 
 6. Thanks
 
-   Thanks to Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
-   for porting the patches from 2.1.4x to 2.1.6x for taking care of
-   the integration of these patches into m68k, ppc and alpha.
+   Thanks to Geert Uytterhoeven <geert@linux-m68k.org> for porting
+   the patches from 2.1.4x to 2.1.6x and for taking care of the
+   integration of these patches into m68k, ppc and alpha.
 
 Miquel van Smoorenburg <miquels@cistron.nl>, 21-Mar-1998
diff -urN linux-2.2.17-pre12/Makefile linux/Makefile
--- linux-2.2.17-pre12/Makefile	Mon Dec  3 22:09:38 2001
+++ linux/Makefile	Mon Dec  3 22:09:50 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre12
+EXTRAVERSION = pre13
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.17-pre12/Rules.make linux/Rules.make
--- linux-2.2.17-pre12/Rules.make	Tue Oct 26 17:53:39 1999
+++ linux/Rules.make	Mon Dec  3 22:09:50 2001
@@ -61,6 +61,9 @@
 %.o: %.s
 	$(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
 
+%.lst: %.c
+	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
 #
 #
 #
diff -urN linux-2.2.17-pre12/arch/alpha/config.in linux/arch/alpha/config.in
--- linux-2.2.17-pre12/arch/alpha/config.in	Wed Jun  7 14:26:42 2000
+++ linux/arch/alpha/config.in	Mon Dec  3 22:09:50 2001
@@ -149,22 +149,26 @@
 	define_bool CONFIG_ALPHA_IRONGATE y
 fi
 
+if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
+        -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
+        -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
+        -o "$CONFIG_ALPHA_EIGER" = "y" ]
+then
+        define_bool CONFIG_ALPHA_SRM y
+fi
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
-	-o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \
-	-o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
-	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
-	-o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-	-o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \
-	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
-	-o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_NAUTILUS" = "y" ]
+        -o "$CONFIG_ALPHA_EB64P" = "y"  -o "$CONFIG_ALPHA_PC164" = "y" \
+        -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \
+        -o "$CONFIG_ALPHA_ALCOR" = "y"  -o "$CONFIG_ALPHA_MIATA" = "y" \
+        -o "$CONFIG_ALPHA_LX164" = "y"  -o "$CONFIG_ALPHA_SX164" = "y" \
+	-o "$CONFIG_ALPHA_NAUTILUS" = "y" ]
 then
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
-      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
-    fi
-  fi
+#  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
+#      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
+#    fi
+#  fi
 fi
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
 	-o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
diff -urN linux-2.2.17-pre12/arch/alpha/kernel/sys_mikasa.c linux/arch/alpha/kernel/sys_mikasa.c
--- linux-2.2.17-pre12/arch/alpha/kernel/sys_mikasa.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/alpha/kernel/sys_mikasa.c	Mon Dec  3 22:09:50 2001
@@ -151,8 +151,9 @@
 	common_pci_fixup(mikasa_map_irq, common_swizzle);
 }
 
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
 static void
-mikasa_machine_check(unsigned long vector, unsigned long la_ptr,
+mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
 		     struct pt_regs * regs)
 {
 #define MCHK_NO_DEVSEL 0x205U
@@ -175,14 +176,14 @@
 		(la_ptr + mchk_header->sys_offset);
 
 #ifdef DEBUG
-	printk("mikasa_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+	printk("mikasa_apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n",
 	       vector, la_ptr);
 	printk("        pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 	       regs->pc, mchk_header->size, mchk_header->proc_offset,
 	       mchk_header->sys_offset);
-	printk("mikasa_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
-	       apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
-	       mchk_sysdata->epic_pear);
+	printk("mikasa_apecs_machine_check: expected %d DCSR 0x%lx"
+	       " PEAR 0x%lx\n", apecs_mcheck_expected,
+	       mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear);
 	ptr = (unsigned long *)la_ptr;
 	for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
 		printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
@@ -213,7 +214,7 @@
 		wrmces(0x1f);
 		mb();
 		draina();
-		printk("mikasa_machine_check: HW correctable (0x%lx)\n",
+		printk("mikasa_apecs_machine_check: HW correctable (0x%lx)\n",
 		       vector);
 	}
 	else {
@@ -239,6 +240,7 @@
 #endif
 	}
 }
+#endif
 
 
 /*
@@ -252,7 +254,7 @@
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		mikasa_machine_check,
+	machine_check:		mikasa_apecs_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		32,
diff -urN linux-2.2.17-pre12/arch/alpha/kernel/sys_noritake.c linux/arch/alpha/kernel/sys_noritake.c
--- linux-2.2.17-pre12/arch/alpha/kernel/sys_noritake.c	Sun Sep  6 10:34:33 1998
+++ linux/arch/alpha/kernel/sys_noritake.c	Mon Dec  3 22:09:50 2001
@@ -238,6 +238,97 @@
 	common_pci_fixup(noritake_map_irq, noritake_swizzle);
 }
 
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+static void
+noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
+		     struct pt_regs * regs)
+{
+#define MCHK_NO_DEVSEL 0x205U
+#define MCHK_NO_TABT 0x204U
+
+	struct el_common *mchk_header;
+	struct el_apecs_procdata *mchk_procdata;
+	struct el_apecs_mikasa_sysdata_mcheck *mchk_sysdata;
+	unsigned long *ptr;
+	unsigned int code; /* workaround EGCS problem */
+	int i;
+
+	mchk_header = (struct el_common *)la_ptr;
+
+	mchk_procdata = (struct el_apecs_procdata *)
+		(la_ptr + mchk_header->proc_offset
+		 - sizeof(mchk_procdata->paltemp));
+
+	mchk_sysdata = (struct el_apecs_mikasa_sysdata_mcheck *)
+		(la_ptr + mchk_header->sys_offset);
+
+#ifdef DEBUG
+	printk("noritake_apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+	       vector, la_ptr);
+	printk("        pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+	       regs->pc, mchk_header->size, mchk_header->proc_offset,
+	       mchk_header->sys_offset);
+	printk("noritake_apecs_machine_check: expected %d DCSR 0x%lx"
+	       " PEAR 0x%lx\n", apecs_mcheck_expected,
+	       mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear);
+	ptr = (unsigned long *)la_ptr;
+	for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+		printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+	}
+#endif
+
+	/*
+	 * Check if machine check is due to a badaddr() and if so,
+	 * ignore the machine check.
+	 */
+
+	code = mchk_header->code; /* workaround EGCS problem */
+
+	if (apecs_mcheck_expected &&
+	    (code == MCHK_NO_DEVSEL || code == MCHK_NO_TABT))
+	{
+		apecs_mcheck_expected = 0;
+		apecs_mcheck_taken = 1;
+		mb();
+		mb(); /* magic */
+		apecs_pci_clr_err();
+		wrmces(0x7);
+		mb();
+		draina();
+	}
+	else if (vector == 0x620 || vector == 0x630) {
+		/* Disable correctable from now on.  */
+		wrmces(0x1f);
+		mb();
+		draina();
+		printk("noritake_apecs_machine_check: HW correctable (0x%lx)\n",
+		       vector);
+	}
+	else {
+		printk(KERN_CRIT "NORITAKE APECS machine check:\n");
+		printk(KERN_CRIT "  vector=0x%lx la_ptr=0x%lx code=0x%x\n",
+		       vector, la_ptr, code);
+		printk(KERN_CRIT
+		       "  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+		       regs->pc, mchk_header->size, mchk_header->proc_offset,
+		       mchk_header->sys_offset);
+		printk(KERN_CRIT "  expected %d DCSR 0x%lx PEAR 0x%lx\n",
+		       apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
+		       mchk_sysdata->epic_pear);
+
+		ptr = (unsigned long *)la_ptr;
+		for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+			printk(KERN_CRIT " +%lx %lx %lx\n",
+			       i*sizeof(long), ptr[i], ptr[i+1]);
+		}
+#if 0
+		/* doesn't work with MILO */
+		show_regs(regs);
+#endif
+	}
+}
+#endif
+
 
 /*
  * The System Vectors
@@ -250,7 +341,7 @@
 	DO_DEFAULT_RTC,
 	DO_APECS_IO,
 	DO_APECS_BUS,
-	machine_check:		apecs_machine_check,
+	machine_check:		noritake_apecs_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
 
 	nr_irqs:		48,
diff -urN linux-2.2.17-pre12/arch/m68k/amiga/chipram.c linux/arch/m68k/amiga/chipram.c
--- linux-2.2.17-pre12/arch/m68k/amiga/chipram.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/chipram.c	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 /*
 **  linux/amiga/chipram.c
 **
-**      Modified 03-May-94 by Geert Uytterhoeven
-**                           (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**      Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
 **          - 64-bit aligned allocations for full AGA compatibility
 */
 
diff -urN linux-2.2.17-pre12/arch/m68k/tools/amiga/dmesg.c linux/arch/m68k/tools/amiga/dmesg.c
--- linux-2.2.17-pre12/arch/m68k/tools/amiga/dmesg.c	Wed Sep 25 00:47:40 1996
+++ linux/arch/m68k/tools/amiga/dmesg.c	Mon Dec  3 22:09:50 2001
@@ -3,8 +3,7 @@
  *					   in Chip RAM with the kernel command
  *					   line option `debug=mem'.
  *
- *  © Copyright 1996 by Geert Uytterhoeven
- *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  © Copyright 1996 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  *
  *  Usage:
diff -urN linux-2.2.17-pre12/arch/s390/Makefile linux/arch/s390/Makefile
--- linux-2.2.17-pre12/arch/s390/Makefile	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/Makefile	Mon Dec  3 22:09:50 2001
@@ -1,5 +1,5 @@
 
-# i386/Makefile
+# s390/Makefile
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
diff -urN linux-2.2.17-pre12/arch/s390/boot/Makefile linux/arch/s390/boot/Makefile
--- linux-2.2.17-pre12/arch/s390/boot/Makefile	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/boot/Makefile	Mon Dec  3 22:09:50 2001
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the linux s390-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
diff -urN linux-2.2.17-pre12/arch/s390/defconfig linux/arch/s390/defconfig
--- linux-2.2.17-pre12/arch/s390/defconfig	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/defconfig	Mon Dec  3 22:09:50 2001
@@ -26,8 +26,8 @@
 #
 CONFIG_FAST_IRQ=y
 CONFIG_IPL=y
-# CONFIG_IPL_TAPE is not set
-CONFIG_IPL_VM=y
+CONFIG_IPL_TAPE=y
+# CONFIG_IPL_VM is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -41,9 +41,9 @@
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_BLK_DEV_XPRAM=y
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_XPRAM=m
 # CONFIG_MDISK is not set
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
@@ -140,7 +140,8 @@
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
diff -urN linux-2.2.17-pre12/arch/s390/kernel/debug.c linux/arch/s390/kernel/debug.c
--- linux-2.2.17-pre12/arch/s390/kernel/debug.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/debug.c	Mon Dec  3 22:09:50 2001
@@ -3,6 +3,7 @@
 #include <linux/errno.h>
 #include <linux/malloc.h>
 #include <asm/ebcdic.h>
+#include <asm/debug.h>
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -10,9 +11,7 @@
 
 #include <asm/ebcdic.h>
 
-#include "debug.h"
-
-debug_info_t debug_areas[MAX_DEBUG_AREAS];
+debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },};
 debug_info_t *free_area = 0;
 static int initialized = 0;
 
@@ -38,6 +37,7 @@
   rc = free_area;
   free_area = *((debug_info_t **) rc);
 
+  memset(rc, 0, nr_areas * sizeof(debug_info_t));
   rc->areas = (debug_entry_t **) kmalloc (nr_areas *
 					  sizeof (debug_entry_t *),
 					  GFP_ATOMIC);
@@ -59,14 +59,16 @@
 	  goto nopages;
 	}
     }
-
   rc->page_order = page_order;
   rc->nr_areas = nr_areas;
   rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC);
   strncpy (rc->name, name, strlen (name));
+  ASCEBC(rc->name, strlen (name));
   rc->name[strlen (name)] = 0;
+
   rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC);
   memset(rc->active_entry, 0, nr_areas * sizeof(int));
+  rc->level=3;
   printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n",
 	  nr_areas, 1 << page_order, name);
   goto exit;
diff -urN linux-2.2.17-pre12/arch/s390/kernel/debug.h linux/arch/s390/kernel/debug.h
--- linux-2.2.17-pre12/arch/s390/kernel/debug.h	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/debug.h	Wed Dec 31 16:00:00 1969
@@ -1,55 +0,0 @@
-
-#ifndef DEBUG_H
-#define DEBUG_H
-
-#include <asm/spinlock.h>
-
-#define MAX_DEBUG_AREAS 16
-
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
-
-typedef struct
-{
-  union
-  {
-    struct
-    {
-      unsigned long long cpuid:4;
-      unsigned long long clock:60;
-    }
-    fields;
-    unsigned long long stck;
-  }
-  id;
-  void *caller;
-  union
-  {
-    unsigned long tag;
-    char text[4];
-  }
-  tag;
-}
-debug_entry_t;
-
-typedef struct
-{
-  char *name;
-  int level;
-  int nr_areas;
-  int page_order;
-  debug_entry_t **areas;
-  int active_area;
-  int *active_entry;
-  spinlock_t lock;
-}
-debug_info_t;
-
-int debug_init (void);
-debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
-void debug_unregister (debug_info_t * id, char *name);
-void debug_event (debug_info_t * id, int level, unsigned int tag);
-void debug_text_event (debug_info_t * id, int level, char tag[4]);
-void debug_exception (debug_info_t * id, int level, unsigned int tag);
-void debug_text_exception (debug_info_t * id, int level, char tag[4]);
-
-#endif
diff -urN linux-2.2.17-pre12/arch/s390/kernel/entry.S linux/arch/s390/kernel/entry.S
--- linux-2.2.17-pre12/arch/s390/kernel/entry.S	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/entry.S	Mon Dec  3 22:09:50 2001
@@ -300,7 +300,7 @@
         stosm   24(%r15),0x03     # reenable interrupts
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
         l       %r1,BASED(.Lschedtail)
 	la      %r14,BASED(sysc_return)
         br      %r1               # call schedule_tail, return to sysc_return
@@ -787,7 +787,7 @@
 mcck_return:
         RESTORE_ALL
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /*
  * Restart interruption handler, kick starter for additional CPUs
  */
@@ -862,6 +862,6 @@
 .Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 .Lschedtail:   .long  schedule_tail
 #endif
diff -urN linux-2.2.17-pre12/arch/s390/kernel/head.S linux/arch/s390/kernel/head.S
--- linux-2.2.17-pre12/arch/s390/kernel/head.S	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/head.S	Mon Dec  3 22:09:50 2001
@@ -5,8 +5,9 @@
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Rob van der Heij
  *
- * There are 4 different IPL methods
+ * There are 5 different IPL methods
  *  1) load the image directly into ram at address 0 and do an PSW restart
  *  2) linload will load the image from address 0x10000 to memory 0x10000
  *     and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
@@ -14,6 +15,7 @@
  *     and ipl from it
  *  4) generate the vm reader ipl header, move the generated image to the
  *     VM reader (use option NOH!) and do a ipl from reader (VM only)
+ *  5) direct call of start by the SALIPL loader
  *  We use the cpuid to distinguish between VM and native ipl
  *  params for kernel are pushed to 0x10400 (see setup.h)
  */
@@ -24,34 +26,7 @@
 
 #ifndef CONFIG_IPL
         .org   0
-        .long  0x00080000,0x80000000+iplstart  # Just a restart PSW
-
-iplstart:
-        l     %r12,.Lparm                      # pointer to parameter area
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0          # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        slr   %r2,%r2
-        st    %r2,INITRD_SIZE-PARMAREA(%r12)  # null ramdisk
-        st    %r2,INITRD_START-PARMAREA(%r12)
-        j     start
-
-.Lparm: .long  PARMAREA
-.L4malign0:.long 0xffc00000
-        .align 8
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
-
+        .long  0x00080000,0x80000000+startup   # Just a restart PSW
 #else
 #ifdef CONFIG_IPL_TAPE
 #define IPL_BS 1024
@@ -74,92 +49,6 @@
         .long  0x00080000,0x80000000+.Lioint   # io new psw
 
         .org   0x100
-iplstart:
-	l     %r1,0xb8                         # load ipl subchannel number
-        lhi   %r2,IPL_BS                       # load start address
-        bras  %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-        l     %r12,.Lparm                      # pointer to parameter area
-
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0          # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        c     %r2,.Lbigmem               # more than 64 MB of memory ?
-        jl    .Lmemok                    # if yes load ramdisk to 32 MB
-        mvc   INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from tape
-#
- 	l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
-        bras  %r14,.Lloader                    # load parameter file
-        ltr   %r2,%r2                          # got anything ?
-        jz    .Lnopf
-	chi   %r2,895
-	jnh   .Lnotrunc
-	lhi   %r2,895
-.Lnotrunc:
-	l     %r4,INITRD_START-PARMAREA(%r12)
-        la    %r5,0(%r4,%r2)
-        lr    %r3,%r2
-.Lidebc:
-        tm    0(%r5),0x80                      # high order bit set ?
-        jo    .Ldocv                           #  yes -> convert from EBCDIC
-        ahi   %r5,-1
-        brct  %r3,.Lidebc
-        j     .Lnocv
-.Ldocv:
-        l     %r3,.Lcvtab
-        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
-        tr    256(256,%r4),0(%r3)
-        tr    512(256,%r4),0(%r3)
-        tr    768(122,%r4),0(%r3)
-.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
-	mvc   0(256,%r3),0(%r4)
-	mvc   256(256,%r3),256(%r4)
-	mvc   512(256,%r3),512(%r4)
-	mvc   768(122,%r3),768(%r4)
-        slr   %r0,%r0
-        j     .Lcntlp
-.Ldelspc:
-        ic    %r0,0(%r2,%r3)
-        chi   %r0,0x20                         # is it a space ?
-        je    .Lcntlp
-        ahi   %r2,1
-        j     .Leolp
-.Lcntlp:
-        brct  %r2,.Ldelspc
-.Leolp:
-        slr   %r0,%r0
-        stc   %r0,0(%r2,%r3)                   # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from tape
-#	
- 	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
-        bras  %r14,.Lloader                    # load ramdisk
- 	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
-        ltr   %r2,%r2
-        jnz   .Lrdcont
-        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
-.Lrdcont:
-#
-# everything loaded, go for it
-#
-        j     start
 #
 # subroutine for loading from tape
 # Paramters:	
@@ -173,32 +62,32 @@
         lctl  %c6,%c6,.Lcr6               
         slr   %r2,%r2
 .Lldlp:
-        lhi   %r6,3                            # 3 retries
+        la    %r6,3                            # 3 retries
 .Lssch:
         ssch  0(%r3)                           # load chunk of IPL_BS bytes
-        jnz   .Llderr
+        bnz   .Llderr
 .Lw4end:
-        bras  %r14,.Lwait4io
+        bas   %r14,.Lwait4io
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Lrecov
+        bnz   .Lrecov
         slr   %r7,%r7
         icm   %r7,3,10(%r5)                    # get residual count
         lcr   %r7,%r7
-        ahi   %r7,IPL_BS                       # IPL_BS-residual=#bytes read
+        la    %r7,IPL_BS(%r7)                  # IPL_BS-residual=#bytes read
         ar    %r2,%r7                          # add to total size
         tm    8(%r5),0x01                      # found a tape mark ?
-        jnz   .Ldone
+        bnz   .Ldone
         l     %r0,.Lccwread+4                  # update CCW data addresses
         ar    %r0,%r7
         st    %r0,.Lccwread+4                
-        j     .Lldlp
+        b     .Lldlp
 .Ldone:
         l     %r14,.Lldret
         br    %r14                             # r2 contains the total size
 .Lrecov:
-        bras  %r14,.Lsense                     # do the sensing
-        brct  %r6,.Lssch                       # dec. retry count & branch
-        j     .Llderr
+        bas   %r14,.Lsense                     # do the sensing
+        bct   %r6,.Lssch                       # dec. retry count & branch
+        b     .Llderr
 #
 # Sense subroutine
 #
@@ -206,11 +95,11 @@
         st    %r14,.Lsnsret
         la    %r7,.Lorbsense              
         ssch  0(%r7)                           # start sense command
-        jnz   .Llderr
-        bras  %r14,.Lwait4io
+        bnz   .Llderr
+        bas   %r14,.Lwait4io
         l     %r14,.Lsnsret
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Llderr
+        bnz   .Llderr
         br    %r14
 #
 # Wait for interrupt subroutine
@@ -219,13 +108,13 @@
         lpsw  .Lwaitpsw                 
 .Lioint:
         c     %r1,0xb8                         # compare subchannel number
-        jne   .Lwait4io
+        bne   .Lwait4io
         tsch  0(%r5)
         slr   %r0,%r0
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Lwtexit
+        bnz   .Lwtexit
         tm    8(%r5),0x04                      # got device end ?
-        jz    .Lwait4io
+        bz    .Lwait4io
 .Lwtexit:
         br    %r14
 .Llderr:
@@ -249,18 +138,12 @@
 .Lcr6:  .long  0xff000000
         .align 8
 .Lcrash:.long  0x000a0000,0x00000000
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
-.Lparm: .long  PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
 .Lldret:.long  0
 .Lsnsret: .long 0
-.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
-
-#endif  /* CONFIG_IPL_TAPE */
+#endif  /* CONFIG_IPL_NONE */
 
 #ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
         .org   0
         .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
         .long  0x02000018,0x60000050           # by ipl to addresses 0-23.
@@ -287,103 +170,7 @@
         .long  0x02000690,0x60000050
         .long  0x020006e0,0x20000050
 
-
         .org   0xf0
-iplstart:
-	l     %r1,0xb8                         # load ipl subchannel number
-        lhi   %r2,0x730                        # load start address
-        bras  %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-	l     %r12,.Lparm                      # pointer to parameter area
-
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0           # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        c     %r2,.Lbigmem               # more than 64 MB of memory ?
-        jl    .Lmemok                    # if yes load ramdisk to 32 MB
-        mvc   INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from reader
-#
-        l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
-        bras  %r14,.Lloader                    # load parameter file
-        ltr   %r2,%r2                          # got anything ?
-        jz    .Lnopf
-        chi   %r2,895
-        jnh   .Lnotrunc
-        lhi   %r2,895
-.Lnotrunc:
-        l     %r4,INITRD_START-PARMAREA(%r12)
-        la    %r5,0(%r4,%r2)
-        lr    %r3,%r2
-.Lidebc:
-        tm    0(%r5),0x80                      # high order bit set ?
-        jo    .Ldocv                           #  yes -> convert from EBCDIC
-        ahi   %r5,-1
-        brct  %r3,.Lidebc
-        j     .Lnocv
-.Ldocv:
-        l     %r3,.Lcvtab
-        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
-        tr    256(256,%r4),0(%r3)
-        tr    512(256,%r4),0(%r3)
-        tr    768(122,%r4),0(%r3)
-.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
-        mvc   0(256,%r3),0(%r4)
-        mvc   256(256,%r3),256(%r4)
-        mvc   512(256,%r3),512(%r4)
-        mvc   768(122,%r3),768(%r4)
-        slr   %r0,%r0
-        j     .Lcntlp
-.Ldelspc:
-        ic    %r0,0(%r2,%r3)
-        chi   %r0,0x20                         # is it a space ?
-        je    .Lcntlp
-        ahi   %r2,1
-        j     .Leolp
-.Lcntlp:
-        brct  %r2,.Ldelspc
-.Leolp:
-        slr   %r0,%r0
-        stc   %r0,0(%r2,%r3)                   # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from reader
-#	
-	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
-        bras  %r14,.Lloader                    # load ramdisk
-	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
-        ltr   %r2,%r2
-        jnz   .Lrdcont
-        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
-.Lrdcont:
-
-#
-# everything loaded, reset files in reader, then go for it
-#
-        stidp __LC_CPUID                       # store cpuid
-        lh    %r0,__LC_CPUID+4                 # get cpu version
-        chi   %r0,0x7490                       # running on P/390 ?
-        je   start                             #   no -> skip reset
-        la    %r2,.Lreset              
-        lhi   %r3,26
-        .long 0x83230008
-	j     start
-
 #
 # subroutine for loading cards from the reader
 #
@@ -394,29 +181,29 @@
         la    %r7,20
 .Linit:
         st    %r2,4(%r6)                       # initialize CCW data addresses
-        ahi   %r2,0x50
-        ahi   %r6,8
-        brct  7,.Linit
+        la    %r2,0x50(%r2)
+        la    %r6,8(%r6)
+        bct   7,.Linit
 
         lctl  %c6,%c6,.Lcr6                    # set IO subclass mask
 	slr   %r2,%r2
 .Lldlp:
         ssch  0(%r3)                           # load chunk of 1600 bytes
-        jnz   .Llderr
+        bnz   .Llderr
 .Lwait4irq:
         mvc   __LC_IO_NEW_PSW(8),.Lnewpsw      # set up IO interrupt psw
         lpsw  .Lwaitpsw              
 .Lioint:
         c     %r1,0xb8                         # compare subchannel number
-	jne   .Lwait4irq
+	bne   .Lwait4irq
 	tsch  0(%r5)
 
 	slr   %r0,%r0
 	ic    %r0,8(%r5)                       # get device status
 	chi   %r0,8                            # channel end ?
-	je    .Lcont
+	be    .Lcont
 	chi   %r0,12                           # channel end + device end ?
-	je    .Lcont
+	be    .Lcont
 
         l     %r0,4(%r5)
         s     %r0,8(%r3)                       # r0/8 = number of ccws executed
@@ -436,9 +223,9 @@
         ahi   %r0,0x640
         st    %r0,4(%r6)
         ahi   %r6,8
-        brct  7,.Lincr
+        bct   7,.Lincr
 
-        j     .Lldlp
+        b     .Lldlp
 .Llderr:
         lpsw  .Lcrash              
 
@@ -447,16 +234,7 @@
 .Lirb:	.long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 .Lcr6:  .long  0xff000000
 .Lloadp:.long  0,0
-.Lparm:	.long  PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
-.Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
-        .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
-        .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
         .align 8
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
 .Lcrash:.long  0x000a0000,0x00000000
 .Lnewpsw:
         .long  0x00080000,0x80000000+.Lioint
@@ -468,28 +246,203 @@
         .long  0x02600050,0x00000000
         .endr
         .long  0x02200050,0x00000000
-	
-        .org   0x730     # end of the area loaded by the ipl channel program
 #endif  /* CONFIG_IPL_VM */
 
+iplstart:
+        lh    %r1,0xb8                         # test if subchannel number
+        bct   %r1,.Lnoload                     #  is valid
+	l     %r1,0xb8                         # load ipl subchannel number
+        la    %r2,IPL_BS                       # load start address
+        bas   %r14,.Lloader                    # load rest of ipl image
+        st    %r1,__LC_IPLDEV                  # store ipl device number
+        l     %r12,.Lparm                      # pointer to parameter area
+
+#
+# load parameter file from ipl device
+#
+ 	l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
+        bas   %r14,.Lloader                    # load parameter file
+        ltr   %r2,%r2                          # got anything ?
+        bz    .Lnopf
+	chi   %r2,895
+	bnh   .Lnotrunc
+	la    %r2,895
+.Lnotrunc:
+	l     %r4,INITRD_START-PARMAREA(%r12)
+        la    %r5,0(%r4,%r2)
+        lr    %r3,%r2
+.Lidebc:
+        tm    0(%r5),0x80                      # high order bit set ?
+        bo    .Ldocv                           #  yes -> convert from EBCDIC
+        ahi   %r5,-1
+        bct   %r3,.Lidebc
+        b     .Lnocv
+.Ldocv:
+        l     %r3,.Lcvtab
+        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
+        tr    256(256,%r4),0(%r3)
+        tr    512(256,%r4),0(%r3)
+        tr    768(122,%r4),0(%r3)
+.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
+	mvc   0(256,%r3),0(%r4)
+	mvc   256(256,%r3),256(%r4)
+	mvc   512(256,%r3),512(%r4)
+	mvc   768(122,%r3),768(%r4)
+        slr   %r0,%r0
+        b     .Lcntlp
+.Ldelspc:
+        ic    %r0,0(%r2,%r3)
+        chi   %r0,0x20                         # is it a space ?
+        be    .Lcntlp
+        ahi   %r2,1
+        b     .Leolp
+.Lcntlp:
+        brct  %r2,.Ldelspc
+.Leolp:
+        slr   %r0,%r0
+        stc   %r0,0(%r2,%r3)                   # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#	
+ 	l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
+        bas   %r14,.Lloader                    # load ramdisk
+ 	st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
+        ltr   %r2,%r2
+        bnz   .Lrdcont
+        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
+.Lrdcont:
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+        stidp __LC_CPUID                       # store cpuid
+        lh    %r0,__LC_CPUID+4                 # get cpu version
+        chi   %r0,0x7490                       # running on P/390 ?
+        be    start                            #   no -> skip reset
+        la    %r2,.Lreset              
+        lhi   %r3,26
+        .long 0x83230008
+#endif
+	
+#
+# everything loaded, go for it
+#
+.Lnoload:
+        l     %r1,.Lstartup
+        br    %r1
+
+.Lparm:	.long  PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
+.Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+        .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+        .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
+
 #endif  /* CONFIG_IPL */
 
 #
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+        .org  0x800
+	.globl start
+start:
+	stm   %r0,%r15,0x07b0		# store registers
+	basr  %r12,%r0
+.base:
+	l     %r11,.parm
+	l     %r8,.cmd			# pointer to command buffer
+
+	ltr   %r9,%r9			# do we have SALIPL parameters?
+	bp    .sk8x8
+
+	mvc   0(64,%r8),0x00b0		# copy saved registers
+	xc    64(240-64,%r8),0(%r8)	# remainder of buffer
+	tr    0(64,%r8),.lowcase	
+	b     .gotr
+.sk8x8:
+	mvc   0(240,%r8),0(%r9)		# copy iplparms into buffer
+.gotr:
+	l     %r10,.tbl			# EBCDIC to ASCII table
+	tr    0(240,%r8),0(%r10)
+	stidp __LC_CPUID		# Are we running on VM maybe
+	cli   __LC_CPUID,0xff
+	bnz   .test
+	.long 0x83300060		# diag 3,0,x'0060' - storage size
+	b     .done
+.test:
+	mvc   0x68(8,0),.pgmnw		# set up pgm check handler
+	l     %r2,.fourmeg
+	lr    %r3,%r2
+	bctr  %r3,%r0			# 4M-1
+.loop:  iske  %r0,%r3
+	ar    %r3,%r2
+.pgmx:
+	sr    %r3,%r2
+	la    %r3,1(%r3)
+.done:
+	st    %r3,MEMORY_SIZE-PARMAREA(%r11)	
+	slr   %r0,%r0
+	st    %r0,INITRD_SIZE-PARMAREA(%r11)
+	st    %r0,INITRD_START-PARMAREA(%r11)
+	j     startup                   # continue with startup
+.tbl:	.long _ebcasc			# translate table
+.cmd:	.long COMMAND_LINE		# address of command line buffer
+.parm:	.long PARMAREA
+.fourmeg: .long 0x00400000      	# 4M
+.pgmnw:	.long 0x00080000,.pgmx
+.lowcase:
+	.byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 
+	.byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+	.byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 
+	.byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+	.byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 
+	.byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+	.byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 
+	.byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+	.byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 
+	.byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+	.byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 
+	.byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+	.byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 
+	.byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+	.byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 
+	.byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+	.byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 
+	.byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+	.byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 
+	.byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+	.byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 
+	.byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+	.byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 
+	.byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+	.byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87	# .abcdefg 
+	.byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf	# hi
+	.byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 	# .jklmnop
+	.byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf	# qr
+	.byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7	# ..stuvwx
+	.byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef	# yz
+	.byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 
+	.byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
+#
 # startup-code at 0x10000, running in real mode
-# this is called either by the ipl loader or directly by PSW restart or linload
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
 #
         .org  0x10000
-        .globl start
-start:  basr  %r13,0                     # get base
+startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load all control registers
 	l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
 
 #
-# find out memory size. That is done in the ipl loader too but for
-# ipl from dasd the size of the memory has to be detected too...
+# find out memory size.
 #
-        icm   %r0,15,MEMORY_SIZE-PARMAREA(%r12)
-        jnz   .Lsizeok
 	mvc   104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
         slr   %r1,%r1
         lhi   %r2,1
@@ -497,23 +450,57 @@
 .Lloop:	
 	l     %r0,0(%r1)                 # test page
 	ar    %r1,%r2                    # add 1M
-	jnm   .Lloop                     # r1 < 0x80000000 -> loop
+	bnm   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
 .Lchkmem:
 	n     %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
 	st    %r1,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
 .Lsizeok:
 
 #
+# Now we have to move the ramdisk to a location approriate for the
+# memory size. If we have more than 64 MB of memory we move it to 32MB
+# to make room for the page tables set up by paging_init.
+#
+        l     %r1,MEMORY_SIZE-PARMAREA(%r12)
+        cl    %r1,.Lbigmem-.LPG1(%r13)   # memory < 64mb ?
+        bl    .Lnomove-.LPG1(%r13)       # if yes ramdisk @8MB is ok
+        icm   %r4,15,INITRD_START-PARMAREA(%r12)
+        bz    .Lnomove-.LPG1(%r13)
+	l     %r2,.Lrdstart-.LPG1(%r13)  # new address of ramdisk
+	st    %r2,INITRD_START-PARMAREA(%r12)
+        l     %r1,INITRD_SIZE-PARMAREA(%r12)
+	ar    %r2,%r1                    # we start moving at the end
+	ar    %r4,%r1                    #  because new location > old location
+.Lmove:	lr    %r0,%r2                    # new - old is the maximum we can move
+	sr    %r0,%r4                    #  because of overlapping
+	cr    %r0,%r1                    # we shouldn't move more than there is
+	bnh   .Lnoend-.LPG1(%r13)
+	lr    %r0,%r1
+.Lnoend:cl    %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go
+	bnh   .Lchunk-.LPG1(%r13)
+	l     %r0,.Lmaxchunk-.LPG1(%r13)
+.Lchunk:sr    %r2,%r0                    # make source & destination pointer
+	sr    %r4,%r0
+	lr    %r3,%r0                    # set source & destination length
+	lr    %r5,%r0
+	mvcl  %r2,%r4
+	sr    %r2,%r0                    # substract length again, since
+	sr    %r4,%r0                    #  mvcl added it to the pointers
+	sr    %r1,%r0                    # substract chunk size from length
+	bnz   .Lmove-.LPG1(%r13)
+.Lnomove:
+
+#
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
 	tm     __LC_CPUID,0xff          # running under VM ?
-	jno    .Lnovm
+	bno    .Lnovm-.LPG1(%r13)
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),1    # set VM flag
 .Lnovm:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
-        jne    .Lnop390
+        bne    .Lnop390-.LPG1(%r13)
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),4    # set P/390 flag
 .Lnop390:
 
@@ -526,6 +513,7 @@
         adbr   %f0,%f2                  # test IEEE add instruction
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),2    # set IEEE fpu flag
 .Lchkfpu:
+
 #
 # find out if we have the CSP instruction
 #
@@ -563,6 +551,9 @@
 .Lflt0: .double 0
 .Lparm1:.long  PARMAREA
 .L4malign:.long 0xffc00000
+.Lbigmem:.long 0x04000000
+.Lrdstart:.long 0x02000000
+.Lmaxchunk:.long  0x00ffffff
 
 #
 # params at 10400 (setup.h)
@@ -573,21 +564,12 @@
 	.long  0                        # MEMORY_SIZE
 	.long  0                        # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE)
         .long  RAMDISK_ORIGIN           # INITRD_START
-        .long  0x800000                 # INITRD_SIZE
+        .long  RAMDISK_SIZE             # INITRD_SIZE
 	.word  0                        # RAMDISK_FLAGS
 
         .org   COMMAND_LINE
-#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-#       .byte  "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
-#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-#       .byte  "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
-#       .byte  "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-#       .byte  "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
-#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
-#       .byte  "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
     	.byte  "root=/dev/ram0 ro"
-#       .byte  0
+        .byte  0
 
 #
 # startup-code, running in virtual mode
diff -urN linux-2.2.17-pre12/arch/s390/kernel/irq.c linux/arch/s390/kernel/irq.c
--- linux-2.2.17-pre12/arch/s390/kernel/irq.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/irq.c	Mon Dec  3 22:09:50 2001
@@ -86,7 +86,7 @@
 			continue;
 
 		p += sprintf(p, "%3d: ",i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 		p += sprintf(p, "%10u ", kstat_irqs(i));
 #else
 		for (j=0; j<smp_num_cpus; j++)
@@ -107,7 +107,7 @@
 	} /* endfor */
 
 	p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
 #endif
 
@@ -119,7 +119,7 @@
  * Global interrupt locks for SMP. Allow interrupts to come in on any
  * CPU, yet make cli/sti act globally to protect critical regions..
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
 atomic_t global_irq_lock;
 atomic_t global_irq_count = ATOMIC_INIT(0);
diff -urN linux-2.2.17-pre12/arch/s390/kernel/mathemu.c linux/arch/s390/kernel/mathemu.c
--- linux-2.2.17-pre12/arch/s390/kernel/mathemu.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/s390/kernel/mathemu.c	Mon Dec  3 22:09:50 2001
@@ -17,6 +17,18 @@
 #include <asm/uaccess.h>
 #include <asm/mathemu.h>
 
+static void display_emulation_not_implemented(char *instr)
+{
+	struct pt_regs *regs=current->tss.regs;
+	printk("%s not implemented\n",instr);
+	printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n",
+	       instr,
+                current->comm, current->pid, 4096+(addr_t)current);
+	printk("%s's PSW:    %08lx %08lx\n",instr,
+                (unsigned long) regs->psw.mask,
+                (unsigned long) regs->psw.addr);
+}
+
 static void set_CC_df(__u64 val1,__u64 val2) {
         int rc;
         rc = __cmpdf2(val1,val2);
@@ -69,7 +81,7 @@
 }
 
 static void emu_axbr (int rx, int ry) {
-        printk("axbr emulation not implemented!\n");
+        display_emulation_not_implemented("axbr");
 }
 
 static void emu_cdb (int rx, __u64 val) {
@@ -109,15 +121,15 @@
 }
 
 static void emu_cfxbr (int rx, int ry, int mask) {
-        printk("cfxbr emulation not implemented!\n");
+        display_emulation_not_implemented("cfxbr");
 }
 
 static void emu_cxbr (int rx, int ry) {
-        printk("cxbr emulation not implemented!\n");
+        display_emulation_not_implemented("cxbr");
 }
 
 static void emu_cxfbr (int rx, int ry) {
-        printk("cxfbr emulation not implemented!\n");
+        display_emulation_not_implemented("cxfbr");
 }
 
 static void emu_ddb (int rx, __u64 val) {
@@ -143,51 +155,51 @@
 }
 
 static void emu_didbr (int rx, int ry, int mask) {
-        printk("didbr emulation not implemented!\n");
+        display_emulation_not_implemented("didbr");
 }
 
 static void emu_diebr (int rx, int ry, int mask) {
-        printk("diebr emulation not implemented!\n");
+        display_emulation_not_implemented("diebr");
 }
 
 static void emu_dxbr (int rx, int ry) {
-        printk("dxbr emulation not implemented!\n");
+        display_emulation_not_implemented("dxbr");
 }
 
 static void emu_efpc (int rx, int ry) {
-        printk("efpc emulation not implemented!\n");
+        display_emulation_not_implemented("efpc");
 }
 
 static void emu_fidbr (int rx, int ry, int mask) {
-        printk("fidbr emulation not implemented!\n");
+        display_emulation_not_implemented("fidbr");
 }
 
 static void emu_fiebr (int rx, int ry, int mask) {
-        printk("fiebr emulation not implemented!\n");
+        display_emulation_not_implemented("fiebr");
 }
 
 static void emu_fixbr (int rx, int ry, int mask) {
-        printk("fixbr emulation not implemented!\n");
+        display_emulation_not_implemented("fixbr");
 }
 
 static void emu_kdb (int rx, __u64 val) {
-        printk("kdb emulation not implemented!\n");
+        display_emulation_not_implemented("kdb");
 }
 
 static void emu_kdbr (int rx, int ry) {
-        printk("kdbr emulation not implemented!\n");
+        display_emulation_not_implemented("kdbr");
 }
 
 static void emu_keb (int rx, __u32 val) {
-        printk("keb emulation not implemented!\n");
+        display_emulation_not_implemented("keb");
 }
 
 static void emu_kebr (int rx, int ry) {
-        printk("kebr emulation not implemented!\n");
+        display_emulation_not_implemented("kebr");
 }
 
 static void emu_kxbr (int rx, int ry) {
-        printk("kxbr emulation not implemented!\n");
+        display_emulation_not_implemented("kxbr");
 }
 
 static void emu_lcdbr (int rx, int ry) {
@@ -203,7 +215,7 @@
 }
 
 static void emu_lcxbr (int rx, int ry) {
-        printk("lcxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lcxbr");
 }
 
 static void emu_ldeb (int rx, __u32 val) {
@@ -216,7 +228,7 @@
 }
 
 static void emu_ldxbr (int rx, int ry) {
-        printk("ldxbr emulation not implemented!\n");
+        display_emulation_not_implemented("ldxbr");
 }
 
 static void emu_ledbr (int rx, int ry) {
@@ -225,19 +237,19 @@
 }
 
 static void emu_lexbr (int rx, int ry) {
-        printk("lexbr emulation not implemented!\n");
+        display_emulation_not_implemented("lexbr");
 }
 
 static void emu_lndbr (int rx, int ry) {
-        printk("lndbr emulation not implemented!\n");
+        display_emulation_not_implemented("lndbr");
 }
 
 static void emu_lnebr (int rx, int ry) {
-        printk("lnebr emulation not implemented!\n");
+        display_emulation_not_implemented("lnebr");
 }
 
 static void emu_lnxbr (int rx, int ry) {
-        printk("lnxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lnxbr");
 }
 
 static void emu_lpdbr (int rx, int ry) {
@@ -251,7 +263,7 @@
 }
 
 static void emu_lpxbr (int rx, int ry) {
-        printk("lpxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lpxbr");
 }
 
 static void emu_ltdbr (int rx, int ry) {
@@ -265,39 +277,39 @@
 }
 
 static void emu_ltxbr (int rx, int ry) {
-        printk("ltxbr emulation not implemented!\n");
+        display_emulation_not_implemented("ltxbr");
 }
 
 static void emu_lxdb (int rx, __u64 val) {
-        printk("lxdb emulation not implemented!\n");
+        display_emulation_not_implemented("lxdb");
 }
 
 static void emu_lxdbr (int rx, int ry) {
-        printk("lxdbr emulation not implemented!\n");
+        display_emulation_not_implemented("lxdbr");
 }
 
 static void emu_lxeb (int rx, __u32 val) {
-        printk("lxeb emulation not implemented!\n");
+        display_emulation_not_implemented("lxeb");
 }
 
 static void emu_lxebr (int rx, int ry) {
-        printk("lxebr emulation not implemented!\n");
+        display_emulation_not_implemented("lxebr");
 }
 
 static void emu_madb (int rx, __u64 val, int mask) {
-        printk("madb emulation not implemented!\n");
+        display_emulation_not_implemented("madb");
 }
 
 static void emu_madbr (int rx, int ry, int mask) {
-        printk(" emulation not implemented!\n");
+        display_emulation_not_implemented("madbr");
 }
 
 static void emu_maeb (int rx, __u32 val, int mask) {
-        printk("maeb emulation not implemented!\n");
+        display_emulation_not_implemented("maeb");
 }
 
 static void emu_maebr (int rx, int ry, int mask) {
-        printk("maebr emulation not implemented!\n");
+        display_emulation_not_implemented("maebr");
 }
 
 static void emu_mdb (int rx, __u64 val) {
@@ -312,11 +324,11 @@
 }
 
 static void emu_mdeb (int rx, __u32 val) {
-        printk("mdeb emulation not implemented!\n");
+        display_emulation_not_implemented("mdeb");
 }
 
 static void emu_mdebr (int rx, int ry) {
-        printk("mdebr emulation not implemented!\n");
+        display_emulation_not_implemented("mdebr");
 }
 
 static void emu_meeb (int rx, __u32 val) {
@@ -332,31 +344,31 @@
 }
 
 static void emu_msdb (int rx, __u64 val, int mask) {
-        printk("msdb emulation not implemented!\n");
+        display_emulation_not_implemented("msdb");
 }
 
 static void emu_msdbr (int rx, int ry, int mask) {
-        printk("msdbr emulation not implemented!\n");
+        display_emulation_not_implemented("msdbr");
 }
 
 static void emu_mseb (int rx, __u32 val, int mask) {
-        printk("mseb emulation not implemented!\n");
+        display_emulation_not_implemented("mseb");
 }
 
 static void emu_msebr (int rx, int ry, int mask) {
-        printk("msebr emulation not implemented!\n");
+        display_emulation_not_implemented("msebr");
 }
 
 static void emu_mxbr (int rx, int ry) {
-        printk("mxbr emulation not implemented!\n");
+        display_emulation_not_implemented("mxbr");
 }
 
 static void emu_mxdb (int rx, __u64 val) {
-        printk("mxdb emulation not implemented!\n");
+        display_emulation_not_implemented("mxdb");
 }
 
 static void emu_mxdbr (int rx, int ry) {
-        printk("mxdbr emulation not implemented!\n");
+        display_emulation_not_implemented("mxdbr");
 }
 
 static void emu_sdb (int rx, __u64 val) {
@@ -384,43 +396,43 @@
 }
 
 static void emu_sfpc (int rx, int ry) {
-        printk("sfpc emulation not implemented!\n");
+        display_emulation_not_implemented("sfpc");
 }
 
 static void emu_sqdb (int rx, __u64 val) {
-        printk("sqdb emulation not implemented!\n");
+        display_emulation_not_implemented("sqdb");
 }
 
 static void emu_sqdbr (int rx, int ry) {
-        printk("sqdbr emulation not implemented!\n");
+        display_emulation_not_implemented("sqdbr");
 }
 
 static void emu_sqeb (int rx, __u32 val) {
-        printk("sqeb emulation not implemented!\n");
+        display_emulation_not_implemented("sqeb");
 }
 
 static void emu_sqebr (int rx, int ry) {
-        printk("sqebr emulation not implemented!\n");
+        display_emulation_not_implemented("sqebr");
 }
 
 static void emu_sqxbr (int rx, int ry) {
-        printk("sqxbr emulation not implemented!\n");
+        display_emulation_not_implemented("sqxbr");
 }
 
 static void emu_sxbr (int rx, int ry) {
-        printk("sxbr emulation not implemented!\n");
+        display_emulation_not_implemented("sxbr");
 }
 
 static void emu_tcdb (int rx, __u64 val) {
-        printk("tcdb emulation not implemented!\n");
+        display_emulation_not_implemented("tcdb");
 }
 
 static void emu_tceb (int rx, __u32 val) {
-        printk("tceb emulation not implemented!\n");
+        display_emulation_not_implemented("tceb");
 }
 
 static void emu_tcxb (int rx, __u64 val) {
-        printk("tcxb emulation not implemented!\n");
+        display_emulation_not_implemented("tcxb");
 }
 
 
diff -urN linux-2.2.17-pre12/arch/s390/kernel/process.c linux/arch/s390/kernel/process.c
--- linux-2.2.17-pre12/arch/s390/kernel/process.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/process.c	Mon Dec  3 22:09:50 2001
@@ -57,7 +57,7 @@
 
 static psw_t wait_psw;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 static
 #endif
 int cpu_idle(void *unused)
@@ -69,7 +69,12 @@
 	wait_psw.mask = _WAIT_PSW_MASK;
 	wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
 	while(1) {
+#ifdef CONFIG_SMP
+                if (atomic_read(&global_bh_lock) == 0 &&
+                    (bh_mask & bh_active)) {
+#else
                 if (bh_mask & bh_active) {
+#endif
                         do_bottom_half();
                         continue;
                 }
diff -urN linux-2.2.17-pre12/arch/s390/kernel/s390_ksyms.c linux/arch/s390/kernel/s390_ksyms.c
--- linux-2.2.17-pre12/arch/s390/kernel/s390_ksyms.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/s390_ksyms.c	Mon Dec  3 22:09:50 2001
@@ -5,10 +5,17 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <asm/debug.h>
+#include <linux/genhd.h>
+#include <asm/ccwcache.h>
 #include <asm/irq.h>
 #include <asm/string.h>
 #include <asm/checksum.h>
 #include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
+#include <asm/ebcdic.h>
+#include <asm/timex.h>
+#include <asm/delay.h>
 #if CONFIG_CHANDEV
 #include <asm/chandev.h>
 #endif
@@ -16,7 +23,6 @@
 #include <net/arp.h>
 #endif
 
-
 /*
  * I/O subsystem
  */
@@ -30,14 +36,29 @@
 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_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
 
-/*
- * External interrupts
- */
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
 /*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister); 
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_text_exception);
+
+/*
  * memory management
  */
 EXPORT_SYMBOL(init_mm);
@@ -61,10 +82,18 @@
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
 /*
  * misc.
  */
-#ifdef __SMP__
+EXPORT_SYMBOL(__udelay);
+#ifdef CONFIG_SMP
 #include <asm/smplock.h>
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
@@ -73,17 +102,14 @@
 EXPORT_SYMBOL(global_bh_lock);
 EXPORT_SYMBOL(synchronize_bh);
 EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
 #endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
-#if CONFIG_CHANDEV
-EXPORT_SYMBOL(chandev_register_and_probe);
-EXPORT_SYMBOL(chandev_unregister);
-EXPORT_SYMBOL(chandev_initdevice);
-EXPORT_SYMBOL(chandev_initnetdevice);
-#endif
+EXPORT_SYMBOL(genhd_dasd_name);
+
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
 EXPORT_SYMBOL(arp_mc_map);
 #endif
-
diff -urN linux-2.2.17-pre12/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c
--- linux-2.2.17-pre12/arch/s390/kernel/s390io.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/s390io.c	Mon Dec  3 22:09:50 2001
@@ -49,7 +49,6 @@
 static spinlock_t sync_isc = SPIN_LOCK_UNLOCKED;
                                           // synchronous irq processing lock
 static psw_t      io_sync_wait;           // wait PSW for sync IO, prot. by sync_isc
-static psw_t      io_new_psw;             // save I/O new PSW, prot. by sync_isc
 static int        cons_dev          = -1; // identify console device
 static int        init_IRQ_complete = 0;
 static schib_t    init_schib;
@@ -340,7 +339,8 @@
 		{
 			s390irq_spin_unlock_irqrestore( irq, flags);
 
-			printk("free_irq() : error, dev_id does not match !");
+			printk( "free_irq(%04X) : error, "
+			        "dev_id does not match !", irq);
 
 		} /* endif */
 
@@ -349,7 +349,8 @@
 	{
 		s390irq_spin_unlock_irqrestore( irq, flags);
 
-		printk("free_irq() : error, no action block ... !");
+		printk( "free_irq(%04X) : error, "
+		        "no action block ... !\n", irq);
 
 	} /* endif */
 
@@ -906,7 +907,6 @@
 		if ( flag & DOIO_WAIT_FOR_INTERRUPT )
 		{
 			int              io_sub = -1;
-			__u32            io_parm;
          psw_t            io_new_psw;
          int              ccode;
 			uint64_t         time_start;    	
@@ -2504,15 +2504,7 @@
 				ioinfo[irq]->devstat.flag             |= DEVSTAT_FINAL_STATUS;
 				((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS;
 
-				if ( ioinfo[irq]->ui.flags.newreq )
-				{
-					action->handler( irq, ioinfo[irq]->u_intparm );
-				}
-				else
-				{
-					((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-				} /* endif */
+				action->handler( irq, action->dev_id, &regs );
 
 				//
 				// reset intparm after final status or we will badly present unsolicited
@@ -2544,15 +2536,7 @@
 					 */
 					if ( ret )
 					{
-						if ( ioinfo[irq]->ui.flags.newreq )
-						{
-							action->handler( irq, ioinfo[irq]->u_intparm );
-						}
-						else
-						{
-							((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-						} /* endif */
+						action->handler( irq, action->dev_id, &regs );
 
 					} /* endif */
 
@@ -2573,23 +2557,14 @@
 					((devstat_t *)(action->dev_id))->flag |= DEVSTAT_PCI;
 					ioinfo[irq]->devstat.cstat &= ~SCHN_STAT_PCI;
 				}
-				else if ( actl & SCSW_ACTL_SUSPENDED )
+
+				if ( actl & SCSW_ACTL_SUSPENDED )
 				{
 					((devstat_t *)(action->dev_id))->flag |= DEVSTAT_SUSPENDED;
 
 				} /* endif */
 
-				if ( ioinfo[irq]->ui.flags.newreq )
-				{
-					action->handler( irq, ioinfo[irq]->u_intparm );
-				}
-				else
-				{
-					((io_handler_func1_t)action->handler)( irq,
-					                                       action->dev_id,
-					                                       &regs );
-
-				} /* endif */
+				action->handler( irq, action->dev_id, &regs );
 
 			} /* endif */
 
@@ -2672,15 +2647,7 @@
 
 		if ( !ioinfo[irq]->ui.flags.s_pend )
 		{
-			if ( ioinfo[irq]->ui.flags.newreq )
-			{
-				action->handler( irq, ioinfo[irq]->u_intparm );
-			}
-			else
-			{
-				((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-			} /* endif */
+			action->handler( irq, action->dev_id, &regs );
 
 		} /* endif */
 
@@ -3794,17 +3761,27 @@
 		pdi->devno = ioinfo[irq]->schib.pmcw.dev;
 		pdi->irq   = irq;
 
-		if ( ioinfo[irq]->ui.flags.oper )
+		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;
-			memcpy( &(pdi->sid_data),
+			memset( &(pdi->sid_data),
 			        '\0',
 			        sizeof( senseid_t));
 			pdi->sid_data.cu_type = 0xFFFF;
@@ -3814,10 +3791,9 @@
 		if ( ioinfo[irq]->ui.flags.ready )
 			pdi->status |= DEVSTAT_DEVICE_OWNED;
 
-		return 0;
-
 	} /* endif */
 
+	return 0;
 }
 
 
@@ -3843,23 +3819,37 @@
 			if (    ioinfo[i] != INVALID_STORAGE_AREA
 			     && ioinfo[i]->schib.pmcw.dev == devno )
 			{
-				if ( ioinfo[i]->ui.flags.oper )
-				{
-					pdi->status = 0;
+
 					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;
-					pdi->irq    = i;
-					pdi->devno  = devno;
 
-					memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
+					memset( &(pdi->sid_data),
+                       '\0',
+                       sizeof( senseid_t));
+
 					pdi->sid_data.cu_type = 0xFFFF;
 
 				} /* endif */
@@ -3975,6 +3965,7 @@
 			else
 			{
 				ioinfo[irq]->ui.flags.syncio = 1; // global
+				ioinfo[irq]->ui.flags.unknown = 0;
 
 				memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
 
@@ -4735,14 +4726,14 @@
 			        ioinfo[irq]->schib.pmcw.dev,
 			        irq);
 #endif
-			ioinfo[irq]->ui.flags.oper = 0;
+			ioinfo[irq]->ui.flags.unknown = 1;
 
 		} /* endif */
 
 		/*
 		 * Issue device info message if unit was operational .
 		 */
-		if ( ioinfo[irq]->ui.flags.oper )
+		if ( ioinfo[irq]->ui.flags.unknown )
 	{
 			if ( sid->dev_type != 0 )
       {
@@ -4766,7 +4757,7 @@
 
 	} /* endif */
 
-		if ( ioinfo[irq]->ui.flags.oper )
+		if ( ioinfo[irq]->ui.flags.unknown )
 			irq_ret = 0;
 		else
 			irq_ret = -ENODEV;
@@ -5524,6 +5515,7 @@
 
 
 /* added by Holger Smolinski for reipl support in reipl.S */
+extern void do_reipl (int);
 void 
 reipl ( int sch )
 {
diff -urN linux-2.2.17-pre12/arch/s390/kernel/s390mach.c linux/arch/s390/kernel/s390mach.c
--- linux-2.2.17-pre12/arch/s390/kernel/s390mach.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/s390mach.c	Mon Dec  3 22:09:50 2001
@@ -119,9 +119,9 @@
 
 	down( &s_sem[0]);
 
-	smp_ctl_clear_bit( 14, 25 );  // disable damage MCH 	
+	ctl_clear_bit( 14, 25 );  // disable damage MCH 	
 #if 1
-  	smp_ctl_set_bit( 14, 28 );		// enable channel report MCH
+  	ctl_set_bit( 14, 28 );		// enable channel report MCH
 #endif
 
 #ifdef S390_MACHCHK_DEBUG
diff -urN linux-2.2.17-pre12/arch/s390/kernel/setup.c linux/arch/s390/kernel/setup.c
--- linux-2.2.17-pre12/arch/s390/kernel/setup.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/setup.c	Mon Dec  3 22:09:50 2001
@@ -43,6 +43,7 @@
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
 /*
  * Setup options
@@ -75,6 +76,7 @@
 void cpu_init (void)
 {
         int nr = smp_processor_id();
+        int addr = hard_smp_processor_id();
 
         if (test_and_set_bit(nr,&cpu_initialized)) {
                 printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
@@ -86,7 +88,7 @@
          * Store processor id in lowcore (used e.g. in timer_interrupt)
          */
         asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
-        S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id();
+        S390_lowcore.cpu_data.cpu_addr = addr;
         S390_lowcore.cpu_data.cpu_nr = nr;
 
         /*
@@ -132,7 +134,7 @@
  * Reboot, halt and power_off routines for non SMP.
  */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 void machine_restart(char * __unused)
 {
   reipl(S390_lowcore.ipl_device); 
@@ -142,14 +144,14 @@
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_power_off(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 #endif
 
@@ -190,6 +192,7 @@
          */
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+        __cpu_logical_map[0] = boot_cpu_addr;
 
         /*
          * print what head.S has found out about the machine 
@@ -259,11 +262,14 @@
 				delay = delay*60*1000000;
 				from++;
 			}
-			tod_wait(delay);
+			/* now wait for the requested amount of time */
+			udelay(delay);
                 }
                 cn = *(from++);
                 if (!cn)
                         break;
+                if (cn == '\n')
+                        cn = ' ';  /* replace newlines with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
@@ -271,6 +277,7 @@
                         break;
                 *(to++) = c;
         }
+        if (c == ' ' && to > command_line) to--;
         *to = '\0';
         *cmdline_p = command_line;
         memory_end += PAGE_OFFSET;
@@ -298,12 +305,12 @@
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
 {
    printk("cpu %d "
-#ifdef __SMP__
+#ifdef CONFIG_SMP
            "phys_idx=%d "
 #endif
            "vers=%02X ident=%06X machine=%04X unused=%04X\n",
            cpuinfo->cpu_nr,
-#ifdef __SMP__
+#ifdef CONFIG_SMP
            cpuinfo->cpu_addr,
 #endif
            cpuinfo->cpu_id.version,
diff -urN linux-2.2.17-pre12/arch/s390/kernel/signal.c linux/arch/s390/kernel/signal.c
--- linux-2.2.17-pre12/arch/s390/kernel/signal.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/signal.c	Mon Dec  3 22:09:50 2001
@@ -231,15 +231,12 @@
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 {
 	rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
-	stack_t st;
 
 	if (sigreturn_common(regs,sizeof(rt_sigframe)))
 			goto badframe;
-	if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
-		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
-	do_sigaltstack(&st, NULL, regs->gprs[15]);
+	do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
 	return regs->gprs[2];
 
 badframe:
@@ -359,6 +356,7 @@
 	err |= __put_user(sas_ss_flags(orig_sp),
 			  &frame->uc.uc_stack.ss_flags);
 	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= __put_user(&frame->sc,&frame->uc.sc);
 	regs->gprs[3] = (addr_t)&frame->info;
 	regs->gprs[4] = (addr_t)&frame->uc;
 
diff -urN linux-2.2.17-pre12/arch/s390/kernel/smp.c linux/arch/s390/kernel/smp.c
--- linux-2.2.17-pre12/arch/s390/kernel/smp.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/smp.c	Mon Dec  3 22:09:50 2001
@@ -43,6 +43,7 @@
 extern int cpu_idle(void * unused);
 
 extern __u16 boot_cpu_addr;
+extern volatile int __cpu_logical_map[];
 
 /*
  * An array with a pointer the lowcore of every CPU.
@@ -53,7 +54,6 @@
 unsigned int     prof_multiplier[NR_CPUS];
 unsigned int     prof_counter[NR_CPUS];
 volatile int     cpu_number_map[NR_CPUS];
-volatile int     __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 cycles_t         cacheflush_time=0;
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 unsigned long    ipi_count=0;              /* Number of IPIs delivered. */
@@ -107,7 +107,7 @@
         smp_send_stop();
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_halt(void)
@@ -124,7 +124,7 @@
         smp_send_stop();
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_power_off(void)
@@ -417,7 +417,7 @@
 
 void smp_send_stop(void)
 {
-        smp_signal_others(sigp_stop, 0, TRUE, NULL);
+        smp_signal_others(sigp_stop_and_store_status, 0, TRUE, NULL);
 }
 
 /*
@@ -472,7 +472,6 @@
 {
         int curr_cpu;
 
-        __cpu_logical_map[0] = boot_cpu_addr;
         current->processor = 0;
         smp_num_cpus = 1;
         for (curr_cpu = 0;
@@ -498,11 +497,16 @@
 
 int __init start_secondary(void *cpuvoid)
 {
+        /* Setup the cpu */
         cpu_init();
+        /* Print info about this processor */
         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();
+        /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
 
diff -urN linux-2.2.17-pre12/arch/s390/kernel/time.c linux/arch/s390/kernel/time.c
--- linux-2.2.17-pre12/arch/s390/kernel/time.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/kernel/time.c	Mon Dec  3 22:09:50 2001
@@ -145,7 +145,7 @@
  * as well as call the "do_timer()" routine every clocktick
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern __u16 boot_cpu_addr;
 #endif
 
@@ -160,7 +160,7 @@
  
         save_flags(flags);
         cli();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
 		write_lock(&xtime_lock);
 		last_timer_cc = S390_lowcore.jiffy_timer_cc;
@@ -177,7 +177,7 @@
  * profiling, except when we simulate SMP mode on a uniprocessor
  * system, in that case we have to call the local interrupt handler.
  */
-#ifdef __SMP__
+#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);
@@ -186,12 +186,12 @@
                 s390_do_profile(regs->psw.addr);
 #endif
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 	if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
 #endif
 	{
 		do_timer(regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 		write_unlock(&xtime_lock);
 #endif
 	}
diff -urN linux-2.2.17-pre12/arch/s390/lib/delay.c linux/arch/s390/lib/delay.c
--- linux-2.2.17-pre12/arch/s390/lib/delay.c	Tue Jan  4 10:12:12 2000
+++ linux/arch/s390/lib/delay.c	Mon Dec  3 22:09:50 2001
@@ -20,25 +20,30 @@
 
 void __delay(unsigned long loops)
 {
+        /*
+         * To end the bloody studid and useless discussion about the
+         * BogoMips number I took the liberty to define the __delay
+         * function in a way that that resulting BogoMips number will
+         * yield the megahertz number of the cpu. The important function
+         * is udelay and that is done using the tod clock. -- martin.
+         */
 	__asm__ __volatile__(
-                "0: ahi  %0,-1\n"
-                "   jnm  0b"
-                : /* no outputs */ : "r" (loops) );
+                "0: brct %0,0b"
+                : /* no outputs */ : "r" (loops/2) );
 }
 
-inline void __const_udelay(unsigned long xloops)
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
 {
+        uint64_t start_cc, end_cc;
 
-	__asm__("LR    3,%1\n\t"
-		"MR    2,%2\n\t"
-		"LR    %0,2\n\t"
-		: "=r" (xloops)
-		: "r" (xloops) , "r"  (loops_per_sec)
-		: "2" , "3");
-        __delay(xloops);
+        if (usecs == 0)
+                return;
+        asm volatile ("STCK %0" : "=m" (start_cc));
+        do {
+                asm volatile ("STCK %0" : "=m" (end_cc));
+        } while (((end_cc - start_cc)/4096) < usecs);
 }
 
-void __udelay(unsigned long usecs)
-{
-	__const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
-}
diff -urN linux-2.2.17-pre12/arch/s390/mm/fault.c linux/arch/s390/mm/fault.c
--- linux-2.2.17-pre12/arch/s390/mm/fault.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/mm/fault.c	Mon Dec  3 22:09:50 2001
@@ -74,24 +74,14 @@
         down(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
-        if (!vma) {
-	        printk("no vma for address %lX\n",address);
+        if (!vma)
                 goto bad_area;
-        }
         if (vma->vm_start <= address) 
                 goto good_area;
-        if (!(vma->vm_flags & VM_GROWSDOWN)) {
-                printk("VM_GROWSDOWN not set, but address %lX \n",address);
-                printk("not in vma %p (start %lX end %lX)\n",vma,
-                       vma->vm_start,vma->vm_end);
+        if (!(vma->vm_flags & VM_GROWSDOWN))
                 goto bad_area;
-        }
-        if (expand_stack(vma, address)) {
-                printk("expand of vma failed address %lX\n",address);
-                printk("vma %p (start %lX end %lX)\n",vma,
-                       vma->vm_start,vma->vm_end);
+        if (expand_stack(vma, address))
                 goto bad_area;
-        }
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
@@ -104,13 +94,8 @@
                         break;
                 case 0x10:                                   /* not present*/
                 case 0x11:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
-                                printk("flags %X of vma for address %lX wrong \n",
-                                       vma->vm_flags,address);
-                                printk("vma %p (start %lX end %lX)\n",vma,
-                                       vma->vm_start,vma->vm_end);
+                        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);  
diff -urN linux-2.2.17-pre12/arch/s390/tools/dasdfmt/Makefile linux/arch/s390/tools/dasdfmt/Makefile
--- linux-2.2.17-pre12/arch/s390/tools/dasdfmt/Makefile	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/tools/dasdfmt/Makefile	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,8 @@
 all: dasdfmt
 
 dasdfmt: dasdfmt.c
-	$(CROSS_COMPILE)gcc -o $@ $^
-	$(STRIP) $@
+	$(CROSS_COMPILE)gcc -I$(HPATH) -o $@ $^
+	$(CROSS_COMPILE)strip $@
 
 clean:
 	rm -f dasdfmt
diff -urN linux-2.2.17-pre12/arch/s390/tools/dasdfmt/dasdfmt.8 linux/arch/s390/tools/dasdfmt/dasdfmt.8
--- linux-2.2.17-pre12/arch/s390/tools/dasdfmt/dasdfmt.8	Wed May  3 17:16:31 2000
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.8	Mon Dec  3 22:09:50 2001
@@ -3,8 +3,7 @@
 .SH NAME
 dasdfmt \- formatting of DSAD (ECKD) disk drives.
 .SH SYNOPSIS
-\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI]
-	\fIdiskSpec\fR
+\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
 .SH DESCRIPTION
 \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
 for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
@@ -25,6 +24,10 @@
 Start formatting without further user-confirmation.
 
 .TP
+\fB-L\fR 
+Omit the writing of a disk label after formatting.
+
+.TP
 \fB-V\fR 
 Print version number and exit.
 
@@ -35,26 +38,17 @@
 it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
 
 .TP
-\fIblockRange\fR
-This parameter specifies the number of the first and last block to be
-formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk
-is assumed. The \fIblockRange\fR can be specified in two different formats:
-.sp
-	\fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR
-.br
-or
-.br
-	\fB-r\fR \fIstartBlock\fR-\fIendBlock\fR
-.sp
-If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If
-\fIendBlock\fR is omitted, the last block of the disk is assumed.
+\fB-l\fR \fIdiskLabel\fR
+Specify the label to be written to disk after formatting. If no label is
+specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
+ASCII string and is automatically converted to EBCDIC.
 
 .TP
 \fIdiskSpec\fR
 This parameter specified the device to be formatted. It also can be
 given in two variants:
 .sp
-	\fB-f\fR \fB/dev/dd\fR\fIX\fR
+	\fB-f\fR \fB/dev/dasd\fR\fIX\fR
 .br
 or
 .br
@@ -63,7 +57,7 @@
 The first form uses the commonly used
 .SM UNIX
 device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the VM vdev number.
+The second form uses simply the device number.
 
 .SH BUGS
 None so far ;-)
diff -urN linux-2.2.17-pre12/arch/s390/tools/dasdfmt/dasdfmt.c linux/arch/s390/tools/dasdfmt/dasdfmt.c
--- linux-2.2.17-pre12/arch/s390/tools/dasdfmt/dasdfmt.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/tools/dasdfmt/dasdfmt.c	Mon Dec  3 22:09:50 2001
@@ -12,6 +12,8 @@
  *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
  */
 
+/* #define _LINUX_BLKDEV_H */
+
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -31,7 +33,8 @@
 #undef __KERNEL__
 
 #include <linux/fs.h>
-#include <linux/dasd.h>
+#include <asm/dasd.h>
+#include <linux/hdreg.h>
 
 #define EXIT_MISUSE 1
 #define EXIT_BUSY 2
@@ -39,9 +42,11 @@
 #define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
 #define SLASHDEV "/dev/"
 #define PROC_DASD_DEVICES "/proc/dasd/devices"
-#define PROC_MOUNTS "/proc/mounts"  /* _PATH_MOUNTED is /etc/mtab - maybe bad */
+/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
+#define PROC_MOUNTS _PATH_MOUNTED
 #define PROC_SWAPS "/proc/swaps"
 #define DASD_DRIVER_NAME "dasd"
+#define LABEL_LENGTH 10
 #define PROC_LINE_LENGTH 80
 #define ERR_LENGTH 80
 
@@ -73,19 +78,105 @@
 char *prog_name;/*="dasdfmt";*/
 char tempfilename[]=TEMPFILENAME;
 
+__u8 _ascebc[256] =
+{
+ /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
+     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+ /*              ->NL                               */
+     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
+     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
+ /*                               ->IGS ->IRS ->IUS */
+     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20  SP     !     "     #     $     %     &     ' */
+     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28   (     )     *     +     ,     -    .      / */
+     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30   0     1     2     3     4     5     6     7 */
+     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38   8     9     :     ;     <     =     >     ? */
+     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40   @     A     B     C     D     E     F     G */
+     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48   H     I     J     K     L     M     N     O */
+     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50   P     Q     R     S     T     U     V     W */
+     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58   X     Y     Z     [     \     ]     ^     _ */
+     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60   `     a     b     c     d     e     f     g */
+     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68   h     i     j     k     l     m     n     o */
+     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70   p     q     r     s     t     u     v     w */
+     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78   x     y     z     {     |     }     ~    DL */
+     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0        sz						*/
+     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+void convert_label(char *str)
+{
+	int i;
+	for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
+}
+
 void
 exit_usage(int exitcode)
 {
-	printf("Usage: %s [-htvyV] [-b <blocksize>] [<range>] <diskspec>\n\n",
-	       prog_name);
+#ifdef RANGE_FORMATTING
+	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+		"<diskspec>\n\n",prog_name);
+#else /* RANGE_FORMATTING */
+	printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+		"<diskspec>\n\n",prog_name);
+#endif /* RANGE_FORMATTING */
 	printf("       -t means testmode\n");
 	printf("       -v means verbose mode\n");
 	printf("       -V means print version\n");
+	printf("       -L means don't write disk label\n");
+	printf("       <label> is a label which is converted to EBCDIC and " \
+		"written to disk\n");
 	printf("       <blocksize> has to be power of 2 and at least 512\n");
+#ifdef RANGE_FORMATTING
 	printf("       <range> is either\n");
 	printf("           -s <start_track> -e <end_track>\n");
 	printf("       or\n");
 	printf("           -r <start_track>-<end_track>\n");
+#endif /* RANGE_FORMATTING */
 	printf("       and <diskspec> is either\n");
 	printf("           -f /dev/dasdX\n");
 	printf("       or\n");
@@ -108,9 +199,9 @@
 			PROC_DASD_DEVICES ": %s (do you have the /proc " \
 			"filesystem enabled?)\n",prog_name,strerror(errno));
 
-	fgets(line,sizeof(line),file); /* omit first line */
+	/*	fgets(line,sizeof(line),file); omit first line */ 
 	while (fgets(line,sizeof(line),file)!=NULL) {
-		rc=sscanf(line,"%X%d%d",&d,&ma_i,&mi_i);
+		rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
 		ma=ma_i;
 		mi=mi_i;
 		if ( (rc==3) &&
@@ -255,6 +346,7 @@
 	char *str;
 	char output[60],o2[12];
 
+#ifdef RANGE_FORMATTING
 	i=params.start_unit;
 	do {
 		params.start_unit=i;
@@ -286,6 +378,7 @@
 			ASK_CHECK_PARAM(CHECK_END);
 		}
 	} while (rc!=1);
+#endif /* RANGE_FORMATTING */
 
 	i=params.blksize;
 	do {
@@ -364,12 +457,16 @@
 
 void
 do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-	int verbosity,int withoutprompt)
+	int verbosity,int writenolabel,int labelspec,
+	char *label,int withoutprompt)
 {
 	int fd,rc;
 	struct stat stat_buf;
 	kdev_t minor_no,major_no;
 	int devno;
+	int new_blksize;
+	unsigned int label_position;
+	struct hd_geometry new_geometry;
 	char inp_buffer[5]; /* to contain yes */
 
 	fd=open(dev_name,O_RDWR);
@@ -393,6 +490,10 @@
 	}
 	check_mounted(major_no, minor_no);
 	
+	if ((!writenolabel) && (!labelspec)) {
+		sprintf(label,"LNX1 x%04x",devno);
+	}
+	
 	if ( ((withoutprompt)&&(verbosity>=1)) ||
 		(!withoutprompt) ) {
 		get_xno_from_xno(&devno,&major_no,&minor_no,
@@ -402,6 +503,11 @@
 		printf("   Device number of device : 0x%x\n",devno);
 		printf("   Major number of device  : %u\n",major_no);
 		printf("   Minor number of device  : %u\n",minor_no);
+		printf("   Labelling device        : %s\n",(writenolabel)?
+			"no":"yes");
+		if (!writenolabel)
+			printf("   Disk label              : %s\n",label);
+#ifdef RANGE_FORMATTING
 		printf("   Start track             : %d\n" \
 			,format_params.start_unit);
 		printf("   End track               : ");
@@ -409,6 +515,7 @@
 			printf("last track of disk\n");
 		else
 			printf("%d\n",format_params.stop_unit);
+#endif /* RANGE_FORMATTING */
 		printf("   Blocksize               : %d\n" \
 			,format_params.blksize);
 		if (testmode) printf("Test mode active, omitting ioctl.\n");
@@ -439,6 +546,56 @@
 				"message:\n%s\n",prog_name,strerror(errno));
 		printf("Finished formatting the device.\n");
 
+		if (!writenolabel) {
+			if (verbosity>0)
+				printf("Retrieving disk geometry... ");
+
+			rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
+			if (rc) {
+				ERRMSG("%s: the ioctl call to get geometry " \
+					"returned with the following error " \
+					"message:\n%s\n",prog_name,
+					strerror(errno));
+				goto reread;
+			}
+	
+
+			rc=ioctl(fd,BLKGETBSZ,&new_blksize);
+			if (rc) {
+				ERRMSG("%s: the ioctl call to get blocksize " \
+					"returned with the following error " \
+					"message:\n%s\n",prog_name,
+					strerror(errno));
+				goto reread;
+			}
+	
+			if (verbosity>0) printf("done\n");
+
+			label_position=new_geometry.start*new_blksize;
+	
+			if (verbosity>0) printf("Writing label... ");
+			convert_label(label);
+			rc=lseek(fd,label_position,SEEK_SET);
+			if (rc!=label_position) {
+				ERRMSG("%s: lseek on the device to %i " \
+					"failed with the following error " \
+					"message:\n%s\n",prog_name,
+					label_position,strerror(errno));
+				goto reread;
+			}
+			rc=write(fd,label,LABEL_LENGTH);
+			if (rc!=LABEL_LENGTH) {
+				ERRMSG("%s: writing the label only wrote %d " \
+					"bytes.\n",prog_name,rc);
+				goto reread;
+			}
+
+			sync();
+			sync();
+
+			if (verbosity>0) printf("done\n");
+		}
+ reread:
 		printf("Rereading the partition table... ");
 		rc=ioctl(fd,BLKRRPART,NULL);
 		if (rc) {
@@ -461,11 +618,13 @@
 	int verbosity;
 	int testmode;
 	int withoutprompt;
+	int writenolabel,labelspec;
 
 	char *dev_name;
 	int devno;
 	char *dev_filename,*devno_param_str,*range_param_str;
 	char *start_param_str,*end_param_str,*blksize_param_str;
+	char label[LABEL_LENGTH+1];
 	
 	format_data_t format_params;
 
@@ -474,7 +633,7 @@
 	char *endptr;
 
 	char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-	int i1,i2;
+	int i,i1,i2;
 	char *str;
 
 	int start_specified,end_specified,blksize_specified;
@@ -492,6 +651,11 @@
 	testmode=0;
 	verbosity=0;
 	withoutprompt=0;
+	writenolabel=0;
+	labelspec=0;
+	for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
+	label[LABEL_LENGTH]=0;
+
 	start_specified=end_specified=blksize_specified=0;
 	devfile_specified=devno_specified=range_specified=0;
 
@@ -500,7 +664,10 @@
 	/* avoid error message generated by getopt */
 	opterr=0;
 
-	while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) {
+#ifdef RANGE_FORMATTING
+	while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+#endif /* RANGE_FORMATTING */
+	while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
 		switch (oc) {
 		case 'y':
 			withoutprompt=1;
@@ -525,6 +692,18 @@
 			printf("%s version 0.99\n",prog_name);
 			exit(0);
 
+		case 'l':
+			strncpy(label,optarg,LABEL_LENGTH);
+			if (strlen(optarg)<LABEL_LENGTH)
+				label[strlen(optarg)]=' ';
+			labelspec++;
+			break;
+
+		case 'L':
+			writenolabel++;
+			break;
+
+#ifdef RANGE_FORMATTING
 		case 's' :
 			start_param_str=optarg;
 			start_specified++;
@@ -535,6 +714,12 @@
 			end_specified++;
 			break;
 
+		case 'r' :
+			range_param_str=optarg;
+			range_specified++;
+			break;
+#endif /* RANGE_FORMATTING */
+
 		case 'b' :
 			blksize_param_str=optarg;
 			blksize_specified++;
@@ -549,10 +734,6 @@
 			dev_filename=optarg;
 			devfile_specified++;
 			break;
-		case 'r' :
-			range_param_str=optarg;
-			range_specified++;
-			break;
 		}
 	}
 
@@ -604,6 +785,8 @@
 	CHECK_SPEC_MAX_ONCE(start_specified,"start track");
 	CHECK_SPEC_MAX_ONCE(end_specified,"end track");
 	CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+	CHECK_SPEC_MAX_ONCE(labelspec,"label");
+	CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
 
 	if (devno_specified)
 		PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
@@ -628,7 +811,7 @@
 
 	/******* issue the real command and reread part table *******/
 	do_format_dasd(dev_name,format_params,testmode,verbosity,
-		withoutprompt);
+		writenolabel,labelspec,label,withoutprompt);
 
 	/*************** cleanup ********************************/
 	if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
diff -urN linux-2.2.17-pre12/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c
--- linux-2.2.17-pre12/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c	Mon Dec  3 22:09:50 2001
@@ -12,7 +12,7 @@
 #include <stdio.h>
 
 /* everything about the HWC terminal driver ioctl-commands */
-#include "../../../../drivers/s390/char/sclp_tty.h"
+#include "../../../../drivers/s390/char/hwc_tty.h"
 
 /* standard input, should be our HWC tty */
 #define DESCRIPTOR 0
diff -urN linux-2.2.17-pre12/arch/s390/tools/silo/silo.c linux/arch/s390/tools/silo/silo.c
--- linux-2.2.17-pre12/arch/s390/tools/silo/silo.c	Wed Jun  7 14:26:42 2000
+++ linux/arch/s390/tools/silo/silo.c	Mon Dec  3 22:09:50 2001
@@ -57,7 +57,7 @@
 #define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
 #define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
 #define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
+#define GETARG(x) {int len=strlen(optarg);x=malloc(len+1);strncpy(x,optarg,len+1);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
 
 #define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
 #define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
diff -urN linux-2.2.17-pre12/drivers/char/console.c linux/drivers/char/console.c
--- linux-2.2.17-pre12/drivers/char/console.c	Wed Jun  7 14:26:42 2000
+++ linux/drivers/char/console.c	Mon Dec  3 22:09:50 2001
@@ -33,7 +33,7 @@
  * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
  *
  * Merge with the abstract console driver by Geert Uytterhoeven
- * <Geert.Uytterhoeven@cs.kuleuven.ac.be>, Jan 1997.
+ * <geert@linux-m68k.org>, Jan 1997.
  *
  *   Original m68k console driver modifications by
  *
diff -urN linux-2.2.17-pre12/drivers/net/Space.c linux/drivers/net/Space.c
--- linux-2.2.17-pre12/drivers/net/Space.c	Mon Dec  3 22:09:38 2001
+++ linux/drivers/net/Space.c	Mon Dec  3 22:09:50 2001
@@ -637,6 +637,12 @@
 #   define NEXT_DEV	(&tap0_dev)
 #endif
 
+#ifdef CONFIG_BONDING
+static struct device bonding_dev = { "bond0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, bond_init, };
+#    undef NEXT_DEV
+#    define NEXT_DEV    (&bonding_dev)
+#endif
+
 #ifdef CONFIG_LANMEDIA
 static struct device lmc_dev = { "lmc_dev", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, lmc_probe_fake, };
 #    undef NEXT_DEV
diff -urN linux-2.2.17-pre12/drivers/net/a2065.c linux/drivers/net/a2065.c
--- linux-2.2.17-pre12/drivers/net/a2065.c	Sun Mar 21 07:22:00 1999
+++ linux/drivers/net/a2065.c	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 /*
  * Amiga Linux/68k A2065 Ethernet Driver
  *
- * (C) Copyright 1995 by Geert Uytterhoeven
- *                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ * (C) Copyright 1995 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  * Fixes and tips by:
  *	- Janos Farkas (CHEXUM@sparta.banki.hu)
diff -urN linux-2.2.17-pre12/drivers/net/a2065.h linux/drivers/net/a2065.h
--- linux-2.2.17-pre12/drivers/net/a2065.h	Fri Dec 20 01:20:00 1996
+++ linux/drivers/net/a2065.h	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 /*
  * Amiga Linux/68k A2065 Ethernet Driver
  *
- * (C) Copyright 1995 by Geert Uytterhoeven
- *			(Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ * (C) Copyright 1995 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  * ---------------------------------------------------------------------------
  *
diff -urN linux-2.2.17-pre12/drivers/net/ariadne.c linux/drivers/net/ariadne.c
--- linux-2.2.17-pre12/drivers/net/ariadne.c	Thu Feb 25 10:02:13 1999
+++ linux/drivers/net/ariadne.c	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 /*
  *  Amiga Linux/m68k Ariadne Ethernet Driver
  *
- *  © Copyright 1995 by Geert Uytterhoeven
- *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
  *			Peter De Schrijver
  *		       (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
  *
diff -urN linux-2.2.17-pre12/drivers/net/ariadne.h linux/drivers/net/ariadne.h
--- linux-2.2.17-pre12/drivers/net/ariadne.h	Sun May 19 21:54:28 1996
+++ linux/drivers/net/ariadne.h	Mon Dec  3 22:09:50 2001
@@ -1,8 +1,7 @@
 /*
  *  Amiga Linux/m68k Ariadne Ethernet Driver
  *
- *  © Copyright 1995 by Geert Uytterhoeven
- *		       (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  © Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
  *			Peter De Schrijver
  *		       (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
  *
diff -urN linux-2.2.17-pre12/drivers/net/bonding.c linux/drivers/net/bonding.c
--- linux-2.2.17-pre12/drivers/net/bonding.c	Wed May  3 17:16:40 2000
+++ linux/drivers/net/bonding.c	Mon Dec  3 22:09:50 2001
@@ -71,8 +71,12 @@
 	bonding_t *private = (struct bonding *) master->priv;
 	slave_queue_t *queue = (struct slave_queue *) private->queue;
 	slave_t *slave, *next;
+	unsigned long flags;
 
-	for( slave=queue->head; slave != NULL; slave=next) {
+	save_flags(flags);
+	cli();
+
+	for( slave=queue->head; slave != NULL; ) {
 #ifdef BONDING_DEBUG
 		printk("freeing = %s\n", slave->dev->name);
 #endif
@@ -80,9 +84,12 @@
 		slave->dev->slave = NULL;
 		next = slave->next;
 		kfree(slave);
-		queue->num_slaves++;
+		slave=next;
+		queue->num_slaves--;
 	}
 
+	restore_flags(flags);
+
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
@@ -97,7 +104,7 @@
 	bonding_t *private = (struct bonding *) master->priv;
 	slave_queue_t *queue = (struct slave_queue *) private->queue;
 	slave_t *new_slave;
-	int flags;
+	unsigned long flags;
 	
 	if (master == NULL || slave == NULL) 
 		return -ENODEV;
@@ -121,14 +128,15 @@
 		return -EBUSY;
 	}
 		   
-	slave->slave = master;     /* save the master in slave->slave */
-	slave->flags |= IFF_SLAVE;
-
 	if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
+		restore_flags(flags);
 		return -ENOMEM;
 	}
 	memset(new_slave, 0, sizeof(slave_t));
 
+	slave->slave = master;     /* save the master in slave->slave */
+	slave->flags |= IFF_SLAVE;
+
 	new_slave->dev = slave;
 
 	if (queue->head == NULL) {
@@ -240,6 +248,11 @@
 	struct slave_queue *queue = bond->queue;
 	int good = 0;
 	
+	if(!queue->num_slaves) {
+		dev_kfree_skb(skb);
+		return 0;
+	}
+
 	while (good == 0) {
 		slave = queue->current_slave->dev;
 		if (slave->flags & (IFF_UP|IFF_RUNNING)) {
diff -urN linux-2.2.17-pre12/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- linux-2.2.17-pre12/drivers/net/de4x5.c	Mon Dec  3 22:09:39 2001
+++ linux/drivers/net/de4x5.c	Mon Dec  3 22:09:50 2001
@@ -379,8 +379,7 @@
                           Fix bug in pci_probe() for 64 bit systems reported
 			   by <belliott@accessone.com>.
       0.533   9-Jan-98    Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
-      0.534  24-Jan-98    Fix last (?) endian bug from 
-                           <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+      0.534  24-Jan-98    Fix last (?) endian bug from <geert@linux-m68k.org>
       0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
       0.536  21-Mar-98    Change pci_probe() to use the pci_dev structure.
 			  **Incompatible with 2.0.x from here.**
diff -urN linux-2.2.17-pre12/drivers/net/hydra.c linux/drivers/net/hydra.c
--- linux-2.2.17-pre12/drivers/net/hydra.c	Tue Feb 10 12:56:44 1998
+++ linux/drivers/net/hydra.c	Mon Dec  3 22:09:50 2001
@@ -3,7 +3,7 @@
 /* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi)          */
 
 /* The code is mostly based on the linux/68k Ariadne driver                 */
-/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */
+/* copyrighted by Geert Uytterhoeven (geert@linux-m68k.org)                 */
 /* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)       */
 
 /* This file is subject to the terms and conditions of the GNU General      */
diff -urN linux-2.2.17-pre12/drivers/s390/Config.in linux/drivers/s390/Config.in
--- linux-2.2.17-pre12/drivers/s390/Config.in	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/Config.in	Mon Dec  3 22:09:50 2001
@@ -15,6 +15,7 @@
 if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
   bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
 fi
+
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
   int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 8192
@@ -50,7 +51,6 @@
   comment 'S/390 Network device support'
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    menu_option next_comment
     comment 'S390 Network devices'
     bool 'CTC device support' CONFIG_CTC
     bool 'IUCV device support (VM only)' CONFIG_IUCV
diff -urN linux-2.2.17-pre12/drivers/s390/Makefile linux/drivers/s390/Makefile
--- linux-2.2.17-pre12/drivers/s390/Makefile	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/Makefile	Mon Dec  3 22:09:50 2001
@@ -11,7 +11,7 @@
 
 CFLAGS += 
 O_TARGET := io.o
-O_OBJS    :=         
+O_OBJS   := ccwcache.o
 M_OBJS   :=
 
 SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
@@ -21,7 +21,8 @@
 O_OBJS := block/s390-block.o \
   char/s390-char.o \
   misc/s390-misc.o \
-  net/s390-net.o 
+  net/s390-net.o \
+  ccwcache.o
 
 io.o: $(O_OBJS)
 
@@ -36,5 +37,6 @@
 
 net/s390-net.o: dummy
 	$(MAKE) -C net
+
 
 include $(TOPDIR)/Rules.make
diff -urN linux-2.2.17-pre12/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- linux-2.2.17-pre12/drivers/s390/block/Makefile	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/Makefile	Mon Dec  3 22:09:50 2001
@@ -7,18 +7,15 @@
 D_OBJS   :=
 
 ifeq ($(CONFIG_DASD),y)
-  O_OBJS += dasd.o dasd_ccwstuff.o dasd_erp.o dasd_setup.o
-  ifeq ($(CONFIG_PROC_FS),y)
-   O_OBJS += dasd_proc.o dasd_profile.o
-  endif 
+  O_OBJS += dasd.o
   ifeq ($(CONFIG_DASD_ECKD),y)
-   O_OBJS += dasd_eckd.o dasd_eckd_erp.o dasd_3990_erp.o dasd_9343_erp.o
+   O_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   O_OBJS += dasd_fba.o
+   O_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   O_OBJS += dasd_mdsk.o
+   O_OBJS += dasd_diag.o
   endif 
 #  ifeq ($(CONFIG_DASD_CKD),y)
 #   O_OBJS += dasd_ckd.o
@@ -27,21 +24,18 @@
 
 ifeq ($(CONFIG_DASD),m)
   M_OBJS += dasd_mod.o
-  D_OBJS += dasd.o dasd_ccwstuff.o dasd_erp.o dasd_setup.o
-  ifeq ($(CONFIG_PROC_FS),y)
-   D_OBJS += dasd_proc.o dasd_profile.o
-  endif 
+  D_OBJS += dasd.o 
   ifeq ($(CONFIG_DASD_ECKD),y)
-   D_OBJS += dasd_eckd.o dasd_eckd_erp.o dasd_3990_erp.o dasd_9343_erp.o
+   D_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   D_OBJS += dasd_fba.o
+   D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   D_OBJS += dasd_mdsk.o
+   D_OBJS += dasd_diag.o
   endif 
 #  ifeq ($(CONFIG_DASD_CKD),y)
-#   D_OBJS += dasd_ckd.o
+#   O_OBJS += dasd_ckd.o
 #  endif 
 endif
 
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd.c	Mon Dec  3 22:09:50 2001
@@ -3,11 +3,30 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes (starts July 2000)
+ * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels
+ * 07/05/00 Added some missing cases when shutting down a device
+ * 07/07/00 Fixed memory leak in ccw allocation
+            Adapted request function to make it work on 2.4
+ * 07/10/00 Added some code to the request function to dequeue requests
+            that cannot be handled due to errors
+ * 07/10/00 Moved linux/ccwcache.h to asm/
+ * 07/10/00 Fixed a bug when formatting a 'new' device       
+ * 07/10/00 Removed an annoying message from dasd_format 
+ * 07/11/00 Reanimated probeonly mode    
+ * 07/11/00 Reanimated autodetection mode
+ * 07/12/00 fixed a bug in module cleanup
+ * 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices
+ * 07/13/00 fixed error message when having no device
+ * 07/13/00 added code for dynamic device recognition
  */
 
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
 #include <linux/tqueue.h>
 #include <linux/timer.h>
 #include <linux/malloc.h>
@@ -15,1330 +34,1653 @@
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/ctype.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+#include <linux/blk.h>
+#include <asm/debug.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/devfs_fs_kernel.h>
+#endif /* LINUX_IS_24 */
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif				/* CONFIG_PROC_FS */
+
+#include <asm/atomic.h>
+#include <asm/delay.h>
 #include <asm/io.h>
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #include <asm/spinlock.h>
+#endif /* LINUX_IS_24 */
 #include <asm/semaphore.h>
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
-
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
 
-#include <linux/dasd.h>
-#include <linux/blk.h>
-
-#include "dasd_erp.h"
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
-
-#include "../../../arch/s390/kernel/debug.h"
-
-#define PRINTK_HEADER DASD_NAME":"
-
-#define DASD_SSCH_RETRIES 2
+#include "dasd.h"
+#ifdef CONFIG_DASD_ECKD
+#include "dasd_eckd.h"
+#endif				/*  CONFIG_DASD_ECKD */
+#ifdef CONFIG_DASD_FBA
+#include "dasd_fba.h" 
+#endif				/*  CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_MDSK
+#include "dasd_diag.h" 
+#endif				/*  CONFIG_DASD_MDSK */
 
-/* This macro is a little tricky, but makes the code more easy to read... */
-#define MATCH(info,ct,cm,dt,dm) ( \
-(( info -> sid_data.cu_type  ct ) && ( info -> sid_data.cu_model cm )) && \
-(( info -> sid_data.dev_type dt ) && ( info -> sid_data.dev_model dm )) )
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct block_device_operations dasd_device_operations;
+#endif /* VERSION_CODE */
 
 #ifdef MODULE
+#define EXPORT_SYMTAB
 #include <linux/module.h>
 
-char *dasd[DASD_MAX_DEVICES] =
-{NULL,};
-#ifdef CONFIG_DASD_MDSK
-char *dasd_force_mdsk[DASD_MAX_DEVICES] =
-{NULL,};
-#endif
-
-kdev_t ROOT_DEV;
-
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation");
-MODULE_PARM (dasd, "1-" __MODULE_STRING (DASD_MAX_DEVICES) "s");
-#ifdef CONFIG_DASD_MDSK
-MODULE_PARM (dasd_force_mdsk, "1-" __MODULE_STRING (DASD_MAX_DEVICES) "s");
-#endif
-#endif
+MODULE_SUPPORTED_DEVICE("dasd");
+MODULE_PARM (dasd, "1-" __MODULE_STRING (256)"s");
+EXPORT_SYMBOL (dasd_discipline_enq);
+EXPORT_SYMBOL (dasd_discipline_deq);
+EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_alloc_request);
+EXPORT_SYMBOL (dasd_free_request);
 
-/* Prototypes for the functions called from external */
-void dasd_partn_detect (int di);
-int devindex_from_devno (int devno);
-int dasd_is_accessible (int devno);
-void dasd_add_devno_to_ranges (int devno);
+#else
+#endif				/* MODULE */
 
-#ifdef CONFIG_DASD_MDSK
-extern int dasd_force_mdsk_flag[DASD_MAX_DEVICES];
-extern void do_dasd_mdsk_interrupt (struct pt_regs *regs, __u16 code);
-extern int dasd_parse_module_params (void);
-extern void (**ext_mdisk_int) (void);
+/* SECTION: Constant definitions to be used within this file */
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #endif
+#define PRINTK_HEADER DASD_NAME":"
 
-void dasd_debug (unsigned long tag);
-void dasd_profile_add (cqr_t *cqr);
-void dasd_proc_init (void);
-
-static int dasd_format (int dev, format_data_t * fdata);
-
-static struct file_operations dasd_device_operations;
-
-spinlock_t dasd_lock;		/* general purpose lock for the dasd driver */
-
-/* All asynchronous I/O should waint on this wait_queue */
-struct wait_queue *dasd_waitq = NULL;
-
-extern dasd_chanq_t *cq_head;
-extern int dasd_probeonly;
-
-debug_info_t *dasd_debug_info;
+#define DASD_QUEUE_LIMIT 10
+#define DASD_SSCH_RETRIES 5
+#define QUEUE_SECTORS 128
+
+/* SECTION: prototypes for static functions of dasd.c (try to eliminate!) */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static void do_dasd_request (request_queue_t *);
+#else
+static void do_dasd_request (void);
+#endif /* LINUX_IS_24 */
+static void dasd_do_chanq (void);
+static void schedule_request_fn (void (*func) (void));
+static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
+static int dasd_oper_handler ( int irq, devreg_t *devreg );
+
+/* SECTION: managing setup of dasd_driver */
+typedef struct dasd_range_t {
+	unsigned int from;
+	unsigned int to;
+	char discipline[4];
+        struct dasd_range_t *next;
+} __attribute__ ((packed)) dasd_range_t;
+
+typedef struct dasd_devreg_t {
+        devreg_t devreg;
+        struct dasd_devreg_t *next;
+} dasd_devreg_t;
+
+static int dasd_probeonly = 1;
+static int dasd_autodetect = 1;
+ 
+static dasd_range_t *dasd_range_head = NULL;
+static dasd_devreg_t *dasd_devreg_head = NULL;
+
+static dasd_devreg_t *
+dasd_create_devreg ( int devno ) {
+        dasd_devreg_t *r = kmalloc ( sizeof(dasd_devreg_t), GFP_KERNEL);
+        memset (r,0,sizeof(dasd_devreg_t));
+        if ( r != NULL ) {
+                r -> devreg.ci.devno = devno;
+                r -> devreg.flag = DEVREG_TYPE_DEVNO;
+                r -> devreg.oper_func = dasd_oper_handler;
+        }
+        return r;
+}
 
-extern dasd_information_t **dasd_information;
+static void
+dasd_add_range (int from, int to)
+{
+        dasd_range_t *temp,*range;
+        int i;
 
-dasd_information_t *dasd_info[DASD_MAX_DEVICES] =
-{NULL,};
-static struct hd_struct dd_hdstruct[DASD_MAX_DEVICES << PARTN_BITS];
-static int dasd_blks[256] =
-{0,};
-static int dasd_secsize[256] =
-{0,};
-static int dasd_blksize[256] =
-{0,};
-static int dasd_maxsecs[256] =
-{0,};
+        range = (dasd_range_t *)kmalloc(sizeof(dasd_range_t),GFP_KERNEL);
+        if ( range == NULL )
+                return;
+        memset(range,0,sizeof(dasd_range_t));
+        range -> from = from;
+        if (to == 0) { /* single devno ? */
+                range -> to = from;
+        }  else {
+                range -> to = to;
+        }
 
-void
-dasd_geninit (struct gendisk *dd)
-{
+        /* chain current range to end of list */
+        if ( dasd_range_head == NULL ) {
+                dasd_range_head = range;
+        } else {
+                for ( temp = dasd_range_head; 
+                      temp && temp->next; 
+                      temp = temp->next );
+                temp->next = range;
+        }
+        /* allocate and chain devreg infos for the devnos... */
+        for ( i = range->from; i <= range->to; i ++ ){
+                dasd_devreg_t *reg = dasd_create_devreg(i);
+                s390_device_register(&reg->devreg);
+                reg->next = dasd_devreg_head;
+                dasd_devreg_head = reg;
+        }
 }
 
-struct gendisk dd_gendisk =
+static int
+dasd_strtoul (char *str, char **stra)
 {
-	major:MAJOR_NR,		/* Major number */
-	major_name:"dasd",	/* Major name */
-	minor_shift:PARTN_BITS,	/* Bits to shift to get real from partn */
-	max_p:1 << PARTN_BITS,	/* Number of partitions per real */
-	max_nr:0,		/* number */
-	init:dasd_geninit,
-	part:dd_hdstruct,	/* hd struct */
-	sizes:dasd_blks,	/* sizes in blocks */
-	nr_real:0,
-	real_devices:NULL,	/* internal */
-	next:NULL		/* next */
-};
+	char *temp = str;
+	int val;
+	if (*temp == '0') {
+		temp++;		/* strip leading zero */
+		if (*temp == 'x')
+			temp++;	/* strip leading x */
+	}
+	val = simple_strtoul (temp, &temp, 16);		/* interpret anything as hex */
+	*stra = temp;
+	return val;
+}
 
-static atomic_t bh_scheduled = ATOMIC_INIT (0);
+char *dasd[256] = {NULL,}; /* maximum of 256 ranges supplied on parmline */
 
-void
-dasd_schedule_bh (void (*func) (void))
+#ifndef MODULE
+static void 
+dasd_split_parm_string ( char * str ) 
 {
-	static struct tq_struct dasd_tq =
-	{0,};
-	/* Protect against rescheduling, when already running */
-	if (atomic_compare_and_swap (0, 1, &bh_scheduled))
-		return;
-	dasd_tq.routine = (void *) (void *) func;
-	queue_task (&dasd_tq, &tq_immediate);
-	mark_bh (IMMEDIATE_BH);
-		return;
+        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 ++;
+                }
+                dasd[count] = kmalloc(len * sizeof(char),GFP_ATOMIC);
+                if ( dasd == NULL ) {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "No memory to store dasd= parameter no %d\n",count+1);
+                        break;
+                }
+                memset( dasd[count], 0, len * sizeof(char));
+                memcpy( dasd[count], tmp, len * sizeof(char));
+                count ++;
+                tmp = end;
+        } while ( tmp != NULL && *tmp != '\0' );
 	}
 
-void
-sleep_done (struct semaphore *sem)
+static char dasd_parm_string[1024] = {0,};
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static int
+dasd_setup (char *str) 
 {
-	if (sem != NULL) {
-		up (sem);
+        static int first_time = 1;
+        if ( ! first_time ) {
+                *(dasd_parm_string+strlen(dasd_parm_string))=',';
+        }  else {
+                first_time = 0;
 	}
+        memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
+        return 1;
 }
-
+#else
 void
-sleep (int timeout)
+dasd_setup (char *str, int *ints) 
 {
-	struct semaphore sem = MUTEX_LOCKED;
-	struct timer_list timer;
-
-	init_timer (&timer);
-	timer.data = (unsigned long) &sem;
-	timer.expires = jiffies + timeout;
-	timer.function = (void (*)(unsigned long)) sleep_done;
-	printk (KERN_DEBUG PRINTK_HEADER
-		"Sleeping for timer tics %d\n", timeout);
-	add_timer (&timer);
-	down (&sem);
-	del_timer (&timer);
+        static int first_time = 1;
+        if ( ! first_time ) {
+                *(dasd_parm_string+strlen(dasd_parm_string))=',';
+        }  else {
+                first_time = 0;
+        }
+        memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
 }
+#endif /* LINUX_IS_24 */
 
-#ifdef CONFIG_DASD_ECKD
-extern dasd_operations_t dasd_eckd_operations;
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-extern dasd_operations_t dasd_fba_operations;
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-extern dasd_operations_t dasd_mdsk_operations;
-#endif				/* CONFIG_DASD_MDSK */
 
-dasd_operations_t *dasd_disciplines[] =
-{
-#ifdef CONFIG_DASD_ECKD
-	&dasd_eckd_operations,
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-	&dasd_fba_operations,
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-	&dasd_mdsk_operations,
-#endif				/* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-	&dasd_ckd_operations,
-#endif				/* CONFIG_DASD_CKD */
-	NULL
-};
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+__setup("dasd=", dasd_setup);
+#endif /* LINUX_IS_24 */
 
-char *dasd_name[] =
-{
-#ifdef CONFIG_DASD_ECKD
-	"ECKD",
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-	"FBA",
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-	"MDSK",
-#endif				/* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-	"CKD",
-#endif				/* CONFIG_DASD_CKD */
-	"END"
-};
+#endif
 
-static int
-do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
+void
+dasd_parse (char **str) 
 {
-	int rc;
-	int di;
-	dasd_information_t *dev;
+	char *temp;
+	int from, to;
 
-	di = DEVICE_NR (inp->i_rdev);
-	if (!dasd_info[di]) {
-		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
-		return -EINVAL;
-	}
-	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
-		PRINT_DEBUG ("empty data ptr");
-		return -EINVAL;
-	}
-	dev = dasd_info[di];
-	if (!dev) {
-		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
-		return -EINVAL;
+      	if ( *str ) { 
+        dasd_probeonly = 0;
 	}
-	PRINT_INFO ("ioctl 0x%08x %s'0x%x'%d(%d) on dev %d/%d (%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),
-		    MAJOR (inp->i_rdev), MINOR (inp->i_rdev), di, data);
-
-	switch (no) {
-	case BLKGETSIZE:{	/* Return device size */
-			int blocks = dasd_blks[MINOR (inp->i_rdev)] << 1;
-			rc = copy_to_user ((long *) data,
-					   &blocks,
-					   sizeof (long));
+        while (*str) {
+                temp = *str;
+		from = 0;
+		to = 0;
+                if ( strncmp ( *str,"autodetect",strlen("autodetect"))== 0) {
+                        dasd_autodetect = 1;
+                        printk (KERN_INFO "turning to autodetection mode\n");
+                        break;
+                } else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) {
+                        dasd_probeonly = 1;
+                        printk (KERN_INFO "turning to probeonly mode\n");
 			break;
+                } else {
+                        dasd_autodetect = 0;
+                        from = dasd_strtoul (temp, &temp);          
+                        if (*temp == '-') {
+                                temp++;
+                                to = dasd_strtoul (temp, &temp);
 		}
-	case BLKFLSBUF:{
-			rc = fsync_dev (inp->i_rdev);
-			break;
+                        dasd_add_range (from, to);
 		}
-	case BLKRAGET:{
-			rc = copy_to_user ((long *) data,
-					read_ahead + MAJOR_NR, sizeof (long));
-			break;
+                str ++;
 		}
-	case BLKRASET:{
-			rc = copy_from_user (read_ahead + MAJOR_NR,
-					     (long *) data, sizeof (long));
-			break;
 		}
-	case BLKRRPART:{
-			dasd_partn_detect (di);
-			rc = 0;
+
+int
+devindex_from_devno (int devno)
+{
+	int devindex = 0;
+        dasd_range_t *temp;
+        for ( temp = dasd_range_head; temp; temp = temp->next ) {
+		if (devno < temp -> from || devno > temp -> to) {
+			devindex += temp -> to - temp -> from + 1;
+		} else {
+			devindex += devno - temp -> from;
 			break;
 		}
-	case BIODASDRLB:{
-			rc = copy_to_user ((int *) data,
-					   &dasd_info[di]->sizes.label_block,
-					   sizeof (int));
-			break;
 		}
-	case BLKGETBSZ:{
-			rc = copy_to_user ((int *) data,
-					   &dasd_info[di]->sizes.bp_block,
-					   sizeof (int));
-			break;
+        if ( temp == NULL ) 
+                return -ENODEV;
+	return devindex;
 		}
-	case HDIO_GETGEO:{
-			struct hd_geometry geo;
-			dasd_disciplines[dev->type]->fill_geometry (di, &geo);
-			rc = copy_to_user ((struct hd_geometry *) data, &geo,
-					   sizeof (struct hd_geometry));
-			break;
+
+/* SECTION: ALl needed for multiple major numbers */
+
+static major_info_t dasd_major_info[] =
+{
+	{
+		next:NULL /* &dasd_major_info[1] */ ,
+		request_fn:do_dasd_request,
+		read_ahead:8,
+		gendisk:
+		{
+			major:94,
+			major_name:DASD_NAME,
+			minor_shift:DASD_PARTN_BITS,
+			max_p:1 << DASD_PARTN_BITS,
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+			max_nr:DASD_PER_MAJOR,
+#endif /* LINUX_IS_24 */
+			nr_real:DASD_PER_MAJOR,
 		}
-		RO_IOCTLS (inp->i_rdev, data);
-	case BIODASDRSID:{
-			rc = copy_to_user ((void *) data,
-					   &(dev->info.sid_data),
-					   sizeof (senseid_t));
-			break;
 		}
-	case BIODASDRWTB:{
-			int offset = 0;
-			int xlt;
-			rc = copy_from_user (&xlt, (void *) data,
-					     sizeof (int));
-#if 0
-                        PRINT_INFO("Xlating %d to",xlt);
-#endif
-			if (rc)
-				break;
-			offset = dd_gendisk.part[MINOR (inp->i_rdev)].start_sect >>
-			    dev->sizes.s2b_shift;
-			xlt += offset;
 #if 0
-                        printk(" %d \n",xlt);
-#endif
-			rc = copy_to_user ((void *) data, &xlt,
-					   sizeof (int));
-			break;
-		}
-	case BIODASDFORMAT:{
-			/* fdata == NULL is a valid arg to dasd_format ! */
-			format_data_t *fdata = NULL;
-			PRINT_WARN ("called format ioctl\n");
-			if (data) {
-				fdata = kmalloc (sizeof (format_data_t),
-						 GFP_ATOMIC);
-				if (!fdata) {
-					rc = -ENOMEM;
-					break;
-				}
-				rc = copy_from_user (fdata, (void *) data,
-						     sizeof (format_data_t));
-				if (rc)
-					break;
-			}
-			rc = dasd_format (inp->i_rdev, fdata);
-			if (fdata) {
-				kfree (fdata);
+        ,
+	{
+		next:NULL,
+		request_fn:do_dasd_request,
+		read_ahead:8,
+		gendisk:
+		{
+			major:95,
+			major_name:DASD_NAME,
+			minor_shift:DASD_PARTN_BITS,
+			max_p:1 << DASD_PARTN_BITS,
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+			max_nr:DASD_PER_MAJOR,
+#endif /* LINUX_IS_24 */
+			nr_real:DASD_PER_MAJOR,
 			}
-			break;
 		}
-	default:
-		PRINT_WARN ("unknown ioctl number %08x %08lx\n", no, BIODASDFORMAT);
-		rc = -EINVAL;
-		break;
+#endif
+};
+
+static dasd_device_t *
+find_dasd_device (int devindex)
+{
+	major_info_t *major_info = dasd_major_info;
+	while (major_info && devindex > DASD_PER_MAJOR) {
+		devindex -= DASD_PER_MAJOR;
+		major_info = major_info->next;
 	}
-	return rc;
+	if (!major_info)
+                return NULL;
+	return major_info->dasd_device[devindex];
 }
 
-static void
-dasd_end_request (struct request *req, int uptodate)
+static major_info_t *
+major_info_from_devindex (int devindex)
 {
-	struct buffer_head *bh;
-	FUNCTION_ENTRY ("dasd_end_request");
-#if DASD_PARANOIA > 2
-	if (!req) {
-		INTERNAL_CHECK ("end_request called with zero arg%s\n", "");
-	}
-#endif				/* DASD_PARANOIA */
-	while ((bh = req->bh) != NULL) {
-		req->bh = bh->b_reqnext;
-		bh->b_reqnext = NULL;
-		bh->b_end_io (bh, uptodate);
+	major_info_t *major_info = dasd_major_info;
+	while (major_info && devindex > DASD_PER_MAJOR) {
+		devindex -= DASD_PER_MAJOR;
+		major_info = major_info->next;
 	}
-	if (!end_that_request_first (req, uptodate, DEVICE_NAME)) {
-#ifndef DEVICE_NO_RANDOM
-		add_blkdev_randomness (MAJOR (req->rq_dev));
-#endif
-		DEVICE_OFF (req->rq_dev);
-		end_that_request_last (req);
+	return major_info;
 	}
-	FUNCTION_EXIT ("dasd_end_request");
-	return;
+
+int
+major_from_devindex (int devindex)
+{
+	major_info_t *major_info = major_info_from_devindex (devindex);
+	return major_info->gendisk.major;
 }
 
-void
-dasd_wakeup (void)
+static int
+devindex_from_kdev_t (kdev_t dev)
 {
-	wake_up (&dasd_waitq);
+	int devindex = 0;
+	major_info_t *major_info = dasd_major_info;
+	while (major_info &&
+	       MAJOR (dev) != major_info->gendisk.major) {
+		devindex += (1 << (MINORBITS - DASD_PARTN_BITS));
+		major_info = major_info->next;
+	}
+	if (!major_info)
+		devindex = -ENODEV;
+        devindex += MINOR(dev) >> DASD_PARTN_BITS;
+	return devindex;
 }
 
+/* SECTION: managing dasd disciplines */
 
-int
-dasd_watch_volume (int di)
-{
-        int rc = 0;
+static dasd_discipline_t *dasd_disciplines = NULL;
+static spinlock_t discipline_lock;
 
-        return rc;
-}
+/* 
+ * void dasd_discipline_enq (dasd_discipline_t * d)
+ */
 
 void 
-dasd_watcher (void) 
+dasd_discipline_enq (dasd_discipline_t * d)
 {
-        int i = 0;
-        int rc; 
-        do {
-                for ( i = 0; i < DASD_MAX_DEVICES; i++ ) {
-                        if ( dasd_info [i] ) {
-                                rc = dasd_watch_volume ( i );
-                        }
-                }
-                interruptible_sleep_on(&dasd_waitq);
-        } while(1);
+	spin_lock (&discipline_lock);
+	d->next = dasd_disciplines;
+	dasd_disciplines = d;
+	spin_unlock (&discipline_lock);
 }
 
+/* 
+ * int dasd_discipline_deq (dasd_discipline_t * d)
+ */
+
 int
-dasd_unregister_dasd (int di)
+dasd_discipline_deq (dasd_discipline_t * d)
 {
 	int rc = 0;
-	int minor;
-	int i;
-
-	minor = di << PARTN_BITS;
-	if (!dasd_info[di]) {	/* devindex is not free */
-		INTERNAL_CHECK ("trying to free unallocated device %d\n", di);
-		return -ENODEV;
+	spin_lock (&discipline_lock);
+	if (dasd_disciplines == d) {
+		dasd_disciplines = dasd_disciplines->next;
+	} else {
+		dasd_discipline_t *b;
+		b = dasd_disciplines;
+		while (b && b->next != d)
+			b = b->next;
+		if (b != NULL) {
+			b->next = b->next->next;
+		} else {
+			rc = -ENOENT;
+		}
 	}
-	/* delete all that partition stuff */
-	for (i = 0; i < (1 << PARTN_BITS); i++) {
-		dasd_blks[minor] = 0;
-		dasd_secsize[minor + i] = 0;
-		dasd_blksize[minor + i] = 0;
-		dasd_maxsecs[minor + i] = 0;
-	}
-	/* reset DASD to unknown statuss */
-	atomic_set (&dasd_info[di]->status, DASD_INFO_STATUS_UNKNOWN);
-
-	free_irq (dasd_info[di]->info.irq, &(dasd_info[di]->dev_status));
-	if (dasd_info[di]->rdc_data)
-		kfree (dasd_info[di]->rdc_data);
-	kfree (dasd_info[di]);
-	PRINT_INFO ("%04d deleted from list of valid DASDs\n",
-		    dasd_info[di]->info.devno);
+	spin_unlock (&discipline_lock);
 	return rc;
 }
 
-/* Below you find the functions already cleaned up */
-static dasd_type_t
-check_type (dev_info_t * info)
-{
-	dasd_type_t type = dasd_none;
-	int di;
+/* SECTION: (de)queueing of requests to channel program queues */
 
-	FUNCTION_ENTRY ("check_type");
-	di = devindex_from_devno (info->devno);
+/* 
+ * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
 
-#ifdef CONFIG_DASD_MDSK
-	if (MACHINE_IS_VM && dasd_force_mdsk_flag[di] == 1) {
-		type = dasd_mdsk;
+static void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+	if (q->head != NULL) {
+		q->tail->next = cqr;
 	} else
-#endif				/* CONFIG_DASD_MDSK */
+		q->head = cqr;
+	cqr->next = NULL;
+	q->tail = cqr;
+	q->queued_requests++;
+	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+}
 
-#ifdef CONFIG_DASD_ECKD
-	if (MATCH (info, == 0x3990, ||1, == 0x3390, ||1) ||
-	    MATCH (info, == 0x9343, ||1, == 0x9345, ||1) ||
-	    MATCH (info, == 0x3990, ||1, == 0x3380, ||1)) {
-		type = dasd_eckd;
-	} else
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-	if (MATCH (info, == 0x6310, ||1, == 0x9336, ||1)) {
-		type = dasd_fba;
-	} else
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-	if (MACHINE_IS_VM) {
-		type = dasd_mdsk;
-	} else
-#endif				/* CONFIG_DASD_MDSK */
+/* 
+ * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
+
+static void
+dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
 	{
-		type = dasd_none;
+	cqr->next = q->head;
+	q->head = cqr;
+	if (q->tail == NULL)
+		q->tail = cqr;
+	q->queued_requests++;
+	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
 	}
 
-	FUNCTION_EXIT ("check_type");
-	return type;
-}
+/* 
+ * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
 
 static int
-dasd_read_characteristics (dasd_information_t * info)
+dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
-	int rc = 0;
-	int ct = 0;
-	dev_info_t *di;
-	dasd_type_t dt;
+	ccw_req_t *prev;
 
-	FUNCTION_ENTRY ("read_characteristics");
-	if (info == NULL) {
-		return -ENODEV;
-	}
-	di = &(info->info);
-	if (di == NULL) {
-		return -ENODEV;
-	}
-	dt = check_type (di);
-	/* Some cross-checks, if the cu supports RDC */
-	if (MATCH (di, == 0x2835, ||1, ||1, ||1) ||
-	    MATCH (di, == 0x3830, ||1, ||1, ||1) ||
-	    MATCH (di, == 0x3830, ||1, ||1, ||1) ||
-	    MATCH (di, == 0x3990, <=0x03, == 0x3380, <=0x0d)) {
-		PRINT_WARN ("Device %d (%x/%x at %x/%x) supports no RDC\n",
-			    info->info.irq,
-			    di->sid_data.dev_type,
-			    di->sid_data.dev_model,
-			    di->sid_data.cu_type,
-			    di->sid_data.cu_model);
-		return -EINVAL;
+	if (cqr == NULL)
+		return -ENOENT;
+	if (cqr == (ccw_req_t *) q->head) {
+		q->head = cqr->next;
+		if (q->head == NULL)
+			q->tail = NULL;
+	} else {
+		prev = (ccw_req_t *) q->head;
+		while (prev && prev->next != cqr)
+			prev = prev->next;
+		if (prev == NULL)
+			return -ENOENT;
+		prev->next = cqr->next;
+		if (prev->next == NULL)
+			q->tail = prev;
+	}
+	cqr->next = NULL;
+	q->queued_requests--;
+	return 0;
+}
+
+/* SECTION: Handling of the queue of queues */
+
+#ifdef CONFIG_SMP
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static spinlock_t cq_lock;		/* spinlock for cq_head */
+#else
+static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED;		/* spinlock for cq_head */
+#endif /* LINUX_IS_24 */
+#endif				/* __SMP__ */
+static dasd_chanq_t *qlist_head = NULL;		/* head of queue of queues */
+
+/* 
+ * void qlist_enq (dasd_chanq_t * q)
+ * queues argument to head of the queue of queues
+ * and marks queue to be active
+ */
+
+static void
+qlist_enq (dasd_chanq_t * q)
+{
+	if (q == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n");
+		return;
 	}
-	switch (dt) {
-#ifdef CONFIG_DASD_ECKD
-	case dasd_eckd:
-		ct = 64;
-		rc = read_dev_chars (info->info.irq,
-				     (void *) &(info->rdc_data), ct);
-		break;
-#endif				/*  CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-	case dasd_fba:
-		ct = 32;
-		rc = read_dev_chars (info->info.irq,
-				     (void *) &(info->rdc_data), ct);
-		break;
-#endif				/*  CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-	case dasd_mdsk:
-		ct = 0;
-		break;
-#endif				/*  CONFIG_DASD_FBA */
-	default:
-		INTERNAL_ERROR ("don't know dasd type %d\n", dt);
-	}
-	if (rc) {
-		PRINT_WARN ("RDC resulted in rc=%d\n", rc);
-	}
-	FUNCTION_EXIT ("read_characteristics");
-	return rc;
+	spin_lock (&cq_lock);
+	if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) {
+		printk (KERN_WARNING PRINTK_HEADER " Queue already active");
+	}
+	atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags);
+	q->next_q = qlist_head;
+	qlist_head = q;
+	spin_unlock (&cq_lock);
 }
 
-/* How many sectors must be in a request to dequeue it ? */
-#define QUEUE_BLOCKS 25
-#define QUEUE_SECTORS (QUEUE_BLOCKS << dasd_info[di]->sizes.s2b_shift)
-
-/* How often to retry an I/O before raising an error */
-#define DASD_MAX_RETRIES 5
-
-static inline
- cqr_t *
-dasd_cqr_from_req (struct request *req)
-{
-	cqr_t *cqr = NULL;
-	int di;
-	dasd_information_t *info;
-
-	if (!req) {
-		PRINT_ERR ("No request passed!");
-		return NULL;
-	}
-	di = DEVICE_NR (req->rq_dev);
-	info = dasd_info[di];
-	if (!info)
-		return NULL;
-	/* if applicable relocate block */
-	if (MINOR (req->rq_dev) & ((1 << PARTN_BITS) - 1)) {
-		req->sector +=
-		    dd_gendisk.part[MINOR (req->rq_dev)].start_sect;
-	}
-	/* Now check for consistency */
-	if (!req->nr_sectors) {
-		PRINT_WARN ("req: %p dev: %08x sector: %ld nr_sectors: %ld bh: %p\n",
-		     req, req->rq_dev, req->sector, req->nr_sectors, req->bh);
-		return NULL;
-	}
-	if (((req->sector + req->nr_sectors) >> 1) > info->sizes.kbytes) {
-		printk (KERN_ERR PRINTK_HEADER
-			"Requesting I/O past end of device %d\n",
-			di);
-		return NULL;
-	}
-	cqr = dasd_disciplines[info->type]->get_req_ccw (di, req);
-	if (!cqr) {
-		PRINT_WARN ("empty CQR generated\n");
-	} else {
-		cqr->req = req;
-		cqr->int4cqr = cqr;
-		cqr->devindex = di;
-#ifdef DASD_PROFILE
-		asm volatile ("STCK %0":"=m" (cqr->buildclk));
-#endif				/* DASD_PROFILE */
-		ACS (cqr->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+/* 
+ * void qlist_deq (dasd_chanq_t * q)
+ * dequeues argument from the queue of queues
+ * and marks queue to be inactive
+ */
+
+static void
+qlist_deq (dasd_chanq_t * q)
+{
+
+	if (qlist_head == NULL) {
+		printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", "");
+		return;
 	}
-	return cqr;
+	if (q == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n");
+		return;
+	}
+	spin_lock (&cq_lock);
+	if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
+		printk (KERN_WARNING PRINTK_HEADER " Queue not active\n");
+	} else if (qlist_head == q) {
+		qlist_head = q->next_q;
+	} else {
+		dasd_chanq_t *c = qlist_head;
+		while (c->next_q && c->next_q != q)
+			c = c->next_q;
+		if (c->next_q == NULL)
+			printk (KERN_WARNING PRINTK_HEADER " Queue %p not in queue of queues\n", q);
+		else
+			c->next_q = q->next_q;
+	}
+	atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags);
+	q->next_q = NULL;
+	spin_unlock (&cq_lock);
 }
 
-int
-dasd_start_IO (cqr_t * cqr)
+/* SECTION: All the gendisk stuff */
+
+
+static int
+dasd_partn_detect (int devindex)
 {
 	int rc = 0;
-	int retries = DASD_SSCH_RETRIES;
-	int di, irq;
-
-	dasd_debug ((unsigned long) cqr);	/* cqr */
 
-	if (!cqr) {
-		PRINT_WARN ("(start_IO) no cqr passed\n");
-		return -EINVAL;
-	}
-#ifdef CONFIG_DASD_MDSK
-	if (cqr->magic == MDSK_MAGIC) {
-		return dasd_mdsk_start_IO (cqr);
-	}
-#endif				/* CONFIG_DASD_MDSK */
-	if (cqr->magic != DASD_MAGIC && cqr->magic != ERP_MAGIC) {
-		PRINT_ERR ("(start_IO) magic number mismatch\n");
-		return -EINVAL;
+	major_info_t *major_info = major_info_from_devindex (devindex);
+	struct gendisk *dd = &major_info->gendisk;
+	int minor = ( devindex & 
+                      (( 1 << (MINORBITS-DASD_PARTN_BITS) ) - 1)) << dd->minor_shift;
+	struct dasd_device_t *device = find_dasd_device (devindex);
+        
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        register_disk(dd,
+                      MKDEV (dd->major, minor),
+                      1 << DASD_PARTN_BITS,
+                      &dasd_device_operations,
+                      (device->sizes.blocks << device->sizes.s2b_shift));
+#else
+        dd->sizes[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
+        resetup_one_dev(dd,minor>>DASD_PARTN_BITS);
+#endif /* LINUX_IS_24 */
+	return rc;
 	}
-	ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-        di = cqr->devindex;
-	irq = dasd_info[di]->info.irq;
-	do {
-		asm volatile ("STCK %0":"=m" (cqr->startclk));
-		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
-		switch (rc) {
-		case 0:
-			if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT))
-                        	atomic_set_mask (DASD_CHANQ_BUSY,
-                                	         &dasd_info[di]->queue.flags);
-			break;
-		case -ENODEV:
-			PRINT_WARN ("cqr %p: 0x%04x error, %d retries left\n",
-				    cqr, dasd_info[di]->info.devno, retries);
-			break;
-		case -EIO:
-			PRINT_WARN ("cqr %p: 0x%04x I/O, %d retries left\n",
-				    cqr, dasd_info[di]->info.devno, retries);
-			break;
-		case -EBUSY:	/* set up timer, try later */
 
-			PRINT_WARN ("cqr %p: 0x%04x busy, %d retries left\n",
-				    cqr, dasd_info[di]->info.devno, retries);
-			break;
-		default:
+/* SECTION: Managing wrappers for ccwcache */
 
-			PRINT_WARN ("cqr %p: 0x%04x %d, %d retries left\n",
-				    cqr, rc, dasd_info[di]->info.devno,
-                                    retries);
-			break;
+#define DASD_EMERGENCY_REQUESTS 16
+
+static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS]={NULL,};
+static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+
+static void
+dasd_init_emergency_req ( void ) 
+{
+        int i;
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+          dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL);
 		}
-	} while (rc && --retries);
-	if (rc) {
-		ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
         }
-	return rc;
+
+static void
+dasd_cleanup_emergency_req ( void ) 
+{
+        int i;
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+                if (dasd_emergency_req[i])
+                        free_page((long)(dasd_emergency_req[i]));
+                else
+                        printk (KERN_WARNING PRINTK_HEADER "losing one page for 'in-use' emergency request\n");
+        }
 }
 
-static inline
-void
-dasd_end_cqr (cqr_t * cqr, int uptodate)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize)
 {
-	struct request *req = cqr->req;
-	asm volatile ("STCK %0":"=m" (cqr->endclk));
-#ifdef DASD_PROFILE
-	dasd_profile_add (cqr);
-#endif				/* DASD_PROFILE */
-	dasd_chanq_deq (&dasd_info[cqr->devindex]->queue, cqr);
-        if (req) {
-                dasd_end_request (req, uptodate);
+        ccw_req_t *rv = NULL;
+        int i;
+        if ( ( rv = ccw_alloc_request(magic,cplength,datasize )) != NULL ) {
+                return rv;
+        }
+        if ( cplength * sizeof(ccw1_t) + datasize + sizeof(ccw_req_t) > PAGE_SIZE ) {
+                return NULL;
+        }
+        spin_lock(&dasd_emergency_req_lock);
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+                if ( dasd_emergency_req[i] != NULL ) {
+                        rv = dasd_emergency_req[i];
+                        dasd_emergency_req[i] = NULL;
+                }
         }
+        spin_unlock(&dasd_emergency_req_lock);
+        if ( rv ) {
+                memset (rv,0, PAGE_SIZE);
+                rv -> cache = (kmem_cache_t *)(dasd_emergency_req + i);
+                strncpy ( (char *)(&rv->magic), magic, 4);
+                ASCEBC((char *)(&rv->magic),4);
+                rv -> cplength = cplength;
+                rv -> datasize = datasize;
+                rv -> data = (void *)((long)rv + PAGE_SIZE - datasize);
+                rv -> cpaddr = (ccw1_t *)((long)rv +  sizeof(ccw_req_t));
+        }
+        return rv;
 }
 
 void
-dasd_dump_sense (devstat_t * stat)
+dasd_free_request (ccw_req_t * request)
 {
-	int sl, sct;
-	if (!stat->flag | DEVSTAT_FLAG_SENSE_AVAIL) {
-		PRINT_INFO ("I/O status w/o sense data\n");
+        if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req &&
+             request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) {
+                *((ccw_req_t **)(request -> cache)) = request;
 	} else {
-	printk (KERN_INFO PRINTK_HEADER
-			"-------------------I/O result:-----------\n");
-	for (sl = 0; sl < 4; sl++) {
-		printk (KERN_INFO PRINTK_HEADER "Sense:");
-		for (sct = 0; sct < 8; sct++) {
-			printk (" %2d:0x%02X", 8 * sl + sct,
-				stat->ii.sense.data[8 * sl + sct]);
-		}
-		printk ("\n");
+                ccw_free_request(request);
 	}
 }
+
+/* SECTION: Managing the device queues etc. */
+
+static atomic_t bh_scheduled = ATOMIC_INIT (0);
+static atomic_t request_fn_scheduled = ATOMIC_INIT (0);
+
+static void
+run_bh (void)
+{
+	atomic_set (&bh_scheduled, 0);
+	dasd_do_chanq ();
 }
 
-int
-register_dasd_last (int di)
+void
+dasd_schedule_bh ( void )
 {
-	int rc = 0;
-	int minor;
-	int i;
+	static struct tq_struct bh_tq =
+	{0,};
+	/* Protect against rescheduling, when already running */
+	if (atomic_compare_and_swap (0, 1, &bh_scheduled))
+		return;
+	bh_tq.routine = (void *) (void *) run_bh;
+	queue_task (&bh_tq, &tq_immediate);
+	mark_bh (IMMEDIATE_BH);
+	return;
+}
 
-	rc = dasd_disciplines[dasd_info[di]->type]->fill_sizes_last (di);
-	if (!rc) {
-		ACS (dasd_info[di]->status,
-		     DASD_INFO_STATUS_DETECTED, DASD_INFO_STATUS_FORMATTED);
-	} else {		/* -EMEDIUMTYPE: */
-		ACS (dasd_info[di]->status,
-		     DASD_INFO_STATUS_DETECTED, DASD_INFO_STATUS_ANALYSED);
-	}
-	PRINT_INFO ("%04X (dasd%c):%ld kB <- block: %d on sector %d B\n",
-		    dasd_info[di]->info.devno,
-		    'a' + di,
-		    dasd_info[di]->sizes.kbytes,
-		    dasd_info[di]->sizes.bp_block,
-		    dasd_info[di]->sizes.bp_sector);
-	minor = di << PARTN_BITS;
-	dasd_blks[minor] = dasd_info[di]->sizes.kbytes;
-	for (i = 0; i < (1 << PARTN_BITS); i++) {
-		dasd_secsize[minor + i] = dasd_info[di]->sizes.bp_sector;
-		dasd_blksize[minor + i] = dasd_info[di]->sizes.bp_block;
-		dasd_maxsecs[minor + i] = 252 << dasd_info[di]->sizes.s2b_shift;
+static void
+try_request_fn (void)
+{
+        long flags;
+        spin_lock_irqsave (&io_request_lock,flags);
+	atomic_set (&request_fn_scheduled, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        {
+          major_info_t *mi;
+          for (mi=dasd_major_info; mi != NULL; mi = mi->next ) {
+            do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major));
 	}
-	return rc;
+        }
+#else
+        do_dasd_request ();
+#endif /* LINUX_IS_24 */
+        spin_unlock_irqrestore (&io_request_lock,flags);
 }
 
-void
-dasd_partn_detect (int di)
+static void
+schedule_request_fn (void (*func) (void))
 {
-        int minor = di << PARTN_BITS;
-	while (atomic_read (&dasd_info[di]->status) !=
-	       DASD_INFO_STATUS_FORMATTED) {
-                interruptible_sleep_on(&dasd_info[di]->wait_q);
+	static struct tq_struct req_tq =
+	{0,};
+	/* Protect against rescheduling, when already running */
+	if (func != try_request_fn) {
+		panic (PRINTK_HEADER "Programming error! must call schedule_request_fn (try_request_fn)\n");
 	}
-	dd_gendisk.part[minor].nr_sects = dasd_info[di]->sizes.kbytes << 1;
-	resetup_one_dev (&dd_gendisk, di);
+	if (atomic_compare_and_swap (0, 1, &request_fn_scheduled))
+		return;
+	req_tq.routine = (void *) (void *) func;
+	queue_task (&req_tq, &tq_immediate);
+	mark_bh (IMMEDIATE_BH);
+	return;
 }
 
-void
-dasd_do_chanq (void)
+int
+dasd_start_IO (ccw_req_t * cqr)
 {
-	dasd_chanq_t *qp = NULL;
-	cqr_t *cqr, *next;
-        long flags;
-        int irq;
-        int tasks;
+	int rc = 0;
+	int retries = DASD_SSCH_RETRIES;
+	dasd_device_t *device = cqr->device;
+	int irq, devno;
+	int devindex, partn;
+	major_info_t *major_info;
+	struct request *req;
 
-	atomic_set (&bh_scheduled, 0);
-	dasd_debug (0xc4c40000);	/* DD */
-	for (qp = cq_head; qp != NULL;) {
-/* Get first request */
-		dasd_debug ((unsigned long) qp);
-		cqr = (cqr_t *) (qp->head);
-/* empty queue -> dequeue and proceed */
 		if (!cqr) {
-			dasd_chanq_t *nqp = qp->next_q;
-			cql_deq (qp);
-			qp = nqp;
-			continue;
+		printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
+		return -EINVAL;
 		}
-/* process all requests on that queue */
+	irq = device->devinfo.irq;
+	devno = device->devinfo.devno;
+	req = (struct request *) cqr->req;
+	devindex = devindex_from_kdev_t (req->rq_dev);
+	major_info = major_info_from_devindex (devindex);
+	partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"0x%04X on sch %d = /dev/%s (%d:%d)"
+			" magic number of ccw_req_t 0x%08lX doesn't match"
+			" discipline 0x%08lX\n",
+			devno, irq, device->name,
+			major_from_devindex (devindex),
+			devindex << DASD_PARTN_BITS,
+			cqr->magic, *(long *) device->discipline->name);
+		return -EINVAL;
+	}
+	atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
 		do {
-                        next = NULL;
-			dasd_debug ((unsigned long) cqr);	/* cqr */
-			if (cqr->magic != DASD_MAGIC &&
-			    cqr->magic != MDSK_MAGIC &&
-			    cqr->magic != ERP_MAGIC) {
-				dasd_debug (0xc4c46ff2);	/* DD?2 */
-				panic ( PRINTK_HEADER "do_cq:"
-					"magic mismatch %p -> %x\n", 
-					cqr, cqr -> magic);
-                                break;
+		asm volatile ("STCK %0":"=m" (cqr->startclk));
+		rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+		switch (rc) {
+		case 0:
+                        if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
+				atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags);
 			}
-                        irq = dasd_info[cqr->devindex]->info.irq;
-                        s390irq_spin_lock_irqsave (irq, flags);
-			switch (atomic_read (&cqr->status)) {
-			case CQR_STATUS_IN_IO:
-                                dasd_debug (0xc4c4c9d6);	/* DDIO */
-                                break;
-			case CQR_STATUS_QUEUED:
-                                dasd_debug (0xc4c4e2e3);	/* DDST */
-				if (dasd_start_IO (cqr) != 0) {
-                                  PRINT_WARN("start_io failed\n");
+                        if ( cqr->expires ) {
+                                cqr->expires += cqr->startclk;
                                 }
                                 break;
-			case CQR_STATUS_ERROR:{
-                                dasd_debug (0xc4c4c5d9);	/* DDER */
-                                if ( ++ cqr->retries  < 2 ) {
-                                        atomic_set (&cqr->status,
-                                                    CQR_STATUS_QUEUED);
-                                        dasd_debug (0xc4c4e2e3);
-                                        if (dasd_start_IO (cqr) == 0) {
-                                                atomic_dec (&qp->
-                                                            dirty_requests);
-                                                break;
-                                        }
-                                }
-                                ACS (cqr->status,
-                                     CQR_STATUS_ERROR,
-                                     CQR_STATUS_FAILED);
+		case -ENODEV:
+			printk (KERN_WARNING PRINTK_HEADER
+			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+				" appears not to be present %d retries left\n",
+				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+				retries);
                                 break;
-                        }
-			case CQR_STATUS_ERP_PEND:{
-					/* This case is entered, when an interrupt
-					   ended with a condittion */
-					dasd_erp_action_t erp_action;
-					erp_t *erp = NULL;
-
-                                        if ( cqr -> magic != ERP_MAGIC ) {
-                                                erp = request_er ();
-                                                if (erp == NULL) {
-                                                        PRINT_WARN ("No memory for ERP%s\n", "");
-                                                        break;
-                                                }
-                                                memset (erp, 0, sizeof (erp_t));
-                                                erp->cqr.magic = ERP_MAGIC;
-                                                erp->cqr.int4cqr = cqr;
-                                                erp->cqr.devindex= cqr->devindex;
-                                                erp_action = dasd_erp_action (cqr);
-                                                if (erp_action) {
-                                                        PRINT_WARN ("Taking ERP action %p\n", erp_action);
-                                                        erp_action (erp);
-                                                }
-                                                dasd_chanq_enq_head(qp, (cqr_t *) erp);
-                                                next = (cqr_t *) erp;
-                                } else {
-                                                PRINT_WARN("ERP_ACTION failed\n");
-                                                ACS (cqr->status,
-                                                     CQR_STATUS_ERP_PEND,
-                                                    CQR_STATUS_FAILED);
-                                }
+		case -EIO:
+			printk (KERN_WARNING PRINTK_HEADER
+			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+				" I/O error %d retries left\n",
+				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+				retries);
                                 break;
-                        }
-			case CQR_STATUS_ERP_ACTIVE:
+		case -EBUSY:	/* set up timer, try later */
+			printk (KERN_WARNING PRINTK_HEADER
+			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+				" is busy %d retries left\n",
+				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+				retries);
 				break;
-			case CQR_STATUS_DONE:{
-                                next = cqr->next;
-                                if (cqr->magic == DASD_MAGIC) {
-                                        dasd_debug (0xc4c49692);
-                                } else if (cqr->magic == ERP_MAGIC) {
-                                        dasd_erp_action_t erp_postaction;
-                                        erp_t *erp = (erp_t *) cqr;
-                                        erp_postaction =
-                                                dasd_erp_postaction (erp);
-                                        if (erp_postaction)
-                                                erp_postaction (erp);
-                                        atomic_dec (&qp->dirty_requests);
-                                } else if (cqr->magic == MDSK_MAGIC) {
-                                } else {
-                                        PRINT_WARN ("unknown magic%s\n", "");
-                                }
-                                dasd_end_cqr (cqr, 1);
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+			    " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+				" unknown return code %d, %d retries left."
+			  " Pls report this message to linux390@de.ibm.com\n",
+				devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+				rc, retries);
                                 break;
                         }
-			case CQR_STATUS_FAILED: {
-                                next = cqr->next;
-                                if (cqr->magic == DASD_MAGIC) {
-                                        dasd_debug (0xc4c49692);
-                                } else if (cqr->magic == ERP_MAGIC) {
-                                        dasd_erp_action_t erp_postaction;
-                                        erp_t *erp = (erp_t *) cqr;
-                                        erp_postaction =
-                                                dasd_erp_postaction (erp);
-                                        if (erp_postaction)
-                                                erp_postaction (erp);
-                                } else if (cqr->magic == MDSK_MAGIC) {
-                                } else {
-                                        PRINT_WARN ("unknown magic%s\n", "");
+	} while (rc && retries--);
+	if (rc) {
+                atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_IN_IO, 
+                                               CQR_STATUS_ERROR);
                                 }
-                                dasd_end_cqr (cqr, 0);
-                                atomic_dec (&qp->dirty_requests);
-                                break;
+	return rc;
                         }
-			default:
-                                PRINT_WARN ("unknown cqrstatus\n");
+
+static void
+dasd_end_request (struct request *req, int uptodate)
+{
+	struct buffer_head *bh;
+	while ((bh = req->bh) != NULL) {
+		req->bh = bh->b_reqnext;
+		bh->b_reqnext = NULL;
+		bh->b_end_io (bh, uptodate);
 			}
-                        s390irq_spin_unlock_irqrestore (irq, flags);
-		} while ((cqr = next) != NULL);
-		qp = qp->next_q;
+	if (!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);
 	}
-	spin_lock (&io_request_lock);
-	do_dasd_request ();
-	spin_unlock (&io_request_lock);
-	dasd_debug (0xc4c46d6d);	/* DD__ */
+	return;
 }
 
-/* 
-   The request_fn is called from ll_rw_blk for any new request.
-   We use it to feed the chanqs.
-   This implementation assumes we are serialized by the io_request_lock.
- */
+#undef CURRENT
+#define CURRENT (blk_dev[major].current_request)
 
-#define QUEUE_THRESHOLD 5
-
-void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static void
+do_dasd_request (request_queue_t * queue)
+#else
+static void
 do_dasd_request (void)
+#endif /* LINUX_IS_24 */
 {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	struct request *req;
+        int go;
+#else
 	struct request *req, *next, *prev;
-	cqr_t *cqr;
+#endif /* LINUX_IS_24 */
+	ccw_req_t *cqr;
 	dasd_chanq_t *q;
 	long flags;
-	int di, irq;
+	int devindex, irq, partn;
 	int broken, busy;
+	dasd_device_t *device;
+	major_info_t *major_info;
+	int devno;
+        int major;
         
-	dasd_debug (0xc4d90000);	/* DR */
-	dasd_debug ((unsigned long) __builtin_return_address (0));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        {
+                if ( queue == NULL ) {
+			printk(KERN_ERR PRINTK_HEADER "Null queue !!\n");
+                        return;
+                }
+                go = 1;
+                while (go && !list_empty (&queue->queue_head)) {
+                        req = blkdev_entry_next_request (&queue->queue_head);
+                        major = MAJOR(req->rq_dev);
+                        for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+                                if ( major_info->gendisk.major == major )
+                                        break;
+                        }
+                        if ( major_info == NULL ) {
+                                printk (KERN_ERR PRINTK_HEADER "No major_info\n");
+                                return;
+                        }
+#else
+        for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+                major = major_info->gendisk.major;
 	prev = NULL;
 	for (req = CURRENT; req != NULL; req = next) {
 		next = req->next;
-		di = DEVICE_NR (req->rq_dev);
-		dasd_debug ((unsigned long) req);	/* req */
-		dasd_debug (0xc4d90000 +	/* DR## */
-                            ((((di/16)<9?(di/16)+0xf0:(di/16)+0xc1))<<8) +
-                            (((di%16)<9?(di%16)+0xf0:(di%16)+0xc1)));
-                irq = dasd_info[di]->info.irq;
-                s390irq_spin_lock_irqsave (irq, flags);
-                q = &dasd_info[di]->queue;
-		busy = atomic_read (&q->flags) & DASD_CHANQ_BUSY;
-		broken = atomic_read (&q->flags) & DASD_REQUEST_Q_BROKEN;
-		if (!busy ||
-		    (!broken &&
-		     (req->nr_sectors >= QUEUE_SECTORS))) {
+                        if (req == &blk_dev[major].plug) { /* remove plug if applicable */
+                                req->next = NULL;
                         if (prev) {
                                 prev->next = next;
                         } else {
                                 CURRENT = next;
                         }
-			req->next = NULL;
-			if (req == &blk_dev[MAJOR_NR].plug) {
-					dasd_debug (0xc4d99787); /* DRpg */
-				goto cont;
-			}
-			cqr = dasd_cqr_from_req (req);
-			if (!cqr) {
-					dasd_debug (0xc4d96ff1); /* DR?1 */
+                                continue;
+			}
+#endif /* LINUX_IS_24 */
+                        devindex = devindex_from_kdev_t(req->rq_dev);
+                        if ( devindex < 0 ) {
+                                printk ( KERN_WARNING PRINTK_HEADER 
+                                         "requesting I/O on nonexistent device %d -> %d\n",
+                                         devindex,req->rq_dev);
 				dasd_end_request (req, 0);
-				goto cont;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+					} else {
+                                        CURRENT = next;
                         }
-                        dasd_debug ((unsigned long) cqr);	/* cqr */
-                        dasd_chanq_enq (q, cqr);
-			if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-                                cql_enq_head (q);
+#endif /* LINUX_IS_24 */
+                                continue;
                         }
-			if (!busy) {
-				atomic_clear_mask (DASD_REQUEST_Q_BROKEN,
-						   &q->flags);
-				if ( atomic_read (&q->dirty_requests) == 0 ) {
-					if (dasd_start_IO (cqr) == 0) {
-					} else {
-						dasd_schedule_bh (dasd_do_chanq);
+                        device = find_dasd_device (devindex);
+                        if ( device == NULL ) {
+                                printk ( KERN_WARNING PRINTK_HEADER 
+                                         "requesting I/O on nonexistent device\n");
+				dasd_end_request(req,0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+                                } else {
+                                        CURRENT = next;
+                                }
+#endif /* LINUX_IS_24 */
+                                continue;
+                        }
+                        irq = device->devinfo.irq;
+                        s390irq_spin_lock_irqsave (irq, flags);
+                        devno = device->devinfo.devno;
+                        q = & device->queue;
+                        busy = atomic_read (&q->flags) & DASD_CHANQ_BUSY;
+                        broken = atomic_read (&q->flags) & DASD_REQUEST_Q_BROKEN;
+                        partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+                        if ( ! busy ||
+                             ( ! broken &&
+                               (req->nr_sectors >= QUEUE_SECTORS))) {
+                                if (device->discipline == NULL) {
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " is not assigned to a discipline\n",
+                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS);
+                                        dasd_end_request (req, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                        blkdev_dequeue_request (req);
+#else
+                                        req->next = NULL;
+                                       	if (prev) {
+                                                prev->next = next;
+                         	        } else {
+                                       	        CURRENT = next;
+                                        }
+#endif /* LINUX_IS_24 */	
+					s390irq_spin_unlock_irqrestore (irq, flags);
+                                	continue;
+                                }
+                                if (device->discipline->build_cp_from_req == NULL) {
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " discipline %s hast no builder function\n",
+                                                devno, irq, device->name,major, devindex << DASD_PARTN_BITS,
+                                                device->discipline->name);
+                                        dasd_end_request (req, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                        	        blkdev_dequeue_request (req);
+#else
+                                	req->next = NULL;
+                                	if (prev) {
+                                        	prev->next = next;
+                                	} else {
+                                        	CURRENT = next;
+                                	}
+#endif /* LINUX_IS_24 */
+					s390irq_spin_unlock_irqrestore (irq, flags);
+					continue;                 
+		                }
+                                req->sector += major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
+                                cqr = device->discipline->build_cp_from_req (device, req);
+                                if (cqr == NULL) {
+                                        atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " Could not create channel program for request %p\n",
+                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS, req);
+                                /* put request back to queue*/
+                                        req->sector -= major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
+                                        s390irq_spin_unlock_irqrestore (irq, flags);
+                                        continue;
+                                } 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+                                } else {
+                                        CURRENT = next;
                                 }
+#endif /* LINUX_IS_24 */
+                                dasd_chanq_enq (q, cqr);
+                                if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
+                                        qlist_enq (q);
+                                }
+                                if (!busy) {
+                                        atomic_clear_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+                                        if (atomic_read (&q->dirty_requests) == 0) {
+                                                if (device->discipline->start_IO == NULL) {
+                                                        printk (KERN_WARNING PRINTK_HEADER
+                                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                                " dicsipline %s has no starter function\n",
+                                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS,
+                                                                device->discipline->name);
+                                                } else {
+                                                        if (device->discipline->start_IO (cqr) != 0) {
+                                                                printk (KERN_DEBUG PRINTK_HEADER
+                                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                                        " starting of request from req_fn failed, postponing\n",
+                                                                        devno, irq, device->name, major, devindex << DASD_PARTN_BITS);
+                                                                dasd_schedule_bh ();	/* initiate bh to run */
+                                                        }
+                                                }
+                                        } else {
+						dasd_schedule_bh();
+                                        } 
+                                }
+                        } else {
+                                atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                go = 0;
+#else
+                                prev = req;
+#endif /* LINUX_IS_24 */
                         }
+                        s390irq_spin_unlock_irqrestore (irq, flags);
+                }
+        }
+        return;
+}
+
+static void
+dasd_do_chanq (void)
+{
+	dasd_chanq_t *qp = NULL;
+	dasd_chanq_t *nqp;
+	dasd_device_t *device;
+	ccw_req_t *cqr, *next;
+	long flags;
+	int irq;
+	int devno, devindex;
+	int rc = -1;
+	volatile int cqrstatus;
+
+	for (qp = qlist_head; qp != NULL; qp = nqp) {
+		/* Get first request */
+		cqr = (ccw_req_t *) (qp->head);
+		nqp = qp->next_q;
+/* empty queue -> dequeue and proceed */
+		if (!cqr) {
+			qlist_deq (qp);
+			continue;
+		}
+/* process all requests on that queue */
+		do {
+			dasd_discipline_t *discipline;
+			next = NULL;
+			/* Sanity check... walk through disciplines */
+			for (discipline = dasd_disciplines;
+			     discipline != NULL;
+			     discipline = discipline->next)
+				if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4))
+					break;
+			if (!discipline) {	/* 1st sanity check */
+				panic (PRINTK_HEADER
+				       "in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n",
+				       cqr, cqr->magic);
+			}
+			device = (dasd_device_t *) (cqr->device);
+			if (discipline != device->discipline) {		/* 1st sanity check */
+				printk (KERN_WARNING PRINTK_HEADER
+					"in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n",
+					cqr, cqr->magic);
+				discipline = device->discipline;
+			}
+			irq = device->devinfo.irq;
+			devno = device->devinfo.devno;
+			devindex = devindex_from_devno (devno);
+
+			s390irq_spin_lock_irqsave (irq, flags);
+
+			cqrstatus = atomic_read (&cqr->status);
+			switch (cqrstatus) {
+			case CQR_STATUS_QUEUED:
+				if (discipline->start_IO &&
+				    ((rc = discipline->start_IO (cqr)) == 0)) {
+                                } else {
+					printk (KERN_WARNING PRINTK_HEADER
+						" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+						" Failing to start I/O operation with rc %d\n",
+						devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+					switch (rc) {
+					case EBUSY:
+						if (cqr->retries--) {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" retrying %d retries left\n",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+							break;
+						}
+					default:{	/* Fallthrough ?? */
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" Giving up this request!\n",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+							break;
+						}
+					}
+				}
+				break;
+			case CQR_STATUS_IN_IO:{
+					unsigned long long now;
+					unsigned long long delta;
+
+					asm volatile ("STCK %0":"=m" (now));
+					if (cqr->expires && cqr->startclk &&
+					    cqr->expires < now) {
+                                                delta = cqr->expires - cqr->startclk;
+						printk (KERN_ERR PRINTK_HEADER
+							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+							" I/O operation outstanding longer than %Ld usecs on req %p\n",
+							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr);
+						if ( cqr->retries-- ) {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" waiting %d more times\n",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+							cqr->expires += delta;
+							break;
+						} else {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" You should disable that device by issueing '@#?!'\n",		/* FIXME */
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+							atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+							break;
+						}
+					}
+					break;
+				}
+			case CQR_STATUS_ERROR:{
+					dasd_erp_action_fn_t erp_action;
+					ccw_req_t *erp_cqr = NULL;
+					if (discipline->erp_action &&
+					    ((erp_action = discipline->erp_action (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+							" Taking error recovery action %p on req %p \n",
+							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr);
+						erp_cqr = erp_action (cqr);
+					} else {
+						printk (KERN_WARNING PRINTK_HEADER
+							" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No error recovery action\n",
+							devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+						atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+					}
+					if ( erp_cqr != NULL ) {
+						dasd_chanq_enq_head (qp, erp_cqr);
+						next = erp_cqr;		/* prefer execution of erp ccw */
+					}
+					break;
+				}
+			case CQR_STATUS_DONE:{
+                                        dasd_erp_postaction_fn_t erp_postaction;
+                                        next = cqr->next;
+					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+						if (discipline->erp_postaction &&
+						    ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" postprocessing successful error recovery action %p\n",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+							erp_postaction (cqr, 1);
+                                                        atomic_dec (&device->queue.dirty_requests);
+						} else {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" No procedure to postprocess error recovery action"
+                                                                " giving up request",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+						}
+					} else if ( cqr->req ) {
+						asm volatile ("STCK %0":"=m" (cqr->endclk));
+						dasd_end_request (cqr->req, 1);
+#ifdef DASD_PROFILE
+						dasd_profile_add (cqr);
+#endif				/* DASD_PROFILE */
+					} 
+					dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr);
+					break;
+				}
+			case CQR_STATUS_FAILED:{
+					dasd_erp_postaction_fn_t erp_postaction;
+					next = cqr->next;
+					if (cqr->refers && cqr->function) {	/* we deal with an ERP */
+						if (discipline->erp_postaction &&
+						    ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" postprocessing unsuccessful error recovery action %p\n",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+							erp_postaction (cqr, 0);
+                                                        atomic_dec (&device->queue.dirty_requests);
+
+						} else {
+							printk (KERN_WARNING PRINTK_HEADER
+								" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+								" No procedure to postprocess unsuccessful error recovery action"
+							 " giving up request",
+								devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+							atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+						}
+					} else if (cqr->req) {
+						asm volatile ("STCK %0":"=m" (cqr->endclk));
+						dasd_end_request (cqr->req, 0);
+#ifdef DASD_PROFILE
+						dasd_profile_add (cqr);
+#endif				/* DASD_PROFILE */
+					} else {
+						printk (KERN_WARNING PRINTK_HEADER
+							"Internal error in " __FILE__ " on line %d."
+							" inconsistent content of ccw_req_t"
+							" refers = %p,function = %p, request = %p"
+							" Pls send this message and your System.map to"
+						     " linux390@de.ibm.com\n",
+							__LINE__, cqr->refers, cqr->function, cqr->req);
+					}
+					dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr);
+					break;
+				}
+			default:{
+					printk (KERN_WARNING PRINTK_HEADER
+						"Internal error in " __FILE__ " on line %d."
+					  " inconsistent content of ccw_req_t"
+						" cqrstatus = %d"
+						" Pls send this message and your System.map to"
+						" linux390@de.ibm.com\n",
+						__LINE__, cqrstatus);
 			}
-                } else {
-                        dasd_debug (0xc4d9c2d9);	/* DRBR */
-			atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
-			prev = req;
 		}
-        cont:
                 s390irq_spin_unlock_irqrestore (irq, flags);
+		} while ((cqr = next) != NULL);
 	}
-	dasd_debug (0xc4d96d6d);	/* DR__ */
+	schedule_request_fn (try_request_fn);
+        return;
 }
 
 void
-dasd_handler (int irq, void *ds, struct pt_regs *regs)
+dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
 	devstat_t *stat = (devstat_t *) ds;
 	int ip;
-	cqr_t *cqr;
+	ccw_req_t *cqr;
 	int done_fast_io = 0;
-	dasd_era_t era;
+	dasd_era_t era = dasd_era_fatal;
+	dasd_device_t *device;
+	int devno = -1, devindex = -1;
+        
+#undef ERP_DEBUG
+#ifdef ERP_DEBUG 
         static int counter = 0; 
+#endif
 
-	dasd_debug (0xc4c80000);	/* DH */
 	if (!stat) {
 		PRINT_ERR ("handler called without devstat");
 		return;
 	}
 	ip = stat->intparm;
-	dasd_debug (ip);	/* intparm */
 	if (!ip) {		/* no intparm: unsolicited interrupt */
-		dasd_debug (0xc4c8a489);	/* DHui */
 		PRINT_INFO ("%04X caught unsolicited interrupt\n",
 			    stat->devno);
 		return;
 	}
 		if (ip & 0x80000001) {
-			dasd_debug (0xc4c8a489);	/* DHui */
 		PRINT_INFO ("%04X  caught spurious interrupt with parm %08x\n",
 			    stat->devno, ip);
 			return;
 		}
-		cqr = (cqr_t *) ip;
-	if (cqr->magic == DASD_MAGIC || cqr->magic == ERP_MAGIC) {
+	cqr = (ccw_req_t *) ip;
+	device = (dasd_device_t *) cqr->device;
+	devno = device->devinfo.devno;
+	devindex = devindex_from_devno (devno);
+	if (device == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+		     " IRQ on devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+			" belongs to NULL device\n",
+			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+	}
+	if (device->devinfo.irq != irq) {
+		printk (KERN_WARNING PRINTK_HEADER
+		     " IRQ on devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+			" doesn't belong to device irq %d\n",
+			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+			device->devinfo.irq);
+		return;
+	}
+	if (device->discipline == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+			" is not assigned to a discipline\n",
+			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+	}
+	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"0x%04X on sch %d : /dev/%s (%d:%d)"
+			" magic number of ccw_req_t 0x%08lX doesn't match"
+			" discipline 0x%08X\n",
+			devno, irq, device->name,
+			major_from_devindex (devindex),
+			devindex << DASD_PARTN_BITS,
+			cqr->magic, *(int *) (&device->discipline->name));
+		return;
+	}
 		asm volatile ("STCK %0":"=m" (cqr->stopclk));
 		if ((stat->cstat == 0x00 &&
 		     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
-		    ((era = dasd_erp_examine (cqr, stat)) == dasd_era_none)) {
-			dasd_debug (0xc4c89692);	/* DHok */
-#if 0
-                        if ( counter < 20 || cqr -> magic == ERP_MAGIC) {
-                                counter ++;
-#endif
-                                ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
-#if 0
-                        } else {
-                                counter=0;
-                                PRINT_WARN ("Faking I/O error\n");
-                                ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERP_PEND);
-                                atomic_inc (&dasd_info[cqr->devindex]->
-                                            queue.dirty_requests);
+	    (device->discipline->examine_error &&
+	     (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
+#ifdef ERP_DEBUG
+                if ( ++counter % 137 == 0 ) {
+                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n");
+                        era = dasd_era_recover;
+                        stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+                        stat->dstat |= 0x02;
+                        goto error_fake_done;
                         }
 #endif
-			if (atomic_read (&dasd_info[cqr->devindex]->status) ==
-			    DASD_INFO_STATUS_DETECTED) {
-				register_dasd_last (cqr->devindex);
-                                if ( dasd_info[cqr->devindex]->wait_q ) {
-                                        wake_up( &dasd_info[cqr->devindex]->
-                                                wait_q);
-                                }
-			}
+		atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
+                atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+					 DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                         &device->level);
 			if (cqr->next &&
 			    (atomic_read (&cqr->next->status) ==
 			     CQR_STATUS_QUEUED)) {
-				dasd_debug (0xc4c8e2e3);	/* DHST */
 				if (dasd_start_IO (cqr->next) == 0) {
 					done_fast_io = 1;
-				} else {
 			}
 		}
 		} else {	/* only visited in case of error ! */
-		dasd_debug (0xc4c8c5d9);	/* DHER */
-                        dasd_dump_sense (stat);
-		if (!cqr->dstat)
-			cqr->dstat = kmalloc (sizeof (devstat_t),
-					      GFP_ATOMIC);
+#ifdef ERP_DEBUG
+        error_fake_done:
+#endif
+		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\n");
 		}
-                        atomic_inc (&dasd_info[cqr->devindex]->
-                                    queue.dirty_requests);
+		if (device->discipline &&
+		    device->discipline->dump_sense) {
+			char *errmsg = device->discipline->dump_sense (device, cqr);
+			if (errmsg != NULL) {
+				printk ("%s", errmsg);
+				free_page ((unsigned long) errmsg);
+			} else {
+				printk (KERN_WARNING PRINTK_HEADER
+					"No memory to dump error message\n");
+			}
+		}
+		atomic_inc (&device->queue.dirty_requests);
 		/* errorprocessing */
 			if (era == dasd_era_fatal) {
 				PRINT_WARN ("ERP returned fatal error\n");
-				ACS (cqr->status,
+			atomic_compare_and_swap_debug (&cqr->status,
 				     CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
 			} else {
-                                ACS (cqr->status,
-                                     CQR_STATUS_IN_IO, CQR_STATUS_ERP_PEND);
+			atomic_compare_and_swap_debug (&cqr->status,
+                                                       CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
                         }
 	}
 	if (done_fast_io == 0)
-		atomic_clear_mask (DASD_CHANQ_BUSY,
-				   &dasd_info[cqr->devindex]->
-				   queue.flags);
+		atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
         
-	if (cqr->flags & DASD_DO_IO_SLEEP) {
-		dasd_debug (0xc4c8a6a4);	/* DHwu */
-		dasd_wakeup ();
-	} else if (! (cqr->options & DOIO_WAIT_FOR_INTERRUPT) ){
-                dasd_debug (0xc4c8a293);	/* DHsl */
-                        dasd_schedule_bh (dasd_do_chanq);
-	} else {
-                dasd_debug (0x64686f6f);	/* DH_g */
-                dasd_debug (cqr->flags);	/* DH_g */
-        }
-        } else {
-                dasd_debug (0xc4c86ff1);	/* DH?1 */
-                PRINT_ERR ("handler:magic mismatch on %p %08x\n",
-                           cqr, cqr->magic);
-                return;
-        }
-	dasd_debug (0xc4c86d6d);	/* DHwu */
-}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wake_up (&device->wait_q);
+#else
+	if (device->wait_q) {
+		wake_up (&device->wait_q);
+	}
+#endif /* LINUX_IS_24 */
+	dasd_schedule_bh ();
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static wait_queue_head_t watcher_queue;
+#else
+static struct wait_queue watcher_queue_Qend = {NULL,};
+static struct wait_queue *watcher_queue = &watcher_queue_Qend;
+#endif /* LINUX_IS_24 */
 
-static int
-dasd_format (int dev, format_data_t * fdata)
+static void
+dasd_watcher (void)
 {
-	int rc;
-	int devindex = DEVICE_NR (dev);
-	dasd_chanq_t *q;
-	cqr_t *cqr;
-	int irq;
-	long flags;
-	PRINT_INFO ("%04X called format on %x\n",
-		    dasd_info[devindex]->info.devno, dev);
-	if (MINOR (dev) & (0xff >> (8 - PARTN_BITS))) {
-		PRINT_WARN ("Can't format partition! minor %x %x\n",
-			    MINOR (dev), 0xff >> (8 - PARTN_BITS));
-		return -EINVAL;
+	do {
+		dasd_schedule_bh ();
+		schedule_request_fn (try_request_fn);
+		interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ);
+	} while (1);
+        }
+
+/* SECTION: Some stuff related to error recovery */
+
+ccw_req_t *
+default_erp_action (ccw_req_t * cqr)
+{
+	ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
+
+	erp->cpaddr->cmd_code = CCW_CMD_NOOP;
+	erp->function = default_erp_action;
+	erp->refers = cqr;
+	erp->device = cqr->device;
+        erp->magic = cqr->magic;
+	atomic_set (&erp->status, CQR_STATUS_FILLED);
+        if ( cqr->startclk && cqr->expires )
+                cqr->expires -= cqr->startclk;
+        
+	if (cqr->retries++ <= 16) {
+                atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_ERROR,
+					       CQR_STATUS_QUEUED);
+        } else {
+		printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n");
+		atomic_compare_and_swap_debug (&cqr->status,
+					       CQR_STATUS_ERROR,
+					       CQR_STATUS_FAILED);
 	}
-	down (&dasd_info[devindex]->sem);
-	atomic_set (&dasd_info[devindex]->status,
-		    DASD_INFO_STATUS_UNKNOWN);
-	if (dasd_info[devindex]->open_count == 1) {
-		rc = dasd_disciplines[dasd_info[devindex]->type]->
-		    dasd_format (devindex, fdata);
-		if (rc) {
-			PRINT_WARN ("Formatting failed rc=%d\n", rc);
-			up (&dasd_info[devindex]->sem);
-			return rc;
-		}
-	} else {
-		PRINT_WARN ("device is open! %d\n", dasd_info[devindex]->open_count);
-		up (&dasd_info[devindex]->sem);
+	return erp;
+}
+
+int
+default_erp_postaction (ccw_req_t * cqr, int success)
+{
+	int rc = 0;
+	if (cqr->refers == NULL || cqr->function == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"ERP postaction called for non ERP cqr\n");
 		return -EINVAL;
 	}
-#if DASD_PARANOIA > 1
-	if (!dasd_disciplines[dasd_info[devindex]->type]->fill_sizes_first) {
-		INTERNAL_CHECK ("No fill_sizes for dt=%d\n", dasd_info[devindex]->type);
-	} else
-#endif				/* DASD_PARANOIA */
-	{
-		ACS (dasd_info[devindex]->status,
-		     DASD_INFO_STATUS_UNKNOWN, DASD_INFO_STATUS_DETECTED);
-		irq = dasd_info[devindex]->info.irq;
-		PRINT_INFO ("%04X reacessing, irq %x, index %d\n",
-			    get_devno_by_irq (irq), irq, devindex);
-		s390irq_spin_lock_irqsave (irq, flags);
-		q = &dasd_info[devindex]->queue;
-		cqr = dasd_disciplines[dasd_info[devindex]->type]->
-		    fill_sizes_first (devindex);
-		dasd_chanq_enq (q, cqr);
-		if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-			cql_enq_head (q);
-		}
-		dasd_schedule_bh (dasd_do_chanq);
-		s390irq_spin_unlock_irqrestore (irq, flags);
-	}
-	up (&dasd_info[devindex]->sem);
+	if (cqr->function != default_erp_action) {
+		printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP postaction called for non default ERP cqr\n");
+		return -EINVAL;
+        }
 	return rc;
 }
 
+/* SECTION: The helpers of the struct file_operations */
+
 static int
-register_dasd (int irq, dasd_type_t dt, dev_info_t * info)
+dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
 	int rc = 0;
-	int di;
-	unsigned long flags;
-	dasd_chanq_t *q;
-	cqr_t *cqr;
-	static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
-	spin_lock (&register_lock);
-	FUNCTION_ENTRY ("register_dasd");
-	di = devindex_from_devno (info->devno);
-	if (di < 0) {
-		INTERNAL_CHECK ("Can't get index for devno %d\n", info->devno);
-		return -ENODEV;
-	}
-	if (dasd_info[di]) {	/* devindex is not free */
-		INTERNAL_CHECK ("reusing allocated deviceindex %d\n", di);
-		return -ENODEV;
-	}
-	dasd_info[di] = (dasd_information_t *)
-	    kmalloc (sizeof (dasd_information_t), GFP_ATOMIC);
-	if (dasd_info[di] == NULL) {
-		PRINT_WARN ("No memory for dasd_info_t on irq %d\n", irq);
-		return -ENOMEM;
-	}
-	memset (dasd_info[di], 0, sizeof (dasd_information_t));
-	memcpy (&(dasd_info[di]->info), info, sizeof (dev_info_t));
-	spin_lock_init (&dasd_info[di]->queue.f_lock);
-	spin_lock_init (&dasd_info[di]->queue.q_lock);
-	dasd_info[di]->type = dt;
-	dasd_info[di]->irq = irq;
-	dasd_info[di]->sem = MUTEX;
-#ifdef CONFIG_DASD_MDSK
-	if (dt == dasd_mdsk) {
-		dasd_info[di]->rdc_data = kmalloc (
-				 sizeof (dasd_characteristics_t), GFP_ATOMIC);
-		if (!dasd_info[di]->rdc_data) {
-			PRINT_WARN ("No memory for char on irq %d\n", irq);
-			goto unalloc;
-		}
-		dasd_info[di]->rdc_data->mdsk.dev_nr = dasd_info[di]->
-		    info.devno;
-		dasd_info[di]->rdc_data->mdsk.rdc_len =
-		    sizeof (dasd_mdsk_characteristics_t);
-	} else
-#endif				/* CONFIG_DASD_MDSK */
-	rc = dasd_read_characteristics (dasd_info[di]);
-	if (rc) {
-		PRINT_WARN ("RDC returned error %d\n", rc);
-		rc = -ENODEV;
-		goto unalloc;
-	}
-#if DASD_PARANOIA > 1
-	if (dasd_disciplines[dt]->ck_characteristics)
-#endif				/* DASD_PARANOIA */
-		rc = dasd_disciplines[dt]->
-		    ck_characteristics (dasd_info[di]->rdc_data);
-
-	if (rc) {
-		INTERNAL_CHECK ("Discipline returned non-zero when"
-				"checking device characteristics%s\n", "");
-		rc = -ENODEV;
-		goto unalloc;
-	}
-#ifdef CONFIG_DASD_MDSK
-	if (dt == dasd_mdsk) {
+	int devno = device->devinfo.devno;
+	int irq = device->devinfo.irq;
+	int devindex = devindex_from_devno (devno);
 
-	} else
-#endif				/* CONFIG_DASD_MDSK */
-	rc = request_irq (irq, dasd_handler, 0, "dasd",
-			  &(dasd_info[di]->dev_status));
-	ACS (dasd_info[di]->status,
-	     DASD_INFO_STATUS_UNKNOWN, DASD_INFO_STATUS_DETECTED);
-	if (rc) {
-#if DASD_PARANOIA > 0
+	if (device->open_count != 1) {
 		printk (KERN_WARNING PRINTK_HEADER
-			"Cannot register irq %d, rc=%d\n",
-			irq, rc);
-#endif				/* DASD_PARANOIA */
-		rc = -ENODEV;
-		goto unalloc;
-	}
-#if DASD_PARANOIA > 1
-	if (!dasd_disciplines[dt]->fill_sizes_first) {
-		INTERNAL_CHECK ("No fill_sizes for dt=%d\n", dt);
-		goto unregister;
-	}
-#endif				/* DASD_PARANOIA */
-	irq = dasd_info[di]->info.irq;
-	PRINT_INFO ("%04X trying to access, irq %x, index %d\n",
-		    get_devno_by_irq (irq), irq, di);
-	s390irq_spin_lock_irqsave (irq, flags);
-	q = &dasd_info[di]->queue;
-	cqr = dasd_disciplines[dt]->fill_sizes_first (di);
-	dasd_chanq_enq (q, cqr);
-	if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-		cql_enq_head (q);
-	}
-	if (dasd_start_IO (cqr) != 0) {
-		dasd_schedule_bh (dasd_do_chanq);
+			" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+		      " you shouldn't format a device that is already open\n",
+			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+		return -EINVAL;
 	}
-	s390irq_spin_unlock_irqrestore (irq, flags);
-
-	goto exit;
-
-      unregister:
-	free_irq (irq, &(dasd_info[di]->dev_status));
-      unalloc:
-	kfree (dasd_info[di]);
-	dasd_info[di] = NULL;
-      exit:
-	spin_unlock (&register_lock);
-	FUNCTION_EXIT ("register_dasd");
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_RECOGNIZED,
+                               device->discipline,
+                               0);
+	if (device->discipline->format_device)
+          rc = device->discipline->format_device (device, fdata);
+		if (rc) {
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+			" Formatting failed with rc = %d\n",
+			devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+			return rc;
+		}
+	printk (KERN_WARNING PRINTK_HEADER
+		" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+		" Formatting finished successfully rc = %d\n",
+		devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                               device->discipline,
+                               0);
+        udelay(1500000);
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ANALYSED,
+                               device->discipline,
+                               0);
 	return rc;
 }
 
 static int
-probe_for_dasd (int irq)
+do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
-	int rc;
-	dev_info_t info;
-	dasd_type_t dt;
-
-	rc = get_dev_info_by_irq (irq, &info);
-
-	if (rc == -ENODEV) {	/* end of device list */
-		return rc;
-	} else if ((info.status & DEVSTAT_DEVICE_OWNED)) {
-		return -EBUSY;
-	} else if ((info.status & DEVSTAT_NOT_OPER)) {
-		return -ENODEV;
-	}
-#if DASD_PARANOIA > 2
-	else {
-		INTERNAL_CHECK ("unknown rc %d of get_dev_info", rc);
-		return rc;
+	int rc = 0;
+	int devindex = devindex_from_kdev_t (inp->i_rdev);
+	dasd_device_t *device = find_dasd_device (devindex);
+	major_info_t *major_info = major_info_from_devindex (devindex);
+        
+	if (!device) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"No device registered as 0x%04x (%d)\n",
+			inp->i_rdev, devindex);
+		return -EINVAL;
 	}
-#endif				/* DASD_PARANOIA */
-
-	dt = check_type (&info);	/* make a first guess */
-
-	if (dt == dasd_none) {
-		return -ENODEV;
+	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
+		PRINT_DEBUG ("empty data ptr");
+		return -EINVAL;
 	}
-		if (!dasd_is_accessible (info.devno)) {
-			return -ENODEV;
+#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 BLKGETSIZE:{	/* Return device size */
+			int blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1;
+			rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+			break;
 		}
-	if (!dasd_disciplines[dt]->ck_devinfo) {
-			INTERNAL_ERROR ("no ck_devinfo function%s\n", "");
-			return -ENODEV;
+	case BLKFLSBUF:{
+			rc = fsync_dev (inp->i_rdev);
+			break;
 		}
-	rc = dasd_disciplines[dt]->ck_devinfo (&info);
-	if (rc) {
-			return rc;
+	case BLKRAGET:{
+			rc = copy_to_user ((long *) data, read_ahead + MAJOR (inp->i_rdev), sizeof (long));
+			break;
 		}
-	if (dasd_probeonly) {
-		PRINT_INFO ("%04X not enabled due to probeonly mode\n",
-			    info.devno);
-		dasd_add_devno_to_ranges (info.devno);
-			return -ENODEV;
-	} else {
-		rc = register_dasd (irq, dt, &info);
-	}
-		if (rc) {
-		PRINT_WARN ("%04X not enabled due to errors\n",
-			    info.devno);
-		} else {
-		PRINT_INFO ("%04X is (dasd%c) minor %d (%s)\n",
-				    info.devno,
-			    'a' + devindex_from_devno (info.devno),
-			       devindex_from_devno (info.devno) << PARTN_BITS,
-				    dasd_name[dt]);
+	case BLKRASET:{
+			rc = copy_from_user (read_ahead + MAJOR (inp->i_rdev), (long *) data, sizeof (long));
+			break;
 		}
+	case BLKRRPART:{
+			dasd_partn_detect (devindex);
+			rc = 0;
+			break;
+		}
+	case BLKGETBSZ:{
+			rc = copy_to_user ((int *) data, &blksize_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)],
+					   sizeof (int));
+			break;
+		}
+	case HDIO_GETGEO:{
+			struct hd_geometry geo =
+			{0,};
+			if (device->discipline->fill_geometry)
+				device->discipline->fill_geometry (device, &geo);
+			rc = copy_to_user ((struct hd_geometry *) data, &geo,
+					   sizeof (struct hd_geometry));
+			break;
+		}
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+		RO_IOCTLS (inp->i_rdev, data);
+#endif /* LINUX_IS_24 */
+	case BIODASDRSID:{
+			rc = copy_to_user ((void *) data,
+					   &(device->devinfo.sid_data),
+					   sizeof (senseid_t));
+			break;
+		}
+	case BIODASDRWTB:{
+			int offset = 0;
+			int xlt;
 
-	return rc;
-}
-
-static int
-register_major (int major)
-{
-	int rc = 0;
-
-	FUNCTION_ENTRY ("register_major");
-	rc = register_blkdev (major, DASD_NAME, &dasd_device_operations);
-#if DASD_PARANOIA > 1
-	if (rc) {
-		PRINT_WARN ("registering major -> rc=%d aborting... \n", rc);
-		return rc;
+			rc = copy_from_user (&xlt, (void *) data,
+					     sizeof (int));
+			if (rc)
+				break;
+			offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
+			    device->sizes.s2b_shift;
+			xlt += offset;
+			rc = copy_to_user ((void *) data, &xlt,
+					   sizeof (int));
+			break;
+		}
+	case BIODASDFORMAT:{
+			/* fdata == NULL is a valid arg to dasd_format ! */
+			int partn;
+			format_data_t *fdata = NULL;
+			if (data) {
+				fdata = kmalloc (sizeof (format_data_t),
+						 GFP_ATOMIC);
+				if (!fdata) {
+					rc = -ENOMEM;
+					break;
+				}
+				rc = copy_from_user (fdata, (void *) data,
+						     sizeof (format_data_t));
+				if (rc)
+					break;
+			}
+			partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
+			if (partn != 0) {
+				printk (KERN_WARNING PRINTK_HEADER
+					" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+				     " Cannot low-level format a partition\n",
+					device->devinfo.devno, device->devinfo.irq, device->name,
+				    MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+				return -EINVAL;
+			}
+			rc = dasd_format (device, fdata);
+			if (fdata) {
+				kfree (fdata);
+			}
+			break;
+		}
+	case BIODASDEXCP:{
+			printk (KERN_WARNING PRINTK_HEADER
+				"Unsupported ioctl BIODASDEXCP\n");
+                        break;
+		}
+        default:{
+          printk (KERN_WARNING PRINTK_HEADER
+                  "unknown 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);
+          rc = -EINVAL;
+          break;
+		}
 	}
-#endif				/* DASD_PARANOIA */
-	blk_dev[major].request_fn = do_dasd_request;
-	FUNCTION_CONTROL ("successfully registered major: %d\n", major);
-	FUNCTION_EXIT ("register_major");
 	return rc;
 }
 
-/* 
-   Below you find functions which are called from outside. Some of them may be
-   static, because they are called by their function pointers only. Thus static
-   modifier is to make sure, that they are only called via the kernel's methods
- */
+/* SECTION: The members of the struct file_operations */
 
 static int
 dasd_ioctl (struct inode *inp, struct file *filp,
 	    unsigned int no, unsigned long data)
-{
+	{
 	int rc = 0;
-	FUNCTION_ENTRY ("dasd_ioctl");
 	if ((!inp) || !(inp->i_rdev)) {
 		return -EINVAL;
-	}
+		}
 	rc = do_dasd_ioctl (inp, no, data);
-	FUNCTION_EXIT ("dasd_ioctl");
 	return rc;
 }
 
@@ -1346,31 +1688,45 @@
 dasd_open (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
-	dasd_information_t *dev;
-	FUNCTION_ENTRY ("dasd_open");
+	int devindex;
+	int partn;
+	dasd_device_t *device;
+	major_info_t *major_info;
+
 	if ((!inp) || !(inp->i_rdev)) {
 		return -EINVAL;
 	}
-	dev = dasd_info[DEVICE_NR (inp->i_rdev)];
-	if (!dev) {
-		PRINT_DEBUG ("No device registered as %d (%d)\n",
-			    inp->i_rdev, DEVICE_NR (inp->i_rdev));
+	if ( dasd_probeonly ) {
+		printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n",MAJOR(inp->i_rdev),MINOR(inp->i_rdev));
+		return -EPERM;
+	}
+	devindex = devindex_from_kdev_t (inp->i_rdev);
+	if (devindex < 0) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"No device registered as %d\n", inp->i_rdev);
+		return devindex;
+	}
+	device = find_dasd_device (devindex);
+	major_info = major_info_from_devindex (devindex);
+	partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
+	if (device == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"No device registered as %d\n", inp->i_rdev);
+		return -EINVAL;
+	}
+	if (atomic_read (&device->level) < DASD_DEVICE_LEVEL_RECOGNIZED ||
+	    device->discipline == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+			" Cannot open unrecognized device\n",
+		     device->devinfo.devno, device->devinfo.irq, device->name,
+			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
 		return -EINVAL;
 	}
-	down (&dev->sem);
-	up (&dev->sem);
 #ifdef MODULE
 	MOD_INC_USE_COUNT;
 #endif				/* MODULE */
-#if DASD_PARANOIA > 2
-	if (dev->open_count < 0) {
-		INTERNAL_ERROR ("open count cannot be less than 0: %d",
-				dev->open_count);
-		return -EINVAL;
-	}
-#endif				/* DASD_PARANOIA */
-	dev->open_count++;
-	FUNCTION_EXIT ("dasd_open");
+	device->open_count++;
 	return rc;
 }
 
@@ -1378,37 +1734,38 @@
 dasd_release (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
-	dasd_information_t *dev;
-	FUNCTION_ENTRY ("dasd_release");
+	dasd_device_t *device;
+	int devindex;
+
 	if ((!inp) || !(inp->i_rdev)) {
 		return -EINVAL;
 	}
-	dev = dasd_info[DEVICE_NR (inp->i_rdev)];
-	if (!dev) {
-		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
+	devindex = devindex_from_kdev_t (inp->i_rdev);
+	device = find_dasd_device (devindex);
+	if (device == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"No device registered as %d:%d\n",
+			MAJOR(inp->i_rdev),MINOR(inp->i_rdev));
 		return -EINVAL;
 	}
+	if(device->open_count--) {
 #ifdef MODULE
 	MOD_DEC_USE_COUNT;
 #endif				/* MODULE */
-#if DASD_PARANOIA > 2
-	if (!dev->open_count) {
-		PRINT_WARN ("device %d has not been opened before:\n",
-			    inp->i_rdev);
-	}
-#endif				/* DASD_PARANOIA */
-	dev->open_count--;
-#if DASD_PARANOIA > 2
-	if (dev->open_count < 0) {
-		INTERNAL_ERROR ("open count cannot be less than 0: %d",
-				dev->open_count);
-		return -EINVAL;
 	}
-#endif				/* DASD_PARANOIA */
-	FUNCTION_EXIT ("dasd_release");
 	return rc;
 }
 
+/* SECTION: All that stuff related to major numbers */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct
+block_device_operations dasd_device_operations =
+{
+	ioctl:dasd_ioctl,
+	open:dasd_open,
+	release:dasd_release,
+};
+#else
 static struct
 file_operations dasd_device_operations =
 {
@@ -1419,156 +1776,894 @@
 	open:dasd_open,
 	release:dasd_release,
 };
+#endif /* LINUX_IS_24 */
 
-int
-dasd_init (void)
+static major_info_t *
+get_new_major_info (void)
 {
+	major_info_t *major_info = NULL;
+	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
+	if (major_info) {
+                major_info_t *temp = dasd_major_info;
+                while (temp->next)
+                        temp = temp->next;
+		temp->next = major_info;
+                
+		memset (major_info, 0, sizeof (major_info_t));
+		major_info->read_ahead = 8;
+		major_info->request_fn = do_dasd_request;
+                
+		major_info->gendisk.major_name = DASD_NAME;
+		major_info->gendisk.minor_shift = DASD_PARTN_BITS;
+		major_info->gendisk.max_p = 1 << DASD_PARTN_BITS;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+		major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS;
+#endif /* LINUX_IS_24 */
+		major_info->gendisk.nr_real=DASD_PER_MAJOR;
+	}
+	return major_info;
+}
+
+static int
+dasd_register_major (major_info_t * major_info)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        request_queue_t *q;
+#endif /* LINUX_IS_24 */
 	int rc = 0;
-	int i;
+	int major;
 
-	PRINT_INFO ("initializing...\n");
-	atomic_set (&bh_scheduled, 0);
-	spin_lock_init (&dasd_lock);
-#ifdef CONFIG_DASD_MDSK
-	/*
-	 * enable service-signal external interruptions,
-	 * Control Register 0 bit 22 := 1
-	 * (besides PSW bit 7 must be set to 1 somewhere for external
-	 * interruptions)
-	 */
-	ctl_set_bit (0, 9);
-	register_external_interrupt (0x2603, do_dasd_mdsk_interrupt);
-#endif
-	dasd_debug_info = debug_register ("dasd", 1, 4);
-	/* First register to the major number */
+	if (major_info == NULL) {
+		major_info = get_new_major_info ();
+		if (!major_info) {
+			printk (KERN_WARNING PRINTK_HEADER
+				"Cannot get memory to allocate another major number\n");
+			return -ENOMEM;
+		} else {
+			printk (KERN_INFO PRINTK_HEADER
+				"Created another major number\n");
+		}
+	}
+	major = major_info->gendisk.major;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
+#else
+	rc = register_blkdev (major, DASD_NAME, &dasd_device_operations);
+#endif /* LINUX_IS_24 */
+	if (rc < 0) {
+		printk (KERN_WARNING PRINTK_HEADER
+		      "Cannot register to major no %d, rc = %d\n", major, rc);
+	return rc;
+	} else if (rc > 0) {
+		if (major == 0) {
+			major = rc;
+			rc = 0;
+		} else {
+			printk (KERN_DEBUG PRINTK_HEADER
+			    "Unknown condition when registering major number."
+			  "Please report this line to Linux390@de.ibm.com\n");
+		}
+	} else {
+		if (major == 0) {
+			printk (KERN_DEBUG PRINTK_HEADER
+				"Unknown condition when registering to dynamic major number."
+			  "Please report this line to Linux390@de.ibm.com\n");
 
-	rc = register_major (MAJOR_NR);
-#if DASD_PARANOIA > 1
-	if (rc) {
-		PRINT_WARN ("registering major_nr returned rc=%d\n", rc);
+		}
+	}
+        major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), 
+                                                              GFP_ATOMIC);
+        memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*));
+        blk_size[major] = major_info->blk_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->blk_size ,0,(1<<MINORBITS) * sizeof(int));
+        blksize_size[major] = major_info->blksize_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->blksize_size ,0,(1<<MINORBITS) * sizeof(int));
+        hardsect_size[major] = major_info->hardsect_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->hardsect_size ,0,(1<<MINORBITS) * sizeof(int));
+        max_sectors[major] = major_info->max_sectors = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->max_sectors ,0,(1<<MINORBITS) * sizeof(int));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        q = BLK_DEFAULT_QUEUE (major);
+        blk_init_queue (q, do_dasd_request);
+        blk_queue_headactive (BLK_DEFAULT_QUEUE (major), 0);
+#else
+	blk_dev[major].request_fn = major_info->request_fn;
+#endif /* LINUX_IS_24 */
+
+        
+	/* finally do the gendisk stuff */
+        major_info->gendisk.part = kmalloc ((1 << MINORBITS) * 
+                                            sizeof (struct hd_struct),
+                                            GFP_ATOMIC);
+        memset (major_info->gendisk.part,0,(1 << MINORBITS) * 
+                sizeof (struct hd_struct));
+	major_info->gendisk.major = major;
+	major_info->gendisk.next = gendisk_head;
+        major_info->gendisk.sizes = major_info->blk_size;
+	gendisk_head = &major_info->gendisk;
+	return major;
+}
+
+static int
+dasd_unregister_major (major_info_t * major_info)
+{
+	int rc = 0;
+	int major;
+        struct gendisk *dd,*prev=NULL;
+
+	if (major_info == NULL) {
+                return -EINVAL;
+	}
+	major = major_info->gendisk.major;
+	rc = 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;
+	} 
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        blk_dev[major].request_fn = NULL;
+#endif /* LINUX_IS_24 */
+        blk_size[major]= NULL;
+        blksize_size[major]= NULL;
+        hardsect_size[major]= NULL;
+        max_sectors[major]= NULL;
+
+        kfree(major_info->dasd_device);
+        kfree(major_info->blk_size);
+        kfree(major_info->blksize_size);
+        kfree(major_info->hardsect_size);
+        kfree(major_info->max_sectors);
+        kfree(major_info->gendisk.part);
+        
+	/* finally do the gendisk stuff */
+        for (dd = gendisk_head; dd ; dd = dd -> next ) {
+                if ( dd == &major_info->gendisk ) {
+                        if ( prev )
+                                prev->next = dd->next;
+                        else 
+                                gendisk_head = dd->next;
+                        break;
+                }
+                prev = dd;
+        }
+        if ( dd == NULL ) {
+                return -ENOENT;
+        }
+        if  ( major_info->gendisk.major > 128 )
+                kfree(major_info);
+	return rc;
+}
+/* SECTION: Management of device list */
+
+/* This one is needed for naming 18000+ possible dasd devices */
+int
+dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
+{
+	int len = 0;
+        char first,second,third;
+
+        if ( hd ) {
+                index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
+}
+        third = index % 26;
+        second = (index / 26) % 27;
+	first = ((index / 26) / 27) % 27;
+
+	len = sprintf (str, "dasd");
+	if (first) {
+                len += sprintf (str + len, "%c", first + 'a' - 1 );
 	}
-#endif	/* DASD_PARANOIA */ read_ahead[MAJOR_NR] = 8;
-        blk_size[MAJOR_NR] = dasd_blks;
-	hardsect_size[MAJOR_NR] = dasd_secsize;
-	blksize_size[MAJOR_NR] = dasd_blksize;
-	max_sectors[MAJOR_NR] = dasd_maxsecs;
-#ifdef CONFIG_PROC_FS
-	dasd_proc_init ();
-#endif				/* CONFIG_PROC_FS */
-	/* Now scan the device list for DASDs */
-	for (i = 0; i < NR_IRQS; i++) {
-		int irc;	/* Internal return code */
-		irc = probe_for_dasd (i);
-		switch (irc) {
-		case 0:
-			break;
-		case -ENODEV:
-		case -EBUSY:
-			break;
-		case -EMEDIUMTYPE:
-			PRINT_WARN ("DASD not formatted%s\n", "");
+	if (second) {
+                len += sprintf (str + len, "%c", second + 'a' - 1 );
+	}
+        len += sprintf (str + len, "%c", third + 'a' );
+	if (partition) {
+		if (partition > 9) {
+			return -EINVAL;
+		} else {
+			len += sprintf (str + len, "%d", partition);
+	}
+	}
+	str[len] = '\0';
+	return 0;
+}
+
+static void
+dasd_not_oper_handler ( int irq, int status ) {
+        int devno,devindex;
+        dasd_device_t *device;
+        devno = get_devno_by_irq(irq);
+        if ( devno < 0 ) {
+		printk (KERN_WARNING PRINTK_HEADER
+                         "not_oper_handler called on irq %d no devno!\n", irq);
+                return;
+	}
+        printk ( KERN_INFO PRINTK_HEADER
+                 "not_oper_handler called on irq %d devno %04X\n", irq,devno);
+        devindex = devindex_from_devno(devno);
+        device = find_dasd_device(devindex);
+        dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+	}
+
+static int
+dasd_enable_single_volume ( int irq ) {
+        int rc = 0;
+        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                               NULL, 0);
+	printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
+        {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                static wait_queue_head_t wait_queue;
+                init_waitqueue_head(&wait_queue);
+#else
+                static struct wait_queue *wait_queue = NULL;
+#endif /* LINUX_IS_24 */
+                interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
+        }
+        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+                               NULL, 0);
+	return rc;
+}
+
+static int
+dasd_oper_handler ( int irq, devreg_t *devreg ) {
+        int devno;
+        int devindex;
+	int rc;
+        devno = get_devno_by_irq(irq);
+        if ( devno == -ENODEV )
+                return -ENODEV;
+        do {
+                devindex = devindex_from_devno(devno);
+                if ( dasd_autodetect ) {
+                        dasd_add_range(devno,0);
+                } else {
+		return -ENODEV;
+	}
+        } while ( devindex == -ENODEV );
+        rc = dasd_enable_single_volume(irq);
+		return rc;
+	}
+
+/* 
+ * int
+ * dasd_set_device_level (unsigned int irq, int desired_level,
+ *                        dasd_discipline_t * discipline, int flags)
+ */
+
+static int
+dasd_set_device_level (unsigned int irq, int desired_level,
+		       dasd_discipline_t * discipline, int flags)
+{
+	int rc = 0;
+	int devno;
+	int devindex;
+	dasd_device_t *device;
+	int current_level;
+	major_info_t *major_info = NULL;
+	int i, minor;
+	ccw_req_t *cqr = NULL;
+        int ind;
+        dasd_discipline_t *temp;
+        struct gendisk *dd;
+
+	devno = get_devno_by_irq (irq);
+	if (devno < 0) {
+		printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq);
+		return -ENODEV;
+	}
+	devindex = devindex_from_devno (devno);
+	if (devindex < 0) {
+		printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq);
+			return -ENODEV;
+		}
+	device = find_dasd_device (devindex);
+        while ( (major_info = major_info_from_devindex (devindex)) == NULL ) {
+                if ((rc = dasd_register_major (major_info)) > 0) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Registered successfully to another major number: %u\n", rc);
+                } else {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "Couldn't register successfully to another major no\n");
+                        return -ERANGE;
+		}
+		}
+        ind = devindex & (DASD_PER_MAJOR-1);
+        device = major_info->dasd_device[ind];
+        if (!device) {		/* allocate device descriptor */
+                device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+		if (!device) {
+			printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n");
+			goto nomem;
+		}
+		memset (device, 0, sizeof (dasd_device_t));
+                major_info->dasd_device[ind] = device;
+                dasd_device_name (device->name, devindex, 0,NULL);
+	}
+        device->kdev = MKDEV(major_info->gendisk.major,ind << DASD_PARTN_BITS);
+        device->major_info = major_info;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        init_waitqueue_head(&device->wait_q);
+#endif /* KERNEL_VERSION */
+        minor = MINOR(device->kdev);
+	current_level = atomic_read (&device->level);
+	if (desired_level > current_level) {
+		switch (current_level) {
+		case DASD_DEVICE_LEVEL_UNKNOWN:	/* Find a discipline */
+			rc = get_dev_info_by_irq (irq, &device->devinfo);
+			if (rc < 0) {
+				break;
+			}
+                        for ( temp = dasd_disciplines; temp != NULL; temp = temp->next ) {
+                                if ( discipline == NULL || temp == discipline ) {
+                                        if (temp->id_check)
+                                                if (temp->id_check (&device->devinfo))
+                                                        continue;
+                                        if (temp->check_characteristics) {
+                                                if (temp->check_characteristics (device)) 
+                                                        continue;
+	}
+                                        discipline = temp;
+                                        break;
+                                }
+                        }
+			if (discipline && !rc) {
+				printk (KERN_INFO PRINTK_HEADER
+					" devno 0x%04X on subchannel %d (%s) is /dev/%s (%d:%d)\n",
+					devno, irq, discipline->name,
+                                        device->name, major_from_devindex (devindex),
+					(devindex % 64) << DASD_PARTN_BITS);
+		} else {
+				break;
+		}
+			device->discipline = discipline;
+			if (device->discipline->int_handler) {
+                                s390_request_irq_special(irq, 
+                                                         device->discipline->int_handler, 
+                                                         dasd_not_oper_handler,
+                                                         0, 
+                                                         DASD_NAME, 
+                                                         &device->dev_status);
+			}
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_UNKNOWN,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED);
+			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
+				break;
+		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
+			if (device->discipline->init_analysis) {
+				cqr = device->discipline->init_analysis (device);
+                                if (cqr != NULL) {
+                                        dasd_chanq_enq (&device->queue, cqr);
+                                        if (device->discipline->start_IO) {
+                                                long flags;
+                                                s390irq_spin_lock_irqsave (irq, flags);
+                                                device->discipline->start_IO (cqr);
+                                                atomic_compare_and_swap_debug (&device->level,
+                                                                               DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                                               DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
+                                                s390irq_spin_unlock_irqrestore (irq, flags);
+}
+                                }
+                        } else {
+                                atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                               DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
+                        }
+			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+				break;
+		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
+			return -EAGAIN;
+		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:	/* Re-entering here ! */
+                        if (device->discipline->do_analysis) 
+                                if (device->discipline->do_analysis (device))
+					return -ENODEV;
+			switch (device->sizes.bp_block) {
+			case 512:
+			case 1024:
+			case 2048:
+			case 4096:
+				break;
+			default:
+{
+					printk (KERN_INFO PRINTK_HEADER
+						"/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
+						" Did you format the drive?\n",
+						device->name, devno, device->sizes.bp_block);
+					return -EMEDIUMTYPE;
+                        }
+			}
+			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                if (i == 0)
+					major_info->blk_size[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
+				else
+					major_info->blk_size[minor + i] = 0;
+				major_info->hardsect_size[minor + i] = device->sizes.bp_block;
+				major_info->blksize_size[minor + i] = device->sizes.bp_block;
+                                if (major_info->blksize_size[minor + i] < 1024 )
+                                        major_info->blksize_size[minor + i] = 1024;
+                                
+				major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift;	/* FIXME !!! */
+			}
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                                       DASD_DEVICE_LEVEL_ANALYSED);
+                        dd = &major_info->gendisk;
+                        dd->sizes[minor] = ( device->sizes.blocks << 
+                                             device->sizes.s2b_shift) >> 1;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#ifndef MODULE
+                        if ( flags & 0x80 )
+#endif
+#endif /* KERNEL_VERSION */
+                                dasd_partn_detect(devindex);
+			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
+				break;
+		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
+
 			break;
 		default:
-			INTERNAL_CHECK ("probe_for_dasd: unknown rc=%d", irc);
+			printk (KERN_WARNING PRINTK_HEADER
+				"Internal error in " __FILE__ " on line %d."
+				" validate_dasd called from %p with "
+				" desired_level = %d, current_level =%d"
+				" Pls send this message and your System.map to"
+				" linux390@de.ibm.com\n",
+				__LINE__, __builtin_return_address (0),
+				desired_level, current_level);
+			break;
+		}
+	} else 	if (desired_level < current_level) {		/* donwgrade device status */
+		switch (current_level) {
+		case DASD_DEVICE_LEVEL_PARTITIONED:	/* Fallthrough ?? */
+                        /* delete the partition information */
+			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                struct hd_struct *p = &major_info->gendisk.part[minor+i];
+                                p->start_sect = 0;
+                                p->nr_sects = 0;
+                                p->type = 0;
+                        }
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_PARTITIONED,
+                                                       DASD_DEVICE_LEVEL_ANALYSED);
+			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
+				break;
+		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSED,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
+                        if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
+                                break;
+		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
+			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                major_info->blk_size[minor] = 0;
+                                major_info->hardsect_size[minor + i] = 0;
+                                major_info->blksize_size[minor + i] = 0;
+                                major_info->max_sectors[minor + i] = 0;
+			}
+                        memset( &device->sizes,0,sizeof(dasd_sizes_t));
+                        atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
+			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+				break;
+		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED);
+			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
+				break;
+		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
+                        if (device->discipline->int_handler) {
+                                free_irq (irq, &device->dev_status);
+			}
+			device->discipline = NULL;
+			atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                       DASD_DEVICE_LEVEL_UNKNOWN);
+			if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
+				break;
+		case DASD_DEVICE_LEVEL_UNKNOWN:	
+                        break;
+		default:
+			printk (KERN_WARNING PRINTK_HEADER
+				"Internal error in " __FILE__ " on line %d."
+				" validate_dasd called from %p with "
+				" desired_level = %d, current_level =%d"
+				" Pls send this message and your System.map to"
+				" linux390@de.ibm.com\n",
+				__LINE__, __builtin_return_address (0),
+				desired_level, current_level);
 			break;
 		}
 	}
-	FUNCTION_CONTROL ("detection loop completed %s partn check...\n", "");
-/* Finally do the genhd stuff */
-	dd_gendisk.next = gendisk_head;
-	gendisk_head = &dd_gendisk;
-	dasd_information = dasd_info;	/* to enable genhd to know about DASD */
-        tod_wait (1000000);
-
-	/* wait on root filesystem before detecting partitions */
-	if (MAJOR (ROOT_DEV) == DASD_MAJOR) {
-		int count = 10;
-		i = DEVICE_NR (ROOT_DEV);
-		if (dasd_info[i] == NULL) {
-			panic ("root device not accessible\n");
-		}
-                while ((atomic_read (&dasd_info[i]->status) !=
-                        DASD_INFO_STATUS_FORMATTED) &&
-                       count ) {
-                        PRINT_INFO ("Waiting on root volume...%d seconds left\n", count);
-			tod_wait (1000000);
-			count--;
-		}
-		if (count == 0) {
-			panic ("Waiting on root volume...giving up!\n");
-		}
-	}
-	for (i = 0; i < DASD_MAX_DEVICES; i++) {
-		if (dasd_info[i]) {
-			if (atomic_read (&dasd_info[i]->status) ==
-			    DASD_INFO_STATUS_FORMATTED) {
-				dasd_partn_detect (i);
-			} else {	/* start kernel thread for devices not ready now */
-				kernel_thread (dasd_partn_detect, (void *) i,
-                                               CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (rc) {
+		goto exit;
+	}
+      nomem:
+	rc = -ENOMEM;
+      exit:
+	return 0;
+}
+
+
+/* SECTION: Procfs stuff */
+typedef struct {
+        char *data;
+        int len;
+} tempinfo_t;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct proc_dir_entry *dasd_proc_root_entry = NULL;
+#else
+static struct proc_dir_entry dasd_proc_root_entry =
+{
+	low_ino:0,
+	namelen:4,
+	name:"dasd",
+	mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+	nlink:1,
+	uid:0,
+	gid:0,
+	size:0
+};
+#endif /* KERNEL_VERSION */
+static struct proc_dir_entry* dasd_devices_entry;
+
+
+static int
+dasd_devices_open (struct inode* inode, struct file*  file )
+{
+	int rc = 0;
+	int size = 0;
+	int len = 0;
+	major_info_t * temp = dasd_major_info;
+        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;
+	}
+        while ( temp ) {
+                int i;
+                for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
+                        dasd_device_t *device = temp->dasd_device[i];
+                        if ( device ) {
+				size+=128;
+			}
+		}
+		temp = temp->next;
+	}
+	temp = dasd_major_info;
+	info->data=(char*)vmalloc(size); /* FIXME! determine space needed in a better way */
+        if( size && info->data == NULL ) {
+		printk ( KERN_WARNING "No memory available for data\n");
+                vfree ( info );
+		return -ENOMEM;
+	}
+	while ( temp ) {
+		int i;
+		for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
+			dasd_device_t *device = temp->dasd_device[i];
+			if ( device ) {
+				len += sprintf ( info->data + len,
+						 "%04X(%s) at (%d:%d) is %7s:",
+						 device->devinfo.devno,
+						 device->discipline ? device->discipline->name : "none",
+						 temp->gendisk.major,i<<DASD_PARTN_BITS,
+						 device->name);
+                                switch ( atomic_read(&device->level) ) {
+                                case DASD_DEVICE_LEVEL_UNKNOWN:
+                                        len += sprintf ( info->data + len,"unknown\n");
+                                        break;
+                                case DASD_DEVICE_LEVEL_RECOGNIZED:
+                                        len += sprintf ( info->data + len,"passive");
+                                        len += sprintf ( info->data + len," at blocksize: %d, %d blocks, %d MB\n",
+                                                         device->sizes.bp_block,
+                                                         device->sizes.blocks,
+                                                         ((device->sizes.bp_block>>9)*device->sizes.blocks)>>11);
+                                        break;
+                                case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
+                                        len += sprintf ( info->data + len,"busy   \n");
+                                        break;
+				case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
+					len += sprintf ( info->data + len,"n/f    \n");
+					break;
+                                case DASD_DEVICE_LEVEL_ANALYSED:
+                                        len += sprintf ( info->data + len,"active ");
+                                        len += sprintf ( info->data + len," at blocksize: %d, %d blocks, %d MB\n",
+                                                         device->sizes.bp_block,
+                                                         device->sizes.blocks,
+                                                         ((device->sizes.bp_block>>9)*device->sizes.blocks)>>11);
+                                        break;
+                                default:
+                                        len += sprintf ( info->data + len,"no stat\n");
+                                        break;
+                                }
 			}
 		}
+		temp = temp->next;
 	}
+        info->len=len;
 	return rc;
 }
 
-#ifdef MODULE
+#define MIN(a,b) ((a)<(b)?(a):(b))
 
-int
-init_module (void)
+static ssize_t 
+dasd_devices_read (  struct  file *file, char*   user_buf,  size_t  user_len, loff_t* offset )
 {
-	int rc = 0;
+        loff_t len;
+        tempinfo_t* p_info = (tempinfo_t*)file->private_data;
 
-	PRINT_INFO ("Initializing module\n");
-	rc = dasd_parse_module_params ();
-	if (rc == 0) {
-		PRINT_INFO ("module parameters parsed successfully\n");
-	} else {
-		PRINT_WARN ("parsing parameters returned rc=%d\n", rc);
+        if(*offset >= p_info->len)
+        {
+                return 0; /* EOF */
+	}
+        else
+        {
+                len = MIN(user_len, (p_info->len - *offset));
+                copy_to_user(user_buf, &(p_info->data[*offset]), len);
+                (*offset) += len;
+                return len;  /* number of bytes "read" */
 	}
-	rc = dasd_init ();
-	if (rc == 0) {
-		PRINT_INFO ("module initialized successfully\n");
-	} else {
-		PRINT_WARN ("initializing module returned rc=%d\n", rc);
+}
+
+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);
 	}
-	FUNCTION_EXIT ("init_module");
 	return rc;
 }
 
+
+static struct file_operations dasd_devices_file_ops =
+{
+  NULL,          /* lseek */
+  dasd_devices_read,  /* read */
+  NULL, /* dasd_devices_write, */   /* write */
+  NULL,          /* readdir */
+  NULL,          /* select */
+  NULL,          /* ioctl */
+  NULL,          /* mmap */
+  dasd_devices_open,    /* open */
+  NULL,          /* flush */
+  dasd_devices_close,   /* close */
+};
+
+static struct inode_operations dasd_devices_inode_ops =
+{
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+  default_file_ops: &dasd_devices_file_ops /* file ops */
+#endif /* LINUX_IS_24 */
+};
+
+void
+dasd_proc_init (void)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        dasd_proc_root_entry = create_proc_entry("dasd", 
+                                                 S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR,
+                                                 &proc_root);
+        dasd_devices_entry = create_proc_entry("devices", 
+                                               S_IFREG | S_IRUGO | S_IWUSR,
+                                               dasd_proc_root_entry);
+#else
+	proc_register (&proc_root, &dasd_proc_root_entry);
+	dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
+        if ( dasd_devices_entry) {
+                memset(dasd_devices_entry, 0, sizeof(struct proc_dir_entry));
+                dasd_devices_entry->name     = "devices";
+                dasd_devices_entry->namelen  = strlen("devices");
+                dasd_devices_entry->low_ino  = 0;
+                dasd_devices_entry->mode     = (S_IFREG | S_IRUGO | S_IWUSR);
+                dasd_devices_entry->nlink    = 1;
+                dasd_devices_entry->uid      = 0;
+                dasd_devices_entry->gid      = 0;
+                dasd_devices_entry->size     = 0;
+                dasd_devices_entry->get_info = NULL;
+                dasd_devices_entry->ops      = &dasd_devices_inode_ops;
+                proc_register(&dasd_proc_root_entry, dasd_devices_entry);
+        }
+#endif /* LINUX_IS_24 */
+}
+
 void
-cleanup_module (void)
+dasd_proc_cleanup (void)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        remove_proc_entry("devices", dasd_proc_root_entry);
+        remove_proc_entry("dasd", &proc_root);
+#else
+        proc_unregister(&dasd_proc_root_entry, dasd_devices_entry->low_ino);
+	kfree(dasd_devices_entry);
+	proc_unregister (&proc_root, dasd_proc_root_entry.low_ino);
+#endif /* LINUX_IS_24 */
+}
+
+/* SECTION: Initializing the driver */
+
+int
+dasd_init (void)
 {
 	int rc = 0;
-	struct gendisk *genhd = gendisk_head, *prev = NULL;
+	int irq;
+	int j;
+	major_info_t *major_info;
+        dasd_range_t *range;
+
+	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
+        genhd_dasd_name = dasd_device_name;
+#ifndef MODULE
+        dasd_split_parm_string(dasd_parm_string);
+#endif /* ! MODULE */
+        dasd_parse(dasd);
+
+        dasd_proc_init();
+        dasd_init_emergency_req();
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        init_waitqueue_head(&watcher_queue);
+        spin_lock_init(&cq_lock);
+#endif /* LINUX_IS_24 */
+
+	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+		if ((rc = dasd_register_major (major_info)) > 0) {
+			printk (KERN_INFO PRINTK_HEADER
+				"Registered successfully to major no %u\n", major_info->gendisk.major);
+		} else {
+			printk (KERN_WARNING PRINTK_HEADER
+				"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
+	}
+		}
+        
+#ifdef CONFIG_DASD_ECKD
+	rc = dasd_eckd_init ();
+	if (rc==0)  {
+		printk (KERN_INFO PRINTK_HEADER
+			"Registered ECKD discipline successfully\n");
+	}
+#endif				/* CONFIG_DASD_ECKD */
+#ifdef CONFIG_DASD_FBA
+	rc = dasd_fba_init ();
+	if (rc == 0) {
+		printk (KERN_INFO PRINTK_HEADER
+			"Registered FBA discipline successfully\n");
+	}
+#endif				/* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_MDSK
+	rc = dasd_diag_init ();
+	if (rc == 0)  {
+		printk (KERN_INFO PRINTK_HEADER
+			"Registered MDSK discipline successfully\n");
+	}
+#endif				/* CONFIG_DASD_MDSK */
+	rc = 0;
+	for (range = dasd_range_head; range; range= range->next) {
+		for (j = range->from; j <= range->to; j++) {
+			irq = get_irq_by_devno (j);
+			if (irq >= 0)
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+						       NULL, 0);
+	}
+			}
+        if ( dasd_autodetect ) {
+                for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) {
+                        int devno = get_devno_by_irq(irq);
+                        int index = devindex_from_devno(devno);
+                        if ( index == -ENODEV ) { /* not included in ranges */
+                                dasd_add_range (devno,0);
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+						       NULL, 0);
+		}
+	}
+}
+	printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                static wait_queue_head_t wait_queue;
+                init_waitqueue_head(&wait_queue);
+#else
+                static struct wait_queue *wait_queue = NULL;
+#endif /* LINUX_IS_24 */
+                interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
+	}
+	for (range = dasd_range_head; range; range= range->next) {
+		for (j = range->from; j <= range->to; j++) {
+			irq = get_irq_by_devno (j);
+			if (irq >= 0) {
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+						       NULL, 0);
+	}
+		}
+	}
 
-	PRINT_INFO ("trying to unload module \n");
+	printk (KERN_INFO PRINTK_HEADER "initialization completed\n");
+	return rc;
+}
 
-	/* unregister gendisk stuff */
-	for (genhd = gendisk_head; genhd; prev = genhd, genhd = genhd->next) {
-		if (genhd == dd_gendisk) {
-			if (prev)
-				prev->next = genhd->next;
-			else {
-				gendisk_head = genhd->next;
+void
+cleanup_dasd (void)
+{
+        int j,rc=0;
+        int irq;
+        major_info_t *major_info;
+        dasd_range_t *range,*next;
+        dasd_devreg_t *reg;
+
+	printk (KERN_INFO PRINTK_HEADER "shutting down\n");
+
+        dasd_proc_cleanup();
+
+	for (range = dasd_range_head; range; range= range->next) {
+		for (j = range->from; j <= range->to; j++) {
+			irq = get_irq_by_devno (j);
+			if (irq >= 0) {
+				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
+						       NULL, 0);
+                                kfree(find_dasd_device(devindex_from_devno(j)));
 			}
-			break;
 		}
 	}
-	/* unregister devices */
-	for (i = 0; i = DASD_MAX_DEVICES; i++) {
-		if (dasd_info[i])
-			dasd_unregister_dasd (i);
+	for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+		if ((rc = dasd_unregister_major (major_info)) == 0) {
+			printk (KERN_INFO PRINTK_HEADER
+				"Unregistered successfully from major no %u\n", major_info->gendisk.major);
+		} else {
+			printk (KERN_WARNING PRINTK_HEADER
+				"Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major,rc);
+		}
+	}
+        dasd_cleanup_emergency_req();
+        
+        range = dasd_range_head;
+        while ( range ) {
+                next = range -> next;
+                kfree (range);
+                if ( next == NULL )
+			break;
+                else
+                        range = next;
+		}
+        dasd_range_head = NULL;
+
+        while ( dasd_devreg_head ) {
+                reg = dasd_devreg_head->next;
+                kfree ( dasd_devreg_head );
+                dasd_devreg_head = reg;
+	}
+	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
 	}
 
-	if (rc == 0) {
-		PRINT_INFO ("module unloaded successfully\n");
-	} else {
-		PRINT_WARN ("module unloaded with errors\n");
+#ifdef MODULE
+int
+init_module ( void )
+{
+        int rc=0;
+        return dasd_init(); 
+        return rc;
 	}
+
+void 
+cleanup_module ( void ) 
+{
+        cleanup_dasd();
+        return;
 }
-#endif				/* MODULE */
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd.h linux/drivers/s390/block/dasd.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd.h	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,10 @@
+ccw_req_t *default_erp_action (ccw_req_t *);
+int default_erp_postaction ( ccw_req_t *, int);
+int dasd_start_IO (ccw_req_t * cqr);
+void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t * dasd_alloc_request (char *, int , int ) ;
+void dasd_free_request(ccw_req_t *);
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
+
+
+
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_3370_erp.c linux/drivers/s390/block/dasd_3370_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_3370_erp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_3370_erp.c	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,105 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3370_erp.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#define PRINTK_HEADER "dasd_erp(3370)"
+#endif /* PRINTK_HEADER */
+
+/*
+ * DASD_3370_ERP_EXAMINE 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recover error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+ *   '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_t
+dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+{
+	char *sense = stat->ii.sense.data;
+
+	/* check for successful execution first */
+	if ( stat->cstat == 0x00 &&
+             stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))             
+                return dasd_era_none;
+        if ( sense[0] & 0x80 ) { /* CMD reject */
+                return dasd_era_fatal;
+        }
+        if ( sense[0] & 0x40 ) { /* Drive offline */
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x20 ) { /* Bus out parity */
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x10 ) { /* equipment check */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x08 ) { /* data check */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x04 ) { /* overrun */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[1] & 0x40 ) { /* invalid blocksize */
+                return dasd_era_fatal;
+        }
+        if ( sense[1] & 0x04 ) { /* file protected */
+                return dasd_era_recover;
+        }
+        if ( sense[1] & 0x01 ) { /* operation incomplete */
+                return dasd_era_recover;
+        }
+        if ( sense[2] & 0x80 ) { /* check data erroor */
+                return dasd_era_recover;
+        }
+        if ( sense[2] & 0x10 ) { /* Env. data present */
+                return dasd_era_recover;
+        }
+        /* examine the 24 byte sense data */
+        return dasd_era_recover;
+        
+}				/* END dasd_3370_erp_examine */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_3990_erp.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_3990_erp.c	Mon Dec  3 22:09:50 2001
@@ -6,10 +6,13 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
-#include "dasd_erp.h"
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(3990)"
+#endif /* PRINTK_HEADER */
 
 /*
  * DASD_3990_ERP_EXAMINE_32 
@@ -95,7 +98,7 @@
  *   dasd_era_recover   for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine (cqr_t * cqr, devstat_t * stat)
+dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 
 	char *sense = stat->ii.sense.data;
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_9336_erp.c linux/drivers/s390/block/dasd_9336_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_9336_erp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_9336_erp.c	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,64 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9336_erp.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#define PRINTK_HEADER "dasd_erp(9336)"
+#endif /* PRINTK_HEADER */
+
+/*
+ * DASD_9336_ERP_EXAMINE 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recover error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+ *   '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_t
+dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+{
+	char *sense = stat->ii.sense.data;
+
+	/* check for successful execution first */
+	if (stat->cstat == 0x00 &&
+	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+                return dasd_era_none;
+        
+        /* examine the 24 byte sense data */
+        return dasd_era_recover;
+        
+}				/* END dasd_9336_erp_examine */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_9343_erp.c linux/drivers/s390/block/dasd_9343_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_9343_erp.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_9343_erp.c	Mon Dec  3 22:09:50 2001
@@ -5,13 +5,16 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
-#include "dasd_erp.h"
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(9343)"
+#endif /* PRINTK_HEADER */
 
 dasd_era_t
-dasd_9343_erp_examine (cqr_t * cqr, devstat_t * stat)
+dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_ccwstuff.c linux/drivers/s390/block/dasd_ccwstuff.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_ccwstuff.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_ccwstuff.c	Wed Dec 31 16:00:00 1969
@@ -1,546 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_ccwstuff.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <asm/spinlock.h>
-#include <linux/dasd.h>
-#include <asm/atomic.h>
-
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd_ccw:"
-#define MAX_CP_POWER 9		/* Maximum allowed index */
-#define CP_PER_PAGE_POWER 9	/* Maximum index, fitting on page */
-
-#define get_free_pages __get_free_pages
-
-/* Stuff for the handling task_list */
-dasd_chanq_t *cq_head = NULL;	/* head of task_list */
-atomic_t chanq_tasks;
-
-/* Array of freelists for the channel programs' -space */
-static ccw1_t *ccwarea[CP_PER_PAGE_POWER + 1] =
-{NULL,};
-
-/* array of pages retrieved for internal use */
-#define MAX_DASD_PAGES 64
-static int dasd_page_count = 0;
-static long dasd_page[MAX_DASD_PAGES];
-
-#ifdef __SMP__
-static spinlock_t ccw_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for ccwareas */
-static spinlock_t cq_lock=SPIN_LOCK_UNLOCKED;	/* spinlock for cq_head */
-#endif				/* __SMP__ */
-
-void
-ccwarea_enq (int index, ccw1_t * area)
-{
-	FUNCTION_ENTRY ("ccwarea_enq");
-#if DASD_PARANOIA > 2
-	if (!area) {
-		INTERNAL_CHECK ("zero area %s\n", "");
-	}
-	if (index > CP_PER_PAGE_POWER) {
-		INTERNAL_CHECK ("index too large %d\n", index);
-	}
-#endif
-	*(ccw1_t **) area = ccwarea[index];
-	ccwarea[index] = area;
-	FUNCTION_EXIT ("ccwarea_enq");
-	return;
-}
-
-ccw1_t *
-ccwarea_deq (int index)
-{
-	ccw1_t *cp;
-	FUNCTION_ENTRY ("ccwarea_deq");
-#if DASD_PARANOIA > 2
-	if (index > CP_PER_PAGE_POWER) {
-		INTERNAL_CHECK ("index too large %d\n", index);
-	}
-#endif
-	cp = ccwarea[index];
-	ccwarea[index] = *(ccw1_t **) ccwarea[index];
-#if DASD_PARANOIA > 2
-	if (!cp) {
-		INTERNAL_CHECK ("returning NULL %s\n", "");
-	}
-#endif
-	FUNCTION_EXIT ("ccwarea_deq");
-	return cp;
-}
-
-ccw1_t *
-request_cpa (int index)
-{
-	ccw1_t *freeblk;
-	FUNCTION_ENTRY ("request_cpa");
-	if (index > MAX_CP_POWER) {
-		INTERNAL_ERROR ("index too large %d\n", index);
-		freeblk = NULL;
-		goto exit;
-	}
-	if (index > CP_PER_PAGE_POWER) {
-		int pc = 1 << (index - CP_PER_PAGE_POWER);
-		do {
-			freeblk = (ccw1_t *) get_free_pages (GFP_ATOMIC, index - CP_PER_PAGE_POWER);
-			if (dasd_page_count + pc >= MAX_DASD_PAGES) {
-				PRINT_WARN ("Requesting too many pages...");
-			} else {
-				int i;
-				for (i = 0; i < pc; i++)
-					dasd_page[dasd_page_count++] =
-						(long) freeblk + i * PAGE_SIZE;
-			}
-			FUNCTION_CONTROL ("requesting index %d", index);
-			if ( ! freeblk ) {
-				panic ("No memory received\n");
-			}
-		} while (!freeblk);
-		memset(freeblk,0,PAGE_SIZE<<(index-CP_PER_PAGE_POWER));
-		goto exit;
-	}
-	while (ccwarea[index] == NULL) {
-		ccw1_t *blk;
-		if (index == CP_PER_PAGE_POWER) {
-			do {
-				blk = (ccw1_t *) get_free_page (GFP_ATOMIC);
-				if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-					PRINT_WARN ("Requesting too many pages...");
-				} else {
-					dasd_page[dasd_page_count++] =
-						(long) blk;
-				}
-				if (blk == NULL) {
-					PRINT_WARN ("Can't allocate page!\n");
-				}
-			} while ( ! blk );
-			memset(blk,0,PAGE_SIZE);
-			ccwarea_enq (CP_PER_PAGE_POWER, blk);
-			continue;
-		}
-		blk = request_cpa (index + 1);
-#if DASD_PARANOIA > 1
-		if (!blk) {
-			PRINT_WARN ("retrieved NULL");
-		}
-#endif				/* DASD_PARANOIA */
-		ccwarea_enq (index, blk);
-		ccwarea_enq (index, blk + (1 << index));
-	}
-#if DASD_PARANOIA > 2
-	if (!ccwarea[index]) {
-		INTERNAL_ERROR ("ccwarea is NULL\n%s", "");
-	}
-#endif				/* DASD_PARANOIA */
-
-	freeblk = ccwarea_deq (index);
-#if DASD_PARANOIA > 1
-	if (!freeblk) {
-		INTERNAL_ERROR ("freeblk is NULL\n%s", "");
-	}
-#endif				/* DASD_PARANOIA */
-      exit:
-	return freeblk;
-}
-
-ccw1_t *
-request_cp (int size)
-{
-	ccw1_t *freeblk;
-	int index;
-	int blksize;
-	/* Determine the index of ccwarea to look at */
-	for (index = 0, blksize = 1;
-	     size > blksize;
-	     index++, blksize = blksize << 1) {
-	}
-	if (index > MAX_CP_POWER) {
-		INTERNAL_ERROR ("index too large %d\n", index);
-	}
-	spin_lock (&ccw_lock);
-	freeblk = request_cpa (index);
-	spin_unlock (&ccw_lock);
-	if (freeblk == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No way to deliver free ccw space\n");
-	}
-	return freeblk;
-}
-
-void
-release_cp (int size, ccw1_t * area)
-{
-	int index;
-	int blksize;
-	/* Determine the index of ccwarea to look at */
-	for (index = 0, blksize = 1;
-	     size > blksize;
-	     index++, blksize = blksize << 1) {
-	}
-	if (index > MAX_CP_POWER) {
-		INTERNAL_ERROR ("index too large %d\n", index);
-	} else if (index > CP_PER_PAGE_POWER) {
-		free_pages ((unsigned long) area,
-			    index - CP_PER_PAGE_POWER);
-		INTERNAL_CHECK ("large index used: %d\n", index);
-	} else {
-		spin_lock (&ccw_lock);
-		ccwarea_enq (index, area);
-		spin_unlock (&ccw_lock);
-	}
-	return;
-}
-
-/* ---------------------------------------------------------- */
-
-static cqr_t *cqrp = NULL;
-#ifdef __SMP__
-static spinlock_t cqr_lock=SPIN_LOCK_UNLOCKED;
-#endif				/* __SMP__ */
-
-void
-cqf_enq (cqr_t * cqf)
-{
-	*(cqr_t **) cqf = cqrp;
-	cqrp = cqf;
-}
-
-cqr_t *
-cqf_deq (void)
-{
-	cqr_t *cqr = cqrp;
-	cqrp = *(cqr_t **) cqrp;
-	return cqr;
-}
-
-cqr_t *
-request_cq (void)
-{
-	cqr_t *cqr = NULL;
-	int i;
-	cqr_t *area;
-
-	spin_lock (&cqr_lock);
-	while (cqrp == NULL) {
-		do {
-			area = (cqr_t *) get_free_page (GFP_ATOMIC);
-			if (area == NULL) {
-				printk (KERN_WARNING PRINTK_HEADER
-					"No memory for chanq area\n");
-			}
-		} while ( ! area );
-		memset(area,0,PAGE_SIZE);
-		if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-			PRINT_WARN ("Requesting too many pages...");
-		} else {
-			dasd_page[dasd_page_count++] =
-				(long) area;
-		}
-		for (i = 0; i < 4096 / sizeof (cqr_t); i++) {
-				cqf_enq (area + i);
-		}
-	}
-	cqr = cqf_deq ();
-	spin_unlock (&cqr_lock);
-	return cqr;
-}
-
-void
-release_cq (cqr_t * cqr)
-{
-	spin_lock (&cqr_lock);
-	cqf_enq (cqr);
-	spin_unlock (&cqr_lock);
-	return;
-}
-
-/* ---------------------------------------------------------- */
-
-static erp_t *erpp = NULL;
-#ifdef __SMP__
-static spinlock_t erp_lock = SPIN_LOCK_UNLOCKED;
-#endif				/* __SMP__ */
-
-void
-erf_enq (erp_t * cqf)
-{
-	*(erp_t **) cqf = erpp;
-	erpp = cqf;
-}
-
-erp_t *
-erf_deq (void)
-{
-	erp_t *erp = erpp;
-	erpp = *(erp_t **) erpp;
-	return erp;
-}
-
-erp_t *
-request_er (void)
-{
-	erp_t *erp = NULL;
-	int i;
-	erp_t *area;
-
-	spin_lock (&erp_lock);
-	while (erpp == NULL) {
-		do {
-			area = (erp_t *) get_free_page (GFP_ATOMIC);
-			if (area == NULL) {
-				printk (KERN_WARNING PRINTK_HEADER
-					"No memory for chanq area\n");
-			}
-		} while (!area);
-		memset (area, 0, PAGE_SIZE);
-		if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-			PRINT_WARN ("Requesting too many pages...");
-		} else {
-			dasd_page[dasd_page_count++] =
-			    (long) area;
-		}
-		for (i = 0; i < 4096 / sizeof (erp_t); i++) {
-			erf_enq (area + i);
-		}
-	}
-	erp = erf_deq ();
-	spin_unlock (&erp_lock);
-	return erp;
-}
-
-void
-release_er (erp_t * erp)
-{
-	spin_lock (&erp_lock);
-	erf_enq (erp);
-	spin_unlock (&erp_lock);
-	return;
-}
-
-/* ----------------------------------------------------------- */
-cqr_t *
-request_cqr (int cpsize, int datasize)
-{
-	cqr_t *cqr = NULL;
-	cqr = request_cq ();
-	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER __FILE__
-			"No memory for chanq request\n");
-		goto exit;
-	}
-	memset (cqr, 0, sizeof (cqr_t));
-	cqr -> magic = DASD_MAGIC;
-	if (cpsize) {
-		cqr->cpaddr = request_cp (cpsize);
-		if (cqr->cpaddr == NULL) {
-			printk (KERN_WARNING PRINTK_HEADER __FILE__
-				"No memory for channel program\n");
-			goto nocp;
-		}
-		cqr->cplength = cpsize;
-	}
-	if (datasize) {
-		do {
-			cqr->data = (char *) kmalloc (datasize, GFP_ATOMIC);
-			if (cqr->data == NULL) {
-				printk (KERN_WARNING PRINTK_HEADER __FILE__
-					"No memory for cqr data area\n");
-			}
-		} while (!cqr->data);
-		memset (cqr->data,0,datasize);
-	}
-	goto exit;
-      nocp:
-	release_cq (cqr);
-	cqr = NULL;
-      exit:
-	return cqr;
-}
-
-int
-release_cqr (cqr_t * cqr)
-{
-	int rc = 0;
-	if (cqr == NULL) {
-		rc = -ENOENT;
-		return rc;
-	}
-	if (cqr->data) {
-		kfree (cqr->data);
-	}
-	if (cqr->dstat) {
-		kfree (cqr->dstat);
-	}
-	if (cqr->cpaddr) {
-		release_cp (cqr->cplength, cqr->cpaddr);
-	}
-	cqr -> magic = dasd_MAGIC;
-	release_cq (cqr);
-	return rc;
-}
-
-/* ----------------------------------------------------------- */
-erp_t *
-allloc_erp (erp_t * erp, int cpsize, int datasize)
-{
-	if (cpsize) {
-		erp->cqr.cpaddr = request_cp (cpsize);
-		if (erp->cqr.cpaddr == NULL) {
-			printk (KERN_WARNING PRINTK_HEADER __FILE__
-				"No memory for channel program\n");
-			goto nocp;
-		}
-		erp->cqr.cplength = cpsize;
-	}
-	if (datasize) {
-		do {
-			erp->cqr.data = (char *) kmalloc (datasize, GFP_ATOMIC);
-			if (erp->cqr.data == NULL) {
-				printk (KERN_WARNING PRINTK_HEADER __FILE__
-					"No memory for ERP data area\n");
-			}
-		} while (!erp->cqr.data);
-		memset (erp->cqr.data, 0, datasize);
-	}
-	goto exit;
-      nocp:
-	release_er (erp);
-	erp = NULL;
-      exit:
-	return erp;
-}
-
-int
-release_erp (erp_t * erp)
-{
-	int rc = 0;
-	if (erp == NULL) {
-		rc = -ENOENT;
-		return rc;
-	}
-	if (erp->cqr.data) {
-		kfree (erp->cqr.data);
-	}
-	if (erp->cqr.dstat) {
-		kfree (erp->cqr.dstat);
-	}
-	if (erp->cqr.cpaddr) {
-		release_cp (erp->cqr.cplength, erp->cqr.cpaddr);
-	}
-	erp->cqr.magic = dasd_MAGIC;
-	release_er (erp);
-	return rc;
-}
-
-/* -------------------------------------------------------------- */
-void
-dasd_chanq_enq (dasd_chanq_t * q, cqr_t * cqr)
-{
-	if (q->head != NULL) {
-		q->tail->next = cqr;
-	} else
-		q->head = cqr;
-	cqr->next = NULL;
-	q->tail = cqr;
-	q->queued_requests ++;
-	ACS (cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
-	}
-
-void
-dasd_chanq_enq_head (dasd_chanq_t * q, cqr_t * cqr)
-{
-	cqr->next = q->head;
-	q->head = cqr;
-	if (q->tail == NULL)
-		q->tail = cqr;
-	q->queued_requests++;
-	ACS (cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
-}
-
-int
-dasd_chanq_deq (dasd_chanq_t * q, cqr_t * cqr)
-{
-	cqr_t *prev;
-
-	if (cqr == NULL)
-		return -ENOENT;
-	if (cqr == (cqr_t *) q->head) {
-		q->head = cqr->next;
-		if (q->head == NULL)
-			q->tail = NULL;
-	} else {
-		prev = (cqr_t *) q->head; 
-		while (prev && prev->next != cqr)
-			prev = prev->next;
-		if (prev == NULL)
-			return -ENOENT;
-		prev->next = cqr->next;
-		if (prev->next == NULL)
-			q->tail = prev;
-	}
-	cqr->next = NULL;
-	q->queued_requests --;
-	if (cqr->magic == ERP_MAGIC)
-		return release_erp ((erp_t *) cqr);
-	else
-	return release_cqr(cqr);
-}
-
-/* -------------------------------------------------------------------------- */
-void
-cql_enq_head (dasd_chanq_t * q)
-{
-	if (q == NULL) {
-		INTERNAL_ERROR ("NULL queue passed%s\n", "");
-		return;
-	}
-	if (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE) {
-		PRINT_WARN("Queue already active");
-		return;
-	}
-	spin_lock(&cq_lock);
-	atomic_set_mask(DASD_CHANQ_ACTIVE,&q->flags);
-	q->next_q = cq_head;
-	cq_head = q;
-	spin_unlock(&cq_lock);
-}
-
-void
-cql_deq (dasd_chanq_t * q)
-{
-	dasd_chanq_t *c;
-
-        if (cq_head == NULL) {
-                INTERNAL_ERROR ("Channel queue is empty%s\n", "");
-		return;
-	}
-	if (q == NULL) {
-		INTERNAL_ERROR ("NULL queue passed%s\n", "");
-		return;
-	}
-	spin_lock(&cq_lock);
-	if (! (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE)) {
-		PRINT_WARN("Queue not active\n");
-	} else if (cq_head == q) {
-		cq_head = q->next_q;
-	} else {
-		c = cq_head;
-		while (c->next_q && c->next_q != q)
-			c = c->next_q;
-		if (c->next_q != q)
-			INTERNAL_ERROR ("Entry not in queue%s\n", "");
-		else
-			c->next_q = q->next_q;
-	}
-	q->next_q = NULL;
-	atomic_clear_mask(DASD_CHANQ_ACTIVE,&q->flags);
-	spin_unlock(&cq_lock);
-}
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_ccwstuff.h linux/drivers/s390/block/dasd_ccwstuff.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_ccwstuff.h	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_ccwstuff.h	Wed Dec 31 16:00:00 1969
@@ -1,11 +0,0 @@
-extern atomic_t chanq_tasks;
-extern dasd_chanq_t *cq_head;
-
-cqr_t *request_cqr (int, int);
-int release_cqr (cqr_t *);
-erp_t *request_er (void);
-int release_er (erp_t *);
-int dasd_chanq_enq (dasd_chanq_t *, cqr_t *);
-int dasd_chanq_deq (dasd_chanq_t *, cqr_t *);
-void cql_enq_head (dasd_chanq_t * q);
-void cql_deq (dasd_chanq_t * q);
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_diag.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_diag.c	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,555 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_diag.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Based on.......: linux/drivers/s390/block/mdisk.c
+ * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <asm/debug.h>
+
+#include <linux/malloc.h>
+#include <linux/hdreg.h>	/* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "dasd.h"
+#include "dasd_diag.h"
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif				/* PRINTK_HEADER */
+#define PRINTK_HEADER DASD_NAME"(diag):"
+
+dasd_discipline_t dasd_diag_discipline;
+
+
+
+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;
+} dasd_diag_private_t;
+
+static __inline__ int
+dia210 (void *devchar)
+{
+	int rc;
+
+	__asm__ __volatile__ ("    lr    2,%1\n"
+                              "    .long 0x83200210\n"
+                              "0:  ipm   %0\n"
+                              "    srl   %0,28"
+                              :"=d" (rc)
+                              :"d" ((void *) __pa (devchar))
+                              :"2");
+	return rc;
+}
+
+static __inline__ int
+dia250 (void *iob, int cmd)
+{
+	int rc;
+
+	__asm__ __volatile__ ("    lr    2,%1\n"
+                              "    lr    3,%2\n"
+                              "    .long 0x83230250\n"
+                              "    lr    %0,3"
+                              :"=d" (rc)
+                              :"d" ((void *) __pa (iob)), "d" (cmd)
+                              :"2", "3");
+	return rc;
+}
+
+static __inline__ int
+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;
+	int rc;
+
+	memset (iib, 0, sizeof (diag_init_io_t));
+
+	iib->dev_nr = device->devinfo.devno;
+	iib->block_size = blocksize;
+	iib->offset = offset;
+	iib->start_block = 0;
+	iib->end_block = size;
+
+	rc = dia250 (iib, INIT_BIO);
+
+	return rc;
+}
+
+static __inline__ int
+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;
+	int rc;
+	
+	memset (iib, 0, sizeof (diag_init_io_t));
+	iib->dev_nr = device->devinfo.devno;
+	rc = dia250 (iib, TERM_BIO);
+	return rc;
+}
+
+int
+dasd_start_diag (ccw_req_t * cqr)
+{
+	int rc;
+	dasd_device_t *device = cqr->device;
+        dasd_diag_private_t *private;
+	diag_rw_io_t *iob;
+
+        private = (dasd_diag_private_t *)device->private;
+	iob = &private->iob;
+
+	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);
+
+	asm volatile ("STCK %0":"=m" (cqr->startclk));
+	rc = dia250 (iob, RW_BIO);
+	if (rc > 8) {
+		PRINT_WARN ("dia250 returned CC %d\n", rc);
+		atomic_compare_and_swap_debug(&cqr->status, 
+                                              CQR_STATUS_QUEUED, 
+                                              CQR_STATUS_ERROR);
+	} else {
+		if ( cqr->expires ) {
+			cqr->expires += cqr->startclk;
+		}
+		atomic_compare_and_swap_debug(&cqr->status, 
+                                              CQR_STATUS_QUEUED, 
+                                              CQR_STATUS_IN_IO);
+                rc = 0;
+	}
+	return rc;
+}
+
+void 
+dasd_ext_handler (struct pt_regs *regs, __u16 code)
+{
+	ccw_req_t *cqr;
+	int ip = S390_lowcore.ext_params;
+	char status = *((char *) S390_lowcore.ext_params + 5);
+        dasd_device_t *device;
+	int done_fast_io = 0;
+        int devno,devindex;
+
+	if (!ip) {		/* no intparm: unsolicited interrupt */
+		printk ( KERN_WARNING PRINTK_HEADER
+			 "caught unsolicited interrupt\n");
+		return;
+	}
+	if (ip & 0x80000001) {
+		printk ( KERN_WARNING PRINTK_HEADER
+			 "caught spurious interrupt with parm %08x\n",
+			 ip);
+		return;
+	}
+	cqr = (ccw_req_t *) ip;
+	device = (dasd_device_t *) cqr->device;
+	devno = device->devinfo.devno;
+	devindex = devindex_from_devno (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_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+	}
+	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%08lX doesn't match"
+			" discipline 0x%08X\n",
+			devno, device->name,
+			major_from_devindex (devindex),
+			devindex << DASD_PARTN_BITS,
+			cqr->magic, *(int *) (&device->discipline->name));
+		return;
+	}
+	asm volatile ("STCK %0":"=m" (cqr->stopclk));
+	switch (status) {
+	case 0x00:
+		atomic_compare_and_swap_debug (&cqr->status, 
+					       CQR_STATUS_IN_IO, 
+					       CQR_STATUS_DONE);
+		atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+					 DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+					 &device->level);
+		if (cqr->next &&
+		    (atomic_read (&cqr->next->status) ==
+		     CQR_STATUS_QUEUED)) {
+			if (dasd_start_diag (cqr->next) == 0) {
+				done_fast_io = 1;
+			}
+		}
+
+		break;
+	case 0x01:
+	case 0x02:
+	case 0x03:
+	default:
+		atomic_compare_and_swap_debug (&cqr->status, 
+					       CQR_STATUS_IN_IO, 
+					       CQR_STATUS_FAILED);
+		atomic_inc (&device->queue.dirty_requests);
+		break;
+	}
+	if (done_fast_io == 0)
+		atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wake_up (&device->wait_q);
+#else
+	if (device->wait_q) {
+		wake_up (&device->wait_q);
+	}
+#endif /* LINUX_VERSION_CODE */
+	dasd_schedule_bh ();
+}
+
+static int
+dasd_diag_check_characteristics (struct 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;
+	long *label;
+        int sb;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+		device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
+		if ( device->private == NULL ) {
+			printk ( KERN_WARNING PRINTK_HEADER
+				 "memory allocation failed for private data\n");
+			return -ENOMEM;
+		}
+        }
+        private = (dasd_diag_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+	
+	rdc_data->dev_nr = device->devinfo.devno;
+	rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
+	
+	if (dia210 (rdc_data) != 0) {
+	  return -ENODEV;
+	}
+	if (rdc_data->vdev_class != DEV_CLASS_FBA &&
+	    rdc_data->vdev_class != DEV_CLASS_ECKD &&
+	    rdc_data->vdev_class != DEV_CLASS_CKD) {
+		return -ENODEV;
+	}
+#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
+	/* Figure out position of label block */
+	if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
+		label_block = 1;
+	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
+		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
+		label_block = 2;
+	} else {
+		return -ENODEV;
+	}
+	private->label = (long *) get_free_page (GFP_KERNEL);
+        label = private->label;	
+	mdsk_term_io (device); /* first terminate all outstanding operations */
+	/* figure out blocksize of device */
+	for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
+                diag_bio_t *bio;
+                diag_rw_io_t *iob = &private ->iob;
+        
+                rc = mdsk_init_io (device, bsize, 0, 64);
+                if (rc > 4) {
+                        continue;
+		}
+                cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0);
+                if ( cqr == NULL ) {
+                        printk ( KERN_WARNING PRINTK_HEADER
+                                 "No memory to allocate initialization request\n");
+                        return -ENOMEM;
+                }
+                bio = (diag_bio_t *) (cqr->cpaddr);
+                memset (bio, 0, sizeof (diag_bio_t));
+                bio->type = MDSK_READ_REQ;
+                bio->block_number = label_block + 1;
+                bio->buffer = __pa (private->label);
+                cqr->device = device;
+                atomic_set (&cqr->status, CQR_STATUS_FILLED);
+                memset (iob, 0, sizeof(diag_rw_io_t));
+                iob->dev_nr      = rdc_data->dev_nr;
+                iob->key         = 0;
+                iob->flags       = 0;
+                iob->block_count = 1;
+                iob->interrupt_params = cqr;
+                iob->bio_list     = virt_to_phys(bio);
+                rc = dia250(iob,RW_BIO);
+                if ( rc == 0 ) {
+                        if (label[3] != bsize) {
+/*                                printk ( KERN_INFO PRINTK_HEADER 
+                                         "%04X mismatching blocksizes disk %d, reserved file %d\n", 
+                                         device->devinfo.devno, bsize, label[3]);
+*/  
+                              return -EINVAL; 
+                        }
+                        if (label[0] != 0xc3d4e2f1) {	/* CMS1 */
+/*                                PRINT_WARN ("volume %04X is not CMS formatted, accessing anyway\n", 
+                                            device->devinfo.devno);
+*/
+                                return -ENODEV;
+                        }
+                        if (label[13] == 0) {
+/*                                PRINT_WARN ("%04X is not reserved, accessing anyway\n",  
+                                  device->devinfo.devno); */
+                                return -ENODEV;
+                        }
+                        
+                        break;
+                }
+		mdsk_term_io (device);
+	}
+	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++;
+
+	return rc;
+}
+
+
+static int
+dasd_diag_do_analysis (struct dasd_device_t *device)
+{
+	int sb;
+        dasd_diag_private_t *private = (dasd_diag_private_t *)device->private;
+
+	long *label = private->label;
+	
+	/* real size of the volume */
+        device->sizes.blocks = label[7];
+	
+        printk ( KERN_INFO PRINTK_HEADER 
+                 "/dev/%s (%04X): capacity (%dkB blks): %dkB\n",
+                 device->name, device->devinfo.devno,
+                 (device->sizes.bp_block>>10),
+		 (device->sizes.blocks<<device->sizes.s2b_shift)>>1);
+	return 0;
+}
+
+
+static int
+dasd_diag_fill_geometry(struct 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:
+                return -EINVAL;
+        }
+	geo->cylinders = cyls;
+	geo->heads = 16;
+	geo->sectors = 128 >> device->sizes.s2b_shift;
+	if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
+		geo->start = 1;
+	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
+		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
+		geo->start = 2;
+	} else {
+		return -EINVAL;
+	}
+        return rc;
+}
+
+static dasd_era_t
+dasd_diag_examine_error  (ccw_req_t *cqr, devstat_t * stat)
+{
+	return dasd_era_fatal;
+}
+
+static dasd_erp_action_fn_t 
+dasd_diag_erp_action ( ccw_req_t * cqr ) 
+{
+        return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_diag_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+	return NULL;
+}
+
+static ccw_req_t *
+dasd_diag_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+	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) {
+		rw_cmd = MDSK_READ_REQ;
+	} else
+	if (req->cmd == WRITE)
+	{
+		rw_cmd = MDSK_WRITE_REQ;
+	}
+	bhct = 0;
+	for (bh = req->bh; bh; bh = bh->b_reqnext) {
+		if (bh->b_size > byt_per_blk)
+			for (size = 0; size < bh->b_size; size += byt_per_blk)
+				bhct++;
+		else
+			bhct++;
+	}
+	/* Build the request */
+        rw_cp = dasd_alloc_request (dasd_diag_discipline.name, 2 * bhct, 0);
+	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) {
+		if (bh->b_size >= byt_per_blk) {
+			memset (bio, 0, sizeof (diag_bio_t));
+			for (size = 0; size < bh->b_size; size += byt_per_blk) {
+				bio->type = rw_cmd;
+				bio->block_number = block + 1;
+				bio->buffer = __pa (bh->b_data + size);
+				bio++;
+				block++;
+			}
+		} else {
+			PRINT_WARN ("Cannot fulfill request smaller than block\n");
+			ccw_free_request (rw_cp);
+			return NULL;
+		}
+	}
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
+	return rw_cp;
+}
+
+static char *
+dasd_diag_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
+{
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        int len;
+        if ( page == NULL ) {
+                return NULL;
+        }
+
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+                        
+
+        return page;
+}
+
+dasd_discipline_t dasd_diag_discipline = {
+	name :                          "DIAG",
+	ebcname :                       "DIAG",
+        check_characteristics:          dasd_diag_check_characteristics,
+        do_analysis:                    dasd_diag_do_analysis,          
+        fill_geometry:                  dasd_diag_fill_geometry,
+        start_IO:                       dasd_start_diag,           
+        examine_error:                  dasd_diag_examine_error,          
+        erp_action:                     dasd_diag_erp_action,             
+        erp_postaction:                 dasd_diag_erp_postaction,         
+        build_cp_from_req:              dasd_diag_build_cp_from_req,      
+        dump_sense:                     dasd_diag_dump_sense,            
+        int_handler:                    dasd_ext_handler            
+};
+
+int
+dasd_diag_init( void ) {
+        int rc = 0;
+        if ( MACHINE_IS_VM ) {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "%s discipline initializing\n", dasd_diag_discipline.name);
+          ASCEBC(dasd_diag_discipline.ebcname,4);
+          ctl_set_bit (0, 9);
+          register_external_interrupt (0x2603, dasd_ext_handler);
+          dasd_discipline_enq(&dasd_diag_discipline);
+        } else {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+          rc = -EINVAL;
+        }
+        return rc;
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_diag.h linux/drivers/s390/block/dasd_diag.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_diag.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_diag.h	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,67 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_diag.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Based on.......: linux/drivers/s390/block/mdisk.h
+ * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
+
+#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	
+
+typedef struct dasd_diag_characteristics_t {
+	u16 dev_nr;
+	u16 rdc_len;
+	u8 vdev_class;
+	u8 vdev_type;
+	u8 vdev_status;
+	u8 vdev_flags;
+	u8 rdev_class;
+	u8 rdev_type;
+	u8 rdev_model;
+	u8 rdev_features;
+} __attribute__ ((packed, aligned (4))) dasd_diag_characteristics_t;
+
+typedef struct diag_bio_t {
+	u8 type;
+	u8 status;
+	u16 spare1;
+	u32 block_number;
+	u32 alet;
+	u32 buffer;
+} __attribute__ ((packed, aligned (8))) diag_bio_t;
+
+typedef struct diag_init_io_t{
+	u16 dev_nr;
+	u16 spare1[11];
+	u32 block_size;
+	u32 offset;
+	u32 start_block;
+	u32 end_block;
+	u32 spare2[6];
+} __attribute__ ((packed, aligned (8))) diag_init_io_t;
+
+
+typedef struct diag_rw_io_t{
+	u16 dev_nr;
+	u16 spare1[11];
+	u8 key;
+	u8 flags;
+	u16 spare2;
+	u32 block_count;
+	u32 alet;
+	u32 bio_list;
+	u32 interrupt_params;
+	u32 spare3[5];
+} __attribute__ ((packed, aligned (8))) diag_rw_io_t;
+
+int dasd_diag_init(void);
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_eckd.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_eckd.c	Mon Dec  3 22:09:50 2001
@@ -3,26 +3,33 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes (starts July 2000)
+ * 07/11/00 Enabled rotational position sensing
  */
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <asm/debug.h>
 
 #include <linux/malloc.h>
-#include <linux/dasd.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#include <asm/ebcdic.h>
 #include <asm/io.h>
-
 #include <asm/irq.h>
 
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
+#include "dasd.h"
+#include "dasd_eckd.h"
+
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eckd):"
+#define PRINTK_HEADER DASD_NAME"(eckd):"
 
 #define ECKD_C0(i) (i->home_bytes)
 #define ECKD_F(i) (i -> formula)
@@ -35,255 +42,45 @@
 #define ECKD_F7(i) (i -> factor7)
 #define ECKD_F8(i) (i -> factor8)
 
-#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-
-#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
+#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_RECORD_ZERO 0x16
-#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
-
+#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
 #define DASD_ECKD_CCW_READ_COUNT 0x12
-#define DASD_ECKD_CCW_READ 0x06
-#define DASD_ECKD_CCW_READ_MT 0x86
-#define DASD_ECKD_CCW_WRITE 0x05
-#define DASD_ECKD_CCW_WRITE_MT 0x85
+#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_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD 0x1d
 #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
 
-typedef
-struct {
-	__u16 cyl;
-	__u16 head;
-} __attribute__ ((packed))
-
-ch_t;
-
-typedef
-struct {
-	__u16 cyl;
-	__u16 head;
-	__u32 sector;
-} __attribute__ ((packed))
-
-chs_t;
-
-typedef
-struct {
-	__u16 cyl;
-	__u16 head;
-	__u8 record;
-} __attribute__ ((packed))
-
-chr_t;
-
-typedef
-struct {
-	__u16 cyl;
-	__u16 head;
-	__u32 sector;
-} geom_t;
-
-typedef struct {
-	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 dev_class;
-		__u8 reserved;
-		unsigned char dev_type[6];
-		unsigned char dev_model[3];
-		unsigned char HDA_manufacturer[3];
-		unsigned char HDA_location[2];
-		unsigned char HDA_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned1;
-	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 reserved[2];
-		unsigned char dev_type[6];
-		unsigned char dev_model[3];
-		unsigned char DASD_manufacturer[3];
-		unsigned char DASD_location[2];
-		unsigned char DASD_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned2;
-	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 reserved[2];
-		unsigned char cont_type[6];
-		unsigned char cont_model[3];
-		unsigned char cont_manufacturer[3];
-		unsigned char cont_location[2];
-		unsigned char cont_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned3;
-	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char token_id:1;
-			unsigned char sno_valid:1;
-			unsigned char subst_sno:1;
-			unsigned char recNED:1;
-			unsigned char emuNED:1;
-			unsigned char reserved:1;
-		} __attribute__ ((packed)) flags;
-		__u8 descriptor;
-		__u8 reserved[2];
-		unsigned char cont_type[6];
-		unsigned char empty[3];
-		unsigned char cont_manufacturer[3];
-		unsigned char cont_location[2];
-		unsigned char cont_seqno[12];
-		__u16 ID;
-	} __attribute__ ((packed)) ned4;
-	unsigned char ned5[32];
-	unsigned char ned6[32];
-	unsigned char ned7[32];
-	struct {
-		struct {
-			unsigned char identifier:2;
-			unsigned char reserved:6;
-		} __attribute__ ((packed)) flags;
-		__u8 selector;
-		__u16 interfaceID;
-		__u32 reserved;
-		__u16 subsystemID;
-		struct {
-			unsigned char sp0:1;
-			unsigned char sp1:1;
-			unsigned char reserved:5;
-			unsigned char scluster:1;
-		} __attribute__ ((packed)) spathID;
-		__u8 unit_address;
-		__u8 dev_ID;
-		__u8 dev_address;
-		__u8 adapterID;
-		__u16 link_address;
-		struct {
-			unsigned char parallel:1;
-			unsigned char escon:1;
-			unsigned char reserved:1;
-			unsigned char ficon:1;
-			unsigned char reserved2:4;
-		} __attribute__ ((packed)) protocol_type;
-		struct {
-			unsigned char PID_in_236:1;
-			unsigned char reserved:7;
-		} __attribute__ ((packed)) format_flags;
-		__u8 log_dev_address;
-		unsigned char reserved2[12];
-	} __attribute__ ((packed)) neq;
-
-} __attribute__ ((packed))
-
-eckd_confdata_t;
-
-typedef
-struct {
-	struct {
-		unsigned char perm:2;	/* Permissions on this extent */
-		unsigned char reserved:1;
-		unsigned char seek:2;	/* Seek control */
-		unsigned char auth:2;	/* Access authorization */
-		unsigned char pci:1;	/* PCI Fetch mode */
-	} __attribute__ ((packed)) mask;
-	struct {
-		unsigned char mode:2;	/* Architecture mode */
-		unsigned char ckd:1;	/* CKD Conversion */
-		unsigned char operation:3;	/* Operation mode */
-		unsigned char cfw:1;	/* Cache fast write */
-		unsigned char dfw:1;	/* DASD fast write */
-	} __attribute__ ((packed)) attributes;
-	__u16 short blk_size;	/* Blocksize */
-	__u16 fast_write_id;
-	__u8 unused;
-	__u8 reserved;
-	ch_t beg_ext;
-	ch_t end_ext;
-} __attribute__ ((packed, aligned (32)))
-
-DE_eckd_data_t;
-
-typedef
-struct {
-	struct {
-		unsigned char orientation:2;
-		unsigned char operation:6;
-	} __attribute__ ((packed)) operation;
-	struct {
-		unsigned char last_bytes_used:1;
-		unsigned char reserved:6;
-		unsigned char read_count_suffix:1;
-	} __attribute__ ((packed)) auxiliary;
-	__u8 unused;
-	__u8 count;
-	ch_t seek_addr;
-	chr_t search_arg;
-	__u8 sector;
-	__u16 length;
-} __attribute__ ((packed, aligned (32)))
-
-LO_eckd_data_t;
-
-/* Stuff for handling home addresses */
-typedef struct {
-	__u8 skip_control[14];
-	__u16 cell_number;
-	__u8 physical_addr[3];
-	__u8 flag;
-	ch_t track_addr;
-	__u8 reserved;
-	__u8 key_length;
-	__u8 reserved2[2];
-} __attribute__ ((packed, aligned (32)))
+dasd_discipline_t dasd_eckd_discipline;
 
-eckd_home_t;
+typedef struct
+dasd_eckd_private_t {
+        dasd_eckd_characteristics_t rdc_data;
+        dasd_eckd_confdata_t conf_data;
+        eckd_count_t count_area;
+} dasd_eckd_private_t;
 
-dasd_era_t dasd_eckd_erp_examine (cqr_t *, devstat_t *);
-
-static unsigned int
+static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
 {
 	int rem = no % mult;
 	return (rem ? no - rem + mult : no);
-/*      return (no % mult ? no - (no % mult) + mult : no); */
 }
 
-static unsigned int
+static inline unsigned int
 ceil_quot (unsigned int d1, unsigned int d2)
 {
 	return (d1 + (d2 - 1)) / d2;
 }
 
-static int
+static inline int
 bytes_per_record (dasd_eckd_characteristics_t * rdc,
 		  int kl,	/* key length */
 		  int dl /* data length */ )
@@ -330,7 +127,7 @@
 	return *(unsigned int *) (rdc->byte_per_track) >> 8;
 }
 
-static unsigned int
+static inline unsigned int
 recs_per_track (dasd_eckd_characteristics_t * rdc,
 		unsigned int kl, unsigned int dl)
 {
@@ -368,26 +165,26 @@
 	return rpt;
 }
 
-static
-void
+static inline void
 define_extent (ccw1_t * de_ccw,
 	       DE_eckd_data_t * data,
 	       int trk,
 	       int totrk,
 	       int cmd,
-	       dasd_information_t * info)
+	       dasd_device_t *device)
 {
 	ch_t geo, beg, end;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
 
-	geo.cyl = info->rdc_data->eckd.no_cyl;
-	geo.head = info->rdc_data->eckd.trk_per_cyl;
+	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;
 
 	memset (de_ccw, 0, sizeof (ccw1_t));
-	de_ccw->cmd_code = CCW_DEFINE_EXTENT;
+	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	de_ccw->count = 16;
 	de_ccw->cda = (void *) __pa (data);
 
@@ -436,14 +233,15 @@
 	       int rec_on_trk,
 	       int no_rec,
 	       int cmd,
-	       dasd_information_t * info)
+	       dasd_device_t * device)
 {
-	ch_t geo =
-	{info->rdc_data->eckd.no_cyl,
-	 info->rdc_data->eckd.trk_per_cyl};
-	ch_t seek =
-	{trk / (geo.head), trk % (geo.head)};
-	int reclen = info->sizes.bp_block;
+        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 reclen = device->sizes.bp_block;
+        int sector;
+
 	memset (lo_ccw, 0, sizeof (ccw1_t));
 	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	lo_ccw->count = 16;
@@ -499,100 +297,310 @@
 	default:
 		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
 	}
+        switch ( private -> rdc_data.dev_type == 0x3390 ) {
+        case 0x3390: {
+                int dn,d;
+                dn = ceil_quot(reclen + 6,232);
+                d = 9 + ceil_quot(reclen + 6 * (dn + 1),34);
+                sector = (49 + (rec_on_trk - 1) * ( 10 + d ))/8;
+                break;
+        }
+        case 0x3380: {
+                int d;
+                d = 7 + ceil_quot(reclen + 12, 32);
+                sector = (39 + (rec_on_trk - 1) * ( 8 + d ))/7;
+                break;
+        }
+        case 0x9345:
+        default:
+                sector = 0;
+        }
+        data -> sector = sector;
 	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
 	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
 	data->search_arg.record = rec_on_trk;
 	data->count += no_rec;
 }
 
-void
-dasd_eckd_print_error (devstat_t * stat)
+static int 
+dasd_eckd_id_check ( dev_info_t *info )
 {
-	int sct, sl;
-	char *sense = stat->ii.sense.data;
-	PRINT_WARN ("IRQ on devno %x: with intparm:%x DS:0x%02x CS:0x%02x\n",
-		    stat->devno, stat->intparm, stat->dstat, stat->cstat);
-	PRINT_WARN ("Failing CCW: %p\n", (ccw1_t *) stat->cpa);
-	for (sl = 0; sl < 4; sl++) {
-		PRINT_DEBUG ("Sense:");
-		for (sct = 0; sct < 8; sct++) {
-			printk (" %2d:0x%02x",
-				8 * sl + sct, sense[8 * sl + sct]);
+        if ( info->sid_data.cu_type == 0x3990 )
+                if ( info->sid_data.dev_type == 0x3390 )
+                        return 0;
+        if ( info->sid_data.cu_type == 0x3990 )
+                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;
 		}
-		printk ("\n");
-	}
-	if (sense[27] & 0x80) {	/* 32 Byte Sense Data */
-		PRINT_INFO ("Sense Data is 32 Byte information\n");
-		PRINT_INFO ("Format: %x Exception class %x\n",
-			    sense[6] & 0x0f, sense[22] >> 4);
-	} else {		/* 24 Byte Sense Data */
-		PRINT_INFO ("Sense Data is 24 Byte information\n");
-		PRINT_INFO ("FMT: %x MSG %x, %s MSGb to SYSOP\n",
-			    sense[7] >> 4, sense[7] & 0x0f,
-			    sense[1] & 0x10 ? "" : "no");
+
+static int
+dasd_eckd_check_characteristics (struct dasd_device_t *device)
+{
+        int rc = -ENODEV;
+        void *conf_data;
+        void *rdc_data;
+        int conf_len;
+        dasd_eckd_private_t *private;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+          device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
+          if ( device->private == NULL ) {
+            printk ( KERN_WARNING PRINTK_HEADER
+                     "memory allocation failed for private data\n");
+            return -ENOMEM;
+          }
+        }
+        private = (dasd_eckd_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+        rc = read_dev_chars (device->devinfo.irq, &rdc_data , 64);
+        if ( rc ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read device characteristics returned error %d\n",rc);
+                return rc;
+	}
+	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 ) {
+                if ( rc == -EOPNOTSUPP )
+                        return 0;
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read configuration data returned error %d\n",rc);
+                return rc;
+	}
+        if ( conf_len != sizeof(dasd_eckd_confdata_t)) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
+                         conf_len, sizeof(dasd_eckd_confdata_t));
+                return rc;
+        }
+        if ( conf_data == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "No configuration data retrieved\n");
+                return -ENOMEM;
+        }
+        memcpy (&private->conf_data,conf_data,sizeof(dasd_eckd_confdata_t));
+	printk ( KERN_INFO PRINTK_HEADER 
+                 "%04X on sch %d: %04X/%02X (CU: %04X/%02X): Configuration data read\n",
+                 device->devinfo.devno, device->devinfo.irq,
+                 private->rdc_data.dev_type, private->rdc_data.dev_model,
+                 private->rdc_data.cu_type, private->rdc_data.cu_model.model);
+        device->sizes.bp_block = 4096;
+        device->sizes.s2b_shift = 3;
+        device->sizes.blocks = ( private->rdc_data.no_cyl * 
+                                 private->rdc_data.trk_per_cyl *
+                                 recs_per_track (&private->rdc_data, 
+                                                 0, device->sizes.bp_block));
+        return 0;
+}
+
+static ccw_req_t *
+dasd_eckd_init_analysis (struct dasd_device_t *device)
+{
+	ccw_req_t *cqr = NULL;
+	ccw1_t *ccw;
+	DE_eckd_data_t *DE_data;
+	LO_eckd_data_t *LO_data;
+	eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area);
+
+        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
+        if ( cqr == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "No memory to allocate initialization request\n");
+                return NULL;
+        }
+	DE_data = cqr->data;
+	LO_data = cqr->data + sizeof (DE_eckd_data_t);
+	ccw = cqr->cpaddr;
+	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
+	ccw->flags = CCW_FLAG_CC;
+	ccw++;
+	locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device);
+	ccw->flags = CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	ccw->cda = (void *) __pa (count_data);
+	cqr->device = device;
+	atomic_set (&cqr->status, CQR_STATUS_FILLED);
+        
+        return cqr;
+}
+
+static int
+dasd_eckd_do_analysis (struct dasd_device_t *device)
+{
+        int rc = 0;
+	int sb, rpt;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+	int bs = private->count_area.dl;
+
+        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): invalid blocksize %d\n"
+                         KERN_INFO PRINTK_HEADER 
+                         "/dev/%s (%04X): capacity (at 4kB blks): %dkB at %dkB/trk\n",
+                         device->name, device->devinfo.devno,bs,
+                         device->name, device->devinfo.devno,
+                         ( private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
+                          recs_per_track (&private->rdc_data, 0, 4096)),
+                        recs_per_track (&private->rdc_data, 0, 4096));
+		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++;
+        
+	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));
+                
+        printk ( KERN_INFO PRINTK_HEADER 
+                 "/dev/%s (%04X): capacity (%dkB blks): %dkB at %dkB/trk\n",
+                 device->name, device->devinfo.devno,
+                 (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);
+	return 0;
+        
+        return rc;
 }
 
-int
-dasd_eckd_format_track (int di, int trk, int bs)
+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:
+                break;
+        default:
+                return -EINVAL;
+        }
+	geo->cylinders = private->rdc_data.no_cyl;
+	geo->heads = private->rdc_data.trk_per_cyl;
+	geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block);
+	geo->start = 2;
+        return rc;
+}
+
+static inline int
+dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags)
 {
 	int rc = 0;
 	int i;
-	int flags = 0x00;	/* FORMAT_R0 = 0x01, FORMAT_HA = 0x03 */
-        dasd_information_t * info=dasd_info[di];
-	cqr_t *fcp;
-	DE_eckd_data_t *DE_data;
-	LO_eckd_data_t *LO_data;
-	eckd_count_t *ct_data;
-	eckd_count_t *r0_data;
-	ccw1_t *last_ccw;
-        int retries = 5;
-
-	int rpt = recs_per_track (&(info->rdc_data->eckd), 0, bs);
-	int cyl = trk / info->rdc_data->eckd.trk_per_cyl;
-	int head = trk % info->rdc_data->eckd.trk_per_cyl;
-
-	fcp = request_cqr (2 + 1 + rpt,
-			   sizeof (DE_eckd_data_t) +
-			   sizeof (LO_eckd_data_t) +
-			   (rpt + 1) * sizeof (eckd_count_t));
-        fcp -> devindex=di;
-	DE_data = (DE_eckd_data_t *) fcp->data;
-	LO_data = (LO_eckd_data_t *) (((long) DE_data) +
-				      sizeof (DE_eckd_data_t));
-	r0_data = (eckd_count_t *) (((long) LO_data) +
-				    sizeof (LO_eckd_data_t));
-	ct_data = (eckd_count_t *) (((long) r0_data) +
-				    sizeof (eckd_count_t));
+	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 retries;
+
+	int rpt = recs_per_track (&(private->rdc_data), 0, bs);
+	int cyl = trk / private->rdc_data.trk_per_cyl;
+	int head = trk % private->rdc_data.trk_per_cyl;
+        int wrccws = rpt;
+        int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
+        
+        switch ( flags ) {
+        case 0x00:
+        case 0x01:
+        case 0x03:
+          break;
+        default:
+          return -EINVAL;
+        }
+        
+        if ( flags & 0x1 ) {
+          wrccws++;
+          datasize += sizeof(eckd_count_t);
+        }
+        if ( flags & 0x2 ) {
+          wrccws++;
+          datasize += sizeof(eckd_home_t);
+        }
+	fcp = ccw_alloc_request (dasd_eckd_discipline.name, 
+                                 wrccws + 2,
+                                 datasize+rpt*sizeof(eckd_count_t));
+	fcp->device = device;
+
+        last_data = fcp->data;
+	DE_data = (DE_eckd_data_t *) last_data;
+        last_data = (void*)(DE_data +1);
+	LO_data = (LO_eckd_data_t *) last_data;
+        last_data = (void*)(LO_data +1);
+        if ( flags & 0x2 ) {
+          ha_data = (eckd_home_t *) last_data;
+          last_data = (void*)(ha_data +1);
+        }
+        if ( flags & 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 (flags) {
 	case 0x03:
 		define_extent (last_ccw, DE_data, trk, trk,
-			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+                               DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, rpt,
-			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+		locate_record (last_ccw, LO_data, trk, 0, wrccws,
+			       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
 		break;
 	case 0x01:
 		define_extent (last_ccw, DE_data, trk, trk,
-			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, rpt,
-			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+		locate_record (last_ccw, LO_data, trk, 0, wrccws,
+			       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
+		memset (r0_data, 0, sizeof (eckd_count_t));
 		break;
 	case 0x00:
 		define_extent (last_ccw, DE_data, trk, trk,
-			       DASD_ECKD_CCW_WRITE_CKD, info);
+			       DASD_ECKD_CCW_WRITE_CKD, device);
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
-		locate_record (last_ccw, LO_data, trk, 0, rpt,
-			       DASD_ECKD_CCW_WRITE_CKD, info);
+		locate_record (last_ccw, LO_data, trk, 0, wrccws,
+			       DASD_ECKD_CCW_WRITE_CKD, device);
                 LO_data->length = bs;
 		last_ccw->flags = CCW_FLAG_CC;
 		last_ccw++;
@@ -606,7 +614,6 @@
 		return -EINVAL;
 	}
 	if (flags & 0x01) {	/* write record zero */
-		memset (r0_data, 0, sizeof (eckd_count_t));
 		r0_data->cyl = cyl;
 		r0_data->head = head;
 		r0_data->record = 0;
@@ -632,89 +639,204 @@
 		last_ccw->cda = (void *) __pa (ct_data + i);
 	}
 	(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
-        fcp -> devindex = di;
-        fcp -> flags = DASD_DO_IO_SLEEP;
+	fcp->device = device;
         do {
-		struct wait_queue wait =
-		{current, NULL};
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                DECLARE_WAITQUEUE (wait,current);
+#else
+                struct wait_queue wait = {current, NULL};
+#endif /* LINUX_VERSION_CODE */
                 unsigned long flags;
-                int irq;
                 int cs;
 
-                irq = dasd_info[fcp->devindex]->info.irq;
-                s390irq_spin_lock_irqsave (irq, flags);
+                retries = 1;
+		s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
                 atomic_set(&fcp->status,CQR_STATUS_QUEUED);
-                rc = dasd_start_IO ( fcp );
-                add_wait_queue (&dasd_waitq, &wait);
                 do {
-                        current->state = TASK_UNINTERRUPTIBLE;
-                        s390irq_spin_unlock_irqrestore (irq, flags);
+                        rc = dasd_eckd_discipline.start_IO (fcp);
+                } while ( rc && retries-- );
+                if ( rc && retries == 0 )
+                        break;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+		add_wait_queue (&device->wait_q, &wait);
+#endif /* LINUX_VERSION_CODE */
+		do {
+			current->state = TASK_INTERRUPTIBLE;
+			s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
                         schedule ();
-                        s390irq_spin_lock_irqsave (irq, flags);
-                } while (((cs = atomic_read (&fcp->status)) !=
-                          CQR_STATUS_DONE) &&
-                         (cs != CQR_STATUS_ERROR));
-                remove_wait_queue (&dasd_waitq, &wait);
-		s390irq_spin_unlock_irqrestore (irq, flags);
-
-                retries --;
+			s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                        cs = atomic_read (&fcp->status);
+		} while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR));
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+		remove_wait_queue (&device->wait_q, &wait);
+#endif /* LINUX_VERSION_CODE */
+		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
 	} while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) &&
-                  retries);
-        if ((rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)))
+                 retries--);
+	if ( retries == 0 )
                 rc = -EIO;
-	release_cqr (fcp);
+	ccw_free_request (fcp);
 	return rc;
 }
 
-int
-dasd_eckd_ck_devinfo (dev_info_t * info)
+static int
+dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata)
 {
-	return 0;
+        int rc = 0;
+	int i;
+	format_data_t fd;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+        int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1;
+        int intensity;
+        kdev_t kdev = device->kdev;
+        int nr_tracks, blocksize;
+
+	if (fdata==NULL) {
+		fd.start_unit = 0;
+		fd.stop_unit = last_track;
+		fd.blksize = 4096;
+	} else {
+		memcpy (&fd, fdata, sizeof (format_data_t));
+		if (fd.stop_unit == -1) {
+			fd.stop_unit = last_track;
+		}
+		if (fd.blksize == 0) {
+			fd.blksize = 4096;
+		}
+	}
+	if (fd.start_unit > fd.stop_unit) {
+		return -EINVAL;
+	}
+	if (fd.start_unit > last_track ) {
+		return -EINVAL;
+	}
+	if (fd.stop_unit > last_track ) {
+		return -EINVAL;
+	}
+        switch(fd.blksize) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+        fd.intensity = 0x0;
+        intensity = fd.intensity;
+        set_blocksize(kdev, fd.blksize);
+	printk (KERN_INFO PRINTK_HEADER
+                "Formatting device %04X from track %d to %d with bs %d\n",
+                device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize);
+        nr_tracks = fd.stop_unit-fd.start_unit+1;
+	for (i = 0; i <= nr_tracks; i++) {
+		/* print 20 messages per format cmd at all */
+                if ( i % (nr_tracks / 20) == 0 ) { 
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Format %04X Cylinder: %d Track %d Intensity %d\n", 
+                                device->devinfo.devno,
+                                (i+fd.start_unit) / private->rdc_data.trk_per_cyl,
+                                (i+fd.start_unit) % private->rdc_data.trk_per_cyl,
+                                intensity);
+                }
+                do {
+                        if ( i == 0 ) {
+                                blocksize = 8;
+                        } else {
+                                blocksize = fd.blksize;
+                        }
+                        rc = dasd_eckd_format_track (device, 
+                                                     (i % nr_tracks) + fd.start_unit , 
+                                                     blocksize, intensity);
+                                /* fix VM controlled minidisk */
+                        if ( rc ) {
+                                if ( intensity ) {
+                                        intensity = intensity >> 1;
+                                }
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        "decreasing format intensity to %d\n", 
+                                        intensity);
+                        }
+                } while ( rc && intensity > 0);
+                if (rc) {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "Formatting of device %04X Cylinder %d Track %d failed...exiting\n",
+                                device->devinfo.devno,
+                                i / private->rdc_data.trk_per_cyl,
+                                i % private->rdc_data.trk_per_cyl);
+                        break;
+		}
+	}
+	printk ( KERN_INFO PRINTK_HEADER
+                 "Formatting of device %04X completed from track %d to %d with bs %d\n",
+                 device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize);
+        return rc;
+}
+
+static dasd_era_t
+dasd_eckd_examine_error  (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;
+        
+	switch (device->devinfo.sid_data.cu_model) {
+	case 0x3990:
+		return dasd_3990_erp_examine (cqr, stat);
+	case 0x9343:
+		return dasd_9343_erp_examine (cqr, stat);
+	default:
+		return dasd_era_recover;
+	}
 }
 
-cqr_t *
-dasd_eckd_build_req (int devindex,
-		     struct request * req)
+static dasd_erp_action_fn_t 
+dasd_eckd_erp_action ( ccw_req_t * cqr ) 
 {
-	cqr_t *rw_cp = NULL;
-	ccw1_t *ccw;
+        return default_erp_action;
+}
 
-	DE_eckd_data_t *DE_data;
-	LO_eckd_data_t *LO_data;
-	struct buffer_head *bh;
+static dasd_erp_postaction_fn_t
+dasd_eckd_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+	return NULL;
+}
+
+static ccw_req_t *
+dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+        ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	dasd_information_t *info = dasd_info[devindex];
-	int blk_per_trk = recs_per_track (&(info->rdc_data->eckd),
-					  0, info->sizes.bp_block);
-	int byt_per_blk = info->sizes.bp_block;
-	int btrk = (req->sector >> info->sizes.s2b_shift) / blk_per_trk;
-	int etrk = ((req->sector + req->nr_sectors - 1) >>
-		    info->sizes.s2b_shift) / blk_per_trk;
 	int bhct;
 	long size;
+        ccw1_t *ccw;
+	DE_eckd_data_t *DE_data;
+	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;
 
 	if (req->cmd == READ) {
 		rw_cmd = DASD_ECKD_CCW_READ_MT;
-	} else
-#if DASD_PARANOIA > 2
-	if (req->cmd == WRITE)
-#endif				/* DASD_PARANOIA */
-	{
+	} else if (req->cmd == WRITE) {
 		rw_cmd = DASD_ECKD_CCW_WRITE_MT;
-	}
-#if DASD_PARANOIA > 2
-	else {
+	} else {
 		PRINT_ERR ("Unknown command %d\n", req->cmd);
 		return NULL;
 	}
-#endif				/* DASD_PARANOIA */
 	/* Build the request */
-#if 0
-	PRINT_INFO ("req %d %d %d %d\n", devindex, req->cmd, req->sector, req->nr_sectors);
-#endif
 	/* count bhs to prevent errors, when bh smaller than block */
 	bhct = 0;
-
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
 		if (bh->b_size > byt_per_blk)
 			for (size = 0; size < bh->b_size; size += byt_per_blk)
@@ -723,7 +845,8 @@
 			bhct++;
 	}
 
-	rw_cp = request_cqr (2 + bhct,
+	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
+                                   2 + bhct,
 			     sizeof (DE_eckd_data_t) +
 			     sizeof (LO_eckd_data_t));
         if ( ! rw_cp ) {
@@ -733,14 +856,11 @@
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
 
-	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, info);
+	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device);
 	ccw->flags = CCW_FLAG_CC;
 	ccw++;
-	locate_record (ccw, LO_data, btrk,
-		       (req->sector >> info->sizes.s2b_shift) %
-		       blk_per_trk + 1,
-		       req->nr_sectors >> info->sizes.s2b_shift,
-		       rw_cmd, info);
+	locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
+		       req->nr_sectors >> shift, rw_cmd, device);
 	ccw->flags = CCW_FLAG_CC;
 	for (bh = req->bh; bh != NULL;) {
 		if (bh->b_size > byt_per_blk) {
@@ -764,202 +884,93 @@
 	}
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors);
-				release_cqr (rw_cp);
+				ccw_free_request (rw_cp);
 		return NULL;
 	}
 			ccw->flags = CCW_FLAG_CC;
 		}
 	}
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
 	return rw_cp;
 }
 
-void
-dasd_eckd_print_char (dasd_characteristics_t * i)
-{
-        dasd_eckd_characteristics_t * c = 
-                (dasd_eckd_characteristics_t *)i;
-	PRINT_INFO ("%x/%x (%x/%x) Cyl: %d Head: %d Sec: %d \n",
-		    c->dev_type, c->dev_model,
-		    c->cu_type, c->cu_model.model,
-		    c->no_cyl, c->trk_per_cyl,
-		    c->sec_per_trk);
-	PRINT_INFO ("Estimate: %d Byte/trk %d byte/kByte %d kByte/trk \n",
-		    bytes_per_track (c),
-		    bytes_per_record (c, 0, 1024),
-		    recs_per_track (c, 0, 1024));
-};
-
-int
-dasd_eckd_ck_char (dasd_characteristics_t * i)
-{
-	int rc = 0;
-	dasd_eckd_print_char (i);
-	return rc;
-}
-
-int
-dasd_eckd_format (int devindex, format_data_t * fdata)
+static char *
+dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-	int rc = 0;
-	int i;
-	dasd_information_t *info = dasd_info[devindex];
-	format_data_t fd;
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        devstat_t *stat = &device->dev_status;
+	char *sense = stat->ii.sense.data;
+        int len,sl,sct;
 
-	if (!fdata) {
-		fd.start_unit = 0;
-		fd.stop_unit = info->rdc_data->eckd.no_cyl *
-                        info->rdc_data->eckd.trk_per_cyl - 1;
-		fd.blksize = 4096;
-	} else {
-		memcpy (&fd, fdata, sizeof (format_data_t));
-		if ( fd.stop_unit == -1 ) {
-                        fd.stop_unit = info->rdc_data->eckd.no_cyl *
-                                info->rdc_data->eckd.trk_per_cyl - 1;
-		}
-                if ( fd.blksize == 0 ) {
-                        fd.blksize = 4096;
-                }
-	}
-        PRINT_INFO("Formatting device %d from %d to %d with bs %d\n",
-                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
-        if ( fd.start_unit > fd.stop_unit ) {
-                PRINT_WARN ("start unit .gt. stop unit\n");
-                return -EINVAL;
-        }
-        if ( (fd.start_unit > info->rdc_data->eckd.no_cyl *
-              info->rdc_data->eckd.trk_per_cyl - 1) ) {
-                PRINT_WARN ("start unit beyond end of disk\n");
-                return -EINVAL;
-        }
-        if ( (fd.stop_unit > info->rdc_data->eckd.no_cyl *
-              info->rdc_data->eckd.trk_per_cyl - 1) ) {
-                PRINT_WARN ("stop unit beyond end of disk\n");
-                return -EINVAL;
+        if ( page == NULL ) {
+                return NULL;
         }
-        switch (fd.blksize) {
-        case 512:
-        case 1024:
-        case 2048:
-        case 4096:
-                break;
-        default:
-                PRINT_WARN ("invalid blocksize\n");
-                return -EINVAL;
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                         "in req: %p CS: 0x%02X DS: 0x%02X\n",
+                         req,stat->cstat,stat->dstat);
+        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                         "Failing CCW: %p\n", (void *)stat->cpa);
+        if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) {
+                for (sl = 0; sl < 4; sl++) {
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "Sense:");
+                        for (sct = 0; sct < 8; sct++) {
+                                len += sprintf ( page + len," %2d:0x%02x",
+                                                 8 * sl + sct, sense[8 * sl + sct]);
         }
-	for (i = fd.start_unit; i <= fd.stop_unit; i++) {
-                /* print 20 messages per disk at all */
-                if ( ! ( i % (info->rdc_data->eckd.trk_per_cyl  *
-                                (info->rdc_data->eckd.no_cyl / 20 ) )))  {
-                        PRINT_INFO ("Format %d Cylinder: %d\n",devindex,
-                                    i/info->rdc_data->eckd.trk_per_cyl);
+                        len += sprintf ( page + len,"\n");
                 }
-		rc = dasd_eckd_format_track (devindex, i, fd.blksize);
-		if (rc) {
-			PRINT_WARN ("Formatting of Track %d failed...exiting\n", i);
-			break;
+                if (sense[27] & 0x80) {	
+                        /* 24 Byte Sense Data */
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
+                                         sense[7] >> 4, sense[7] & 0x0f,
+                                         sense[1] & 0x10 ? "" : "no");
+                } else {		
+                        /* 32 Byte Sense Data */
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "32 Byte: Format: %x Exception class %x\n",
+                                         sense[6] & 0x0f, sense[22] >> 4);
 		}
 	}
-        PRINT_INFO("Formated device %d from %d to %d with bs %d\n",
-                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
-	return rc;
+        return page;
 }
 
-cqr_t *
-dasd_eckd_fill_sizes_first (int di)
-{
-	cqr_t *rw_cp = NULL;
-	ccw1_t *ccw;
-	DE_eckd_data_t *DE_data;
-	LO_eckd_data_t *LO_data;
-	dasd_information_t *info = dasd_info[di];
-	eckd_count_t *count_data = &(info->private.eckd.count_data);
-
-	dasd_info[di]->sizes.label_block = 2;
-
-	rw_cp = request_cqr (3,
-			     sizeof (DE_eckd_data_t) +
-			     sizeof (LO_eckd_data_t));
-	DE_data = rw_cp->data;
-	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
-	ccw = rw_cp->cpaddr;
-	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, info);
-	ccw->flags = CCW_FLAG_CC;
-	ccw++;
-	locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, info);
-	ccw->flags = CCW_FLAG_CC;
-	ccw++;
-	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-	ccw->count = 8;
-	ccw->cda = (void *) __pa (count_data);
-	rw_cp->devindex = di;
-	atomic_set (&rw_cp->status, CQR_STATUS_FILLED);
-	return rw_cp;
-}
+dasd_discipline_t dasd_eckd_discipline = {
+	name :                          "ECKD",
+	ebcname :                       "ECKD",
+        id_check:                       dasd_eckd_id_check,          
+        check_characteristics:          dasd_eckd_check_characteristics,
+        init_analysis:                  dasd_eckd_init_analysis,
+        do_analysis:                    dasd_eckd_do_analysis,          
+        fill_geometry:                  dasd_eckd_fill_geometry,
+        start_IO:                       dasd_start_IO,           
+        format_device:                  dasd_eckd_format_device,          
+        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,      
+        dump_sense:                     dasd_eckd_dump_sense,            
+        int_handler:                    dasd_int_handler            
+};
 
 int
-dasd_eckd_fill_sizes_last (int devindex)
-{
-	int sb,rpt;
-	dasd_information_t *in = dasd_info[devindex];
-	int bs = in->private.eckd.count_data.dl;
-	if (bs <= 0) {
-                PRINT_INFO("Cannot figure out blocksize. did you format the disk?\n");
-                memset (&(in -> sizes), 0, sizeof(dasd_sizes_t ));
-                return -EMEDIUMTYPE;
-	} else {
-		in->sizes.bp_block = bs;
-	}
-	in->sizes.bp_sector = in->sizes.bp_block;
-        
-	if (bs & 511) {
-		PRINT_INFO ("Probably no Linux formatted device!\n");
-		return -EMEDIUMTYPE;
-	}
-	in->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
-	for (sb = 512; sb < bs; sb = sb << 1)
-                in->sizes.s2b_shift++;
+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_enq(&dasd_eckd_discipline);
         
-	in->sizes.blocks = in->rdc_data->eckd.no_cyl *
-                in->rdc_data->eckd.trk_per_cyl *
-                recs_per_track (&(in->rdc_data->eckd), 0, bs);
-
-        in->sizes.kbytes = ( in->sizes.blocks << in->sizes.s2b_shift) >> 1;
-
-        rpt = recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block),
-        
-	PRINT_INFO ("Verified: %d B/trk %d B/Blk(%d B) %d Blks/trk %d kB/trk \n",
-		    bytes_per_track (&(in->rdc_data->eckd)),
-                    bytes_per_record (&(in->rdc_data->eckd), 0, 
-                                      in->sizes.bp_block),
-                    in->sizes.bp_block,
-                    rpt,
-                    (rpt << in->sizes.s2b_shift) >> 1);
-                    return 0;
-}
-
-void
-dasd_eckd_fill_geometry (int di, struct hd_geometry *geo)
-{
-	dasd_information_t *info = dasd_info[di];
-	geo->cylinders = info->rdc_data->eckd.no_cyl;
-	geo->heads = info->rdc_data->eckd.trk_per_cyl;
-	geo->sectors = recs_per_track (&(info->rdc_data->eckd),
-				       0, info->sizes.bp_block);
-	geo->start = info->sizes.label_block + 1;
-}
-
-dasd_operations_t dasd_eckd_operations =
-{
-	ck_devinfo:dasd_eckd_ck_devinfo,
-	get_req_ccw:dasd_eckd_build_req,
-	ck_characteristics:dasd_eckd_ck_char,
-	fill_sizes_first:dasd_eckd_fill_sizes_first,
-	fill_sizes_last:dasd_eckd_fill_sizes_last,
-	dasd_format:dasd_eckd_format,
-	fill_geometry:dasd_eckd_fill_geometry,
-	erp_examine:dasd_eckd_erp_examine
-};
+        return rc;
+}
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_eckd.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_eckd.h	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,286 @@
+#ifndef DASD_ECKD_H
+#define DASD_ECKD_H
+
+typedef 
+struct eckd_count_t {
+	__u16 cyl;
+	__u16 head;
+	__u8 record;
+	__u8 kl;
+	__u16 dl;
+} __attribute__ ((packed)) eckd_count_t;
+
+typedef
+struct ch_t {
+	__u16 cyl;
+	__u16 head;
+} __attribute__ ((packed)) ch_t;
+
+typedef
+struct chs_t {
+	__u16 cyl;
+	__u16 head;
+	__u32 sector;
+} __attribute__ ((packed)) chs_t;
+
+typedef
+struct chr_t {
+	__u16 cyl;
+	__u16 head;
+	__u8 record;
+} __attribute__ ((packed)) chr_t;
+
+typedef
+struct geom_t {
+	__u16 cyl;
+	__u16 head;
+	__u32 sector;
+} __attribute__ ((packed)) geom_t;
+
+typedef struct eckd_home_t {
+	__u8 skip_control[14];
+	__u16 cell_number;
+	__u8 physical_addr[3];
+	__u8 flag;
+	ch_t track_addr;
+	__u8 reserved;
+	__u8 key_length;
+	__u8 reserved2[2];
+} __attribute__ ((packed)) eckd_home_t;
+
+typedef
+struct DE_eckd_data_t {
+	struct {
+		unsigned char perm:2;	/* Permissions on this extent */
+		unsigned char reserved:1;
+		unsigned char seek:2;	/* Seek control */
+		unsigned char auth:2;	/* Access authorization */
+		unsigned char pci:1;	/* PCI Fetch mode */
+	} __attribute__ ((packed)) mask;
+	struct {
+		unsigned char mode:2;	/* Architecture mode */
+		unsigned char ckd:1;	/* CKD Conversion */
+		unsigned char operation:3;	/* Operation mode */
+		unsigned char cfw:1;	/* Cache fast write */
+		unsigned char dfw:1;	/* DASD fast write */
+	} __attribute__ ((packed)) attributes;
+	__u16 short blk_size;	/* Blocksize */
+	__u16 fast_write_id;
+	__u8 unused;
+	__u8 reserved;
+	ch_t beg_ext;
+	ch_t end_ext;
+} __attribute__ ((packed)) DE_eckd_data_t;
+
+typedef
+struct LO_eckd_data_t {
+	struct {
+		unsigned char orientation:2;
+		unsigned char operation:6;
+	} __attribute__ ((packed)) operation;
+	struct {
+		unsigned char last_bytes_used:1;
+		unsigned char reserved:6;
+		unsigned char read_count_suffix:1;
+	} __attribute__ ((packed)) auxiliary;
+	__u8 unused;
+	__u8 count;
+	ch_t seek_addr;
+	chr_t search_arg;
+	__u8 sector;
+	__u16 length;
+} __attribute__ ((packed)) LO_eckd_data_t;
+
+typedef
+struct dasd_eckd_characteristics_t {
+	__u16 cu_type;
+	struct {
+		unsigned char support:2;
+		unsigned char async:1;
+		unsigned char reserved:1;
+		unsigned char cache_info:1;
+		unsigned char model:3;
+	} __attribute__ ((packed)) cu_model;
+	__u16 dev_type;
+	__u8 dev_model;
+	struct {
+		unsigned char mult_burst:1;
+		unsigned char RT_in_LR:1;
+		unsigned char reserved1:1;
+		unsigned char RD_IN_LR:1;
+		unsigned char reserved2:4;
+		unsigned char reserved3:8;
+		unsigned char defect_wr:1;
+		unsigned char reserved4:2;
+		unsigned char striping:1;
+		unsigned char reserved5:4;
+		unsigned char cfw:1;
+		unsigned char reserved6:2;
+		unsigned char cache:1;
+		unsigned char dual_copy:1;
+		unsigned char dfw:1;
+		unsigned char reset_alleg:1;
+		unsigned char sense_down:1;
+	} __attribute__ ((packed)) facilities;
+	__u8 dev_class;
+	__u8 unit_type;
+	__u16 no_cyl;
+	__u16 trk_per_cyl;
+	__u8 sec_per_trk;
+	__u8 byte_per_track[3];
+	__u16 home_bytes;
+	__u8 formula;
+	union {
+		struct {
+			__u8 f1;
+			__u16 f2;
+			__u16 f3;
+		} __attribute__ ((packed)) f_0x01;
+		struct {
+			__u8 f1;
+			__u8 f2;
+			__u8 f3;
+			__u8 f4;
+			__u8 f5;
+		} __attribute__ ((packed)) f_0x02;
+	} __attribute__ ((packed)) factors;
+	__u16 first_alt_trk;
+	__u16 no_alt_trk;
+	__u16 first_dia_trk;
+	__u16 no_dia_trk;
+	__u16 first_sup_trk;
+	__u16 no_sup_trk;
+	__u8 MDR_ID;
+	__u8 OBR_ID;
+	__u8 director;
+	__u8 rd_trk_set;
+	__u16 max_rec_zero;
+	__u8 reserved1;
+	__u8 RWANY_in_LR;
+	__u8 factor6;
+	__u8 factor7;
+	__u8 factor8;
+	__u8 reserved2[3];
+	__u8 reserved3[10];
+} __attribute__ ((packed)) dasd_eckd_characteristics_t;
+
+typedef struct dasd_eckd_confdata_t {
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 dev_class;
+		__u8 reserved;
+		unsigned char dev_type[6];
+		unsigned char dev_model[3];
+		unsigned char HDA_manufacturer[3];
+		unsigned char HDA_location[2];
+		unsigned char HDA_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned1;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char dev_type[6];
+		unsigned char dev_model[3];
+		unsigned char DASD_manufacturer[3];
+		unsigned char DASD_location[2];
+		unsigned char DASD_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned2;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char cont_type[6];
+		unsigned char cont_model[3];
+		unsigned char cont_manufacturer[3];
+		unsigned char cont_location[2];
+		unsigned char cont_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned3;
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char token_id:1;
+			unsigned char sno_valid:1;
+			unsigned char subst_sno:1;
+			unsigned char recNED:1;
+			unsigned char emuNED:1;
+			unsigned char reserved:1;
+		} __attribute__ ((packed)) flags;
+		__u8 descriptor;
+		__u8 reserved[2];
+		unsigned char cont_type[6];
+		unsigned char empty[3];
+		unsigned char cont_manufacturer[3];
+		unsigned char cont_location[2];
+		unsigned char cont_seqno[12];
+		__u16 ID;
+	} __attribute__ ((packed)) ned4;
+	unsigned char ned5[32];
+	unsigned char ned6[32];
+	unsigned char ned7[32];
+	struct {
+		struct {
+			unsigned char identifier:2;
+			unsigned char reserved:6;
+		} __attribute__ ((packed)) flags;
+		__u8 selector;
+		__u16 interfaceID;
+		__u32 reserved;
+		__u16 subsystemID;
+		struct {
+			unsigned char sp0:1;
+			unsigned char sp1:1;
+			unsigned char reserved:5;
+			unsigned char scluster:1;
+		} __attribute__ ((packed)) spathID;
+		__u8 unit_address;
+		__u8 dev_ID;
+		__u8 dev_address;
+		__u8 adapterID;
+		__u16 link_address;
+		struct {
+			unsigned char parallel:1;
+			unsigned char escon:1;
+			unsigned char reserved:1;
+			unsigned char ficon:1;
+			unsigned char reserved2:4;
+		} __attribute__ ((packed)) protocol_type;
+		struct {
+			unsigned char PID_in_236:1;
+			unsigned char reserved:7;
+		} __attribute__ ((packed)) format_flags;
+		__u8 log_dev_address;
+		unsigned char reserved2[12];
+	} __attribute__ ((packed)) neq;
+} __attribute__ ((packed)) dasd_eckd_confdata_t;
+
+int dasd_eckd_init( void );
+
+#endif /* DASD_ECKD_H */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_eckd_erp.c linux/drivers/s390/block/dasd_eckd_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_eckd_erp.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_eckd_erp.c	Mon Dec  3 22:09:50 2001
@@ -5,7 +5,7 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
+#include <asm/dasd.h>
 #include "dasd_erp.h"
 
 #define PRINTK_HEADER "dasd_erp(eckd)"
@@ -14,16 +14,4 @@
 dasd_eckd_erp_examine (cqr_t * cqr, devstat_t * stat)
 {
 
-	if (stat->cstat == 0x00 &&
-	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
-
-	switch (dasd_info[cqr->devindex]->info.sid_data.cu_model) {
-	case 0x3990:
-		return dasd_3990_erp_examine (cqr, stat);
-	case 0x9343:
-		return dasd_9343_erp_examine (cqr, stat);
-	default:
-		return dasd_era_recover;
-	}
 }
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_erp.c linux/drivers/s390/block/dasd_erp.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_erp.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_erp.c	Wed Dec 31 16:00:00 1969
@@ -1,77 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- */
-
-#include <asm/irq.h>
-#include <linux/dasd.h>
-#include "dasd_erp.h"
-
-#define PRINTK_HEADER "dasd_erp"
-
-dasd_era_t
-dasd_erp_examine (cqr_t * cqr, devstat_t * stat)
-{
-	int rc;
-	if (stat->cstat == 0x00 &&
-	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-		PRINT_WARN ("No error detected\n");
-		rc = dasd_era_none;
-	} else if (!(stat->flag & DEVSTAT_FLAG_SENSE_AVAIL)) {
-		PRINT_WARN ("No sense data available, try to recover anyway\n");
-		rc = dasd_era_recover;
-	} else
-#if DASD_PARANOIA > 1
-	if (!dasd_disciplines[dasd_info[cqr->devindex]->type]->
-		 erp_examine) {
-		INTERNAL_CHECK ("No erp_examinator for dt=%d\n",
-				dasd_info[cqr->devindex]->type);
-		rc = dasd_era_fatal;
-	} else
-#endif
-	{
-		PRINT_WARN ("calling examinator\n");
-		rc = dasd_disciplines[dasd_info[cqr->devindex]->type]->
-			erp_examine (cqr, stat);
-	}
-	PRINT_WARN("ERP action code = %d\n",rc);
-	return rc;
-}
-
-void
-default_erp_action (erp_t * erp)
-{
-	cqr_t *cqr = erp->cqr.int4cqr;
-	ccw1_t *cpa = request_cp(1,0);
-
-	memset (cpa,0,sizeof(ccw1_t));
-
-	cpa -> cmd_code = CCW_CMD_NOOP;
-	
-	((cqr_t *) erp)->cpaddr = cpa;
-	if (cqr->retries++ <= 16) {
-		ACS (cqr->status,
-		     CQR_STATUS_ERP_PEND,
-		     CQR_STATUS_QUEUED);
-	} else {
-		PRINT_WARN ("ERP retry count exceeded\n");
-		ACS (cqr->status,
-		     CQR_STATUS_ERP_PEND,
-		     CQR_STATUS_FAILED);
-	}
-	atomic_set (&(((cqr_t *) erp)->status), CQR_STATUS_FILLED);
-}
-
-dasd_erp_action_t
-dasd_erp_action (struct cqr_t *cqr)
-{
-	return default_erp_action;
-}
-
-dasd_erp_action_t
-dasd_erp_postaction (struct erp_t * erp)
-{
-	return NULL;
-}
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_erp.h linux/drivers/s390/block/dasd_erp.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_erp.h	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_erp.h	Wed Dec 31 16:00:00 1969
@@ -1,32 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_erp.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 DASD_ERP_H
-#define DASD_ERP_H
-
-typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover              */
-	dasd_era_none = 0,	/* don't recover, everything alright */
-	dasd_era_msg = 1,	/* don't recover, just report...     */
-	dasd_era_recover = 2	/* recovery action recommended       */
-} dasd_era_t;
-
-#include "dasd_types.h"
-
-typedef struct erp_t {
-	struct cqr_t cqr;
-} __attribute__ ((packed)) 
-
-erp_t;
-
-typedef void (*dasd_erp_action_t) (erp_t *);
-
-dasd_era_t dasd_erp_examine (struct cqr_t *, devstat_t *);
-dasd_erp_action_t dasd_erp_action (struct cqr_t *);
-dasd_erp_action_t dasd_erp_postaction (struct erp_t *);
-
-#endif				/* DASD_ERP_H */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_fba.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_fba.c	Mon Dec  3 22:09:50 2001
@@ -1,68 +1,51 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_fba.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
-#ifdef MODULE
-#include <linux/module.h>
-#endif				/* MODULE */
+#include <asm/debug.h>
 
 #include <linux/malloc.h>
-#include <linux/dasd.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#include <asm/ebcdic.h>
 #include <asm/io.h>
-
 #include <asm/irq.h>
 
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
+#include "dasd.h"
+#include "dasd_fba.h"
 
-#define DASD_FBA_CCW_LOCATE 0x43
-#define DASD_FBA_CCW_READ   0x42
-#define DASD_FBA_CCW_WRITE  0x41
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(fba):"
+#define PRINTK_HEADER DASD_NAME"(fba):"
 
-typedef
-struct {
-	struct {
-		unsigned char perm:2;	/* Permissions on this extent */
-		unsigned char zero:2;	/* Must be zero */
-		unsigned char da:1;	/* usually zero */
-		unsigned char diag:1;	/* allow diagnose */
-		unsigned char zero2:2;	/* zero */
-	} __attribute__ ((packed)) mask;
-	unsigned char zero;	/* Must be zero */
-	unsigned short blk_size;	/* Blocksize */
-	unsigned long ext_loc;	/* Extent locator */
-	unsigned long ext_beg;	/* logical number of block 0 in extent */
-	unsigned long ext_end;	/* logocal number of last block in extent */
-} __attribute__ ((packed, aligned (32)))
-
-DE_fba_data_t;
-
-typedef
-struct {
-	struct {
-		unsigned char zero:4;
-		unsigned char cmd:4;
-	} __attribute__ ((packed)) operation;
-	unsigned char auxiliary;
-	unsigned short blk_ct;
-	unsigned long blk_nr;
-} __attribute__ ((packed, aligned (32)))
+#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;
 
-LO_fba_data_t;
+typedef struct
+dasd_fba_private_t {
+        dasd_fba_characteristics_t rdc_data;
+} dasd_fba_private_t;
 
-static void
+static inline void
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
 	       int blksize, int beg, int nr)
 {
 	memset (DE_data, 0, sizeof (DE_fba_data_t));
-	ccw->cmd_code = CCW_DEFINE_EXTENT;
+	ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
 	ccw->count = 16;
 	ccw->cda = (void *) __pa (DE_data);
 	if (rw == WRITE)
@@ -76,7 +59,7 @@
 	DE_data->ext_end = nr - 1;
 }
 
-static void
+static inline void
 locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
 	       int block_ct)
 {
@@ -94,46 +77,174 @@
 	LO_data->blk_ct = block_ct;
 }
 
-int
-dasd_fba_ck_devinfo (dev_info_t * info)
+
+static int 
+dasd_fba_id_check ( dev_info_t *info )
 {
+	if ( info->sid_data.cu_type == 0x3880 ) 
+                if ( info->sid_data.dev_type == 0x3370 )
+                        return 0;
+        if ( info->sid_data.cu_type == 0x6310 )
+                if ( info->sid_data.dev_type == 0x9336 )
 	return 0;
+        return -ENODEV;
 }
 
-cqr_t *
-dasd_fba_build_req (int devindex,
-		    struct request * req)
+static int
+dasd_fba_check_characteristics (struct dasd_device_t *device)
 {
-	cqr_t *rw_cp = NULL;
-	ccw1_t *ccw;
+        int rc = -ENODEV;
+        void *rdc_data;
+        dasd_fba_private_t *private;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+		device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
+		if ( device->private == NULL ) {
+			printk ( KERN_WARNING PRINTK_HEADER
+				 "memory allocation failed for private data\n");
+			return -ENOMEM;
+		}
+        }
+        private = (dasd_fba_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+        rc = read_dev_chars (device->devinfo.irq, &rdc_data , 32);
+        if ( rc ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read device characteristics returned error %d\n",rc);
+                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);
+        return 0;
+}
 
-	DE_fba_data_t *DE_data;
-	LO_fba_data_t *LO_data;
-	struct buffer_head *bh;
+static int
+dasd_fba_do_analysis (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++;
+	
+	device->sizes.blocks = (private->rdc_data.blk_bdsa);
+
+	return rc;
+}
+
+static int
+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 trk_rem = sectors & ((1<<6)-1);
+	unsigned long cyls = tracks >> 4;
+	unsigned long cyls_rem = tracks & ((1<<4)-1);
+
+        switch(device->sizes.bp_block) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+	geo->cylinders = cyls;
+	geo->heads = 16;
+	geo->sectors = 128 >> device->sizes.s2b_shift;
+	geo->start = 1;
+        return rc;
+}
+
+static dasd_era_t
+dasd_fba_examine_error  (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;
+        
+	switch (device->devinfo.sid_data.dev_model) {
+	case 0x3370:
+		return dasd_3370_erp_examine (cqr, stat);
+	case 0x9336:
+		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 ) 
+{
+        return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_fba_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+	return NULL;
+}
+
+static ccw_req_t *
+dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+        ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	int byt_per_blk = dasd_info[devindex]->sizes.bp_block;
 	int bhct;
 	long size;
+        ccw1_t *ccw;
+	DE_fba_data_t *DE_data;
+	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->nr_sectors) {
-		PRINT_ERR ("No blocks to write...returning\n");
-		return NULL;
-	}
 	if (req->cmd == READ) {
 		rw_cmd = DASD_FBA_CCW_READ;
-	} else
-#if DASD_PARANOIA > 2
-	if (req->cmd == WRITE)
-#endif				/* DASD_PARANOIA */
-	{
+	} else if (req->cmd == WRITE) {
 		rw_cmd = DASD_FBA_CCW_WRITE;
-	}
-#if DASD_PARANOIA > 2
-	else {
+	} else {
 		PRINT_ERR ("Unknown command %d\n", req->cmd);
 		return NULL;
 	}
-#endif				/* DASD_PARANOIA */
+	/* 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)
@@ -143,8 +254,8 @@
 			bhct++;
 	}
 
-	/* Build the request */
-	rw_cp = request_cqr (2 + bhct,
+	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                   2 + bhct,
 			     sizeof (DE_fba_data_t) +
 			     sizeof (LO_fba_data_t));
 	if (!rw_cp) {
@@ -160,11 +271,12 @@
 	ccw++;
 	locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors);
 	ccw->flags = CCW_FLAG_CC;
+
 	for (bh = req->bh; bh;) {
 		if (bh->b_size > byt_per_blk) {
 			for (size = 0; size < bh->b_size; size += byt_per_blk) {
 				ccw++;
-				if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+				if (private->rdc_data.mode.bits.data_chain) {
 					ccw->flags = CCW_FLAG_DC;
 				} else {
 					ccw->flags = CCW_FLAG_CC;
@@ -177,11 +289,11 @@
 		} else {	/* group N bhs to fit into byt_per_blk */
 			for (size = 0; bh != NULL && size < byt_per_blk;) {
 				ccw++;
-				if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+				if (private->rdc_data.mode.bits.data_chain) {
 					ccw->flags = CCW_FLAG_DC;
 				} else {
 					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					release_cqr (rw_cp);
+					ccw_free_request (rw_cp);
 					return NULL;
 				}
 				ccw->cmd_code = rw_cmd;
@@ -193,164 +305,80 @@
 			ccw->flags = CCW_FLAG_CC;
 			if (size != byt_per_blk) {
 				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				release_cqr (rw_cp);
+				ccw_free_request (rw_cp);
 				return NULL;
 			}
 		}
 	}
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
 	return rw_cp;
 }
 
-void
-dasd_fba_print_char (dasd_characteristics_t * ct)
-{
-	dasd_fba_characteristics_t *c =
-	(dasd_fba_characteristics_t *) ct;
-	PRINT_INFO ("%d blocks of %d bytes %d MB\n",
-		    c->blk_bdsa, c->blk_size,
-		    (c->blk_bdsa * (c->blk_size >> 9)) >> 11);
-	PRINT_INFO ("%soverrun, %s mode, data chains %sallowed\n"
-		    "%sremovable, %sshared\n",
-		    (c->mode.bits.overrunnable ? "" : "no "),
-		    (c->mode.bits.burst_byte ? "burst" : "byte"),
-		    (c->mode.bits.data_chain ? "" : "not "),
-		    (c->features.bits.removable ? "" : "not "),
-		    (c->features.bits.shared ? "" : "not "));
-};
-
-int
-dasd_fba_ck_char (dasd_characteristics_t * rdc)
+static char *
+dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-	int rc = 0;
-	dasd_fba_print_char (rdc);
-	return rc;
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        int len;
+        if ( page == NULL ) {
+                return NULL;
 }
 
-cqr_t *
-dasd_fba_fill_sizes_first (int di)
-{
-	cqr_t *rw_cp = NULL;
-	ccw1_t *ccw;
-	DE_fba_data_t *DE_data;
-	LO_fba_data_t *LO_data;
-	dasd_information_t *info = dasd_info[di];
-	static char buffer[8];
-
-	dasd_info[di]->sizes.label_block = 1;
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+                        
 
-	rw_cp = request_cqr (3,
-			     sizeof (DE_fba_data_t) +
-			     sizeof (LO_fba_data_t));
-	DE_data = rw_cp->data;
-	LO_data = rw_cp->data + sizeof (DE_fba_data_t);
-	ccw = rw_cp->cpaddr;
-	define_extent (ccw, DE_data, READ, info->sizes.bp_block, 1, 1);
-	ccw->flags = CCW_FLAG_CC;
-	ccw++;
-	locate_record (ccw, LO_data, READ, 0, 1);
-	ccw->flags = CCW_FLAG_CC;
-	ccw++;
-	ccw->cmd_code = DASD_FBA_CCW_READ;
-	ccw->flags = CCW_FLAG_SLI;
-	ccw->count = 8;
-	ccw->cda = (void *) __pa (buffer);
-	rw_cp->devindex = di;
-	atomic_set (&rw_cp->status, CQR_STATUS_FILLED);
-	return rw_cp;
+        return page;
 }
 
-int
-dasd_fba_fill_sizes_last (int devindex)
-{
-	int rc = 0;
-	int sb;
-	dasd_information_t *info = dasd_info[devindex];
-
-	info->sizes.bp_sector = info->rdc_data->fba.blk_size;
-	info->sizes.bp_block = info->sizes.bp_sector;
-
-	info->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < info->sizes.bp_sector; sb = sb << 1)
-		info->sizes.s2b_shift++;
-
-	info->sizes.blocks = (info->rdc_data->fba.blk_bdsa);
-
-	if (info->sizes.s2b_shift >= 1)
-		info->sizes.kbytes = info->sizes.blocks <<
-		    (info->sizes.s2b_shift - 1);
-	else
-		info->sizes.kbytes = info->sizes.blocks >>
-		    (-(info->sizes.s2b_shift - 1));
-
-	return rc;
-}
+dasd_discipline_t dasd_fba_discipline = {
+	name :                          "FBA ",
+	ebcname :                       "FBA ",
+        id_check:                       dasd_fba_id_check,          
+        check_characteristics:          dasd_fba_check_characteristics,
+        do_analysis:                    dasd_fba_do_analysis,          
+        fill_geometry:                  dasd_fba_fill_geometry,
+        start_IO:                       dasd_start_IO,           
+        examine_error:                  dasd_fba_examine_error,          
+        erp_action:                     dasd_fba_erp_action,             
+        erp_postaction:                 dasd_fba_erp_postaction,         
+        build_cp_from_req:              dasd_fba_build_cp_from_req,      
+        dump_sense:                     dasd_fba_dump_sense,            
+        int_handler:                    dasd_int_handler            
+};
 
 int
-dasd_fba_format (int devindex, format_data_t * fdata)
-{
+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_enq(&dasd_fba_discipline);
+
 	return rc;
 }
+/*
+ * 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:
+ */
 
-void
-dasd_fba_fill_geometry (int di, struct hd_geometry *geo)
-{
-	int bfactor, nr_sectors, sec_size;
-	int trk_cap, trk_low, trk_high, tfactor, nr_trks, trk_size;
-	int cfactor, nr_cyls, cyl_size;
-	int remainder;
-
-	dasd_information_t *info = dasd_info[di];
-	PRINT_INFO ("FBA has no geometry! Faking one...\n%s", "");
-
-	/* determine the blocking factor of sectors */
-	for (bfactor = 8; bfactor > 0; bfactor--) {
-		remainder = info->rdc_data->fba.blk_bdsa % bfactor;
-		PRINT_INFO ("bfactor %d remainder %d\n", bfactor, remainder);
-		if (!remainder)
-			break;
-	}
-	nr_sectors = info->rdc_data->fba.blk_bdsa / bfactor;
-	sec_size = info->rdc_data->fba.blk_size * bfactor;
-	
-	geo -> sectors = bfactor;
 
-	/* determine the nr of sectors per track */
-	trk_cap = (64 * 1 << 10) / sec_size;	/* 64k in sectors */
-	trk_low = trk_cap * 2 / 3;
-	trk_high = trk_cap * 4 / 3;
-	for (tfactor = trk_high; tfactor > trk_low; tfactor--) {
-		PRINT_INFO ("remainder %d\n", remainder);
-		remainder = nr_sectors % bfactor;
-		if (!remainder)
-			break;
-	}
-	nr_trks = nr_sectors / tfactor;
-	trk_size = sec_size * tfactor;
-
-	/* determine the nr of trks per cylinder */
-	for (cfactor = 31; cfactor > 0; cfactor--) {
-		PRINT_INFO ("remainder %d\n", remainder);
-		remainder = nr_trks % bfactor;
-		if (!remainder)
-			break;
-	}
-	nr_cyls = nr_trks / cfactor;
-	sec_size = info->rdc_data->fba.blk_size * bfactor;
-
-	geo -> heads = nr_trks;
-	geo -> cylinders = nr_cyls;
-	geo -> start = info->sizes.label_block + 1;
-}
-
-dasd_operations_t dasd_fba_operations =
-{
-	ck_devinfo:dasd_fba_ck_devinfo,
-	get_req_ccw:dasd_fba_build_req,
-	ck_characteristics:dasd_fba_ck_char,
-	fill_sizes_first:dasd_fba_fill_sizes_first,
-	fill_sizes_last:dasd_fba_fill_sizes_last,
-	dasd_format:dasd_fba_format,
-	fill_geometry:dasd_fba_fill_geometry
-};
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_fba.h linux/drivers/s390/block/dasd_fba.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_fba.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_fba.h	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,70 @@
+#ifndef DASD_FBA_H
+#define DASD_FBA_H
+
+typedef 
+struct DE_fba_data_t {
+	struct {
+		unsigned char perm:2;	/* Permissions on this extent */
+		unsigned char zero:2;	/* Must be zero */
+		unsigned char da:1;	/* usually zero */
+		unsigned char diag:1;	/* allow diagnose */
+		unsigned char zero2:2;	/* zero */
+	} __attribute__ ((packed)) mask;
+	__u8 zero;	/* Must be zero */
+	__u16 blk_size;	/* Blocksize */
+	__u32 ext_loc;	/* Extent locator */
+	__u32 ext_beg;	/* logical number of block 0 in extent */
+	__u32 ext_end;	/* logocal number of last block in extent */
+} __attribute__ ((packed)) DE_fba_data_t;
+
+typedef 
+struct LO_fba_data_t {
+	struct {
+		unsigned char zero:4;
+		unsigned char cmd:4;
+	} __attribute__ ((packed)) operation;
+	__u8 auxiliary;
+	__u16 blk_ct;
+	__u32 blk_nr;
+} __attribute__ ((packed)) LO_fba_data_t; 
+
+
+typedef 
+struct dasd_fba_characteristics_t {
+	union {
+		__u8 c;
+		struct {
+			unsigned char reserved:1;
+			unsigned char overrunnable:1;
+			unsigned char burst_byte:1;
+			unsigned char data_chain:1;
+			unsigned char zeros:4;
+		} __attribute__ ((packed)) bits;
+	} __attribute__ ((packed)) mode;
+	union {
+		__u8 c;
+		struct {
+			unsigned char zero0:1;
+			unsigned char removable:1;
+			unsigned char shared:1;
+			unsigned char zero1:1;
+			unsigned char mam:1;
+			unsigned char zeros:3;
+		} __attribute__ ((packed)) bits;
+	} __attribute__ ((packed)) features;
+	__u8 dev_class;
+	__u8 unit_type;
+	__u16 blk_size;
+	__u32 blk_per_cycl;
+	__u32 blk_per_bound;
+	__u32 blk_bdsa;
+	__u32 reserved0;
+	__u16 reserved1;
+	__u16 blk_ce;
+	__u32 reserved2;
+	__u16 reserved3;
+} __attribute__ ((packed)) dasd_fba_characteristics_t;
+
+int dasd_fba_init( void );
+
+#endif /* DASD_FBA_H */
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_mdsk.c linux/drivers/s390/block/dasd_mdsk.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_mdsk.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_mdsk.c	Wed Dec 31 16:00:00 1969
@@ -1,366 +0,0 @@
-#include <linux/dasd.h>
-#include <linux/malloc.h>
-#include <linux/ctype.h>
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
-#include "dasd_mdsk.h"
-
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(mdsk):"
-
-int dasd_is_accessible (int devno);
-void dasd_insert_range (int start, int end);
-
-/*
- * The device characteristics function
- */
-static __inline__ int
-dia210 (void *devchar)
-{
-	int rc;
-
-	asm volatile ("    lr    2,%1\n"
-		      "    .long 0x83200210\n"
-		      "    ipm   %0\n"
-		      "    srl   %0,28"
-		      :"=d" (rc)
-		      :"d" ((void *) __pa (devchar))
-		      :"2");
-	return rc;
-}
-
-static __inline__ int
-dia250 (void *iob, int cmd)
-{
-	int rc;
-
-	asm volatile ("    lr    2,%1\n"
-		      "    lr    3,%2\n"
-		      "    .long 0x83230250\n"
-		      "    lr    %0,3"
-		      :"=d" (rc)
-		      :"d" ((void *) __pa (iob)), "d" (cmd)
-		      :"2", "3");
-	return rc;
-}
-
-/*
- * Init of minidisk device
- */
-
-static __inline__ int
-mdsk_init_io (int di, int blocksize, int offset, int size)
-{
-	mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
-	int rc;
-
-	memset (iib, 0, sizeof (mdsk_init_io_t));
-
-	iib->dev_nr = dasd_info[di]->info.devno;
-	iib->block_size = blocksize;
-	iib->offset = offset;
-	iib->start_block = 0;
-	iib->end_block = size;
-
-	rc = dia250 (iib, INIT_BIO);
-
-	return rc;
-}
-
-/*
- * release of minidisk device
- */
-
-static __inline__ int
-mdsk_term_io (int di)
-{
-	mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
-	int rc;
-
-	memset (iib, 0, sizeof (mdsk_init_io_t));
-	iib->dev_nr = dasd_info[di]->info.devno;
-	rc = dia250 (iib, TERM_BIO);
-	return rc;
-}
-
-void dasd_do_chanq (void);
-void dasd_schedule_bh (void (*func) (void));
-int register_dasd_last (int di);
-
-int
-dasd_mdsk_start_IO (cqr_t * cqr)
-{
-	int rc;
-	mdsk_rw_io_t *iob = &(dasd_info[cqr->devindex]->private.mdsk.iob);
-
-	iob->dev_nr = dasd_info[cqr->devindex]->info.devno;
-	iob->key = 0;
-	iob->flags = 2;
-	iob->block_count = cqr->cplength >> 1;
-	iob->interrupt_params = (u32) cqr;
-	iob->bio_list = __pa (cqr->cpaddr);
-
-	asm volatile ("STCK %0":"=m" (cqr->startclk));
-	rc = dia250 (iob, RW_BIO);
-	if (rc > 8) {
-		PRINT_WARN ("dia250 returned CC %d\n", rc);
-		ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
-	} else {
-		ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-		atomic_dec (&chanq_tasks);
-	}
-	return rc;
-}
-
-void 
-do_dasd_mdsk_interrupt (struct pt_regs *regs, __u16 code)
-{
-	int intparm = S390_lowcore.ext_params;
-	char status = *((char *) S390_lowcore.ext_params + 5);
-	cqr_t *cqr = (cqr_t *) intparm;
-	if (!intparm)
-		return;
-	if (cqr->magic != MDSK_MAGIC) {
-		panic ("unknown magic number\n");
-	}
-	asm volatile ("STCK %0":"=m" (cqr->stopclk));
-	if (atomic_read (&dasd_info[cqr->devindex]->status) ==
-	    DASD_INFO_STATUS_DETECTED) {
-		register_dasd_last (cqr->devindex);
-	}
-	switch (status) {
-	case 0x00:
-		ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
-		break;
-	case 0x01:
-	case 0x02:
-	case 0x03:
-	default:
-		ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-		atomic_inc (&dasd_info[cqr->devindex]->
-			    queue.dirty_requests);
-		break;
-	}
-	atomic_inc (&chanq_tasks);
-	dasd_schedule_bh (dasd_do_chanq);
-}
-
-cqr_t *
-dasd_mdsk_build_req (int devindex,
-		     struct request *req)
-{
-	cqr_t *rw_cp = NULL;
-	struct buffer_head *bh;
-	int rw_cmd;
-	dasd_information_t *info = dasd_info[devindex];
-	int noblk = req->nr_sectors >> info->sizes.s2b_shift;
-	int byt_per_blk = info->sizes.bp_block;
-	int block;
-	mdsk_bio_t *bio;
-	int bhct;
-	long size;
-
-	if (!noblk) {
-		PRINT_ERR ("No blocks to write...returning\n");
-		return NULL;
-	}
-	if (req->cmd == READ) {
-		rw_cmd = MDSK_READ_REQ;
-	} else
-#if DASD_PARANOIA > 2
-	if (req->cmd == WRITE)
-#endif				/* DASD_PARANOIA */
-	{
-		rw_cmd = MDSK_WRITE_REQ;
-	}
-#if DASD_PARANOIA > 2
-	else {
-		PRINT_ERR ("Unknown command %d\n", req->cmd);
-		return NULL;
-	}
-#endif				/* DASD_PARANOIA */
-	bhct = 0;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
-	}
-	/* Build the request */
-	rw_cp = request_cqr (MDSK_BIOS (bhct), 0);
-	if (!rw_cp) {
-		return NULL;
-	}
-	rw_cp->magic = MDSK_MAGIC;
-	bio = (mdsk_bio_t *) (rw_cp->cpaddr);
-
-	block = req->sector >> info->sizes.s2b_shift;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size >= byt_per_blk) {
-			memset (bio, 0, sizeof (mdsk_bio_t));
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-				bio->type = rw_cmd;
-				bio->block_number = block + 1;
-				bio->buffer = __pa (bh->b_data + size);
-				bio++;
-				block++;
-			}
-		} else {
-			PRINT_WARN ("Cannot fulfill request smaller than block\n");
-			release_cqr (rw_cp);
-			return NULL;
-		}
-	}
-	return rw_cp;
-}
-
-int
-dasd_mdsk_ck_devinfo (dev_info_t * info)
-{
-	int rc = 0;
-
-	dasd_mdsk_characteristics_t devchar =
-	{0,};
-
-	devchar.dev_nr = info->devno;
-	devchar.rdc_len = sizeof (dasd_mdsk_characteristics_t);
-
-	if (dia210 (&devchar) != 0) {
-		return -ENODEV;
-	}
-	if (devchar.vdev_class == DEV_CLASS_FBA ||
-	    devchar.vdev_class == DEV_CLASS_ECKD ||
-	    devchar.vdev_class == DEV_CLASS_CKD) {
-		return 0;
-	} else {
-		return -ENODEV;
-	}
-	return rc;
-}
-
-int
-dasd_mdsk_ck_characteristics (dasd_characteristics_t * dchar)
-{
-	int rc = 0;
-	dasd_mdsk_characteristics_t *devchar =
-	(dasd_mdsk_characteristics_t *) dchar;
-
-	if (dia210 (devchar) != 0) {
-		return -ENODEV;
-	}
-	if (devchar->vdev_class != DEV_CLASS_FBA &&
-	    devchar->vdev_class != DEV_CLASS_ECKD &&
-	    devchar->vdev_class != DEV_CLASS_CKD) {
-		return -ENODEV;
-	}
-	return rc;
-}
-
-cqr_t *
-dasd_mdsk_fill_sizes_first (int di)
-{
-	cqr_t *cqr = NULL;
-	dasd_information_t *info = dasd_info[di];
-	mdsk_bio_t *bio;
-	int bsize;
-	int rc;
-	/* Figure out position of label block */
-	if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_FBA) {
-		info->sizes.label_block = 1;
-	} else if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_ECKD ||
-		   info->rdc_data->mdsk.vdev_class == DEV_CLASS_CKD) {
-		dasd_info[di]->sizes.label_block = 2;
-	} else {
-		return NULL;
-	}
-
-	/* figure out blocksize of device */
-	mdsk_term_io (di);
-	for (bsize = 512; bsize <= PAGE_SIZE; bsize = bsize << 1) {
-		rc = mdsk_init_io (di, bsize, 0, 64);
-		if (rc <= 4) {
-			break;
-		}
-	}
-	if (bsize > PAGE_SIZE) {
-		PRINT_INFO ("Blocksize larger than 4096??\n");
-		rc = mdsk_term_io (di);
-		return NULL;
-	}
-	dasd_info[di]->sizes.bp_sector = bsize;
-
-	info->private.mdsk.label = (long *) get_free_page (GFP_KERNEL);
-	cqr = request_cqr (MDSK_BIOS (1), 0);
-	cqr->magic = MDSK_MAGIC;
-	bio = (mdsk_bio_t *) (cqr->cpaddr);
-	memset (bio, 0, sizeof (mdsk_bio_t));
-	bio->type = MDSK_READ_REQ;
-	bio->block_number = info->sizes.label_block + 1;
-	bio->buffer = __pa (info->private.mdsk.label);
-	cqr->devindex = di;
-	atomic_set (&cqr->status, CQR_STATUS_FILLED);
-
-	return cqr;
-}
-
-int
-dasd_mdsk_fill_sizes_last (int di)
-{
-	int sb;
-	dasd_information_t *info = dasd_info[di];
-	long *label = info->private.mdsk.label;
-	int bs = info->private.mdsk.iib.block_size;
-
-	info->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-	for (sb = 512; sb < bs; sb = sb << 1)
-		info->sizes.s2b_shift++;
-
-	if (label[3] != bs) {
-		PRINT_WARN ("%04X mismatching blocksizes\n", info->info.devno);
-		atomic_set (&dasd_info[di]->status,
-			    DASD_INFO_STATUS_DETECTED);
-		return -EINVAL;
-	}
-	if (label[0] != 0xc3d4e2f1) {	/* CMS1 */
-		PRINT_WARN ("%04X is not CMS formatted\n", info->info.devno);
-	}
-	if (label[13] == 0) {
-		PRINT_WARN ("%04X is not reserved\n", info->info.devno);
-	}
-	/* defaults for first partition */
-	info->private.mdsk.setup.size =
-	    (label[7] - 1 - label[13]) * (label[3] >> 9) >> 1;
-	info->private.mdsk.setup.blksize = label[3];
-	info->private.mdsk.setup.offset = label[13] + 1;
-
-	/* real size of the volume */
-	info->sizes.bp_block = label[3];
-	info->sizes.kbytes = label[7] * (label[3] >> 9) >> 1;
-
-	if (info->sizes.s2b_shift >= 1)
-		info->sizes.blocks = info->sizes.kbytes >>
-		    (info->sizes.s2b_shift - 1);
-	else
-		info->sizes.blocks = info->sizes.kbytes <<
-		    (-(info->sizes.s2b_shift - 1));
-
-	PRINT_INFO ("%ld kBytes in %d blocks of %d Bytes\n",
-		    info->sizes.kbytes,
-		    info->sizes.blocks,
-		    info->sizes.bp_sector);
-	return 0;
-
-}
-
-dasd_operations_t dasd_mdsk_operations =
-{
-	ck_devinfo:dasd_mdsk_ck_devinfo,
-	get_req_ccw:dasd_mdsk_build_req,
-	ck_characteristics:dasd_mdsk_ck_characteristics,
-	fill_sizes_first:dasd_mdsk_fill_sizes_first,
-	fill_sizes_last:dasd_mdsk_fill_sizes_last,
-	dasd_format:NULL
-};
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_mdsk.h linux/drivers/s390/block/dasd_mdsk.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_mdsk.h	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_mdsk.h	Wed Dec 31 16:00:00 1969
@@ -1,63 +0,0 @@
-#ifndef DASD_MDSK_H
-#define DASD_MDSK_H
-
-#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   0x02	/* sure ?? */
-#define DEV_CLASS_CKD   0x04	/* sure ?? */
-
-#define MDSK_BIOS(x) (2*(x))
-
-typedef struct mdsk_dev_char_t {
-	u8 type;
-	u8 status;
-	u16 spare1;
-	u32 block_number;
-	u32 alet;
-	u32 buffer;
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_bio_t;
-
-typedef struct {
-	u16 dev_nr;
-	u16 spare1[11];
-	u32 block_size;
-	u32 offset;
-	u32 start_block;
-	u32 end_block;
-	u32 spare2[6];
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_init_io_t;
-
-typedef struct {
-	u16 dev_nr;
-	u16 spare1[11];
-	u8 key;
-	u8 flags;
-	u16 spare2;
-	u32 block_count;
-	u32 alet;
-	u32 bio_list;
-	u32 interrupt_params;
-	u32 spare3[5];
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_rw_io_t;
-
-typedef struct {
-	long vdev;
-	long size;
-	long offset;
-	long blksize;
-	int force_mdsk;
-} mdsk_setup_data_t;
-
-#endif
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_proc.c linux/drivers/s390/block/dasd_proc.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_proc.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_proc.c	Wed Dec 31 16:00:00 1969
@@ -1,135 +0,0 @@
-/*
-  Structure of the proc filesystem:
-  /proc/dasd/
-  /proc/dasd/devices                  # List of devices
-  /proc/dasd/ddabcd                   # Device node for devno abcd            
-  /proc/dasd/ddabcd1                  # Device node for partition abcd  
-  /proc/dasd/abcd                     # Device information for devno abcd
-*/
-
-#include <linux/proc_fs.h>
-
-#include <linux/dasd.h>
-
-#include "dasd_types.h"
-
-int dasd_proc_read_devices ( char *, char **, off_t, int, int);
-#ifdef DASD_PROFILE
-extern int dasd_proc_read_statistics ( char *, char **, off_t, int, int);
-extern int dasd_proc_read_debug ( char *, char **, off_t, int, int);
-#endif /* DASD_PROFILE */
-
-struct proc_dir_entry dasd_proc_root_entry =
-{
-	low_ino:0,
-	namelen:4,
-	name:"dasd",
-	mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0
-};
-
-struct proc_dir_entry dasd_proc_devices_entry =
-{
-	low_ino:0,
-	namelen:7,
-	name:"devices",
-	mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0,
-	get_info:&dasd_proc_read_devices,
-};
-
-#ifdef DASD_PROFILE
-struct proc_dir_entry dasd_proc_stats_entry =
-{
-	low_ino:0,
-	namelen:10,
-	name:"statistics",
-	mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0,
-	get_info:&dasd_proc_read_statistics
-};
-
-struct proc_dir_entry dasd_proc_debug_entry =
-{
-	low_ino:0,
-	namelen:5,
-	name:"debug",
-	mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0,
-	get_info:&dasd_proc_read_debug
-};
-#endif /* DASD_PROFILE */
-
-struct proc_dir_entry dasd_proc_device_template =
-{
-	0,
-	6,"dd????",
-	S_IFBLK | S_IRUGO | S_IWUSR | S_IWGRP,
-	1,0,0,
-	0,
-	NULL,
-};
-
-void
-dasd_proc_init ( void )
-{
-	proc_register( & proc_root, & dasd_proc_root_entry);
-	proc_register( & dasd_proc_root_entry, & dasd_proc_devices_entry);
-#ifdef DASD_PROFILE
- 	proc_register( & dasd_proc_root_entry, & dasd_proc_stats_entry); 
- 	proc_register( & dasd_proc_root_entry, & dasd_proc_debug_entry); 
-#endif /* DASD_PROFILE */
-}
-
-int 
-dasd_proc_read_devices ( char * buf, char **start, off_t off, int len, int d)
-{
-	int i;
-	len = sprintf ( buf, "dev# MAJ minor node        Format\n");
-	for ( i = 0; i < DASD_MAX_DEVICES; i++ ) {
-		dasd_information_t *info = dasd_info[i];
-		if ( ! info ) 
-			continue;
-		if ( len >= PAGE_SIZE - 80 )
-			len += sprintf ( buf + len, "terminated...\n");
-		len += sprintf ( buf + len,
-				 "%04X %3d %5d /dev/dasd%c",
-				 dasd_info[i]->info.devno,
-				 DASD_MAJOR,
-				 i << PARTN_BITS,
-				 'a' + i );
-		switch (atomic_read (&info->status)) {
-		case DASD_INFO_STATUS_UNKNOWN:
-			len += sprintf (buf + len, " unknown");
-			break;
-		case DASD_INFO_STATUS_DETECTED:
-			len += sprintf (buf + len, "   avail");
-			break;
-		case DASD_INFO_STATUS_ANALYSED:
-			len += sprintf (buf + len, "     n/f");
-			break;
-		default:
-			len += sprintf (buf + len, " %7d",
-					 info->sizes.bp_block);
-		}
-		len += sprintf ( buf + len, "\n");
-	} 
-	return len;
-}
-
-void 
-dasd_proc_add_node (int di) 
-{
-}
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_profile.c linux/drivers/s390/block/dasd_profile.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_profile.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_profile.c	Wed Dec 31 16:00:00 1969
@@ -1,212 +0,0 @@
-
-#include <linux/mm.h>
-#include <asm/spinlock.h>
-
-#include <linux/dasd.h>
-
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd_profile:"
-
-static long dasd_io_reqs=0; /* number of requests processed at all */
-static long dasd_io_secs[16]; /* histogram of request's sizes */
-static long dasd_io_times[16]; /* histogram of requests's times */
-static long dasd_io_timps[16]; /* histogram of requests's times per sector */
-static long dasd_io_time1[16]; /* histogram of time from build to start */
-static long dasd_io_time2[16]; /* histogram of time from start to irq */
-static long dasd_io_time2ps[16]; /* histogram of time from start to irq */
-static long dasd_io_time3[16]; /* histogram of time from irq to end */
-
-void
-dasd_profile_add ( cqr_t *cqr )
-{
-	int ind;
-	long strtime,irqtime,endtime,tottime;
-	long tottimeps,sectors;
-	long help;
-	if ( ! cqr -> req ) 
-	  return;
-	sectors = cqr -> req -> nr_sectors;
-	strtime = ((cqr->startclk - cqr->buildclk) >> 12);
-	irqtime = ((cqr->stopclk - cqr->startclk) >> 12);
-	endtime = ((cqr->endclk - cqr->stopclk) >> 12);
-	tottime = ((cqr->endclk - cqr->buildclk) >> 12);
-	tottimeps = tottime / sectors;
-
-	if (! dasd_io_reqs ++){
-	  for ( ind = 0; ind < 16; ind ++) {
-		dasd_io_secs[ind] = 0;
-		dasd_io_times[ind]=0;
-		dasd_io_timps[ind]=0;
-		dasd_io_time1[ind]=0;
-		dasd_io_time2[ind]=0;
-		dasd_io_time2ps[ind]=0;
-		dasd_io_time3[ind]=0;
-	  }
-	};
-	
-	for ( ind = 0, help = sectors >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_secs[ind] ++;
-
-	for ( ind = 0, help = tottime >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_times[ind] ++;
-
-	for ( ind = 0, help = tottimeps >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_timps[ind] ++;
-
-	for ( ind = 0, help = strtime >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_time1[ind] ++;
-
-	for ( ind = 0, help = irqtime >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_time2[ind] ++;
-
-	for ( ind = 0, help = (irqtime/sectors) >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_time2ps[ind] ++;
-
-	for ( ind = 0, help = endtime >> 3; 
-	      ind < 15 && help; 
-	      help = help >> 1,ind ++);
-	dasd_io_time3[ind] ++;
-}
-
-int 
-dasd_proc_read_statistics ( char * buf, char **start, 
-			    off_t off, int len, int d)
-{
-	int i;
-	int shift, help;
-	
-	for ( shift = 0, help = dasd_io_reqs; 
-	      help > 8192; 
-	      help = help >> 1,shift ++);
-	len = sprintf ( buf, "%ld dasd I/O requests\n", dasd_io_reqs); 
-	len += sprintf ( buf+len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k >64k\n");
-	len += sprintf ( buf+len, "Histogram of sizes (512B secs)\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_secs[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O times\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_times[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O times per sector\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_timps[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O time till ssch\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_time1[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_time2[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq per sector\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_time2ps[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	len += sprintf ( buf+len, "Histogram of I/O time between irq and end\n");
-	for ( i = 0; i < 16; i ++) {
-		len += sprintf ( buf+len, "%4ld ",dasd_io_time3[i] >> shift );
-	}
-	len += sprintf ( buf+len, "\n");
-	return len;
-}
-typedef
-struct {
-	union {
-		unsigned long long  clock;
-		struct {
-			unsigned int ts1;
-			unsigned int ts2 : 20;
-			unsigned int unused : 8;
-			unsigned int cpu : 4;
-		} __attribute__ ((packed)) s;
-	} __attribute__ ((packed)) u;
-	unsigned long caller_address;
-	unsigned long tag;
-} __attribute__ ((packed))
-
-dasd_debug_entry;
-
-static dasd_debug_entry *dasd_debug_area = NULL;
-static dasd_debug_entry *dasd_debug_actual;
-static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED;
-
-void 
-dasd_debug ( unsigned long tag )
-{
-	long flags;
-	dasd_debug_entry *d;
-	/* initialize in first call ... */
-	if ( ! dasd_debug_area ) {
-		dasd_debug_actual = dasd_debug_area = 
-		    (dasd_debug_entry *) get_free_page (GFP_ATOMIC);
-		if ( ! dasd_debug_area ) {
-			PRINT_WARN("No debug area allocated\n");
-			return;
-		}
-		memset (dasd_debug_area,0,PAGE_SIZE);
-	}
-	/* renormalize to page */
-	spin_lock_irqsave(&debug_lock,flags);
-	dasd_debug_actual = (dasd_debug_entry *)
-		( (unsigned long) dasd_debug_area +
-		  ( ( (unsigned long)dasd_debug_actual -
-		      (unsigned long)dasd_debug_area ) % PAGE_SIZE ) );
-	d = dasd_debug_actual ++;
-	spin_unlock_irqrestore(&debug_lock,flags);
-	/* write CPUID to lowest 12 bits of clock... */
-	__asm__ __volatile__ ( "STCK  %0"
-			       :"=m" (d->u.clock));
-	d->tag = tag;
-	d->caller_address = (unsigned long) __builtin_return_address (0);
-	d->u.s.cpu = smp_processor_id();
-}
-
-int 
-dasd_proc_read_debug ( char * buf, char **start, 
-		       off_t off, int len, int dd)
-{
-	dasd_debug_entry *d;
-	char tag[9] =
-	{0,};
-	long flags;
-	spin_lock_irqsave(&debug_lock,flags);
-	len = 0;
-       	for( d = dasd_debug_area; 
-	     len < 4068 ;
-	     d ++ ) {
-		if ( *(char*)(&d->tag) == 'D' ) {
-			memcpy(tag,&(d->tag),4);
-			tag[4]=0;
-		} else {
-			sprintf (tag, "%08lx", d->tag);
-			tag[8]=0;
-		}
-		len += sprintf ( buf+len,
-				"%x %08x%05x %08lx (%8s)\n",
-				 d->u.s.cpu, d->u.s.ts1, d->u.s.ts2,
-				 d->caller_address,tag);
-	}
-	spin_unlock_irqrestore(&debug_lock,flags);
-	return len;
-}
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_setup.c linux/drivers/s390/block/dasd_setup.c
--- linux-2.2.17-pre12/drivers/s390/block/dasd_setup.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_setup.c	Wed Dec 31 16:00:00 1969
@@ -1,343 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_setup.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                : Utz Bacher <utz.bacher@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- */
-
-#include <linux/ctype.h>
-#include <linux/malloc.h>
-
-#include <linux/dasd.h>
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd(setup):"
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
-static int dasd_autodetect = 0;
-int dasd_probeonly = 1;
-static int dasd_count = 0;
-static int dasd_devno[DASD_MAX_DEVICES] =
-{0,};
-int dasd_force_mdsk_flag[DASD_MAX_DEVICES] =
-{0,};
-
-extern char *dasd[DASD_MAX_DEVICES];
-#ifdef CONFIG_DASD_MDSK
-extern char *dasd_force_mdsk[DASD_MAX_DEVICES];
-#endif
-
-typedef struct dasd_range {
-	int from, to;
-	struct dasd_range *next;
-} dasd_range;
-
-static dasd_range *first_range = NULL;
-
-void 
-dasd_add_devno_to_ranges (int devno)
-{
-	dasd_range *p, *prev;
-	for (p = first_range; p; prev = p, p = prev->next) {
-		if (devno >= p->from && devno <= p->to) {
-			PRINT_WARN ("devno %04X already in range %04X-%04X\n",
-				    devno, p->from, p->to);
-			return;
-		}
-		if (devno == (p->from - 1)) {
-			p->from--;
-			return;
-		}
-		if (devno == (p->to + 1)) {
-			p->to++;
-			return;
-		}
-	}
-	prev = kmalloc (sizeof (dasd_range), GFP_ATOMIC);
-	prev->from = prev->to = devno;
-	if (!first_range) {
-		first_range = prev;
-	}
-	return;
-}
-
-int
-dasd_proc_print_probed_ranges (char *buf, char **start, off_t off, int len, int d)
-{
-	dasd_range *p;
-	len = sprintf (buf, "Probed ranges of the DASD driver\n");
-	for (p = first_range; p; p = p->next) {
-		if (len >= PAGE_SIZE - 80)
-			len += sprintf (buf + len, "terminated...\n");
-		if (p != first_range) {
-			len += sprintf (buf + len, ",");
-		}
-		if (p->from == p->to) {
-			len += sprintf (buf + len, "%04x", p->from);
-		} else {
-			len += sprintf (buf + len, "%04x-%04x",
-					p->from, p->to);
-		}
-	}
-	len += sprintf (buf + len, "\n");
-	return len;
-}
-
-static int
-dasd_get_hexdigit (char c)
-{
-	if ((c >= '0') && (c <= '9'))
-		return c - '0';
-	if ((c >= 'a') && (c <= 'f'))
-		return c + 10 - 'a';
-	if ((c >= 'A') && (c <= 'F'))
-		return c + 10 - 'A';
-	return -1;
-}
-
-/* sets the string pointer after the next comma */
-static void
-dasd_scan_for_next_comma (char **strptr)
-{
-	while (((**strptr) != ',') && (**strptr))
-		(*strptr)++;
-
-	/* set the position AFTER the comma */
-	if (**strptr == ',')
-		(*strptr)++;
-}
-
-/*sets the string pointer after the next comma, if a parse error occured */
-static int
-dasd_get_next_int (char **strptr)
-{
-	int j, i = -1;		/* for cosmetic reasons first -1, then 0 */
-	if (isxdigit (**strptr)) {
-		for (i = 0; isxdigit (**strptr);) {
-			i <<= 4;
-			j = dasd_get_hexdigit (**strptr);
-			if (j == -1) {
-				PRINT_ERR ("no integer: skipping range.\n");
-				dasd_scan_for_next_comma (strptr);
-				i = -1;
-				break;
-			}
-			i += j;
-			(*strptr)++;
-			if (i > 0xffff) {
-				PRINT_ERR (" value too big, skipping range.\n");
-				dasd_scan_for_next_comma (strptr);
-				i = -1;
-				break;
-			}
-		}
-	}
-	return i;
-}
-
-int
-devindex_from_devno (int devno)
-{
-	int i;
-	if (dasd_probeonly) {
-		return 0;
-	}
-	for (i = 0; i < dasd_count; i++) {
-		if (dasd_devno[i] == devno)
-			return i;
-	}
-	if (dasd_autodetect) {
-		if (dasd_count < DASD_MAX_DEVICES) {
-			dasd_devno[dasd_count] = devno;
-			return dasd_count++;
-		}
-		return -EOVERFLOW;
-	}
-	return -ENODEV;
-}
-
-/* returns 1, if dasd_no is in the specified ranges, otherwise 0 */
-int
-dasd_is_accessible (int devno)
-{
-	return (devindex_from_devno (devno) >= 0);
-}
-
-/* dasd_insert_range skips ranges, if the start or the end is -1 */
-void
-dasd_insert_range (int start, int end)
-{
-	int curr;
-	if (dasd_count >= DASD_MAX_DEVICES) {
-		PRINT_ERR (" too many devices specified, ignoring some.\n");
-		return;
-	}
-	if ((start == -1) || (end == -1)) {
-		PRINT_ERR
-		    ("invalid format of parameter, skipping range\n");
-		return;
-	}
-	if (end < start) {
-		PRINT_ERR (" ignoring range from %x to %x - start value " \
-			   "must be less than end value.\n", start, end);
-		return;
-	}
-/* concurrent execution would be critical, but will not occur here */
-	for (curr = start; curr <= end; curr++) {
-		if (dasd_is_accessible (curr)) {
-			PRINT_WARN (" %x is already in list as device %d\n",
-				    curr, devindex_from_devno (curr));
-		}
-		dasd_devno[dasd_count] = curr;
-		dasd_count++;
-		if (dasd_count >= DASD_MAX_DEVICES) {
-			PRINT_ERR (" too many devices specified, ignoring some.\n");
-			break;
-		}
-	}
-	PRINT_INFO (" added dasd range from %x to %x.\n",
-		    start, dasd_devno[dasd_count - 1]);
-
-}
-
-void
-dasd_setup (char *str, int *ints)
-{
-	int devno, devno2;
-	static const char *adstring = "autodetect";
-	static const char *prstring = "probeonly";
-	if (!strncmp (str, prstring,
-		      MIN (strlen (str), strlen (prstring)))) {
-		dasd_autodetect = 1;
-		return;
-	}
-	if (!strncmp (str, adstring,
-		      MIN (strlen (str), strlen (adstring)))) {
-		dasd_autodetect = 1;
-		dasd_probeonly = 0;
-		return;
-	}
-	dasd_probeonly = 0;
-	while (*str && *str != 1) {
-		if (!isxdigit (*str)) {
-			str++;	/* to avoid looping on two commas */
-			PRINT_ERR (" kernel parameter in invalid format.\n");
-			continue;
-		}
-		devno = dasd_get_next_int (&str);
-
-		/* range was skipped? -> scan for comma has been done */
-		if (devno == -1)
-			continue;
-
-		if (*str == ',') {
-			str++;
-			dasd_insert_range (devno, devno);
-			continue;
-		}
-		if (*str == '-') {
-			str++;
-			devno2 = dasd_get_next_int (&str);
-			if (devno2 == -1) {
-				PRINT_ERR (" invalid character in " \
-					   "kernel parameters.");
-			} else {
-				dasd_insert_range (devno, devno2);
-			}
-			dasd_scan_for_next_comma (&str);
-			continue;
-		}
-		if (*str == 0) {
-			dasd_insert_range (devno, devno);
-			break;
-		}
-		PRINT_ERR (" unexpected character in kernel parameter, " \
-			   "skipping range.\n");
-	}
-}
-#ifdef CONFIG_DASD_MDSK
-int dasd_force_mdsk_flag[DASD_MAX_DEVICES];
-
-/*
- * Parameter parsing function, called from init/main.c
- * size    : size in kbyte
- * offset  : offset after which minidisk is available
- * blksize : blocksize minidisk is formated
- * Format is: mdisk=<vdev>,<vdev>,...
- */
-void
-dasd_mdsk_setup (char *str, int *ints)
-{
-	int devno, devno2;
-	int di, i;
-
-	while (*str && *str != 1) {
-		if (!isxdigit (*str)) {
-			str++;	/* to avoid looping on two commas */
-			PRINT_ERR (" kernel parameter in invalid format.\n");
-			continue;
-		}
-		devno = dasd_get_next_int (&str);
-
-		/* range was skipped? -> scan for comma has been done */
-		if (devno == -1)
-			continue;
-
-		if (*str == ',') {
-			str++;
-			di = devindex_from_devno (devno);
-			if (di >= DASD_MAX_DEVICES) {
-				return;
-			} else if (di < 0)
-				dasd_insert_range (devno, devno);
-			dasd_force_mdsk_flag[di] = 1;
-			continue;
-		}
-		if (*str == '-') {
-			str++;
-			devno2 = dasd_get_next_int (&str);
-			if (devno2 == -1) {
-				PRINT_ERR (" invalid character in " \
-					   "kernel parameters.");
-			} else {
-				for (i = devno; i <= devno2; i++) {
-					di = devindex_from_devno (i);
-					if (di >= DASD_MAX_DEVICES) {
-						return;
-					} else if (di < 0)
-						dasd_insert_range (i, i);
-					dasd_force_mdsk_flag[di] = 1;
-				}
-			}
-			dasd_scan_for_next_comma (&str);
-			continue;
-		}
-		if (*str == 0) {
-			di = devindex_from_devno (devno);
-			if (di >= DASD_MAX_DEVICES) {
-				return;
-			} else if (di < 0)
-				dasd_insert_range (devno, devno);
-			dasd_force_mdsk_flag[di] = 1;
-			break;
-		}
-		PRINT_ERR (" unexpected character in kernel parameter, " \
-			   "skipping range.\n");
-	}
-}
-#endif
-
-#ifdef MODULE
-int
-dasd_parse_module_params (void)
-{
-	while (dasd)
-		dasd_setup (dasd, NULL);
-#ifdef CONFIG_DASD_MDSK
-	while (dasd_force_mdsk)
-		dasd_mdsk_setup (dasd_force_mdsk, NULL);
-#endif
-}
-#endif
diff -urN linux-2.2.17-pre12/drivers/s390/block/dasd_types.h linux/drivers/s390/block/dasd_types.h
--- linux-2.2.17-pre12/drivers/s390/block/dasd_types.h	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/block/dasd_types.h	Wed Dec 31 16:00:00 1969
@@ -1,359 +0,0 @@
-
-/*
- * File...........: linux/drivers/s390/block/dasd_types.h
- * Author.........: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Created........: 08/31/1999
- * Last Modified..: 09/29/1999
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
- * List of Changes:
- - Initial Release as of 09/29/1999
-
- * Description
-
- * Restrictions
-
- * Known Bugs
-
- * Todo-List
-
- */
-
-#ifndef DASD_TYPES_H
-#define DASD_TYPES_H
-
-#include <linux/dasd.h>
-
-#include <linux/blkdev.h>
-
-#include <linux/hdreg.h>
-
-#include <asm/irq.h>
-
-#include "dasd_mdsk.h"
-
-#define ACS(where,from,to) if (atomic_compare_and_swap (from, to, &where)) {\
-	PRINT_WARN ("%s/%d atomic %s from %d(%s) to %d(%s) failed, was %d\n",\
-		    __FILE__,__LINE__,#where,from,#from,to,#to,\
-                    atomic_read (&where));\
-        atomic_set(&where,to);}
-
-#define CCW_DEFINE_EXTENT 0x63
-#define CCW_LOCATE_RECORD 0x43
-#define CCW_READ_DEVICE_CHARACTERISTICS 0x64
-
-typedef
-enum {
-	dasd_none = -1,
-#ifdef CONFIG_DASD_ECKD
-	dasd_eckd,
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-	dasd_fba,
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-	dasd_mdsk,
-#endif				/* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-	dasd_ckd,
-#endif				/* CONFIG_DASD_CKD */
-	dasd_end
-} dasd_type_t;
-
-typedef
-struct {
-	union {
-		__u8 c;
-		struct {
-			unsigned char reserved:1;
-			unsigned char overrunnable:1;
-			unsigned char burst_byte:1;
-			unsigned char data_chain:1;
-			unsigned char zeros:4;
-		} __attribute__ ((packed)) bits;
-	} __attribute__ ((packed)) mode;
-	union {
-		__u8 c;
-		struct {
-			unsigned char zero0:1;
-			unsigned char removable:1;
-			unsigned char shared:1;
-			unsigned char zero1:1;
-			unsigned char mam:1;
-			unsigned char zeros:3;
-		} __attribute__ ((packed)) bits;
-	} __attribute__ ((packed)) features;
-	__u8 dev_class;
-	__u8 unit_type;
-	__u16 blk_size;
-	__u32 blk_per_cycl;
-	__u32 blk_per_bound;
-	__u32 blk_bdsa;
-	__u32 reserved0;
-	__u16 reserved1;
-	__u16 blk_ce;
-	__u32 reserved2;
-	__u16 reserved3;
-} __attribute__ ((packed, aligned (32))) 
-
-dasd_fba_characteristics_t;
-
-typedef
-struct {
-	__u16 cu_type;
-	struct {
-		unsigned char support:2;
-		unsigned char async:1;
-		unsigned char reserved:1;
-		unsigned char cache_info:1;
-		unsigned char model:3;
-	} __attribute__ ((packed)) cu_model;
-	__u16 dev_type;
-	__u8 dev_model;
-	struct {
-		unsigned char mult_burst:1;
-		unsigned char RT_in_LR:1;
-		unsigned char reserved1:1;
-		unsigned char RD_IN_LR:1;
-		unsigned char reserved2:4;
-		unsigned char reserved3:8;
-		unsigned char defect_wr:1;
-		unsigned char reserved4:2;
-		unsigned char striping:1;
-		unsigned char reserved5:4;
-		unsigned char cfw:1;
-		unsigned char reserved6:2;
-		unsigned char cache:1;
-		unsigned char dual_copy:1;
-		unsigned char dfw:1;
-		unsigned char reset_alleg:1;
-		unsigned char sense_down:1;
-	} __attribute__ ((packed)) facilities;
-	__u8 dev_class;
-	__u8 unit_type;
-	__u16 no_cyl;
-	__u16 trk_per_cyl;
-	__u8 sec_per_trk;
-	__u8 byte_per_track[3];
-	__u16 home_bytes;
-	__u8 formula;
-	union {
-		struct {
-			__u8 f1;
-			__u16 f2;
-			__u16 f3;
-		} __attribute__ ((packed)) f_0x01;
-		struct {
-			__u8 f1;
-			__u8 f2;
-			__u8 f3;
-			__u8 f4;
-			__u8 f5;
-		} __attribute__ ((packed)) f_0x02;
-	} __attribute__ ((packed)) factors;
-	__u16 first_alt_trk;
-	__u16 no_alt_trk;
-	__u16 first_dia_trk;
-	__u16 no_dia_trk;
-	__u16 first_sup_trk;
-	__u16 no_sup_trk;
-	__u8 MDR_ID;
-	__u8 OBR_ID;
-	__u8 director;
-	__u8 rd_trk_set;
-	__u16 max_rec_zero;
-	__u8 reserved1;
-	__u8 RWANY_in_LR;
-	__u8 factor6;
-	__u8 factor7;
-	__u8 factor8;
-	__u8 reserved2[3];
-	__u8 reserved3[10];
-} __attribute__ ((packed, aligned (32))) 
-
-dasd_eckd_characteristics_t;
-
-typedef struct {
-	u16 dev_nr;
-	u16 rdc_len;
-	u8 vdev_class;
-	u8 vdev_type;
-	u8 vdev_status;
-	u8 vdev_flags;
-	u8 rdev_class;
-	u8 rdev_type;
-	u8 rdev_model;
-	u8 rdev_features;
-} __attribute__ ((packed, aligned (32)))
-
-dasd_mdsk_characteristics_t;
-
-/* eckd count area */
-typedef struct {
-	__u16 cyl;
-	__u16 head;
-	__u8 record;
-	__u8 kl;
-	__u16 dl;
-} __attribute__ ((packed))
-
-eckd_count_t;
-
-#ifdef CONFIG_DASD_CKD
-struct dasd_ckd_characteristics {
-	char info[64];
-};
-
-#endif				/* CONFIG_DASD_CKD */
-
-typedef
-union {
-	char __attribute__ ((aligned (32))) bytes[64];
-#ifdef CONFIG_DASD_FBA
-	dasd_fba_characteristics_t fba;
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_CKD
-	struct dasd_ckd_characteristics ckd;
-#endif				/* CONFIG_DASD_CKD */
-#ifdef CONFIG_DASD_ECKD
-	dasd_eckd_characteristics_t eckd;
-#endif				/* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_MDSK
-	dasd_mdsk_characteristics_t mdsk;
-#endif				/* CONFIG_DASD_ECKD */
-} __attribute__ ((aligned (32))) 
-
-dasd_characteristics_t;
-
-#define CQR_STATUS_EMPTY  0x00
-#define CQR_STATUS_FILLED 0x01
-#define CQR_STATUS_QUEUED 0x02
-#define CQR_STATUS_IN_IO  0x04
-#define CQR_STATUS_DONE   0x08
-#define CQR_STATUS_ERROR  0x10
-#define CQR_STATUS_ERP_PEND  0x20
-#define CQR_STATUS_ERP_ACTIVE  0x40
-#define CQR_STATUS_FAILED 0x80
-
-#define CQR_FLAGS_SLEEP   0x01
-#define CQR_FLAGS_WAIT    0x02
-#define CQR_FLAGS_NOLOCK  0x04
-#define CQR_FLAGS_NORETRY 0x08
-
-typedef
-struct cqr_t {
-	unsigned int    magic;    /* magic number should be "DASD" */
-	atomic_t status;	/* current status of request */
-	unsigned short retries; /* counter for retry in error case */
-	unsigned short cplength;/* Length of channel program  (CP) */
-	unsigned short devindex;/* device number */
-	unsigned short flags;    /* Flags for execution */
-	
-	void * data;		/* additional data area for CP */
-	ccw1_t *cpaddr;		/* Address of CP */
-	struct request *req;	/* backpointer to struct request */
-	struct cqr_t *next;     /* forward chain in chanq */
-	struct cqr_t *int4cqr;  /* which cqr ist the nect PCI for? */
-	unsigned long long buildclk;
-	unsigned long long startclk;
-	unsigned long long stopclk;
-	unsigned long long endclk;
-	devstat_t *dstat;	/* savearea for devstat */
-	spinlock_t lock;
-	int options;
-} __attribute__ ((packed)) 
-
-cqr_t;
-
-typedef
-struct {
-	unsigned long int kbytes;
-	unsigned int bp_sector;
-	unsigned int bp_block;
-	unsigned int blocks;
-	unsigned int s2b_shift;
-	unsigned int label_block;
-} dasd_sizes_t;
-
-#define DASD_CHANQ_ACTIVE 0x01
-#define DASD_CHANQ_BUSY 0x02
-#define DASD_REQUEST_Q_BROKEN 0x04
-
-typedef
-struct dasd_chanq_t {
-	volatile cqr_t *head;
-	volatile cqr_t *tail;
-	spinlock_t q_lock;	/* lock for queue operations */
-	spinlock_t f_lock;	/* lock for flag operations */
-	int queued_requests;
-	atomic_t flags;
-	atomic_t dirty_requests;
-	struct dasd_chanq_t *next_q;	/* pointer to next queue */
-} __attribute__ ((packed, aligned (16))) 
-
-dasd_chanq_t;
-
-#define DASD_INFO_STATUS_UNKNOWN 0x00	/* nothing known about DASD */
-#define DASD_INFO_STATUS_DETECTED 0x01	/* DASD identified as DASD, irq taken */
-#define DASD_INFO_STATUS_ANALYSED 0x02	/* first block read, filled sizes */
-#define DASD_INFO_STATUS_FORMATTED 0x04		/* identified valid format */
-#define DASD_INFO_STATUS_PARTITIONED 0x08	/* identified partitions */
-
-typedef
-struct dasd_information_t {
-	devstat_t dev_status;
-	dasd_characteristics_t *rdc_data;
-	dasd_volume_label_t *label;
-	dasd_type_t type;
-	dev_info_t info;
-	dasd_sizes_t sizes;
-	dasd_chanq_t queue;
-	int open_count;
-	spinlock_t lock;
-	struct semaphore sem;
-	atomic_t status;
-	int irq;
-	mdsk_setup_data_t *mdsk_setup;
-	struct proc_dir_entry *proc_device;
-	union {
-		struct {
-			eckd_count_t count_data;
-		} eckd;
-		struct {
-			char dummy;
-		} fba;
-		struct {
-			mdsk_init_io_t iib;
-			mdsk_rw_io_t iob;
-			mdsk_setup_data_t setup;
-			long *label;
-		} mdsk;
-		struct {
-			char dummy;
-		} ckd;
-	} private;
-	struct wait_queue *wait_q;
-} dasd_information_t;
-
-extern dasd_information_t *dasd_info[];
-
-#include "dasd_erp.h"
-
-typedef
-struct {
-	int (*ck_devinfo) (dev_info_t *);
-	cqr_t *(*get_req_ccw) (int, struct request *);
-	int (*ck_characteristics) (dasd_characteristics_t *);
-	cqr_t *(*fill_sizes_first) (int);
-	int (*fill_sizes_last) (int);
-	int (*dasd_format) (int, format_data_t *);
-	void (*fill_geometry) (int, struct hd_geometry *);
-	 dasd_era_t (*erp_examine) (cqr_t *, devstat_t *);
-} dasd_operations_t;
-
-extern dasd_operations_t *dasd_disciplines[];
-
-/* Prototypes */
-int dasd_start_IO (cqr_t * cqr);
-
-#endif				/* DASD_TYPES_H */
diff -urN linux-2.2.17-pre12/drivers/s390/ccwcache.c linux/drivers/s390/ccwcache.c
--- linux-2.2.17-pre12/drivers/s390/ccwcache.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/ccwcache.c	Mon Dec  3 22:09:50 2001
@@ -0,0 +1,381 @@
+/* 
+   * File...........: linux/drivers/s390/block/ccwcache.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/10/00 moved ccwcache.h from linux/ to asm/
+ */
+
+#include <linux/malloc.h>
+#include <asm/debug.h>
+#include <asm/ccwcache.h>
+
+#include <asm/ebcdic.h>
+#include <asm/spinlock.h>
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif
+#define PRINTK_HEADER "ccwcache"
+
+#ifdef MODULE
+MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
+MODULE_DESCRIPTION ("Linux on S/390 CCW cache,"
+		    "Copyright 2000 IBM Corporation");
+EXPORT_NO_SYMBOLS; 
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
+#endif /* MODULE */
+
+
+/* pointer to list of allocated requests */
+static ccw_req_t *ccwreq_actual = NULL;
+
+/* 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 dechain ( ccw_req_t *request )
+ * dechains the request from the ringbuffer
+ */
+
+static void 
+dechain ( ccw_req_t *request )
+{
+	/* Sanity checks */
+	if ( request == NULL ) {
+		printk( KERN_WARNING PRINTK_HEADER
+			"Trying to deallocate NULL request\n");
+		return;
+	}
+	/* first deallocate request from list of allocates requests */
+	if ( request -> int_next && request -> int_prev ) {
+		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;
+		}
+	} else if ( request -> int_next || request -> int_prev ) {
+	}
+	return;
+}
+
+/* 
+ * 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 cachind = 0;
+	int size_needed = 0;
+
+	debug_text_event ( debug_area, 1, "ALLC");
+	if ( magic ) {
+		debug_text_event ( debug_area, 1, magic);
+	}
+	debug_event ( debug_area, 1, cplength);
+	debug_event ( debug_area, 1, datasize);
+
+	/* Sanity checks */
+	if ( cplength == 0 ) {
+		printk (KERN_DEBUG PRINTK_HEADER
+			"called ccw_alloc_request with cplength of 0 from %p\n",
+			     __builtin_return_address(0));
+		return NULL;
+	}
+	if ( (cplength << 3 ) > PAGE_SIZE ) {
+		printk(KERN_WARNING PRINTK_HEADER
+		       "Channel program to large to fit on one page\n");
+		return NULL;
+	}
+	if ( datasize > PAGE_SIZE ) {
+		printk(KERN_WARNING PRINTK_HEADER
+		       "Data size to large to fit on one page\n");
+		return NULL;
+	}
+	
+	/* Try to keep things together in memory */
+	if ( sizeof (ccw_req_t) + 
+	     (((datasize + 7) >> 3) << 3) +  /* align upper end of data to 8 */
+	     (cplength << 3 ) < PAGE_SIZE ) {
+		/* All fit on one page, is preferred. */
+		size_needed = sizeof (ccw_req_t) + datasize + (cplength << 3 );
+	} else if ( sizeof (ccw_req_t) + (cplength << 3 ) < PAGE_SIZE ) {
+		/* Try to keep CCWs with request */
+		size_needed = sizeof (ccw_req_t) + (cplength << 3 );
+	} else if ( sizeof (ccw_req_t) + datasize < PAGE_SIZE ) {
+		/* Try to keep at least the data with request */
+		size_needed = sizeof (ccw_req_t) + datasize;
+	} else {
+		/* Fall back to hold only the request in cache */
+		size_needed = sizeof (ccw_req_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 */
+	while (  cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */
+	  if ( ccw_cache[cachind] == NULL ){
+	    printk("cache=%p index %d\n",cachind,cachind);
+	  }
+	  request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC );
+	  if ( request != NULL ) {
+	    memset ( request, 0, (SMALLEST_SLAB << cachind));
+	    request->cache = ccw_cache[cachind];
+	    break;
+	  } else {
+	    printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache");
+	  }
+ 	  cachind++;
+	} 
+	/* if no success, fall back to kmalloc */
+	if ( request == NULL ) {
+	  printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc");
+		request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC );
+		if ( request != NULL ) {
+			memset ( request, 0, sizeof(ccw_req_t));
+		}
+	}
+	/* Initialize request */
+	if ( request == NULL ) {  
+		printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request");
+	} else {
+		if ( request -> cache != NULL ) {
+			/* Three cases when coming from a cache */
+			if ( sizeof (ccw_req_t) + 
+			     (((datasize + 7) >> 3) << 3) +
+			     (cplength << 3 ) < 
+			     PAGE_SIZE ) {
+				request->data= (void*)(request + 1);
+				request->cpaddr= (ccw1_t *)(((((long)(request + 1))+ 
+							     datasize + 7)
+							    >> 3) << 3);
+			} else if ( sizeof (ccw_req_t) + (cplength << 3 ) < 
+				    PAGE_SIZE ) {
+				request->cpaddr=(ccw1_t *)(((((long)(request)) + 
+							     sizeof(ccw_req_t) + 7)
+							    >> 3) << 3);
+			} else if ( sizeof (ccw_req_t) + datasize < PAGE_SIZE ) {
+				request->data= (void *)(request + 1);
+			} else {} 
+		}
+		/* Have the rest be done by kmalloc */
+		if ( request -> cpaddr == NULL ) {
+			printk(KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc for CCW area\n");
+			request->cpaddr=(ccw1_t *) kmalloc(sizeof(ccw1_t) * cplength,
+							  GFP_ATOMIC);
+			if ( request -> cpaddr == NULL ) {
+				printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate ccw area\n");
+				ccw_free_request(request);
+				return NULL;
+			}
+		}
+		if ( request -> data == NULL ) {
+			printk(KERN_DEBUG PRINTK_HEADER"Falling back to kmalloc for data area\n");
+			request->data=(void *)kmalloc(datasize, GFP_ATOMIC);
+			if ( request -> data == NULL ) {
+				printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate data area\n");
+				ccw_free_request(request);
+				return NULL;
+			}
+		}
+		memset ( request->data,0,datasize );
+		memset ( request->cpaddr,0,cplength*sizeof(ccw1_t) );
+		if ( magic ) {
+			strncpy ( (char *)(&request->magic), magic, 4);
+		}
+		else {
+			strncpy ( (char *)(&request->magic), "CCWC", 4);
+		}
+		ASCEBC((char *)(&request->magic),4);
+		request -> cplength = cplength;
+		request -> datasize = datasize;
+		/* enqueue request to list of allocated requests */
+		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;
+		}
+	}
+	debug_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 cachind;
+	int slabsize;
+
+	debug_text_event ( debug_area, 1, "FREE");
+	debug_event ( debug_area, 1, (long)request);
+	/* Sanity checks */
+	if ( request == NULL ) {
+		printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n");
+		return;
+	}
+	if ( request -> cache == NULL ) {
+		printk (KERN_WARNING PRINTK_HEADER "Deallocating uncached request\n");
+		if ( request -> data ) {
+			kfree ( request -> data );
+		}
+		if ( request ->cpaddr ) {
+			kfree ( request -> cpaddr );
+		}
+		dechain ( request);
+		kfree ( request );
+	} else {
+		/* Find which area has been allocated by kmalloc */
+		for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ )
+			if ( request->cache == ccw_cache[cachind] )
+				break;
+		if ( request->cache != ccw_cache[cachind] ) {
+			printk(KERN_WARNING PRINTK_HEADER"Cannot find cache in list\n");
+		}
+		slabsize = SMALLEST_SLAB << cachind;
+		if ( request -> data &&
+		     (((unsigned long)(request -> data) >
+		       ((unsigned long)request) + slabsize) ||
+		      ((unsigned long)(request -> data) < 
+		       ((unsigned long)request)))) {
+			kfree ( request -> data );
+		}
+		if ( request ->cpaddr &&
+		     (((unsigned long)(request -> cpaddr) >
+		       ((unsigned long)request) + slabsize) ||
+		      (unsigned long)(request -> cpaddr) < 
+		      ((unsigned long)request))) {
+			kfree ( request -> cpaddr );
+		}
+		dechain ( request);
+		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;
+
+	/* allocate a debug area */
+	debug_area = debug_register( "ccwcache", 2, 4);
+	if ( ! debug_area ) {
+		printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" );
+	} else {
+		printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
+	}
+	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_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,
+							SLAB_HWCACHE_ALIGN, 
+							NULL, NULL );
+		debug_event ( debug_area, 1, (long)ccw_cache[cachind]);
+		if ( ! ccw_cache [cachind] ) {
+			printk (KERN_WARNING PRINTK_HEADER "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;
+			}
+		}
+	}
+	debug_unregister( debug_area ,"ccwcache");
+}
+
+#ifdef MODULE
+int
+init_module ( void )
+{
+	int rc;
+	int i;
+	rc = ccwcache_init();
+	for ( i = 0; i < 200; i ++) {
+		PRINT_INFO ("allocated %p\n",ccw_alloc_request("test",i,200-i));
+	}
+	return rc;
+}
+
+void
+cleanup_module ( void )
+{
+	while ( ccwreq_actual ) {
+		PRINT_INFO ("freeing %p\n",ccwreq_actual -> int_next);
+		ccw_free_request( ccwreq_actual -> int_next );
+		if ( ccwreq_actual ) {
+			PRINT_INFO ("freeing %p\n",ccwreq_actual -> int_prev);
+			ccw_free_request( ccwreq_actual -> int_prev );
+		}
+		if ( ccwreq_actual ) {
+			PRINT_INFO ("freeing %p\n",ccwreq_actual);
+			ccw_free_request( ccwreq_actual);
+		}
+	}
+	ccwcache_cleanup();
+}
+#endif /* MODULE */
diff -urN linux-2.2.17-pre12/drivers/s390/char/con3215.c linux/drivers/s390/char/con3215.c
--- linux-2.2.17-pre12/drivers/s390/char/con3215.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/char/con3215.c	Mon Dec  3 22:09:50 2001
@@ -30,8 +30,9 @@
 #define RAW3215_INBUF_SIZE  256	      /* input buffer size */
 #define RAW3215_MIN_SPACE   128	      /* minimum free space for wakeup */
 #define RAW3215_MIN_WRITE   1024      /* min. length for immediate output */
-#define RAW3215_MAX_CCWLEN  3968      /* max. bytes to write with one ccw */
-#define RAW3215_NR_CCWS	    ((RAW3215_BUFFER_SIZE/RAW3215_MAX_CCWLEN)+2)
+#define RAW3215_MAX_BYTES   3968      /* max. bytes to write with one ssch */
+#define RAW3215_MAX_NEWLINE 50        /* max. lines to write with one ssch */
+#define RAW3215_NR_CCWS	    3
 #define RAW3215_TIMEOUT	    HZ/10     /* time for delayed output */
 
 #define RAW3215_FIXED	    1	      /* 3215 console device is not be freed */
@@ -60,7 +61,8 @@
  */
 typedef struct _raw3215_req {
 	raw3215_type type;	      /* type of the request */
-	int start, end;		      /* start/end index into output buffer */
+	int start, len;		      /* start index & len in output buffer */
+        int delayable;                /* indication to wait for more data */
 	int residual;		      /* residual count for read request */
 	ccw1_t ccws[RAW3215_NR_CCWS]; /* space for the channel program */
 	struct _raw3215_info *info;   /* pointer to main structure */
@@ -74,6 +76,7 @@
 	char *inbuf;		      /* pointer to input buffer */
 	int head;		      /* first free byte in output buffer */
 	int count;		      /* number of bytes in output buffer */
+        int written;                  /* number of bytes in write requests */
 	devstat_t devstat;	      /* device status structure for do_IO */
 	struct tty_struct *tty;	      /* pointer to tty structure if present */
 	struct tq_struct tqueue;      /* task queue to bottom half */
@@ -104,7 +107,7 @@
 {
         int vdev;
 
-        vdev = simple_strtoul(str,&str,16);
+        vdev = simple_strtoul(str,&str,10);
         if (vdev >= 0 && vdev < 65536)
                 raw3215_condevice = vdev;
         return;
@@ -140,61 +143,83 @@
 }
 
 /*
- * Get a write request structure. That is either a new or the last
- * queued write request. The request structure is set up in 
- * raw3215_mk_write_ccw.
+ * Set up a read request that reads up to 160 byte from the 3215 device.
+ * If there is a queued read request it is used, but that shouldn't happen
+ * because a 3215 terminal won't accept a new read before the old one is
+ * completed.
  */
-static raw3215_req *raw3215_mk_write_req(raw3215_info *raw)
+static void raw3215_mk_read_req(raw3215_info *raw)
 {
 	raw3215_req *req;
+        ccw1_t *ccw;
 
-	/* check if there is a queued write request */
-	req = raw->queued_write;
+	/* there can only be ONE read request at a time */
+	req = raw->queued_read;
 	if (req == NULL) {
-		/* no queued write request, use new req structure */
+		/* no queued read request, use new req structure */
 		req = raw3215_alloc_req();
-		req->type = RAW3215_WRITE;
+		req->type = RAW3215_READ;
 		req->info = raw;
-		req->start = raw->head;
-	} else
-		raw->queued_write = NULL;
-	return req;
+                raw->queued_read = req;
+	}
+
+        ccw = req->ccws;
+        ccw->cmd_code = 0x0A; /* read inquiry */
+        ccw->flags = 0x20;    /* ignore incorrect length */
+        ccw->count = 160;
+        ccw->cda = (void *) virt_to_phys(raw->inbuf);
 }
 
 /*
- * Get a read request structure. If there is a queued read request
- * it is used, but that shouldn't happen because a 3215 terminal
- * won't accept a new read before the old one is completed.
+ * Set up a write request with the information from the main structure.
+ * A ccw chain is created that writes as much as possible from the output
+ * buffer to the 3215 device. If a queued write exists it is replaced by
+ * the new, probably lengthened request.
  */
-static raw3215_req *raw3215_mk_read_req(raw3215_info *raw)
+static void raw3215_mk_write_req(raw3215_info *raw)
 {
 	raw3215_req *req;
+	ccw1_t *ccw;
+	int len, count, ix, lines;
 
-	/* there can only be ONE read request at a time */
-	req = raw->queued_read;
+        if (raw->count <= raw->written)
+                return;
+        /* check if there is a queued write request */
+        req = raw->queued_write;
 	if (req == NULL) {
-		/* no queued read request, use new req structure */
+                /* no queued write request, use new req structure */
 		req = raw3215_alloc_req();
-		req->type = RAW3215_READ;
+                req->type = RAW3215_WRITE;
 		req->info = raw;
-	} else
-		raw->queued_read = NULL;
-	return req;
+                raw->queued_write = req;
+        } else {
+                raw->written -= req->len;
 }
 
+	ccw = req->ccws;
+        req->start = (raw->head - raw->count + raw->written) &
+                     (RAW3215_BUFFER_SIZE - 1);
 /*
- * Set up a write request with the information from the main structure.
- * A ccw chain is created that writes everything in the output buffer
- * to the 3215 device.
- */
-static int raw3215_mk_write_ccw(raw3215_info *raw, raw3215_req *req)
-{
-	ccw1_t *ccw;
-	int len, count, ix;
+         * now we have to count newlines. We can at max accept
+         * RAW3215_MAX_NEWLINE newlines in a single ssch due to
+         * a restriction in VM
+ */
+        lines = 0;
+        ix = req->start;
+        while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) {
+                if (raw->buffer[ix] == '\n')
+                        lines++;
+                ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
+        }
+	len = ((ix - 1 - req->start) & (RAW3215_BUFFER_SIZE - 1)) + 1;
+        if (len > RAW3215_MAX_BYTES)
+                len = RAW3215_MAX_BYTES;
+        req->len = len;
+        raw->written += len;
+
+        /* set the indication if we should try to enlarge this request */
+        req->delayable = (ix == raw->head) && (len < RAW3215_MIN_WRITE);
 
-	ccw = req->ccws;
-	req->end = (raw->head - 1) & (RAW3215_BUFFER_SIZE - 1);
-	len = ((req->end - req->start) & (RAW3215_BUFFER_SIZE - 1)) + 1;
 	ix = req->start;
 	while (len > 0) {
 		if (ccw > req->ccws)
@@ -203,8 +228,7 @@
 		ccw->flags = 0x20;    /* ignore incorrect length ind.  */
 		ccw->cda =
 			(void *) virt_to_phys(raw->buffer + ix);
-		count = (len > RAW3215_MAX_CCWLEN) ? 
-			RAW3215_MAX_CCWLEN : len;
+		count = len;
 		if (ix + count > RAW3215_BUFFER_SIZE)
 			count = RAW3215_BUFFER_SIZE-ix;
 		ccw->count = count;
@@ -212,21 +236,17 @@
 		ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
 		ccw++;
 	}
-	return len;
-}
-
 /*
- * Set up a read request that reads up to 160 byte from the 3215 device.
- */
-static void raw3215_mk_read_ccw(raw3215_info *raw, raw3215_req *req)
-{
-	ccw1_t *ccw;
-
-	ccw = req->ccws;
-	ccw->cmd_code = 0x0A; /* read inquiry */
-	ccw->flags = 0x20;    /* ignore incorrect length */
-	ccw->count = 160;
-	ccw->cda = (void *) virt_to_phys(raw->inbuf);
+         * Add a NOP to the channel program. 3215 devices are purely
+         * emulated and its much better to avoid the channel end 
+         * interrupt in this case.
+ */
+        if (ccw > req->ccws)
+                ccw[-1].flags |= 0x40; /* use command chaining */
+        ccw->cmd_code = 0x03; /* NOP */
+        ccw->flags = 0;
+        ccw->cda = 0;
+        ccw->count = 1;
 }
 
 /*
@@ -277,6 +297,7 @@
 	if (raw->flags & RAW3215_TIMER_RUNS) {
 		del_timer(&raw->timer);
 		raw->flags &= ~RAW3215_TIMER_RUNS;
+                raw3215_mk_write_req(raw);
 		raw3215_start_io(raw);
 	}
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
@@ -295,7 +316,7 @@
 	if (raw->queued_read != NULL)
 		raw3215_start_io(raw);
 	else if (raw->queued_write != NULL) {
-		if (raw->count >= RAW3215_MIN_WRITE ||
+		if ((raw->queued_write->delayable == 0) ||
 		    (raw->flags & RAW3215_FLUSHING)) {
 			/* execute write requests bigger than minimum size */
 			raw3215_start_io(raw);
@@ -327,7 +348,8 @@
 
 	raw = (raw3215_info *) data;
 	s390irq_spin_lock_irqsave(raw->irq, flags);
-	raw3215_try_io((raw3215_info *) data);
+        raw3215_mk_write_req(raw);
+        raw3215_try_io(raw);
         raw->flags &= ~RAW3215_BH_PENDING;
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 	/* Check for pending message from raw3215_irq */
@@ -415,9 +437,7 @@
 		if ((raw = raw3215_find_info(irq)) == NULL)
 			return;              /* That shouldn't happen ... */
 		/* Setup a read request */
-		req = raw3215_mk_read_req(raw);
-		raw3215_mk_read_ccw(raw, req);
-		raw->queued_read = req;
+		raw3215_mk_read_req(raw);
                 if (MACHINE_IS_P390)
                         memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
                 raw3215_sched_bh(raw);
@@ -425,7 +445,8 @@
 	case 0x08:
 	case 0x0C:
 		/* Channel end interrupt. */
-		raw = req->info;
+		if ((raw = req->info) == NULL)
+                        return;              /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ) {
 			/* store residual count, then wait for device end */
 			req->residual = stat->rescnt;
@@ -434,7 +455,8 @@
 			break;
 	case 0x04:
 		/* Device end interrupt. */
-		raw = req->info;
+                if ((raw = req->info) == NULL)
+                        return;              /* That shouldn't happen ... */
 		if (req->type == RAW3215_READ && raw->tty != NULL) {
 			tty = raw->tty;
 			count = 160 - req->residual;
@@ -493,8 +515,8 @@
 				tty_flip_buffer_push(raw->tty);
 			}
 		} else if (req->type == RAW3215_WRITE) {
-			raw->count -= ((req->end - req->start) &
-				       (RAW3215_BUFFER_SIZE - 1)) + 1;
+			raw->count -= req->len;
+                        raw->written -= req->len;
 		}
 		raw->flags &= ~RAW3215_WORKING;
 		raw3215_free_req(req);
@@ -511,11 +533,11 @@
 			/* Strange interrupt, I'll do my best to clean up */
                 if ((raw = raw3215_find_info(irq)) == NULL)
                         return;              /* That shouldn't happen ... */
-                if (raw == NULL) break;
 		if (req != NULL && req->type != RAW3215_FREE) {
-		        if (req->type == RAW3215_WRITE) 
-			        raw->count -= ((req->end - req->start) &
-					            (RAW3215_BUFFER_SIZE-1))+1;
+		        if (req->type == RAW3215_WRITE) {
+			        raw->count -= req->len;
+                                raw->written -= req->len;
+                        }
                         raw->flags &= ~RAW3215_WORKING;
                         raw3215_free_req(req);
 			}
@@ -536,7 +558,6 @@
 raw3215_write(raw3215_info *raw, const char *str,
 	      int from_user, unsigned int length)
 {
-	raw3215_req *req;
 	unsigned long flags;
 	int ret, c;
 	int count;
@@ -550,14 +571,15 @@
 
 		while (RAW3215_BUFFER_SIZE - raw->count < count) {
 			/* there might be a request pending */
+                        raw3215_mk_write_req(raw);
 			raw3215_try_io(raw);
 			if (wait_cons_dev(raw->irq) != 0) {
 				/* that shouldn't happen */
 				raw->count = 0;
+                                raw->written = 0;
 			} 
 		}
 
-		req = raw3215_mk_write_req(raw);
 		/* copy string to output buffer and convert it to EBCDIC */
 		if (from_user) {
 			while (1) {
@@ -598,12 +620,12 @@
 				ret += c;
 			}
 		}
-		raw3215_mk_write_ccw(raw, req);
-		raw->queued_write = req;
+                if (!(raw->flags & RAW3215_WORKING)) {
+                        raw3215_mk_write_req(raw);
 		/* start or queue request */
 		raw3215_try_io(raw);
+                }
 		s390irq_spin_unlock_irqrestore(raw->irq, flags);
-
 	}
 
 	return ret;
@@ -614,27 +636,28 @@
  */
 static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
 {
-	raw3215_req *req;
 	unsigned long flags;
 
 	s390irq_spin_lock_irqsave(raw->irq, flags);
 	while (RAW3215_BUFFER_SIZE - raw->count < 1) {
 		/* there might be a request pending */
+                raw3215_mk_write_req(raw);
 		raw3215_try_io(raw);
 		if (wait_cons_dev(raw->irq) != 0) {
 			/* that shouldn't happen */
 			raw->count = 0;
+                        raw->written = 0;
 		}
 	}
 
-	req = raw3215_mk_write_req(raw);
 	raw->buffer[raw->head] = (char) _ascebc[(int) ch];
 	raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
 	raw->count++;
-	raw3215_mk_write_ccw(raw, req);
-	raw->queued_write = req;
+        if (!(raw->flags & RAW3215_WORKING)) {
+                raw3215_mk_write_req(raw);
 	/* start or queue request */
 	raw3215_try_io(raw);
+        }
 	s390irq_spin_unlock_irqrestore(raw->irq, flags);
 }
 
@@ -781,6 +804,7 @@
 		if (wait_cons_dev(raw->irq) != 0) {
 			/* that shouldn't happen */
 			raw->count = 0;
+                        raw->written = 0;
 		}
 		raw->flags &= ~RAW3215_FLUSHING;
 	}
diff -urN linux-2.2.17-pre12/drivers/s390/char/hwc_tty.c linux/drivers/s390/char/hwc_tty.c
--- linux-2.2.17-pre12/drivers/s390/char/hwc_tty.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/char/hwc_tty.c	Mon Dec  3 22:09:50 2001
@@ -73,8 +73,6 @@
 	return 0;
 }
 
-#if 0
-
 static void 
 hwc_tty_close (struct tty_struct *tty,
                            struct file *filp)
@@ -84,11 +82,13 @@
 			"do not close hwc tty because of wrong device number");
 		return;
 	}
+	if (tty->count > 1)
+		return;
+
 	hwc_tty_data.tty = NULL;
 
 	hwc_unregister_calls (&(hwc_tty_data.calls));
 }
-#endif
 
 static int 
 hwc_tty_write_room (struct tty_struct *tty)
@@ -316,7 +316,7 @@
 	hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
 
 	hwc_tty_driver.open = hwc_tty_open;
-	hwc_tty_driver.close = NULL /* hwc_tty_close */;
+	hwc_tty_driver.close = hwc_tty_close;
 	hwc_tty_driver.write = hwc_tty_write;
 	hwc_tty_driver.put_char = hwc_tty_put_char;
 	hwc_tty_driver.flush_chars = hwc_tty_flush_chars;
diff -urN linux-2.2.17-pre12/drivers/s390/net/ctc.c linux/drivers/s390/net/ctc.c
--- linux-2.2.17-pre12/drivers/s390/net/ctc.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/net/ctc.c	Mon Dec  3 22:09:50 2001
@@ -35,7 +35,7 @@
  *    0.50  Initial release shipped
  *    0.51  Bug fixes
  *          - CTC / ESCON network device can now handle up to 64 channels 
- *          - 3088-61 info message supperssed - CISCO 7206 - CLAW - ESCON 
+ *          - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON 
  *          - 3088-62 info message suppressed - OSA/D   
  *          - channel: def ffffffed ... error message suppressed 
  *          - CTC / ESCON device was not recoverable after a lost connection with 
@@ -45,6 +45,19 @@
  *    0.52  Bug fixes 
  *          - Subchannel check message enhanced 
  *          - Read / Write retry routine check for CTC_STOP added  
+ *    0.53  Enhancement 
+ *          - Connect time changed from 150 to 300 seconds
+ *            This gives more a better chance to connect during IPL 
+ *    0.54  Bug fixes 
+ *          - Out of memory message enhanced 
+ *          - Zero buffer problem in ctc_irq_hb solved
+ *            A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
+ *            which could end in a out of memory situation.  
+ *    0.55  Bug fixes 
+ *          - Connect problems with systems which IPL later
+ *            SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
+ *            not available. When systemB comes up it is nearly inpossible to setup a 
+ *            connection.  
  */
 #include <linux/version.h>
 #include <linux/init.h>
@@ -617,6 +630,7 @@
                         kfree(p);
                         return -ENOMEM;
                 }
+                p->block->length = 0; 
         }
    
         if (ctc->free_anchor == NULL) 
@@ -912,9 +926,14 @@
         struct  ctc_priv  *privptr = NULL;
         net_device        *dev = NULL;    
         
-        ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+       /* ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};    */
+                                               
+       ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL},
                                                {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; 
 
+
+
         devstat_t *devstat = ((devstat_t *)initparm);
 
         /* Bypass all 'unsolicited interrupts' */
@@ -990,6 +1009,7 @@
                 case CTC_START_SELECT:
                         if (!ctc->flag & CTC_WRITE) {
                                 ctc->state = CTC_START_READ_TEST;
+                                ctc->free_anchor->block->length = 0;    
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc;
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1000,7 +1020,8 @@
                         } else {
                                 ctc->state = CTC_START_WRITE_TEST;
                                 /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-                                ctc->ccw[1].count = 0;
+                                ctc->free_anchor->block->length = 0;    
+                                ctc->ccw[1].count = 2;              /* Transfer only length */
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc; 
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
@@ -1072,6 +1093,7 @@
                         ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
 
                         if (ctc->free_anchor != NULL) {  
+                                ctc->free_anchor->block->length = 0;
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc;
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1195,8 +1217,9 @@
 
         while (ctc->proc_anchor != NULL) { 
 
-                lp = &ctc->proc_anchor->block->data;
+                if (ctc->proc_anchor->block->length != 0) {
 
+                        lp = &ctc->proc_anchor->block->data;
                 while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
                         data_len = lp->length - PACKET_HEADER_LENGTH;
                         skb = dev_alloc_skb(data_len); 
@@ -1210,10 +1233,11 @@
                                 privptr->stats.rx_packets++;
                         } else {
                                 privptr->stats.rx_dropped++; 
-                                printk(KERN_WARNING "%s: is low on memory\n",dev->name);
+                                        printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
                         }
                         (__u8 *)lp += lp->length;
                 }
+                }
 
                 s390irq_spin_lock_irqsave(ctc->irq, saveflags);
                 ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
@@ -1251,6 +1275,7 @@
         if (ctc->state == CTC_STOP)
                 return;
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+        ctc->free_anchor->block->length = 0;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
         parm = (__u32) ctc; 
         rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1276,8 +1301,15 @@
 #endif 
         if (ctc->state == CTC_STOP)
                 return;
+ 
+        while (ctc->proc_anchor != NULL) { 
+                ctc->proc_anchor->block->length = 0;
+                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+        } 
+
+        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->ccw[1].count = 0;
+        ctc->ccw[1].count = 2;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
         parm = (__u32) ctc; 
         rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1354,7 +1386,7 @@
                 init_timer(&timer);
                 timer.function = (void *)ctc_timer; 
                 timer.data = (__u32)&privptr->channel[i];
-                timer.expires = jiffies + 150*HZ;                        /* time to connect with the remote side */
+                timer.expires = jiffies + 300*HZ;                        /* time to connect with the remote side */
                 add_timer(&timer);
 
                 s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
@@ -1382,13 +1414,13 @@
                 printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
                 
                 for (i = 0; i < 2;  i++) {
-                        s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                     /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
                         parm = (unsigned long) &privptr->channel[i];
                         privptr->channel[i].state = CTC_STOP;
-                        rc = halt_IO(privptr->channel[i].irq, parm, flags);
+                        rc = halt_IO(privptr->channel[i].irq, parm, flags); /
                         s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
                         if (rc != 0)
-                                ccw_check_return_code(dev, rc);
+                                ccw_check_return_code(dev, rc);     */
                         for (j = 0; j < CTC_BLOCKS;  j++) 
                                 ctc_buffer_free(&privptr->channel[i]);
                 }
@@ -1421,7 +1453,6 @@
 static int ctc_release(net_device *dev)
 {   
         int                rc;
-        int                x; 
         int                i;
         int                j;
         __u8               flags = 0x00;
diff -urN linux-2.2.17-pre12/drivers/s390/net/iucv.c linux/drivers/s390/net/iucv.c
--- linux-2.2.17-pre12/drivers/s390/net/iucv.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/s390/net/iucv.c	Mon Dec  3 22:09:50 2001
@@ -7,8 +7,10 @@
  *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
  *               Hartmut Penner <hpenner@de.ibm.com> 
  * 
+ *    
  *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  *                Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *                Alan Altmark (Alan_Altmark@us.ibm.com)
  *                
 
  */
@@ -42,10 +44,10 @@
 
 
 
-
 #define DEBUG123
 #define MAX_DEVICES  10
 
+
 extern char _ascebc[];
 
 /* 
@@ -496,8 +498,6 @@
   /* get own buffer: */
   extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer;
   
-  netif_enter_interrupt(dev);        /* lock ! */
-  
 #ifdef DEBUG
   printk(  "iucv: do_iucv_interrupt %x received; pathid: %02X\n",
 	   extern_int_buffer->iptype,extern_int_buffer->ippathid);
@@ -505,6 +505,14 @@
   dumpit((char *)&extern_int_buffer[0],40);
 #endif
   
+  if (extern_int_buffer->iptype == 0x01)
+    dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
+  else
+    dev = get_device_from_pathid(extern_int_buffer->ippathid);
+
+  netif_enter_interrupt(dev);        /* lock ! */
+  privptr = (struct iucv_priv *)(dev->priv);
+  
   switch (extern_int_buffer->iptype)
     {
     case 0x01: /* connection pending ext interrrupt */
@@ -519,11 +527,7 @@
 	iucv_retrieve_buffer(glob_command_buffer);
 	break;
       }
-#ifdef DEBUG
-      dumpit(&((char *)extern_int_buffer)[8],8);
-#endif
-      dev = get_device_from_userid(&((char*)extern_int_buffer)[8]);
-      privptr = (struct iucv_priv *)(dev->priv);
+
       privptr->pathid =  extern_int_buffer->ippathid;
       
 #ifdef DEBUG
@@ -542,8 +546,6 @@
       if( extern_int_buffer->ipmsgtag !=0)
 	{
 	  /* get ptr's to kernel struct with local & broadcast address */
-	  dev = get_device_from_pathid(extern_int_buffer->ippathid);
-	  privptr = (struct iucv_priv *)(dev->priv);
 	  indev = dev->ip_ptr;
 	  inaddr = (struct in_ifaddr*) indev->ifa_list;
 	}
@@ -595,8 +597,6 @@
 		   (unsigned int)extern_int_buffer->ipaudit);
 	}
       /* a transmission is over: tell we are no more busy */
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
       privptr->stats.tx_packets++;
       netif_wake_queue(dev);                /* transmission is no longer busy*/
       break;
@@ -607,8 +607,6 @@
 #ifdef DEBUG
       printk(  "message pending.\n");
 #endif
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
       rcvptr = &privptr->receive_buffer[0];
       
       /* re-set receive buffer */
diff -urN linux-2.2.17-pre12/include/asm-s390/atomic.h linux/include/asm-s390/atomic.h
--- linux-2.2.17-pre12/include/asm-s390/atomic.h	Wed May  3 17:16:51 2000
+++ linux/include/asm-s390/atomic.h	Mon Dec  3 22:09:51 2001
@@ -38,7 +38,7 @@
 {
         __asm__ __volatile__("st  %1,%0\n\t"
                              "bcr 15,0"
-                             : : "m" (*v), "d" (i) : "memory");
+                             : "=m" (*v) : "d" (i) );
 }
 
 static __inline__ void atomic_add(int i, atomic_t *v)
@@ -48,7 +48,7 @@
                              "   ar    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
@@ -58,7 +58,7 @@
                              "   sr    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
@@ -68,7 +68,7 @@
                              "   ahi   1,1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1" );
+                             : "+m" (*v) : : "0", "1", "cc" );
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
@@ -79,7 +79,7 @@
                              "   ahi   %1,1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i;
 }
 
@@ -90,7 +90,7 @@
                              "   ahi   1,-1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1" );
+                             : "+m" (*v) : : "0", "1", "cc" );
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
@@ -101,7 +101,7 @@
                              "   ahi   %1,-1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i;
 }
 
@@ -113,7 +113,7 @@
                              "   ahi   %1,-1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0");
+                             : "+m" (*v), "=&d" (i) : : "0", "cc");
         return i == 0;
 }
 
@@ -124,7 +124,7 @@
                              "   nr    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (~(mask)) : "0", "1" );
+                             : "+m" (*v) : "d" (~(mask)) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
@@ -134,7 +134,7 @@
                              "   or    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (mask) : "0", "1" );
+                             : "+m" (*v) : "d" (mask) : "0", "1", "cc" );
 }
 
 /*
@@ -153,7 +153,7 @@
                 "0:"
                 : "=&r" (retval), "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "memory", "cc");
+                : "cc");
         return retval;
 }
 
@@ -169,13 +169,13 @@
                 "   jl  0b\n"
                 : "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "memory", "cc", "1");
+                : "cc", "1");
 }
 
 /*
  * Increase and test if atomic counter > 0
  */
-extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v)
+extern __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v)
 {
         int i;
         __asm__ __volatile__("   l     0,%0\n"
@@ -183,8 +183,15 @@
                              "   ahi   %1,1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i > 0;
+}
+
+#define atomic_compare_and_swap_debug(where,from,to) \
+if (atomic_compare_and_swap ((from), (to), (where))) {\
+	printk (KERN_WARNING"%s/%d atomic counter:%s couldn't be changed from %d(%s) to %d(%s), was %d\n",\
+		__FILE__,__LINE__,#where,(from),#from,(to),#to,atomic_read (where));\
+        atomic_set(where,(to));\
 }
 
 #endif                                 /* __ARCH_S390_ATOMIC __            */
diff -urN linux-2.2.17-pre12/include/asm-s390/bitops.h linux/include/asm-s390/bitops.h
--- linux-2.2.17-pre12/include/asm-s390/bitops.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/bitops.h	Mon Dec  3 22:09:51 2001
@@ -79,8 +79,8 @@
              "   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"
+             "   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 */
@@ -109,8 +109,8 @@
              "   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"
+             "   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"
@@ -139,8 +139,8 @@
              "   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"
+             "   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 */
@@ -168,8 +168,8 @@
              "   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"
+             "   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 */
@@ -788,7 +788,6 @@
 #define ext2_test_bit(nr, addr)      test_bit((nr)^24, addr)
 extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
 {
-        static const int mask = 0xffL;
         int res;
 
         if (!size)
@@ -806,6 +805,7 @@
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
                 "   sll  2,3(0)\n"
+                "   lhi  0,0xff\n"
                 "   ahi  2,24\n"
                 "   tmh  1,0xFFFF\n"
                 "   jo   2f\n"
@@ -815,13 +815,12 @@
                 "   jo   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"
+                "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),
-                  "m" (mask), "a" (&_zb_findmap)
+                  "a" (&_zb_findmap)
                   : "cc", "0", "1", "2" );
         return (res < size) ? res : size;
 }
@@ -829,17 +828,6 @@
 extern __inline__ int 
 ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
 {
-        static const int mask = 0xffL;
-        static unsigned long orword[32] = {
-		0x00000000, 0x01000000, 0x03000000, 0x07000000,
-		0x0f000000, 0x1f000000, 0x3f000000, 0x7f000000,
-		0xff000000, 0xff010000, 0xff030000, 0xff070000,
-                0xff0f0000, 0xff1f0000, 0xff3f0000, 0xff7f0000,
-		0xffff0000, 0xffff0100, 0xffff0300, 0xffff0700,
-		0xffff0f00, 0xffff1f00, 0xffff3f00, 0xffff7f00,
-		0xffffff00, 0xffffff01, 0xffffff03, 0xffffff07,
-		0xffffff0f, 0xffffff1f, 0xffffff3f, 0xffffff7f
-	};
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 5);
         unsigned long word;
@@ -849,23 +837,29 @@
                 return size;
 
         if (bit) {
-		word = *p | orword[bit];
+                __asm__("   ic   %0,0(%1)\n"
+                        "   icm  %0,2,1(%1)\n"
+                        "   icm  %0,4,2(%1)\n"
+                        "   icm  %0,8,3(%1)"
+                        : "=&a" (word) : "a" (p) );
+		word >>= bit;
+                res = bit;
                 /* Look for zero in first longword */
-                __asm__("   lhi  %0,24\n"
-                	"   tmh  %1,0xFFFF\n"
-                	"   jo   0f\n"
-                	"   ahi  %0,-16\n"
+                __asm__("   lhi  0,0xff\n"
+                        "   tml  %1,0xffff\n"
+                	"   jno   0f\n"
+                	"   ahi  %0,16\n"
                 	"   srl  %1,16\n"
-                	"0: tml  %1,0xFF00\n"
-                	"   jo   1f\n"
-                	"   ahi  %0,-8\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"
+                	"1: nr   %1,0\n"
+                	"   ic   %1,0(%1,%2)\n"
                 	"   alr  %0,%1"
-                	: "=&d" (res), "+&d" (word)
-                  	: "m" (mask), "a" (&_zb_findmap)
-                	: "cc" );
+                	: "+&d" (res), "+&d" (word)
+                  	: "a" (&_zb_findmap)
+                	: "cc", "0" );
                 if (res < 32)
 			return (p - addr)*32 + res;
                 p++;
diff -urN linux-2.2.17-pre12/include/asm-s390/ccwcache.h linux/include/asm-s390/ccwcache.h
--- linux-2.2.17-pre12/include/asm-s390/ccwcache.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/ccwcache.h	Mon Dec  3 22:09:51 2001
@@ -0,0 +1,88 @@
+/* 
+   * File...........: linux/drivers/s390/block/ccwcache.c
+   * 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__ */
+/* 
+ * smalles slab to be allocated (DASD_MINIMUM_CCW CCWs + metadata) 
+ */
+
+typedef struct ccw_req_t {
+	/* these identify the request */
+	unsigned long magic;	/* magic number */
+	atomic_t status;	/* reflecting the status of this request */
+	unsigned long long expires;	/* clock value, when request expires */
+
+	/* these are important for executing the requests */
+	ccw1_t *cpaddr;		/* address of channel program */
+	void *data;		/* pointer to data area */
+	void *req;		/* pointer to originating request */
+	struct ccw_req_t *next;	/* pointer to next ccw_req_t in queue */
+
+	int options;		/* options for execution */
+	int cplength;		/* length of the channel program in CCWs */
+	int datasize;		/* amount of additional data in bytes */
+	devstat_t *dstat;	/* The device status in case of an error */
+
+	/* these are important for recovering erroneous requests */
+	int retries;		/* A retry counter to be set when filling */
+	devstat_t *devstat;	/* Keeping the device status */
+	struct ccw_req_t *refers;	/* Does this request refer to another one? */
+	void *function; /* refers to the originating ERP action */ ;
+
+	/* 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 */
+	struct ccw_req_t *int_next;	/* for internal queueing */
+	struct ccw_req_t *int_prev;	/* for internal queueing */
+	kmem_cache_t *cache;	/* the cache this data comes from */
+	void *device;		/* index of the device the req is for */
+
+} __attribute__ ((packed,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  0x04	/* request is currently in IO */
+#define CQR_STATUS_DONE   0x08	/* request is completed sucessfully */
+#define CQR_STATUS_ERROR  0x10	/* request is completed with error */
+#define CQR_STATUS_FAILED 0x20	/* request is finally failed */
+
+#ifdef __KERNEL__
+#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
+ sizeof(struct ccw_req_t) <= 256 ? 256 :\
+ sizeof(struct ccw_req_t) <= 512 ? 512 :\
+ sizeof(struct ccw_req_t) <= 1024 ? 1024 : 2048)
+
+/* 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 :\
+ sizeof(struct ccw_req_t) <= 512 ? 4 :\
+ sizeof(struct ccw_req_t) <= 1024 ? 3 : 2)
+
+int ccwcache_init (void);
+
+ccw_req_t *ccw_alloc_request (char *magic, int cplength, int datasize);
+void ccw_free_request (ccw_req_t * request);
+#endif /* __KERNEL__ */
+#endif				/* CCWCACHE_H */
+
+
+
diff -urN linux-2.2.17-pre12/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- linux-2.2.17-pre12/include/asm-s390/dasd.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/dasd.h	Mon Dec  3 22:09:51 2001
@@ -0,0 +1,253 @@
+
+#ifndef DASD_H
+#define DASD_H
+
+/* First of all the external stuff */
+#include <linux/ioctl.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <asm/ccwcache.h>
+/* #include <linux/blkdev.h> */
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/devfs_fs_kernel.h>
+#endif /* LINUX_IS_24 */
+
+#define IOCTL_LETTER 'D'
+/* Format the volume or an extent */
+#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(IOCTL_LETTER,1) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(IOCTL_LETTER,2) 
+/* Stuff for reading and writing the Label-Area to/from user space */
+#define BIODASDGTVLBL  _IOR(IOCTL_LETTER,3,dasd_volume_label_t)
+#define BIODASDSTVLBL  _IOW(IOCTL_LETTER,4,dasd_volume_label_t)
+#define BIODASDRWTB    _IOWR(IOCTL_LETTER,5,int)
+#define BIODASDRSID    _IOR(IOCTL_LETTER,6,senseid_t)
+#define BIODASDRLB     _IOR(IOCTL_LETTER,7,int)
+#define BLKGETBSZ      _IOR(IOCTL_LETTER,8,int)
+#define BIODASDEXCP    _IOWR(IOCTL_LETTER,9,ccw_req_t)
+
+#define DASD_NAME "dasd"
+#define DASD_PARTN_BITS 2
+#define PARTN_BITS DASD_PARTN_BITS
+#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct format_data_t
+ * represents all data necessary to format a dasd
+ */
+typedef struct format_data_t {
+	int start_unit; /* from track */
+	int stop_unit;  /* to track */
+	int blksize;    /* sectorsize */
+        int intensity;  /* 0: normal, 1:record zero, 3:home address */
+} __attribute__ ((packed)) format_data_t;
+
+#define DASD_FORMAT_DEFAULT_START_UNIT 0
+#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
+#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
+#define DASD_FORMAT_DEFAULT_INTENSITY -1
+
+#ifdef __KERNEL__
+
+typedef enum {
+	dasd_era_fatal = -1,	/* no chance to recover              */
+	dasd_era_none = 0,	/* don't recover, everything alright */
+	dasd_era_msg = 1,	/* don't recover, just report...     */
+	dasd_era_recover = 2	/* recovery action recommended       */
+} dasd_era_t;
+
+/* 
+ * struct dasd_sizes_t
+ * represents all data needed to access dasd with properly set up sectors
+ */
+typedef
+struct dasd_sizes_t {
+	unsigned int blocks;
+	unsigned int bp_block;
+	unsigned int s2b_shift;
+} __attribute__ ((packed)) 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;
+	struct dasd_chanq_t *next_q;	/* pointer to next queue */
+	int queued_requests;
+	atomic_t flags;
+	atomic_t dirty_requests;
+} __attribute__ ((packed)) dasd_chanq_t;
+
+#define DASD_CHANQ_BUSY 0x01
+#define DASD_CHANQ_ACTIVE 0x02
+#define DASD_REQUEST_Q_BROKEN 0x04
+
+struct dasd_device_t;
+
+typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
+typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int);
+
+typedef int (*dasd_ck_id_fn_t) (dev_info_t *);
+typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
+typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
+typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
+typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
+typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
+typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
+typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
+typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
+typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
+
+typedef struct dasd_discipline_t {
+	char ebcname[8]; /* a name used for tagging and printks */
+        char name[8];		/* a name used for tagging and printks */
+
+	struct dasd_discipline_t *next;	/* used for list of disciplines */
+
+	dasd_ck_id_fn_t id_check;	/* to check sense data */
+	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
+	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
+	dasd_do_analysis_fn_t do_analysis;	/* to complete the analysis of the volume */
+	dasd_fill_geometry_fn_t fill_geometry;	/* to set up hd_geometry */
+	dasd_io_starter_fn_t start_IO;
+        dasd_format_fn_t format_device;		/* to format the device */
+	dasd_error_examine_fn_t examine_error;
+	dasd_error_analyse_fn_t erp_action;
+	dasd_erp_analyse_fn_t erp_postaction;
+        dasd_cp_builder_fn_t build_cp_from_req;
+        dasd_dump_sense_fn_t dump_sense;
+        dasd_int_handler_fn_t int_handler;
+} __attribute__   ((packed)) dasd_discipline_t;
+
+typedef struct major_info_t {
+	struct major_info_t *next;
+	struct dasd_device_t **dasd_device;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+	void (*request_fn) (request_queue_t *);
+#else
+	void (*request_fn) (void);
+#endif /* LINUX_IS_24 */
+	int read_ahead;
+	int *blk_size;
+	int *hardsect_size;
+	int *blksize_size;
+	int *max_sectors;
+	struct gendisk gendisk;
+} __attribute__ ((packed)) major_info_t;
+
+typedef struct dasd_device_t {
+	dev_info_t devinfo;
+	dasd_discipline_t *discipline;
+	atomic_t level;
+        int open_count;
+        kdev_t kdev;
+        major_info_t *major_info;
+	struct dasd_chanq_t queue;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wait_queue_head_t wait_q;
+        request_queue_t *request_queue;
+#else
+        struct wait_queue wait;
+        struct wait_queue *wait_q;
+#endif /* LINUX_IS_24 */
+        dasd_sizes_t sizes;
+	devstat_t dev_status;
+	char *characteristics;
+        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 */
+}  dasd_device_t;
+
+/* dasd_device_t.level can be: */
+#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
+#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
+#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
+#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
+#define DASD_DEVICE_LEVEL_ANALYSED 0x08
+#define DASD_DEVICE_LEVEL_PARTITIONED 0x10
+
+typedef
+union {
+	char bytes[512];
+	struct {
+		/* 80 Bytes of Label data */
+		char identifier[4];	/* e.g. "LNX1", "VOL1" or "CMS1" */
+		char label[6];	/* Given by user */
+		char security;
+		char vtoc[5];	/* Null in "LNX1"-labelled partitions */
+		char reserved0[5];
+		long ci_size;
+		long blk_per_ci;
+		long lab_per_ci;
+		char reserved1[4];
+		char owner[0xe];
+		char no_part;
+		char reserved2[0x1c];
+		/* 16 Byte of some information on the dasd */
+		short blocksize;
+		char nopart;
+		char unused;
+		long unused2[3];
+		/* 7*10 = 70 Bytes of partition data */
+		struct {
+			char type;
+			long start;
+			long size;
+			char unused;
+		} part[7];
+	} __attribute__ ((packed)) label;
+} dasd_volume_label_t;
+
+typedef union {
+	struct {
+		unsigned long no;
+		unsigned int ct;
+	} __attribute__ ((packed)) input;
+	struct {
+		unsigned long noct;
+	} __attribute__ ((packed)) output;
+} __attribute__ ((packed)) dasd_xlate_t;
+
+int dasd_init (void);
+/* int dasd_device_name (char *, int, int, struct gendisk *); */
+void dasd_discipline_enq (dasd_discipline_t *);
+int dasd_discipline_deq(dasd_discipline_t *);
+int dasd_start_IO (ccw_req_t *);
+void dasd_int_handler (int , void *, struct pt_regs *);
+
+#endif /* __KERNEL__ */
+
+#endif				/* DASD_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.2.17-pre12/include/asm-s390/debug.h linux/include/asm-s390/debug.h
--- linux-2.2.17-pre12/include/asm-s390/debug.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-s390/debug.h	Mon Dec  3 22:09:51 2001
@@ -0,0 +1,120 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <asm/spinlock.h>
+
+#ifdef __KERNEL__
+
+#define MAX_DEBUG_AREAS 16
+
+#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+
+typedef struct
+{
+  union
+  {
+    struct
+    {
+      unsigned long long cpuid:4;
+      unsigned long long clock:60;
+    }
+    fields;
+    unsigned long long stck;
+  }
+  id;
+  void *caller;
+  union
+  {
+    unsigned long tag;
+    char text[4];
+  }
+  tag;
+}
+debug_entry_t;
+
+typedef struct
+{
+  char *name;
+  int level;
+  int nr_areas;
+  int page_order;
+  debug_entry_t **areas;
+  int active_area;
+  int *active_entry;
+  spinlock_t lock;
+}
+debug_info_t;
+
+int debug_init (void);
+debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
+void debug_unregister (debug_info_t * id, char *name);
+void debug_event (debug_info_t * id, int level, unsigned int tag);
+void debug_text_event (debug_info_t * id, int level, char tag[4]);
+void debug_exception (debug_info_t * id, int level, unsigned int tag);
+void debug_text_exception (debug_info_t * id, int level, char tag[4]);
+
+/*
+   define the debug levels:
+   - 0 No debugging output to console or syslog
+   - 1 Log internal errors to syslog, ignore check conditions 
+   - 2 Log internal errors and check conditions to syslog
+   - 3 Log internal errors to console, log check conditions to syslog
+   - 4 Log internal errors and check conditions to console
+   - 5 panic on internal errors, log check conditions to console
+   - 6 panic on both, internal errors and check conditions
+ */
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL 4
+#endif
+
+#define INTERNAL_ERRMSG(x,y...) "E" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_WRNMSG(x,y...) "W" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_INFMSG(x,y...) "I" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_DEBMSG(x,y...) "D" __FILE__ "%d: " x, __LINE__, y
+
+#if DEBUG_LEVEL > 0
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
+#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
+#else
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#endif				/* DASD_DEBUG */
+
+#if DASD_DEBUG > 4
+#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 2
+#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 0
+#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) )
+#else
+#define INTERNAL_ERROR(x...)
+#endif				/* DASD_DEBUG */
+
+#if DASD_DEBUG > 5
+#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 3
+#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 1
+#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) )
+#else
+#define INTERNAL_CHECK(x...)
+#endif				/* DASD_DEBUG */
+
+#undef DEBUG_MALLOC
+#ifdef DEBUG_MALLOC
+void *b;
+#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
+#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
+#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
+#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
+#endif				/* DEBUG_MALLOC */
+
+#endif				/* __KERNEL__ */
+#endif				/* DEBUG_H */
diff -urN linux-2.2.17-pre12/include/asm-s390/delay.h linux/include/asm-s390/delay.h
--- linux-2.2.17-pre12/include/asm-s390/delay.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/delay.h	Mon Dec  3 22:09:51 2001
@@ -15,11 +15,8 @@
 #define _S390_DELAY_H
 
 extern void __udelay(unsigned long usecs);
-extern void __const_udelay(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
-#define udelay(n) (__builtin_constant_p(n) ? \
-	__const_udelay((n) * 0x10c6ul) : \
-	__udelay(n))
+#define udelay(n) __udelay(n)
 
 #endif /* defined(_S390_DELAY_H) */
diff -urN linux-2.2.17-pre12/include/asm-s390/irq.h linux/include/asm-s390/irq.h
--- linux-2.2.17-pre12/include/asm-s390/irq.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/irq.h	Mon Dec  3 22:09:51 2001
@@ -1,6 +1,7 @@
 #ifndef __irq_h
 #define __irq_h
 
+#ifdef __KERNEL__
 #include <asm/hardirq.h>
 
 /*
@@ -9,6 +10,8 @@
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
 
+#define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
+
 #define INVALID_STORAGE_AREA ((void *)(-1 - 0x3FFF ))
 
 extern int disable_irq(unsigned int);
@@ -68,6 +71,8 @@
                                    /*  ... in an operand exception.       */
    } __attribute__ ((packed)) pmcw_t;
 
+#endif /* __KERNEL__ */
+
 /*
  * subchannel status word
  */
@@ -130,6 +135,8 @@
 #define SCHN_STAT_INTF_CTRL_CHK  0x02
 #define SCHN_STAT_CHAIN_CHECK    0x01
 
+#ifdef __KERNEL__
+
 /*
  * subchannel information block
  */
@@ -139,6 +146,8 @@
       char mda[12];            /* model dependent area */
    } schib_t __attribute__ ((packed,aligned(4)));
 
+#endif /* __KERNEL__ */
+
 typedef struct {
       char            cmd_code;/* command code */
       char            flags;   /* flags, like IDA adressing, etc. */
@@ -164,6 +173,8 @@
 #define CCW_CMD_SET_PGID        0xAF
 #define CCW_CMD_SENSE_ID        0xE4
 
+#ifdef __KERNEL__
+
 #define SENSE_MAX_COUNT         0x20
 
 /*
@@ -197,6 +208,8 @@
       ccw1_t        *cpa;      /* channel program address */
    }  __attribute__ ((packed,aligned(4))) orb_t;
 
+#endif /* __KERNEL__ */
+
 typedef struct {
       unsigned int res0  : 4;  /* reserved */
       unsigned int pvrf  : 1;  /* path-verification-required flag */
@@ -284,6 +297,8 @@
       char   ecw[32];          /* extended control word */
    } irb_t __attribute__ ((aligned(4)));
 
+#ifdef __KERNEL__
+
 /*
  * TPI info structure
  */
@@ -323,6 +338,8 @@
       ciw_t    ciw[16];            /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
+#endif /* __KERNEL__ */
+
 /*
  * sense data
  */
@@ -331,6 +348,7 @@
       unsigned char data[32];  /* sense data */
    } sense_t;
 
+
 /*
  * device status area, to be provided by the device driver
  *  when calling request_irq() as parameter "dev_id", later
@@ -367,16 +385,20 @@
 #define DEVSTAT_CLEAR_FUNCTION     0x00000100
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
+#define DEVSTAT_UNKNOWN_DEV        0x00000800
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 
+#ifdef __KERNEL__
+
 typedef  void (* io_handler_func1_t) ( int  irq,
                                        devstat_t *devstat,
                                        struct pt_regs *rgs);
 
 typedef  void (* io_handler_func_t) ( int  irq,
-                                      __u32 intparm );
+                                      void           *devstat,
+                                      struct pt_regs *rgs);
 
 typedef  void ( * not_oper_handler_func_t)( int irq,
                                             int status );
@@ -777,7 +799,7 @@
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
  */
-extern unsigned long _stext;
+extern char _stext;
 static inline void s390_do_profile (unsigned long addr)
 {
         if (prof_buffer && current->pid) {
@@ -808,6 +830,7 @@
 
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+#endif /* __KERNEL__ */
 
 #endif
 
diff -urN linux-2.2.17-pre12/include/asm-s390/pgtable.h linux/include/asm-s390/pgtable.h
--- linux-2.2.17-pre12/include/asm-s390/pgtable.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/pgtable.h	Mon Dec  3 22:09:51 2001
@@ -86,7 +86,7 @@
         __flush_tlb_one(vma->vm_mm,va);
 }
 #else
-#define flush_tlb_page(vma, va) flush_tlb_all()
+#define flush_tlb_page(vma, va) flush_tlb_mm(vma->vm_mm)
 #endif
 
 static inline void flush_tlb_range(struct mm_struct *mm,
@@ -171,7 +171,7 @@
 	__flush_tlb_one(vma->vm_mm,va);
 }
 #else
-#define flush_tlb_page(vma, va) flush_tlb_all()
+#define flush_tlb_page(vma, va) flush_tlb_mm(vma->vm_mm)
 #endif
 
 static inline void flush_tlb_range(struct mm_struct * mm,
@@ -281,6 +281,7 @@
 #define _PAGE_PRESENT   0x001          /* Software                         */
 #define _PAGE_ACCESSED  0x002          /* Software accessed                */
 #define _PAGE_DIRTY     0x004          /* Software dirty                   */
+#define _PAGE_WRITE     0x008          /* Software write-access allowed    */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -305,19 +306,21 @@
 
 #define _SEGMENT_TABLE  (_USER_SEG_TABLE_LEN|0x80000000)
 #define _KERNSEG_TABLE  (_KERNEL_SEG_TABLE_LEN)
+
 /*
  * No mapping available
  */
 #define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_INVALID)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_WRITE | _PAGE_RO)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
 #define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_WRITE | _PAGE_DIRTY)
 
 /*
  * 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..
  */
+         /*xwr*/
 #define __P000  PAGE_NONE
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_COPY
@@ -434,7 +437,7 @@
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_write(pte_t pte)          { return !(pte_val(pte) & _PAGE_RO); }
+extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
 extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 
@@ -447,11 +450,17 @@
 extern inline pte_t pte_mkexec(pte_t pte)       { pte_val(pte) &= _PAGE_INVALID; return pte; }
 */
 
-extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_RO; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) &= ~_PAGE_RO ; return pte; }
+extern inline int __pte_set_ro(int pte)         { if ((pte & (_PAGE_WRITE|_PAGE_DIRTY)) == (_PAGE_WRITE|_PAGE_DIRTY))
+                                                      pte &= ~_PAGE_RO;
+                                                  else
+                                                      pte |= _PAGE_RO;
+                                                  return pte; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) = __pte_set_ro(pte_val(pte) & ~_PAGE_WRITE); return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) | _PAGE_WRITE); return pte; }
 
-extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) & ~_PAGE_DIRTY); return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) | _PAGE_DIRTY); return pte; }
 
 extern inline pte_t pte_mkold(pte_t pte)        { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
diff -urN linux-2.2.17-pre12/include/asm-s390/processor.h linux/include/asm-s390/processor.h
--- linux-2.2.17-pre12/include/asm-s390/processor.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/processor.h	Mon Dec  3 22:09:51 2001
@@ -167,13 +167,33 @@
 static inline void disabled_wait(unsigned long code)
 {
         char psw_buffer[2*sizeof(psw_t)];
+        char ctl_buf[4];
         psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
                                   & -sizeof(psw_t));
 
         dw_psw->mask = 0x000a0000;
         dw_psw->addr = code;
-        /* load disabled wait psw, the processor is dead afterwards */
-        asm volatile ("lpsw 0(%0)" : : "a" (dw_psw));
+        /* 
+         * Store status and then load disabled wait psw,
+         * the processor is dead afterwards
+         */
+
+        asm volatile ("    stctl 0,0,0(%1)\n"
+                      "    ni    0(%1),0xef\n" /* switch off protection */
+                      "    lctl  0,0,0(%1)\n"
+                      "    stpt  0xd8\n"       /* store timer */
+                      "    stckc 0xe0\n"       /* store clock comparator */
+                      "    stpx  0x108\n"      /* store prefix register */
+                      "    stam  0,15,0x120\n" /* store access registers */
+                      "    std   0,0x160\n"    /* store f0 */
+                      "    std   2,0x168\n"    /* store f2 */
+                      "    std   4,0x170\n"    /* store f4 */
+                      "    std   6,0x178\n"    /* store f6 */
+                      "    stm   0,15,0x180\n" /* store general registers */
+                      "    stctl 0,15,0x1c0\n" /* store control registers */
+                      "    oi    0x1c0,0x10\n" /* fake protection bit */
+                      "    lpsw 0(%0)"
+                      : : "a" (dw_psw), "a" (&ctl_buf));
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
diff -urN linux-2.2.17-pre12/include/asm-s390/queue.h linux/include/asm-s390/queue.h
--- linux-2.2.17-pre12/include/asm-s390/queue.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/queue.h	Mon Dec  3 22:09:51 2001
@@ -70,6 +70,15 @@
 	*lhead=member;
 }
 
+static __inline__ list *remove_listhead(list **lhead)
+{
+	list *oldhead=*lhead;
+
+	if(oldhead)
+		*lhead=(*lhead)->next;
+	return(oldhead);
+}
+
 static __inline__ void add_to_list_tail(list **lhead,list *member)
 {
 	list *curr,*prev;
diff -urN linux-2.2.17-pre12/include/asm-s390/s390io.h linux/include/asm-s390/s390io.h
--- linux-2.2.17-pre12/include/asm-s390/s390io.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/s390io.h	Mon Dec  3 22:09:51 2001
@@ -52,7 +52,8 @@
            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  unused    : (sizeof(unsigned int)*8 - 23); /* unused */
+           unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
diff -urN linux-2.2.17-pre12/include/asm-s390/setup.h linux/include/asm-s390/setup.h
--- linux-2.2.17-pre12/include/asm-s390/setup.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/setup.h	Mon Dec  3 22:09:51 2001
@@ -44,6 +44,7 @@
 #define MACHINE_HAS_CSP  (MACHINE_FLAGS & 8)
 
 #define RAMDISK_ORIGIN            0x800000
+#define RAMDISK_SIZE              0x800000
 #define RAMDISK_BLKSIZE           0x1000
 #define RAMDISK_IMAGE_START_MASK  0x07FF
 #define RAMDISK_PROMPT_FLAG       0x8000
diff -urN linux-2.2.17-pre12/include/asm-s390/spinlock.h linux/include/asm-s390/spinlock.h
--- linux-2.2.17-pre12/include/asm-s390/spinlock.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/spinlock.h	Mon Dec  3 22:09:51 2001
@@ -94,12 +94,13 @@
 
 extern inline void spin_lock(spinlock_t *lp)
 {
-	__asm__ __volatile("    basr  1,0\n"
-			   "0:  slr   0,0\n"
+        __asm__ __volatile("    bras  1,1f\n"
+                           "0:  diag  0,0,68\n"
+                           "1:  slr   0,0\n"
 			   "    cs    0,1,%1\n"
-			   "    jl    0b"
+                           "    jl    0b\n"
 			   : "=m" (lp->lock)
-			   : "0" (lp->lock) : "0", "1");
+                           : "0" (lp->lock) : "0", "1", "cc" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
@@ -109,7 +110,7 @@
 			   "    basr  1,0\n"
 			   "0:  cs    %1,1,%0"
 			   : "=m" (lp->lock), "=&d" (result)
-			   : "0" (lp->lock) : "1");
+			   : "0" (lp->lock) : "1", "cc" );
 	return !result;
 }
 
@@ -119,7 +120,7 @@
 {
 	__asm__ __volatile("    xc 0(4,%0),0(%0)\n"
                            "    bcr 15,0"
-			   : /* no output */ : "a" (lp) );
+			   : /* no output */ : "a" (lp) : "memory", "cc" );
 }
 		
 #define spin_lock_irq(lock) \
@@ -156,37 +157,43 @@
 
 #define read_lock(rw)   \
         asm volatile("   l     2,%0\n"   \
-                     "0: sll   2,1\n"    \
-                     "   srl   2,1\n"     /* clear high (=write) bit */ \
-                     "   lr    3,2\n"    \
-                     "   ahi   3,1\n"     /* one more reader */ \
+                     "   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\n"  /* try to write new value */ \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define read_unlock(rw) \
         asm volatile("   l     2,%0\n"   \
-                     "0: lr    3,2\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\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define write_lock(rw) \
         asm volatile("   lhi   3,1\n"    \
                      "   sll   3,31\n"    /* new lock value = 0x80000000 */ \
-                     "0: slr   2,2\n"     /* old lock value must be 0 */ \
+                     "   j     1f\n"     \
+                     "0: diag  0,0,68\n" \
+                     "1: slr   2,2\n"     /* old lock value must be 0 */ \
                      "   cs    2,3,%0\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define write_unlock(rw) \
         asm volatile("   slr   3,3\n"     /* new lock value = 0 */ \
-                     "0: lhi   2,1\n"    \
+                     "   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\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define read_lock_irq(lock)	do { __cli(); read_lock(lock); } while (0)
 #define read_unlock_irq(lock)	do { read_unlock(lock); __sti(); } while (0)
@@ -204,12 +211,4 @@
 
 #endif /* SMP */
 #endif /* __ASM_SPINLOCK_H */
-
-
-
-
-
-
-
-
 
diff -urN linux-2.2.17-pre12/include/asm-s390/string.h linux/include/asm-s390/string.h
--- linux-2.2.17-pre12/include/asm-s390/string.h	Tue Jan  4 10:12:24 2000
+++ linux/include/asm-s390/string.h	Mon Dec  3 22:09:51 2001
@@ -46,14 +46,15 @@
     void *ptr;
 
     __asm__ __volatile__ ("   lr    0,%2\n"
+                          "   lr    1,%1\n"
                           "   la    %0,0(%3,%1)\n"
-                          "0: srst  %0,%1\n"
+                          "0: srst  %0,1\n"
                           "   jo    0b\n"
                           "   brc   13,1f\n"
                           "   slr   %0,%0\n"
                           "1:"
-                          : "=a" (ptr) : "a" (cs), "d" (c), "d" (count)
-                          : "cc", "0" );
+                          : "=&a" (ptr) : "a" (cs), "d" (c), "d" (count)
+                          : "cc", "0", "1" );
     return ptr;
 }
 
diff -urN linux-2.2.17-pre12/include/asm-s390/uaccess.h linux/include/asm-s390/uaccess.h
--- linux-2.2.17-pre12/include/asm-s390/uaccess.h	Wed Jun  7 14:26:44 2000
+++ linux/include/asm-s390/uaccess.h	Mon Dec  3 22:09:51 2001
@@ -84,15 +84,14 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-				"   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
 				"   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: st    %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
-				"2: sacf  0(1)\n"
+				"2: sacf  0\n"
 				"   lhi   %1,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
@@ -105,7 +104,7 @@
 				".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -113,15 +112,14 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-				"   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
 				"   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: sth   %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
-				"2: sacf  0(1)\n"
+				"2: sacf  0\n"
 				"   lhi   %1,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
@@ -134,7 +132,7 @@
 				".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -142,15 +140,14 @@
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-				"   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
 				"   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: stc   %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
 				"1:\n"
 				".section .fixup,\"ax\"\n"
-				"2: sacf  0(1)\n"
+				"2: sacf  0\n"
 				"   lhi   %1,%h3\n"
 				"   bras  4,3f\n"
 				"   .long 1b\n"
@@ -163,7 +160,7 @@
 				".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -208,15 +205,14 @@
 
 #define __get_user_asm_4(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sacf  512\n"                        \
                                 "0: l     %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -229,20 +225,19 @@
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u32*) ptr), "K" (-EFAULT)    \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sacf  512\n"                        \
                                 "0: lh    %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -255,21 +250,20 @@
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u16*) ptr), "K" (-EFAULT)    \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sr    %0,%0\n"                      \
                                 "   sacf  512\n"                        \
                                 "0: ic    %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -282,7 +276,7 @@
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u8*) ptr), "K" (-EFAULT)     \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -345,22 +339,32 @@
 __copy_to_user_asm(void* to, const void* from,  long n)
 {
 
-        __asm__ __volatile__ (  "   iac   1\n"
-                                "   lr    2,%2\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"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,3\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,1b\n"
+				"   .long  0b,2b\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "2", "3", "4", "5" );
         return n;
 }
 
@@ -384,26 +388,35 @@
 extern inline unsigned long
 __copy_from_user_asm(void* to, const void* from,  long n)
 {
-        __asm__ __volatile__ (  "   iac   1\n"
-				"   lr    2,%1\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"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,3\n"
+                                "   sacf  0\n"
+                                "1: lr    %0,5\n"
+                                ".section .fixup,\"ax\"\n"
+                                "2: lhi   3,-4096\n"
+                                "   n     3,0x90\n"
+                                "   sr    3,4\n"
+                                "   mvcle 2,4,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,1b\n"
+				"   .long  0b,2b\n"
 				".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "2", "3", "4", "5" );
         return n;
 }
 
-
 #define __copy_from_user(to, from, n)                           \
 ({                                                              \
         __copy_from_user_asm(to,from,n);                        \
@@ -433,8 +446,7 @@
 strncpy_from_user(char *dst, const char *src, long count)
 {
         long len;
-        __asm__ __volatile__ (  "   iac   1\n"
-				"   slr   %0,%0\n"
+        __asm__ __volatile__ (  "   slr   %0,%0\n"
 				"   lr    2,%1\n"
                                 "   lr    4,%2\n"
                                 "   slr   3,3\n"
@@ -446,7 +458,7 @@
                                 "   ahi   %0,1\n"
                                 "   clr   %0,%3\n"
                                 "   jl    0b\n"
-                                "2: sacf  0(1)\n"
+                                "2: sacf  0\n"
 				".section .fixup,\"ax\"\n"
                                 "3: lhi   %0,%h4\n"
 				"   basr  3,0\n"
@@ -462,7 +474,7 @@
                                 : "=&a" (len)
                                 : "a"  (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "1", "2", "3", "4", "memory" );
+                                : "2", "3", "4", "memory" );
         return len;
 }
 
@@ -474,8 +486,7 @@
 static inline unsigned long
 strnlen_user(const char * src, unsigned long n)
 {
-	__asm__ __volatile__ ("   iac   1\n"
-                              "   alr   %0,%1\n"
+	__asm__ __volatile__ ("   alr   %0,%1\n"
 			      "   slr   0,0\n"
 			      "   lr    4,%1\n"
 			      "   sacf  512\n"
@@ -483,10 +494,10 @@
 			      "   jo    0b\n"
 			      "   slr   %0,%1\n"
 			      "   ahi   %0,1\n"
-			      "   sacf  0(1)\n"
+			      "   sacf  0\n"
                               "1:\n"
                               ".section .fixup,\"ax\"\n"
-                              "2: sacf  0(1)\n"
+                              "2: sacf  0\n"
                               "   slr   %0,%0\n"
                               "   bras  4,3f\n"
                               "   .long 1b\n"
@@ -498,7 +509,7 @@
 			      "   .long  0b,2b\n"
 			      ".previous"
 			      : "+&a" (n) : "d" (src)
-			      : "cc", "0", "1", "4" );
+			      : "cc", "0", "4" );
         return n;
 }
 #define strlen_user(str) strnlen_user(str, ~0UL)
@@ -510,23 +521,33 @@
 static inline unsigned long
 clear_user(void *to, unsigned long n)
 {
-        __asm__ __volatile__ (  "   iac   1\n"
-                                "   sacf  512\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"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,5\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,1b\n"
+				"   .long  0b,2b\n"
 				".previous"
                                 : "+&a" (n)
                                 : "a"   (to)
-                                : "cc", "1", "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
diff -urN linux-2.2.17-pre12/include/asm-s390/ucontext.h linux/include/asm-s390/ucontext.h
--- linux-2.2.17-pre12/include/asm-s390/ucontext.h	Wed May  3 17:16:51 2000
+++ linux/include/asm-s390/ucontext.h	Mon Dec  3 22:09:51 2001
@@ -14,6 +14,7 @@
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
 	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+	struct sigcontext *sc; /* Added for pthread support */
 };
 
 
diff -urN linux-2.2.17-pre12/include/linux/dasd.h linux/include/linux/dasd.h
--- linux-2.2.17-pre12/include/linux/dasd.h	Wed Jun  7 14:26:44 2000
+++ linux/include/linux/dasd.h	Wed Dec 31 16:00:00 1969
@@ -1,241 +0,0 @@
-
-#ifndef DASD_H
-#define DASD_H
-
-/* First of all the external stuff */
-#include <linux/ioctl.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-
-#define IOCTL_LETTER 'D'
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,1) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,2) 
-/* Stuff for reading and writing the Label-Area to/from user space */
-#define BIODASDGTVLBL  _IOR(IOCTL_LETTER,3,dasd_volume_label_t)
-#define BIODASDSTVLBL  _IOW(IOCTL_LETTER,4,dasd_volume_label_t)
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,5,int)
-#define BIODASDRSID    _IOR(IOCTL_LETTER,6,senseid_t)
-#define BIODASDRLB     _IOR(IOCTL_LETTER,7,int)
-#define BLKGETBSZ      _IOR(IOCTL_LETTER,8,int)
-
-typedef struct {
-	int start_unit;
-	int stop_unit;
-	int blksize;
-} format_data_t;
-
-typedef
-union {
-	char bytes[512];
-	struct {
-		/* 80 Bytes of Label data */
-		char identifier[4];	/* e.g. "LNX1", "VOL1" or "CMS1" */
-		char label[6];	/* Given by user */
-		char security;
-		char vtoc[5];	/* Null in "LNX1"-labelled partitions */
-		char reserved0[5];
-		long ci_size;
-		long blk_per_ci;
-		long lab_per_ci;
-		char reserved1[4];
-		char owner[0xe];
-		char no_part;
-		char reserved2[0x1c];
-		/* 16 Byte of some information on the dasd */
-		short blocksize;
-		char nopart;
-		char unused;
-		long unused2[3];
-		/* 7*10 = 70 Bytes of partition data */
-		struct {
-			char type;
-			long start;
-			long size;
-			char unused;
-		} part[7];
-	} __attribute__ ((packed)) label;
-} dasd_volume_label_t;
-
-typedef union {
-	struct {
-		unsigned long no;
-		unsigned int ct;
-	} __attribute__ ((packed)) input;
-	struct {
-		unsigned long noct;
-	} __attribute__ ((packed)) output;
-} __attribute__ ((packed)) dasd_xlate_t;
-
-int dasd_init (void);
-#ifdef MODULE
-int init_module (void);
-void cleanup_module (void);
-#endif				/* MODULE */
-
-/* Definitions for blk.h */
-/* #define DASD_MAGIC 0x44415344  is ascii-"DASD" */
-/* #define dasd_MAGIC 0x64617364;  is ascii-"dasd" */
-#define DASD_MAGIC 0xC4C1E2C4 /* is ebcdic-"DASD" */
-#define dasd_MAGIC 0x8481A284 /* is ebcdic-"dasd" */
-#define MDSK_MAGIC 0xD4C4E2D2 /* is ebcdic-"MDSK" */
-#define mdsk_MAGIC 0x9484A292 /* is ebcdic-"mdsk" */
-#define ERP_MAGIC  0xC5D9D740 /* is ebcdic-"ERP" */
-#define erp_MAGIC  0x45999740 /* is ebcdic-"erp" */
-
-#define DASD_NAME "dasd"
-#define DASD_PARTN_BITS 2
-#define DASD_MAX_DEVICES (256>>DASD_PARTN_BITS)
-
-#define MAJOR_NR DASD_MAJOR
-#define PARTN_BITS DASD_PARTN_BITS
-
-#ifdef __KERNEL__
-/* Now lets turn to the internal sbtuff */
-/*
-   define the debug levels:
-   - 0 No debugging output to console or syslog
-   - 1 Log internal errors to syslog, ignore check conditions 
-   - 2 Log internal errors and check conditions to syslog
-   - 3 Log internal errors to console, log check conditions to syslog
-   - 4 Log internal errors and check conditions to console
-   - 5 panic on internal errors, log check conditions to console
-   - 6 panic on both, internal errors and check conditions
- */
-#define DASD_DEBUG 4
-
-#define DASD_PROFILE
-/*
-   define the level of paranoia
-   - 0 quite sure, that things are going right
-   - 1 sanity checking, only to avoid panics
-   - 2 normal sanity checking
-   - 3 extensive sanity checks
-   - 4 exhaustive debug messages
- */
-#define DASD_PARANOIA 2
-
-/*
-   define the depth of flow control, which is logged as a check condition
-   - 0 No flow control messages
-   - 1 Entry of functions logged like check condition
-   - 2 Entry and exit of functions logged like check conditions
-   - 3 Internal structure broken down
-   - 4 unrolling of loops,...
- */
-#define DASD_FLOW_CONTROL 0
-
-#if DASD_DEBUG > 0
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
-#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
-#else
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#endif				/* DASD_DEBUG */
-
-#define INTERNAL_ERRMSG(x,y...) \
-"Internal error: in file " __FILE__ " line: %d: " x, __LINE__, y
-#define INTERNAL_CHKMSG(x,y...) \
-"Inconsistency: in file " __FILE__ " line: %d: " x, __LINE__, y
-#define INTERNAL_FLWMSG(x,y...) \
-"Flow control: file " __FILE__ " line: %d: " x, __LINE__, y
-
-#if DASD_DEBUG > 4
-#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) )
-#elif DASD_DEBUG > 2
-#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) )
-#elif DASD_DEBUG > 0
-#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) )
-#else
-#define INTERNAL_ERROR(x...)
-#endif				/* DASD_DEBUG */
-
-#if DASD_DEBUG > 5
-#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) )
-#elif DASD_DEBUG > 3
-#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) )
-#elif DASD_DEBUG > 1
-#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) )
-#else
-#define INTERNAL_CHECK(x...)
-#endif				/* DASD_DEBUG */
-
-#if DASD_DEBUG > 3
-#define INTERNAL_FLOW(x...) PRINT_ERR ( INTERNAL_FLWMSG ( x ) )
-#elif DASD_DEBUG > 2
-#define INTERNAL_FLOW(x...) PRINT_WARN ( INTERNAL_FLWMSG ( x ) )
-#else
-#define INTERNAL_FLOW(x...)
-#endif				/* DASD_DEBUG */
-
-#if DASD_FLOW_CONTROL > 0
-#define FUNCTION_ENTRY(x) INTERNAL_FLOW( x "entered %s\n","" );
-#else
-#define FUNCTION_ENTRY(x)
-#endif				/* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 1
-#define FUNCTION_EXIT(x) INTERNAL_FLOW( x "exited %s\n","" );
-#else
-#define FUNCTION_EXIT(x)
-#endif				/* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 2
-#define FUNCTION_CONTROL(x...) INTERNAL_FLOW( x );
-#else
-#define FUNCTION_CONTROL(x...)
-#endif				/* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 3
-#define LOOP_CONTROL(x...) INTERNAL_FLOW( x );
-#else
-#define LOOP_CONTROL(x...)
-#endif				/* DASD_FLOW_CONTROL */
-
-#define DASD_DO_IO_SLEEP 0x01
-#define DASD_DO_IO_NOLOCK 0x02
-#define DASD_DO_IO_NODEC 0x04
-
-#define DASD_NOT_FORMATTED 0x01
-
-extern struct wait_queue *dasd_waitq;
-
-#undef DEBUG_DASD_MALLOC
-#ifdef DEBUG_DASD_MALLOC
-void *b;
-#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
-#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
-#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
-#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
-#endif				/* DEBUG_DASD_MALLOC */
-
-#endif				/* __KERNEL__ */
-#endif				/* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -urN linux-2.2.17-pre12/include/linux/kmod.h linux/include/linux/kmod.h
--- linux-2.2.17-pre12/include/linux/kmod.h	Mon Dec  3 22:09:39 2001
+++ linux/include/linux/kmod.h	Mon Dec  3 22:09:51 2001
@@ -8,6 +8,8 @@
 extern int request_module(const char * name);
 extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
 #else
+#include <linux/errno.h>
+
 #define request_module(x) do {} while(0)
 static inline int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
 {
diff -urN linux-2.2.17-pre12/init/main.c linux/init/main.c
--- linux-2.2.17-pre12/init/main.c	Wed Jun  7 14:26:44 2000
+++ linux/init/main.c	Mon Dec  3 22:09:51 2001
@@ -47,7 +47,7 @@
 #endif
 
 #ifdef CONFIG_DASD
-#include <linux/dasd.h>
+#include <asm/dasd.h>
 #endif
 
 #ifdef CONFIG_BLK_DEV_XPRAM
@@ -199,9 +199,6 @@
 #endif
 #ifdef CONFIG_DASD
 extern void dasd_setup(char *str, int *ints);
-#ifdef CONFIG_DASD_MDSK
-extern void dasd_mdsk_setup(char *str, int *ints);
-#endif
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
 extern void xpram_setup(char *str, int *ints);
@@ -1098,9 +1095,6 @@
 #endif
 #ifdef CONFIG_DASD
         { "dasd=", dasd_setup },
-#ifdef CONFIG_DASD_MDSK
-        { "dasd_force_diag=", dasd_mdsk_setup },
-#endif
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
         { "xpram_parts=", xpram_setup },
@@ -1414,6 +1408,9 @@
 	vma_init();
 	buffer_init(memory_end-memory_start);
  	page_cache_init(memory_end-memory_start);
+#ifdef CONFIG_ARCH_S390
+	ccwcache_init();
+#endif
 	signals_init();
 	inode_init();
 	file_table_init();
@@ -1552,9 +1549,7 @@
 
 	/* Set up devices .. */
 	device_setup();
-#if  CONFIG_CHANDEV
-	chandev_init();
-#endif   
+
 	/* .. executable formats .. */
 	binfmt_setup();
 
diff -urN linux-2.2.17-pre12/net/core/dev.c linux/net/core/dev.c
--- linux-2.2.17-pre12/net/core/dev.c	Mon Dec  3 22:09:39 2001
+++ linux/net/core/dev.c	Mon Dec  3 22:09:51 2001
@@ -774,6 +774,10 @@
 	if (backlog.qlen <= netdev_max_backlog) {
 		if (backlog.qlen) {
 			if (netdev_dropping == 0) {
+				if (skb->dev->flags & IFF_SLAVE  && 
+				    skb->dev->slave) {
+					skb->dev = skb->dev->slave;
+				}
 				skb_queue_tail(&backlog,skb);
 				mark_bh(NET_BH);
 				return;
diff -urN linux-2.2.17-pre12/scripts/makelst linux/scripts/makelst
--- linux-2.2.17-pre12/scripts/makelst	Wed Dec 31 16:00:00 1969
+++ linux/scripts/makelst	Mon Dec  3 22:09:51 2001
@@ -0,0 +1,21 @@
+#!/bin/bash
+# A script to dump mixed source code & assembly
+# with correct relocations from System.map
+# Requires the following lines in Rules.make.
+#
+#%.lst: %.c
+#	$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+#	$(TOPDIR)/scripts/makelst $* $(TOPDIR) $(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 s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g`
+t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
