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

diff -urN linux-2.4.8-pre4/Documentation/pci.txt linux/Documentation/pci.txt
--- linux-2.4.8-pre4/Documentation/pci.txt	Thu Jun 28 14:58:05 2001
+++ linux/Documentation/pci.txt	Mon Dec  3 22:58:52 2001
@@ -80,7 +80,7 @@
 	class_mask	of the class are honored during the comparison.
 	driver_data	Data private to the driver.
 
-When the driver exits, it just calls pci_deregister_driver() and the PCI layer
+When the driver exits, it just calls pci_unregister_driver() and the PCI layer
 automatically calls the remove hook for all devices handled by the driver.
 
 Please mark the initialization and cleanup functions where appropriate
diff -urN linux-2.4.8-pre4/Documentation/sound/btaudio linux/Documentation/sound/btaudio
--- linux-2.4.8-pre4/Documentation/sound/btaudio	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/btaudio	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,81 @@
+
+Intro
+=====
+
+people start bugging me about this with questions, looks like I
+should write up some documentation for this beast.  That way I
+don't have to answer that much mails I hope.  Yes, I'm lazy...
+
+
+You might have noticed that the bt878 grabber cards have actually
+_two_ PCI functions:
+
+$ lspci
+[ ... ]
+00:0a.0 Multimedia video controller: Brooktree Corporation Bt878 (rev 02)
+00:0a.1 Multimedia controller: Brooktree Corporation Bt878 (rev 02)
+[ ... ]
+
+The first does video, it is backward compatible to the bt848.  The second
+does audio.  btaudio is a driver for the second function.  It's a sound
+driver which can be used for recording sound (and _only_ recording, no
+playback).  As most TV cards come with a short cable which can be plugged
+into your sound card's line-in you probably don't need this driver if all
+you want to do is just watching TV...
+
+
+Driver Status
+=============
+
+Still somewhat experimental.  The driver should work stable, i.e. it
+should'nt crash your box.  It might not work as expected, have bugs,
+not being fully OSS API compilant, ...
+
+
+Digital audio mode
+==================
+
+The chip knows different modes.  Right now you have to pick the one you
+want to use at insmod time.  Digital audio mode is the default.  The
+chip gives you 16 bit stereo sound with ~32 kHz sample rate.  According
+to the specs it should be possible to get up to 48 kHz, but I havn't
+figured out yet how this works.  The specs are not very verbose :-(
+
+Lower sample rates are possible too, but the code isn't written yet.
+For now you are limited to the fixed 32 kHz.  Mono works throuth, the
+driver will do that in software for you.
+
+With my Hauppauge I get clear sound, but I got also reports saying that
+digital audio mode does'nt work.  Guess Hauppauge connected the msp34xx
+output to the bt878's I2S digital audio input port.
+
+
+analog mode (A/D)
+=================
+
+You can tell the driver to use this mode with the insmod option "analog=1".
+The chip has three analog inputs.  Consequently you'll get a mixer device
+to control these.
+
+The analog mode supports mono only.  Both 8 + 16 bit.  Both are _signed_
+int, which is uncommon for the 8 bit case.  Sample rate range is 119 kHz
+to 448 kHz.  Yes, the number of digits is correct.  The driver supports
+downsampling by powers of two, so you can ask for more usual sample rates
+like 44 kHz too.
+
+With my Hauppauge I get noisy sound on the second input (mapped to line2
+by the mixer device).  Others get a useable signal on line1.
+
+
+more hints
+==========
+
+/me uses "sox -w -r 32000 -t ossdsp /dev/dsp2 -t ossdsp /dev/dsp"
+to dump audio data from btaudio (dsp2) to es1730 (dsp,dsp1).
+
+Have fun,
+
+  Gerd
+
+-- 
+Gerd Knorr <kraxel@bytesex.org>
diff -urN linux-2.4.8-pre4/Documentation/video4linux/bttv/CARDLIST linux/Documentation/video4linux/bttv/CARDLIST
--- linux-2.4.8-pre4/Documentation/video4linux/bttv/CARDLIST	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/CARDLIST	Mon Dec  3 22:58:52 2001
@@ -53,11 +53,19 @@
   card=51 - Eagle Wireless Capricorn2 (bt878A)
   card=52 - Pinnacle PCTV Studio Pro
   card=53 - Typhoon TView RDS / FM Stereo
-  card=54 - Livetec 9415 TV
+  card=54 - Lifetec LT 9415 TV
   card=55 - BESTBUY Easy TV
   card=56 - FlyVideo '98/FM
   card=57 - GrandTec 'Grand Video Capture'
   card=58 - Phoebe TV Master Only (No FM)
+  card=59 - TV Capturer
+  card=60 - MM100PCTV
+  card=61 - AG Electronics GMV1
+  card=62 - BESTBUY Easy TV (bt878)
+  card=63 - ATI TV-Wonder
+  card=64 - ATI TV-Wonder VE
+  card=65 - FlyVideo 2000S
+  card=66 - Terratec TValueRadio
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
@@ -85,3 +93,9 @@
   type=22 - Temic PAL/SECAM multi (4046 FM5)
   type=23 - Philips PAL_DK
   type=24 - Philips PAL/SECAM multi (FQ1216ME)
+  type=25 - LG PAL_I+FM (TAPC-I001D)
+  type=26 - LG PAL_I (TAPC-I701D)
+  type=27 - LG NTSC+FM (TPI8NSR01F)
+  type=28 - LG PAL_BG+FM (TPI8PSB01D)
+  type=29 - LG PAL_BG (TPI8PSB11D)
+  type=30 - Temic PAL* auto + FM (4009 FN5)
diff -urN linux-2.4.8-pre4/Documentation/video4linux/bttv/Insmod-options linux/Documentation/video4linux/bttv/Insmod-options
--- linux-2.4.8-pre4/Documentation/video4linux/bttv/Insmod-options	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/Insmod-options	Mon Dec  3 22:58:52 2001
@@ -13,6 +13,9 @@
 		triton1=0/1     for Triton1 compatibility
 				Triton1 is automatically recognized
 				but this might also help with other chipsets
+		vsfx=0/1	yet another chipset bug compatibility flag
+				(bt878 docs mentiones via+sis, but no
+				specific chipsets with that problem).
 		bigendian=n	Set the endianness of the gfx framebuffer.
 				Default is native endian.
 		fieldnr=0/1	Count fields.  Some TV descrambling software
diff -urN linux-2.4.8-pre4/Documentation/video4linux/bttv/README linux/Documentation/video4linux/bttv/README
--- linux-2.4.8-pre4/Documentation/video4linux/bttv/README	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/README	Mon Dec  3 22:58:52 2001
@@ -21,8 +21,7 @@
 CONFIG_I2C_ALGOBIT=m
 CONFIG_VIDEO_DEV=m
 
-The latest bttv version is available here:
-	http://www.strusel007.de/linux/bttv/
+The latest bttv version is available from http://bytesex.org/bttv/
 
 You'll find Ralphs original (mostly outdated) documentation in the
 ralphs-doc subdirectory.
diff -urN linux-2.4.8-pre4/Documentation/video4linux/bttv/Sound-FAQ linux/Documentation/video4linux/bttv/Sound-FAQ
--- linux-2.4.8-pre4/Documentation/video4linux/bttv/Sound-FAQ	Mon Feb 19 14:43:36 2001
+++ linux/Documentation/video4linux/bttv/Sound-FAQ	Mon Dec  3 22:58:52 2001
@@ -109,6 +109,29 @@
 in  = 	_in_put bits of the data register,
 	i.e. BT848_GPIO_DATA & ~BT848_GPIO_OUT_EN
 
+
+
+Other elements of the tvcards array
+===================================
+
+If you are trying to make a new card work you might find it useful to
+know what the other elements in the tvcards array are good for:
+
+video_inputs    - # of video inputs the card has
+audio_inputs    - historical cruft, not used any more.
+tuner           - which input is the tuner
+svhs            - which input is svhs (all others are labled composite)
+muxsel          - video mux, input->registervalue mapping
+pll             - same as pll= insmod option
+tuner_type      - same as tuner= insmod option
+*_modulename    - hint whenever some card needs this or that audio
+                  module loaded to work properly.
+
+If some config item is specified both from the tvcards array and as
+insmod option, the insmod option takes precedence.
+
+
+
 Good luck,
 
   Gerd
@@ -117,4 +140,4 @@
 PS: If you have a new working entry, mail it to me.
 
 -- 
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
diff -urN linux-2.4.8-pre4/MAINTAINERS linux/MAINTAINERS
--- linux-2.4.8-pre4/MAINTAINERS	Mon Dec  3 22:58:44 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:58:52 2001
@@ -106,6 +106,13 @@
 L:	linux-net@vger.kernel.org
 S:	Maintained
 
+A2232 SERIAL BOARD DRIVER
+P:      Enver Haase
+M:      ehaase@inf.fu-berlin.de
+M:      A2232@gmx.net
+L:      linux-m68k@lists.linux-m68k.org
+S:      Maintained
+
 ACENIC DRIVER
 P:	Jes Sorensen
 M:	jes@trained-monkey.org
diff -urN linux-2.4.8-pre4/Makefile linux/Makefile
--- linux-2.4.8-pre4/Makefile	Mon Dec  3 22:58:44 2001
+++ linux/Makefile	Mon Dec  3 22:58:52 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 8
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.8-pre4/arch/i386/boot/Makefile linux/arch/i386/boot/Makefile
--- linux-2.4.8-pre4/arch/i386/boot/Makefile	Thu Feb 22 00:25:29 2001
+++ linux/arch/i386/boot/Makefile	Mon Dec  3 22:58:52 2001
@@ -67,7 +67,7 @@
 	$(AS) -o $@ $<
 
 setup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+	$(CPP) $(CPPFLAGS) -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 bsetup: bsetup.o
 	$(LD) -Ttext 0x0 -s --oformat binary -e begtext -o $@ $<
@@ -76,7 +76,7 @@
 	$(AS) -o $@ $<
 
 bsetup.s: setup.S video.S Makefile $(BOOT_INCL) $(TOPDIR)/include/linux/version.h $(TOPDIR)/include/linux/compile.h
-	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
+	$(CPP) $(CPPFLAGS) -D__BIG_KERNEL__ -D__ASSEMBLY__ -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@
 
 dep:
 
diff -urN linux-2.4.8-pre4/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
--- linux-2.4.8-pre4/arch/i386/boot/setup.S	Tue May  1 16:04:56 2001
+++ linux/arch/i386/boot/setup.S	Mon Dec  3 22:58:52 2001
@@ -44,7 +44,6 @@
  *
  */
 
-#define __ASSEMBLY__
 #include <linux/config.h>
 #include <asm/segment.h>
 #include <linux/version.h>
diff -urN linux-2.4.8-pre4/arch/i386/kernel/mpparse.c linux/arch/i386/kernel/mpparse.c
--- linux-2.4.8-pre4/arch/i386/kernel/mpparse.c	Mon Jun 11 19:15:27 2001
+++ linux/arch/i386/kernel/mpparse.c	Mon Dec  3 22:58:52 2001
@@ -273,24 +273,26 @@
 	int count=sizeof(*mpc);
 	unsigned char *mpt=((unsigned char *)mpc)+count;
 
-	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
-	{
+	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4)) {
 		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
 			mpc->mpc_signature[0],
 			mpc->mpc_signature[1],
 			mpc->mpc_signature[2],
 			mpc->mpc_signature[3]);
-		return 1;
+		return 0;
 	}
-	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
-	{
+	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length)) {
 		panic("SMP mptable: checksum error!\n");
-		return 1;
+		return 0;
 	}
-	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
-	{
-		printk("Bad Config Table version (%d)!!\n",mpc->mpc_spec);
-		return 1;
+	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04) {
+		printk(KERN_ERR "SMP mptable: bad table version (%d)!!\n",
+			mpc->mpc_spec);
+		return 0;
+	}
+	if (!mpc->mpc_lapic) {
+		printk(KERN_ERR "SMP mptable: null local APIC address!\n");
+		return 0;
 	}
 	memcpy(str,mpc->mpc_oem,8);
 	str[8]=0;
@@ -358,6 +360,8 @@
 			}
 		}
 	}
+	if (!num_processors)
+		printk(KERN_ERR "SMP mptable: no processors registered!\n");
 	return num_processors;
 }
 
@@ -508,8 +512,12 @@
 		 * Read the physical hardware table.  Anything here will
 		 * override the defaults.
 		 */
-		smp_read_mpc((void *)mpf->mpf_physptr);
-
+		if (!smp_read_mpc((void *)mpf->mpf_physptr)) {
+			smp_found_config = 0;
+			printk(KERN_ERR "BIOS bug, MP table errors detected!...\n");
+			printk(KERN_ERR "... disabling SMP support. (tell your hw vendor)\n");
+			return;
+		}
 		/*
 		 * If there are no explicit MP IRQ entries, then we are
 		 * broken.  We set up most of the low 16 IO-APIC pins to
diff -urN linux-2.4.8-pre4/drivers/block/DAC960.c linux/drivers/block/DAC960.c
--- linux-2.4.8-pre4/drivers/block/DAC960.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/block/DAC960.c	Mon Dec  3 22:58:52 2001
@@ -20,7 +20,7 @@
 
 
 #define DAC960_DriverVersion			"2.4.10"
-#define DAC960_DriverDate			"1 February 2001"
+#define DAC960_DriverDate			"23 July 2001"
 
 
 #include <linux/version.h>
@@ -28,6 +28,7 @@
 #include <linux/types.h>
 #include <linux/blk.h>
 #include <linux/blkdev.h>
+#include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
@@ -40,7 +41,6 @@
 #include <linux/spinlock.h>
 #include <linux/timer.h>
 #include <linux/pci.h>
-#include <linux/completion.h>
 #include <asm/io.h>
 #include <asm/segment.h>
 #include <asm/uaccess.h>
@@ -485,14 +485,14 @@
 static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  DECLARE_COMPLETION(Wait);
+  DECLARE_COMPLETION(Completion);
   unsigned long ProcessorFlags;
-  Command->Waiting = &Wait;
+  Command->Completion = &Completion;
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
   DAC960_QueueCommand(Command);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
   if (in_interrupt()) return;
-  wait_for_completion(&Wait);
+  wait_for_completion(&Completion);
 }
 
 
@@ -1317,7 +1317,7 @@
 						 *Controller)
 {
   DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB;
-  Completion_T Wait[DAC960_V1_MaxChannels], *wait;
+  Completion_T Completions[DAC960_V1_MaxChannels], *Completion;
   unsigned long ProcessorFlags;
   int Channel, TargetID;
   for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
@@ -1328,12 +1328,12 @@
 	  DAC960_SCSI_Inquiry_T *InquiryStandardData =
 	    &Controller->V1.InquiryStandardData[Channel][TargetID];
 	  InquiryStandardData->PeripheralDeviceType = 0x1F;
-	  wait = &Wait[Channel];
-	  init_completion(wait);
+	  Completion = &Completions[Channel];
+	  init_completion(Completion);
 	  DCDB = &DCDBs[Channel];
 	  DAC960_V1_ClearCommand(Command);
 	  Command->CommandType = DAC960_ImmediateCommand;
-	  Command->Waiting = wait;
+	  Command->Completion = Completion;
 	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
 	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB);
 	  DCDB->Channel = Channel;
@@ -1364,11 +1364,11 @@
 	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
 	    &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
 	  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
-	  wait = &Wait[Channel];
-	  wait_for_completion(wait);
+	  Completion = &Completions[Channel];
+	  wait_for_completion(Completion);
 	  if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion)
 	    continue;
-	  Command->Waiting = wait;
+	  Command->Completion = Completion;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
 	  DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber);
@@ -1382,7 +1382,7 @@
 	  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
 	  DAC960_QueueCommand(Command);
 	  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	  wait_for_completion(wait);
+	  wait_for_completion(Completion);
 	}
     }
   return true;
@@ -2769,7 +2769,7 @@
   if (Request->cmd == READ)
     Command->CommandType = DAC960_ReadCommand;
   else Command->CommandType = DAC960_WriteCommand;
-  Command->Waiting = Request->waiting;
+  Command->Completion = Request->waiting;
   Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
   Command->BlockNumber =
     Request->sector
@@ -2922,13 +2922,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  /*
-	    Wake up requestor for swap file paging requests.
-	  */
-	  if (Command->Waiting)
+	  if (Command->Completion != NULL)
 	    {
-	      complete(Command->Waiting);
-	      Command->Waiting = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
@@ -2970,10 +2967,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  if (Command->Waiting)
+	  if (Command->Completion != NULL)
 	    {
-	      complete(Command->Waiting);
-	      Command->Waiting = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	}
     }
@@ -3587,8 +3584,8 @@
     }
   if (CommandType == DAC960_ImmediateCommand)
     {
-      complete(Command->Waiting);
-      Command->Waiting = NULL;
+      complete(Command->Completion);
+      Command->Completion = NULL;
       return;
     }
   if (CommandType == DAC960_QueuedCommand)
@@ -3929,10 +3926,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  if (Command->Waiting)
+	  if (Command->Completion != NULL)
 	    {
-	      complete(Command->Waiting);
-	      Command->Waiting = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
@@ -3974,10 +3971,10 @@
 	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	      BufferHeader = NextBufferHeader;
 	    }
-	  if (Command->Waiting)
+	  if (Command->Completion != NULL)
 	    {
-	      complete(Command->Waiting);
-	      Command->Waiting = NULL;
+	      complete(Command->Completion);
+	      Command->Completion = NULL;
 	    }
 	}
     }
@@ -4531,8 +4528,8 @@
     }
   if (CommandType == DAC960_ImmediateCommand)
     {
-      complete(Command->Waiting);
-      Command->Waiting = NULL;
+      complete(Command->Completion);
+      Command->Completion = NULL;
       return;
     }
   if (CommandType == DAC960_QueuedCommand)
diff -urN linux-2.4.8-pre4/drivers/block/DAC960.h linux/drivers/block/DAC960.h
--- linux-2.4.8-pre4/drivers/block/DAC960.h	Mon Dec  3 22:58:44 2001
+++ linux/drivers/block/DAC960.h	Mon Dec  3 22:58:52 2001
@@ -2139,6 +2139,7 @@
 typedef struct buffer_head BufferHeader_T;
 typedef struct file File_T;
 typedef struct block_device_operations BlockDeviceOperations_T;
+typedef struct completion Completion_T;
 typedef struct gendisk GenericDiskInfo_T;
 typedef struct hd_geometry DiskGeometry_T;
 typedef struct hd_struct DiskPartition_T;
@@ -2153,7 +2154,6 @@
 typedef struct pt_regs Registers_T;
 typedef struct request IO_Request_T;
 typedef request_queue_t RequestQueue_T;
-typedef struct completion Completion_T;
 typedef struct super_block SuperBlock_T;
 typedef struct timer_list Timer_T;
 typedef wait_queue_head_t WaitQueue_T;
@@ -2220,7 +2220,7 @@
   DAC960_CommandType_T CommandType;
   struct DAC960_Controller *Controller;
   struct DAC960_Command *Next;
-  Completion_T *Waiting;
+  Completion_T *Completion;
   unsigned int LogicalDriveNumber;
   unsigned int BlockNumber;
   unsigned int BlockCount;
diff -urN linux-2.4.8-pre4/drivers/block/floppy.c linux/drivers/block/floppy.c
--- linux-2.4.8-pre4/drivers/block/floppy.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/floppy.c	Mon Dec  3 22:58:52 2001
@@ -1034,7 +1034,7 @@
 }
 
 /* waits for a delay (spinup or select) to pass */
-static int wait_for_completion(unsigned long delay, timeout_fn function)
+static int fd_wait_for_completion(unsigned long delay, timeout_fn function)
 {
 	if (FDCS->reset){
 		reset_fdc(); /* do the reset during sleep to win time
@@ -1392,7 +1392,7 @@
 	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
 	 */
 	FDCS->dtr = raw_cmd->rate & 3;
-	return(wait_for_completion(jiffies+2UL*HZ/100,
+	return(fd_wait_for_completion(jiffies+2UL*HZ/100,
 				   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
@@ -1509,7 +1509,7 @@
 			function = (timeout_fn) setup_rw_floppy;
 
 		/* wait until the floppy is spinning fast enough */
-		if (wait_for_completion(ready_date,function))
+		if (fd_wait_for_completion(ready_date,function))
 			return;
 	}
 	dflags = DRS->flags;
@@ -1939,7 +1939,7 @@
 	set_dor(fdc, mask, data);
 
 	/* wait_for_completion also schedules reset if needed. */
-	return(wait_for_completion(DRS->select_date+DP->select_delay,
+	return(fd_wait_for_completion(DRS->select_date+DP->select_delay,
 				   (timeout_fn) function));
 }
 
diff -urN linux-2.4.8-pre4/drivers/char/drm/agpsupport.c linux/drivers/char/drm/agpsupport.c
--- linux-2.4.8-pre4/drivers/char/drm/agpsupport.c	Mon Jul  2 15:27:56 2001
+++ linux/drivers/char/drm/agpsupport.c	Mon Dec  3 22:58:52 2001
@@ -292,8 +292,8 @@
 		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
 		case SVWRKS_GENERIC:	head->chipset = "Serverworks Generic";
 			break;
-		case SVWRKS_HE: 	head->chipset = "Serverworks HE";
-		case SVWRKS_LE: 	head->chipset = "Serverworks LE";
+		case SVWRKS_HE: 	head->chipset = "Serverworks HE"; break;
+		case SVWRKS_LE: 	head->chipset = "Serverworks LE"; break;
 
 		default:		head->chipset = "Unknown";       break;
 		}
diff -urN linux-2.4.8-pre4/drivers/char/mxser.c linux/drivers/char/mxser.c
--- linux-2.4.8-pre4/drivers/char/mxser.c	Wed May 16 10:31:27 2001
+++ linux/drivers/char/mxser.c	Mon Dec  3 22:58:52 2001
@@ -884,8 +884,6 @@
 	if (!tty || !info->xmit_buf || !mxvar_tmp_buf)
 		return (0);
 
-	if (from_user)
-		down(&mxvar_tmp_buf_sem);
 	save_flags(flags);
 	if (from_user) {
 		down(&mxvar_tmp_buf_sem);
diff -urN linux-2.4.8-pre4/drivers/char/nvram.c linux/drivers/char/nvram.c
--- linux-2.4.8-pre4/drivers/char/nvram.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/char/nvram.c	Mon Dec  3 22:58:52 2001
@@ -113,7 +113,7 @@
 #define	NVRAM_EXCL		2		/* opened with O_EXCL */
 
 #define	RTC_FIRST_BYTE		14	/* RTC register number of first NVRAM byte */
-#define	NVRAM_BYTES			128	/* number of NVRAM bytes */
+#define	NVRAM_BYTES			128-RTC_FIRST_BYTE	/* number of NVRAM bytes */
 
 
 static int mach_check_checksum( void );
diff -urN linux-2.4.8-pre4/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- linux-2.4.8-pre4/drivers/char/riscom8.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/char/riscom8.c	Mon Dec  3 22:58:52 2001
@@ -1866,10 +1866,10 @@
 __setup("riscom8=", riscom8_setup);
 #endif
 
-static const char banner[] __initdata =
+static char banner[] __initdata =
 	KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
 		  "1994-1996.\n";
-static const char no_boards_msg[] __initdata =
+static char no_boards_msg[] __initdata =
 	KERN_INFO "rc: No RISCom/8 boards detected.\n";
 
 /* 
diff -urN linux-2.4.8-pre4/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c
--- linux-2.4.8-pre4/drivers/char/sbc60xxwdt.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/char/sbc60xxwdt.c	Mon Dec  3 22:58:52 2001
@@ -178,7 +178,7 @@
 			char c;
 			if(get_user(c, buf+ofs))
 				return -EFAULT;
-			if(buf[ofs] == 'V')
+			if(c == 'V')
 				wdt_expect_close = 1;
 		}
 		/* Well, anyhow someone wrote to us, we should return that favour */
diff -urN linux-2.4.8-pre4/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.8-pre4/drivers/char/serial.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/char/serial.c	Mon Dec  3 22:58:52 2001
@@ -5432,6 +5432,10 @@
 			state->io_type = SERIAL_IO_HUB6;
 		if (state->port && check_region(state->port,8))
 			continue;
+#ifdef CONFIG_MCA			
+		if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus)
+			continue;
+#endif			
 		if (state->flags & ASYNC_BOOT_AUTOCONF)
 			autoconfig(state);
 	}
diff -urN linux-2.4.8-pre4/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- linux-2.4.8-pre4/drivers/char/sysrq.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/sysrq.c	Mon Dec  3 22:58:52 2001
@@ -26,7 +26,6 @@
 
 #include <asm/ptrace.h>
 
-extern void wakeup_bdflush(int);
 extern void reset_vc(unsigned int);
 extern struct list_head super_blocks;
 
@@ -99,12 +98,12 @@
 	case 's':					    /* S -- emergency sync */
 		printk("Emergency Sync\n");
 		emergency_sync_scheduled = EMERG_SYNC;
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		break;
 	case 'u':					    /* U -- emergency remount R/O */
 		printk("Emergency Remount R/O\n");
 		emergency_sync_scheduled = EMERG_REMOUNT;
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		break;
 	case 'p':					    /* P -- show PC */
 		printk("Show Regs\n");
diff -urN linux-2.4.8-pre4/drivers/ide/sis5513.c linux/drivers/ide/sis5513.c
--- linux-2.4.8-pre4/drivers/ide/sis5513.c	Sat May 19 17:43:06 2001
+++ linux/drivers/ide/sis5513.c	Mon Dec  3 22:58:52 2001
@@ -48,7 +48,15 @@
 	{ "SiS540",	PCI_DEVICE_ID_SI_540,	SIS5513_FLAG_ATA_66, },
 	{ "SiS620",	PCI_DEVICE_ID_SI_620,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS630",	PCI_DEVICE_ID_SI_630,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS635",	PCI_DEVICE_ID_SI_635,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS640",	PCI_DEVICE_ID_SI_640,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS645",	PCI_DEVICE_ID_SI_645,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS650",	PCI_DEVICE_ID_SI_650,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS730",	PCI_DEVICE_ID_SI_730,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS735",	PCI_DEVICE_ID_SI_735,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS740",	PCI_DEVICE_ID_SI_740,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS745",	PCI_DEVICE_ID_SI_745,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
+	{ "SiS750",	PCI_DEVICE_ID_SI_750,	SIS5513_FLAG_ATA_66|SIS5513_FLAG_LATENCY, },
 	{ "SiS5591",	PCI_DEVICE_ID_SI_5591,	SIS5513_FLAG_ATA_33, },
 	{ "SiS5597",	PCI_DEVICE_ID_SI_5597,	SIS5513_FLAG_ATA_33, },
 	{ "SiS5600",	PCI_DEVICE_ID_SI_5600,	SIS5513_FLAG_ATA_33, },
@@ -338,7 +346,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				unmask   = 0xF0;
 				four_two = 0x01;
 				break;
@@ -423,7 +439,15 @@
 
 	if (host_dev) {
 		switch(host_dev->device) {
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				ultra_100 = 1;
 			case PCI_DEVICE_ID_SI_530:
 			case PCI_DEVICE_ID_SI_540:
@@ -598,7 +622,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 				ata66 = (reg48h & mask) ? 0 : 1;
 			default:
 				break;
@@ -625,7 +657,15 @@
 			case PCI_DEVICE_ID_SI_540:
 			case PCI_DEVICE_ID_SI_620:
 			case PCI_DEVICE_ID_SI_630:
+			case PCI_DEVICE_ID_SI_635:
+			case PCI_DEVICE_ID_SI_640:
+			case PCI_DEVICE_ID_SI_645:
+			case PCI_DEVICE_ID_SI_650:
 			case PCI_DEVICE_ID_SI_730:
+			case PCI_DEVICE_ID_SI_735:
+			case PCI_DEVICE_ID_SI_740:
+			case PCI_DEVICE_ID_SI_745:
+			case PCI_DEVICE_ID_SI_750:
 			case PCI_DEVICE_ID_SI_5600:
 			case PCI_DEVICE_ID_SI_5597:
 			case PCI_DEVICE_ID_SI_5591:
diff -urN linux-2.4.8-pre4/drivers/ieee1394/ieee1394_core.c linux/drivers/ieee1394/ieee1394_core.c
--- linux-2.4.8-pre4/drivers/ieee1394/ieee1394_core.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/ieee1394/ieee1394_core.c	Mon Dec  3 22:58:52 2001
@@ -353,7 +353,7 @@
         }
 
         if (ackcode != ACK_PENDING || !packet->expect_response) {
-                packet->state = complete;
+                packet->state = completed;
                 up(&packet->state_change);
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -506,7 +506,7 @@
                 break;
         }
 
-        packet->state = complete;
+        packet->state = completed;
         up(&packet->state_change);
         run_task_queue(&packet->complete_tq);
 }
@@ -726,7 +726,7 @@
         while (lh != &llist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
                 lh = lh->next;
-                packet->state = complete;
+                packet->state = completed;
                 packet->ack_code = ACKX_ABORTED;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
@@ -771,7 +771,7 @@
         while (lh != &expiredlist) {
                 packet = list_entry(lh, struct hpsb_packet, list);
                 lh = lh->next;
-                packet->state = complete;
+                packet->state = completed;
                 packet->ack_code = ACKX_TIMEOUT;
                 up(&packet->state_change);
                 run_task_queue(&packet->complete_tq);
diff -urN linux-2.4.8-pre4/drivers/ieee1394/ieee1394_core.h linux/drivers/ieee1394/ieee1394_core.h
--- linux-2.4.8-pre4/drivers/ieee1394/ieee1394_core.h	Thu Jul 19 17:48:15 2001
+++ linux/drivers/ieee1394/ieee1394_core.h	Mon Dec  3 22:58:52 2001
@@ -24,11 +24,11 @@
         /* Okay, this is core internal and a no care for hosts.
          * queued   = queued for sending
          * pending  = sent, waiting for response
-         * complete = processing completed, successful or not
+         * completed = processing completed, successful or not
          * incoming = incoming packet
          */
         enum { 
-                unused, queued, pending, complete, incoming 
+                unused, queued, pending, completed, incoming 
         } __attribute__((packed)) state;
 
         /* These are core internal. */
diff -urN linux-2.4.8-pre4/drivers/media/radio/Config.in linux/drivers/media/radio/Config.in
--- linux-2.4.8-pre4/drivers/media/radio/Config.in	Tue Jun 12 10:56:11 2001
+++ linux/drivers/media/radio/Config.in	Mon Dec  3 22:58:52 2001
@@ -21,6 +21,7 @@
 if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
    hex '    GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
 fi
+dep_tristate '  GemTek PCI Radio Card support' CONFIG_RADIO_GEMTEK_PCI $CONFIG_VIDEO_DEV
 dep_tristate '  Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO $CONFIG_VIDEO_DEV
 dep_tristate '  Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
 dep_tristate '  miroSOUND PCM20 radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV $CONFIG_SOUND_ACI_MIXER
diff -urN linux-2.4.8-pre4/drivers/media/radio/Makefile linux/drivers/media/radio/Makefile
--- linux-2.4.8-pre4/drivers/media/radio/Makefile	Tue Jun 12 10:56:11 2001
+++ linux/drivers/media/radio/Makefile	Mon Dec  3 22:58:52 2001
@@ -39,6 +39,7 @@
 obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o
 obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
+obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
 obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
 
diff -urN linux-2.4.8-pre4/drivers/media/radio/radio-gemtek-pci.c linux/drivers/media/radio/radio-gemtek-pci.c
--- linux-2.4.8-pre4/drivers/media/radio/radio-gemtek-pci.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/radio/radio-gemtek-pci.c	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,451 @@
+/*
+ ***************************************************************************
+ *     
+ *     radio-gemtek-pci.c - Gemtek PCI Radio driver
+ *     (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
+ *
+ ***************************************************************************
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
+ *     USA.
+ *
+ ***************************************************************************
+ *
+ *     Gemtek Corp still silently refuses to release any specifications
+ *     of their multimedia devices, so the protocol still has to be
+ *     reverse engineered.
+ *
+ *     The v4l code was inspired by Jonas Munsin's  Gemtek serial line
+ *     radio device driver.
+ *
+ *     Please, let me know if this piece of code was useful :)
+ * 
+ *     TODO: multiple device support and portability were not tested
+ *
+ ***************************************************************************
+ */
+
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/videodev.h>
+#include <linux/errno.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#ifndef PCI_VENDOR_ID_GEMTEK
+#define PCI_VENDOR_ID_GEMTEK 0x5046
+#endif
+
+#ifndef PCI_DEVICE_ID_GEMTEK_PR103
+#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
+#endif
+
+#ifndef GEMTEK_PCI_RANGE_LOW
+#define GEMTEK_PCI_RANGE_LOW (87*16000)
+#endif
+
+#ifndef GEMTEK_PCI_RANGE_HIGH
+#define GEMTEK_PCI_RANGE_HIGH (108*16000)
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE 
+#define FALSE (0)
+#endif
+
+struct gemtek_pci_card {
+	struct video_device *videodev;
+	
+	u32 iobase;
+	u32 length;
+	u8  chiprev;
+	u16 model;
+	
+	u32 current_frequency;
+	u8  mute;
+};
+
+static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $";
+
+static int nr_radio = -1;
+
+static int gemtek_pci_open( struct video_device *dev, int flags)
+{
+	struct gemtek_pci_card *card =  dev->priv;
+
+/* Paranoid check */
+	if ( !card )
+		return -ENODEV;
+
+	return 0;
+}
+
+static void gemtek_pci_close( struct video_device *dev )
+{
+/*
+ *  The module usage is managed by 'videodev'
+ */
+}
+
+static inline u8 gemtek_pci_out( u16 value, u32 port )
+{
+	outw( value, port );
+
+	return (u8)value;
+}
+
+#define _b0( v ) *((u8 *)&v)  
+static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
+{
+	register u8 byte = *last_byte;
+
+	if ( !value ) {
+		if ( !keep )
+			value = (u16)port;
+		byte &= 0xfd;	
+	} else
+		byte |= 2;
+
+	_b0( value ) = byte;
+	outw( value, port );
+	byte |= 1;
+	_b0( value ) = byte;
+	outw( value, port );
+	byte &= 0xfe;
+	_b0( value ) = byte;
+	outw( value, port );
+	
+	*last_byte = byte;
+}
+
+static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
+{
+	__gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
+}
+
+static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
+{
+	__gemtek_pci_cmd( cmd, port, last_byte, TRUE );
+}
+
+static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
+{
+	register int i;
+	register u32 value = frequency / 200 + 856;
+	register u16 mask = 0x8000;
+	u8 last_byte;
+	u32 port = card->iobase;
+
+	last_byte = gemtek_pci_out( 0x06, port );
+
+	i = 0;
+	do {
+		gemtek_pci_nil( port, &last_byte );
+		i++;
+	} while ( i < 9 );
+
+	i = 0;
+	do {
+		gemtek_pci_cmd( value & mask, port, &last_byte );
+		mask >>= 1;
+		i++;
+	} while ( i < 16 );
+
+	outw( 0x10, port );
+}
+
+
+static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
+{
+	outb( 0x1f, card->iobase );
+	card->mute = TRUE;
+}
+
+static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
+{
+	if ( card->mute ) {
+		gemtek_pci_setfrequency( card, card->current_frequency );
+		card->mute = FALSE;
+	}
+}
+
+static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card )
+{
+	return ( inb( card->iobase ) & 0x08 ) ? 0 : 1;
+}
+
+static int gemtek_pci_ioctl( struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct gemtek_pci_card *card = dev->priv;
+
+	switch ( cmd ) {
+		case VIDIOCGCAP:
+		{
+			struct video_capability c;
+
+			c.type = VID_TYPE_TUNER;
+			c.channels = 1;
+			c.audios = 1;
+			c.maxwidth = 0;
+			c.maxheight = 0;
+			c.minwidth = 0;
+			c.minheight = 0;
+			strcpy( c.name, "Gemtek PCI Radio" );
+			if ( copy_to_user( arg, &c, sizeof( c ) ) )
+				return -EFAULT;
+
+			return 0;
+		} 
+
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner t;
+
+			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			if ( t.tuner ) 
+				return -EINVAL;
+
+			t.rangelow = GEMTEK_PCI_RANGE_LOW;
+			t.rangehigh = GEMTEK_PCI_RANGE_HIGH;
+			t.flags = VIDEO_TUNER_LOW;
+			t.mode = VIDEO_MODE_AUTO;
+			t.signal = 0xFFFF * gemtek_pci_getsignal( card );
+			strcpy( t.name, "FM" );
+
+			if ( copy_to_user( arg, &t, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			return 0;
+		}
+
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner t;
+
+			if ( copy_from_user( &t, arg, sizeof( struct video_tuner ) ) )
+				return -EFAULT;
+
+			if ( t.tuner )
+				return -EINVAL;
+
+			return 0;
+		}
+
+		case VIDIOCGFREQ:
+			return put_user( card->current_frequency, (u32 *)arg );
+
+		case VIDIOCSFREQ:
+		{
+			u32 frequency;
+	 
+			if ( get_user( frequency, (u32 *)arg ) )
+				return -EFAULT;
+
+			if ( (frequency < GEMTEK_PCI_RANGE_LOW) || (frequency > GEMTEK_PCI_RANGE_HIGH) )
+				return -EINVAL;
+
+			gemtek_pci_setfrequency( card, frequency );
+			card->current_frequency = frequency;
+			card->mute = FALSE;
+
+			return 0;
+		}
+  
+		case VIDIOCGAUDIO:
+		{	
+			struct video_audio a;
+
+			memset( &a, 0, sizeof( a ) );
+			a.flags |= VIDEO_AUDIO_MUTABLE;
+			a.volume = 1;
+			a.step = 65535;
+			strcpy( a.name, "Radio" );
+
+			if ( copy_to_user( arg, &a, sizeof( struct video_audio ) ) )
+				return -EFAULT;
+
+			return 0;			
+		}
+
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio a;
+
+			if ( copy_from_user( &a, arg, sizeof( struct video_audio ) ) ) 
+				return -EFAULT;	
+
+			if ( a.audio ) 
+				return -EINVAL;
+
+			if ( a.flags & VIDEO_AUDIO_MUTE ) 
+				gemtek_pci_mute( card );
+
+			else
+				gemtek_pci_unmute( card );
+
+			return 0;
+		}
+
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+enum {
+	GEMTEK_PR103
+};
+
+static char *card_names[] __devinitdata = {
+	"GEMTEK_PR103"
+};
+
+static struct pci_device_id gemtek_pci_id[] =
+{
+	{ PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE( pci, gemtek_pci_id );
+
+static u8 mx = 1;
+
+static char gemtek_pci_videodev_name[] = "Gemtek PCI Radio";
+
+static inline void gemtek_pci_init_struct( struct video_device *dev )
+{
+	memset( dev, 0, sizeof( struct video_device ) );
+	dev->owner = THIS_MODULE;
+	strcpy( dev->name , gemtek_pci_videodev_name );
+	dev->type = VID_TYPE_TUNER;
+	dev->hardware = VID_HARDWARE_GEMTEK;
+	dev->open = gemtek_pci_open;
+	dev->close = gemtek_pci_close;
+	dev->ioctl = gemtek_pci_ioctl;
+}
+
+static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id )
+{
+	struct gemtek_pci_card *card;
+	struct video_device *devradio;
+
+	if ( (card = kmalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: out of memory\n" );
+		return -ENOMEM;
+	}
+	memset( card, 0, sizeof( struct gemtek_pci_card ) );
+
+	if ( pci_enable_device( pci_dev ) ) 
+		goto err_pci;
+	
+	card->iobase = pci_resource_start( pci_dev, 0 );
+	card->length = pci_resource_len( pci_dev, 0 );
+
+	if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: i/o port already in use\n" );
+		goto err_pci;
+	}
+
+	pci_read_config_byte( pci_dev, PCI_REVISION_ID, &card->chiprev );
+	pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
+
+	pci_set_drvdata( pci_dev, card );
+ 
+	if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
+		printk( KERN_ERR "gemtek_pci: out of memory\n" );
+		goto err_video;
+	}
+	gemtek_pci_init_struct( devradio );
+
+	if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) {
+		kfree( devradio );
+		goto err_video;
+	}
+
+	card->videodev = devradio;
+	devradio->priv = card;
+	gemtek_pci_mute( card );
+
+	printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", 
+		card->chiprev, card->iobase, card->iobase + card->length - 1 );
+
+	return 0;
+
+err_video:
+	release_region( card->iobase, card->length );
+
+err_pci:
+	kfree( card );
+	return -ENODEV;        
+}
+
+static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
+{
+	struct gemtek_pci_card *card = pci_get_drvdata( pci_dev );
+
+	video_unregister_device( card->videodev );
+	kfree( card->videodev );
+
+	release_region( card->iobase, card->length );
+	
+	if ( mx )
+		gemtek_pci_mute( card );
+
+	kfree( card );
+	
+	pci_set_drvdata( pci_dev, NULL );
+}
+
+static struct pci_driver gemtek_pci_driver =
+{
+    name:	"gemtek_pci",
+id_table:	gemtek_pci_id,
+   probe:	gemtek_pci_probe,
+  remove:	gemtek_pci_remove
+};
+
+static int __init gemtek_pci_init_module( void )
+{
+	return pci_module_init( &gemtek_pci_driver );
+}
+
+static void __exit gemtek_pci_cleanup_module( void )
+{
+	return pci_unregister_driver( &gemtek_pci_driver );
+}
+
+MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
+MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" );
+MODULE_PARM( mx, "b" );
+MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" );
+MODULE_PARM( nr_radio, "i");
+MODULE_PARM_DESC( nr_radio, "video4linux device number to use");
+
+EXPORT_NO_SYMBOLS;
+
+module_init( gemtek_pci_init_module );
+module_exit( gemtek_pci_cleanup_module );
+
diff -urN linux-2.4.8-pre4/drivers/media/video/adv7175.c linux/drivers/media/video/adv7175.c
--- linux-2.4.8-pre4/drivers/media/video/adv7175.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/adv7175.c	Mon Dec  3 22:58:52 2001
@@ -30,7 +30,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -urN linux-2.4.8-pre4/drivers/media/video/bt819.c linux/drivers/media/video/bt819.c
--- linux-2.4.8-pre4/drivers/media/video/bt819.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/bt819.c	Mon Dec  3 22:58:52 2001
@@ -31,7 +31,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -urN linux-2.4.8-pre4/drivers/media/video/bt848.h linux/drivers/media/video/bt848.h
--- linux-2.4.8-pre4/drivers/media/video/bt848.h	Tue Jul 18 22:35:33 2000
+++ linux/drivers/media/video/bt848.h	Mon Dec  3 22:58:52 2001
@@ -351,5 +351,6 @@
 
 #define BT878_DEVCTRL 0x40
 #define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
 
 #endif
diff -urN linux-2.4.8-pre4/drivers/media/video/bt856.c linux/drivers/media/video/bt856.c
--- linux-2.4.8-pre4/drivers/media/video/bt856.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/bt856.c	Mon Dec  3 22:58:52 2001
@@ -32,7 +32,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -urN linux-2.4.8-pre4/drivers/media/video/bttv-cards.c linux/drivers/media/video/bttv-cards.c
--- linux-2.4.8-pre4/drivers/media/video/bttv-cards.c	Wed Apr 11 19:02:36 2001
+++ linux/drivers/media/video/bttv-cards.c	Mon Dec  3 22:58:52 2001
@@ -46,13 +46,16 @@
 #endif
 
 static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
+static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
 static void avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v,
 				    int set);
 static void terratv_audio(struct bttv *btv, struct video_audio *v, int set);
 static void gvbctv3pci_audio(struct bttv *btv, struct video_audio *v, int set);
+static void winfast2000_audio(struct bttv *btv, struct video_audio *v, int set);
 
 /* config variables */
 static int triton1=0;
+static int vsfx=0;
 int no_overlay=-1;
 static unsigned int card[4]  = { -1, -1, -1, -1 };
 static unsigned int pll[4]   = { -1, -1, -1, -1 };
@@ -111,38 +114,55 @@
 	int cardnr;
 	char *name;
 } cards[] __devinitdata = {
-	{ 0x00011002, BTTV_HAUPPAUGE878,  "ATI TV Wonder" },
-	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00021461, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
-	{ 0x00031002, BTTV_HAUPPAUGE878,  "ATI TV Wonder/VE" },
-	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
-	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
-	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
-	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
-	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TV Value" },
-	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV/Radio+" },
-	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x13eb0070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV" },
-	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
-	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
-	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+	{ 0x45000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV/PVR" },
+	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
+	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
+
+	{ 0x00011002, BTTV_ATI_TVWONDER,  "ATI TV Wonder" },
+	{ 0x00031002, BTTV_ATI_TVWONDERVE,"ATI TV Wonder/VE" },
+
+	{ 0x6606107d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
 	{ 0x263610b4, BTTV_STB2,          "STB TV PCI FM, P/N 6000704" },
+ 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
+	{ 0x405010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV4/PCI" },
+	{ 0x001211bd, BTTV_PINNACLE,      "Pinnacle PCTV" },
 	{ 0x3000121a, 0/* no entry yet */,"VoodooTV 200" },
+
 	{ 0x3000144f, BTTV_MAGICTVIEW063, "TView 99 (CPH063)" },
-	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
 	{ 0x3002144f, BTTV_MAGICTVIEW061, "Askey Magic TView" },
+
+	{ 0x00011461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00021461, BTTV_AVERMEDIA98,   "AVermedia TVCapture 98" },
+	{ 0x00031461, BTTV_AVPHONE98,     "AVerMedia TVPhone98" },
+	{ 0x00041461, BTTV_AVERMEDIA98,   "AVerMedia TVCapture 98" },
+
+	{ 0x300014ff, BTTV_MAGICTVIEW061, "TView 99 (CPH061)" },
 	{ 0x300214ff, BTTV_PHOEBE_TVMAS,  "Phoebe TV Master" },
-	{ 0x39000070, BTTV_HAUPPAUGE878,  "Hauppauge WinTV-D" },
+
+	{ 0x1117153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1118153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1119153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x111a153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1123153b, BTTV_TERRATVRADIO,  "Terratec TV Radio+" },
+	{ 0x1127153b, BTTV_TERRATV,       "Terratec TV+"    },
+	{ 0x1134153b, BTTV_TERRATVALUE,   "Terratec TValue" },
+	{ 0x1135153b, BTTV_TERRATVALUER,  "Terratec TValue Radio" },
+
 	{ 0x400a15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV" },
 	{ 0x400d15b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
 	{ 0x401015b0, BTTV_ZOLTRIX_GENIE, "Zoltrix Genie TV / Radio" },
- 	{ 0x402010fc, BTTV_GVBCTV3PCI,    "I-O Data Co. GV-BCV3/PCI" },
-	{ 0xff000070, BTTV_HAUPPAUGE878,  "Osprey-100" },
-	{ 0xff010070, BTTV_HAUPPAUGE878,  "Osprey-200" },
-#if 0 /* probably wrong */
-	{ 0x14610002, BTTV_AVERMEDIA98,   "Avermedia TVCapture 98" },
-	{ 0x6606217d, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
-#endif
+
+    	{ 0x010115cb, BTTV_GMV1,          "AG GMV1" },
+	{ 0x010114c7, 16 /* FIXME */,     "Modular Technology PCTV" },
+	{ 0x18501851, BTTV_CHRONOS_VS2,   "Chronos Video Shuttle II" },
+	{ 0x18511851, 0 /* FIXME */,      "CyberMail AV" },
+	{ 0x18521852, BTTV_TYPHOON_TVIEW, "Typhoon TView TV/FM Tuner" },
+	{ 0x10b42636, BTTV_HAUPPAUGE878,  "STB ???" },
+	{ 0x217d6606, BTTV_WINFAST2000,   "Leadtek WinFast TV 2000" },
+	{ 0x1200bd11, BTTV_PINNACLE,      "Pinnacle PCTV" },
+
 	{ 0, -1, NULL }
 };
 
@@ -223,13 +243,10 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		3,
-	/* old 
-	gpiomask:	15,
-	audiomux:	{12, 4,11,11, 0},
-	*/
 	muxsel:		{ 2, 3, 1, 1},
 	gpiomask:	0x0f,
-	audiomux:	{ 0x04, 0x04, 0x08, 0x04, 0},
+	audiomux:	{ 0x0c, 0x04, 0x08, 0x04, 0},
+	/*                0x04 for some cards ?? */
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 	audio_hook:	avermedia_tvphone_audio,
@@ -286,9 +303,9 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0x3000f,
+	gpiomask:	0x3014f,
 	muxsel:		{ 2, 3, 1, 1},
-	audiomux:	{ 1,0x10001, 0, 0,10},
+	audiomux:	{ 0x20001,0x10001, 0, 0,10},
 	needs_tvaudio:	1,
 	tuner_type:	-1,
 },{
@@ -490,7 +507,7 @@
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x20000, 0x30000, 0x10000, 0x00000, 0x40000},
 	needs_tvaudio:	1,
-	tuner_type:	-1,
+	tuner_type:	TUNER_PHILIPS_PAL,
 	audio_hook:	terratv_audio,
 },{
 	/* Jannik Fritsch <jannik@techfak.uni-bielefeld.de> */
@@ -556,12 +573,13 @@
 	audio_inputs:	1,
 	tuner:		0,
 	svhs:		2,
-	gpiomask:	0xfff000,
+	gpiomask:	0xc33000,
 	muxsel:		{ 2, 3, 1, 1,0},
-	audiomux:	{ 0x621000,0x6ddf07,0x621100,0x620000,0xE210000,0x620000},
-	needs_tvaudio:	1,
+	audiomux:	{ 0x422000,0x001000,0x621100,0x620000,0x800000,0x620000},
+	needs_tvaudio:	0,
 	pll:		PLL_28,
 	tuner_type:	-1,
+	audio_hook:	winfast2000_audio,
 },{
 	name:		"Chronos Video Shuttle II",
 	video_inputs:	3,
@@ -808,7 +826,7 @@
 		options bttv card=0 pll=1 radio=1 gpiomask=0x18e0
 		audiomux=0x44c71f,0x44d71f,0,0x44d71f,0x44dfff
 		options tuner type=5 */
-	name:		"Livetec 9415 TV",
+	name:		"Lifetec LT 9415 TV",
 	video_inputs:	4,
 	audio_inputs:	1,
 	tuner:		0,
@@ -816,10 +834,15 @@
 	gpiomask:	0x18e0,
 	muxsel:		{ 2, 3, 1, 1},
 	audiomux:	{ 0x0000,0x0800,0x1000,0x1000,0x18e0 },
+		       /* 0x0000: Tuner normal stereo
+			  0x0080: Tuner A2 SAP (second audio program = Zweikanalton)
+			  0x0880: Tuner A2 stereo */
 	pll:		PLL_28,
 	tuner_type:	TUNER_PHILIPS_PAL,
+	audio_hook:	lt9415_audio,
 },{
-	/* Miguel Angel Alvarez <maacruz@navegalia.com> */
+	/* Miguel Angel Alvarez <maacruz@navegalia.com>
+	   old Easy TV BT848 version (model CPH031) */
 	name:           "BESTBUY Easy TV",
 	video_inputs:	4,
 	audio_inputs:   1,
@@ -830,22 +853,22 @@
 	audiomux:       { 2, 0, 0, 0, 10},
 	needs_tvaudio:  0,
 	pll:		PLL_28,
-	tuner_type:	TUNER_TEMIC_PAL_I,
+	tuner_type:	TUNER_TEMIC_PAL,
 },{
 
 /* ---- card 0x38 ---------------------------------- */
-	/* Gordon Heydon <gjheydon@bigfoot.com */
+	/* Gordon Heydon <gjheydon@bigfoot.com ('98) */
 	name:           "FlyVideo '98/FM",
 	video_inputs:   3,
 	audio_inputs:   3,
 	tuner:          0,
 	svhs:           2,
 	gpiomask:       0x1800,
-	muxsel:         { 2, 3, 1, 1},
+	muxsel:         { 2, 3, 0, 1},
 	audiomux:       { 0, 0x800, 0, 0, 0x1800, 0 },
 	needs_tvaudio:  1,
 	pll:            PLL_28,
-	tuner_type:     -1,
+	tuner_type:     5,
 },{
 	/* This is the ultimate cheapo capture card 
 	 * just a BT848A on a small PCB!
@@ -875,6 +898,112 @@
         needs_tvaudio:  1,
         pll:            PLL_NONE,
         tuner_type:     TUNER_TEMIC_4036FY5_NTSC,
+},{
+	/* Matti Mottus <mottus@physic.ut.ee> */
+	name:		"TV Capturer",
+	video_inputs:	4,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+        gpiomask:       0x03000F,
+	muxsel:		{ 2, 3, 1, 0},
+        audiomux:       { 2,0,0,0,1 },
+	pll:            PLL_28,
+	tuner_type:	0,
+},{
+
+/* ---- card 0x3c ---------------------------------- */
+	/* Philip Blundell <philb@gnu.org> */
+	name:           "MM100PCTV",
+	video_inputs:   2,
+	audio_inputs:   2,
+	gpiomask:       11,
+	muxsel:         { 2, 3, 1, 1},
+	audiomux:       { 2, 0, 0, 1, 8},
+	pll:            PLL_NONE,
+	tuner_type:     TUNER_TEMIC_PAL,
+
+},{
+	/* Adrian Cox <adrian@humboldt.co.uk */
+	name:	        "AG Electronics GMV1",
+	video_inputs:   2,
+	audio_inputs:   0,
+	tuner:	        -1,
+	svhs:	        1,
+	gpiomask:       0xF,
+	muxsel:	        { 2, 2},
+	audiomux:       { },
+	no_msp34xx:     1,
+	needs_tvaudio:  0,
+	pll:	        PLL_28,
+	tuner_type:     -1,
+},{
+	/* Miguel Angel Alvarez <maacruz@navegalia.com>
+	   new Easy TV BT878 version (model CPH061) 
+	   special thanks to Informatica Mieres for providing the card */
+	name:           "BESTBUY Easy TV (bt878)",
+	video_inputs:	3,
+	audio_inputs:   2,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:       0xFF,
+	muxsel:         { 2, 3, 1, 0},
+	audiomux:       { 1, 0, 4, 4, 9},
+	needs_tvaudio:  0,
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
+},{
+	/* Lukas Gebauer <geby@volny.cz> */
+	name:		"ATI TV-Wonder",
+	video_inputs:	3,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0xf03f,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0xbffe, 0, 0xbfff, 0, 0xbffe},
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+},{
+
+/* ---- card 0x40 ---------------------------------- */
+	/* Lukas Gebauer <geby@volny.cz> */
+	name:		"ATI TV-Wonder VE",
+	video_inputs:	2,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		-1,
+	gpiomask:	1,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0, 0, 1, 0, 0},
+	no_msp34xx:	1,
+	pll:		PLL_28,
+	tuner_type:	TUNER_TEMIC_4006FN5_MULTI_PAL,
+},{
+	/* DeeJay <deejay@westel900.net (2000S) */
+	name:           "FlyVideo 2000S",
+	video_inputs:   3,
+	audio_inputs:   3,
+	tuner:          0,
+	svhs:           2,
+	gpiomask:	0x18e0,
+	muxsel:		{ 2, 3, 0, 1},
+	audiomux:	{ 0,0x18e0,0x1000,0x1000,0x1080, 0x1080 },
+	needs_tvaudio:  1,
+	pll:            PLL_28,
+	tuner_type:     5,
+},{
+	name:		"Terratec TValueRadio",
+	video_inputs:	3,
+	audio_inputs:	1,
+	tuner:		0,
+	svhs:		2,
+	gpiomask:	0xffff00,
+	muxsel:		{ 2, 3, 1, 1},
+	audiomux:	{ 0x500, 0x500, 0x300, 0x900, 0x900},
+	needs_tvaudio:	1,
+	pll:		PLL_28,
+	tuner_type:	TUNER_PHILIPS_PAL,
 }};
 
 const int bttv_num_tvcards = (sizeof(bttv_tvcards)/sizeof(struct tvcard));
@@ -1031,6 +1160,14 @@
 		btv->mbox_mask    = 0x38;
 	}
 
+	if (btv->type == BTTV_LIFETEC_9415) {
+		if (btread(BT848_GPIO_DATA) & 0x4000)
+			printk("bttv%d: lifetec: tv mono/fm stereo card\n", btv->nr);
+		else
+			printk("bttv%d: lifetec: stereo(TDA9821) card\n",btv->nr);
+		btv->has_radio=1;
+	}
+
 	/* pll configuration */
         if (!(btv->id==848 && btv->revision==0x11)) {
 		/* defaults from card list */
@@ -1149,19 +1286,19 @@
         { TUNER_TEMIC_4066FY5_PAL_I, "Temic 4066FY5" },
         { TUNER_ABSENT,        "Philips TD1536" },
         { TUNER_ABSENT,        "Philips TD1536D" },
-        { TUNER_ABSENT,        "Philips FMR1236" },
+	{ TUNER_PHILIPS_NTSC,  "Philips FMR1236" }, /* mono radio */
         { TUNER_ABSENT,        "Philips FI1256MP" },
         { TUNER_ABSENT,        "Samsung TCPQ9091P" },
         { TUNER_TEMIC_4006FN5_MULTI_PAL, "Temic 4006FN5" },
         { TUNER_TEMIC_4009FR5_PAL, "Temic 4009FR5" },
         { TUNER_TEMIC_4046FM5,     "Temic 4046FM5" },
-	{ TUNER_ABSENT,        "Temic 4009FN5" },
+	{ TUNER_TEMIC_4009FN5_MULTI_PAL_FM, "Temic 4009FN5" },
 	{ TUNER_ABSENT,        "Philips TD1536D_FH_44"},
-	{ TUNER_ABSENT,	       "LG TP18NSR01F"},
-	{ TUNER_ABSENT,        "LG TP18PSB01D"},
-	{ TUNER_ABSENT,        "LG TP18PSB11D"},	
-	{ TUNER_ABSENT,        "LG TAPC_l001D"},
-	{ TUNER_ABSENT,        "LG TAPC_l701D"}
+	{ TUNER_LG_NTSC_FM,    "LG TP18NSR01F"},
+	{ TUNER_LG_PAL_FM,     "LG TP18PSB01D"},
+	{ TUNER_LG_PAL,        "LG TP18PSB11D"},	
+	{ TUNER_LG_PAL_I_FM,   "LG TAPC-I001D"},
+	{ TUNER_LG_PAL_I,      "LG TAPC-I701D"}
 };
 
 static void __devinit hauppauge_eeprom(struct bttv *btv)
@@ -1394,7 +1531,8 @@
 	int bits_out, loops, vol, data;
 
 	if (!set) {
-		v->mode |= VIDEO_AUDIO_VOLUME;
+		/* Fixed by Leandro Lucarella <luca@linuxmendoza.org.ar (07/31/01) */
+		v->flags |= VIDEO_AUDIO_VOLUME;
 		return;
 	}
 	
@@ -1490,6 +1628,37 @@
 	}
 }
 
+/* Lifetec 9415 handling */
+static void
+lt9415_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+        int val = 0;
+
+        if (btread(BT848_GPIO_DATA) & 0x4000) {
+		v->mode = VIDEO_SOUND_MONO;
+		return;
+	}
+
+        if (set) {
+                if (v->mode & VIDEO_SOUND_LANG2)  /* A2 SAP */
+                        val = 0x0080;
+		if (v->mode & VIDEO_SOUND_STEREO) /* A2 stereo */
+                        val = 0x0880;
+                if ((v->mode & VIDEO_SOUND_LANG1) ||
+		    (v->mode & VIDEO_SOUND_MONO))
+			val = 0;
+                btaor(val, ~0x0880, BT848_GPIO_DATA);
+                if (bttv_gpio)
+                        bttv_gpio_tracking(btv,"lt9415");
+        } else {
+		/* autodetect doesn't work with this card :-( */
+                v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+                return;
+        }
+}
+
+
 static void
 terratv_audio(struct bttv *btv, struct video_audio *v, int set)
 {
@@ -1510,6 +1679,31 @@
 	}
 }
 
+static void
+winfast2000_audio(struct bttv *btv, struct video_audio *v, int set)
+{
+	unsigned long val = 0;
+
+	if (set) {
+		/*btor (0xc32000, BT848_GPIO_OUT_EN);*/
+		if (v->mode & VIDEO_SOUND_MONO)		/* Mono */
+			val = 0x420000;
+		if (v->mode & VIDEO_SOUND_LANG1)	/* Mono */
+			val = 0x420000;
+		if (v->mode & VIDEO_SOUND_LANG2)	/* SAP */
+			val = 0x410000;
+		if (v->mode & VIDEO_SOUND_STEREO)	/* Stereo */
+			val = 0x020000;
+		if (val) {
+			btaor(val, ~0x430000, BT848_GPIO_DATA);
+			if (bttv_gpio)
+				bttv_gpio_tracking(btv,"winfast2000");
+		}
+	} else {
+		v->mode = VIDEO_SOUND_MONO | VIDEO_SOUND_STEREO |
+			  VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}
+}
 
 /* ----------------------------------------------------------------------- */
 /* motherboard chipset specific stuff                                      */
@@ -1525,10 +1719,14 @@
 
 	if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
 		triton1 = 1;
+	while ((dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, dev)))
+		vsfx = 1;
 
 	/* print warnings about quirks found */
 	if (triton1)
 		printk(KERN_INFO "bttv: Host bridge needs ETBF enabled.\n");
+	if (vsfx)
+		printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n");
 
 	if (pcipci_fail) {
 		printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n");
@@ -1553,25 +1751,28 @@
 {
  	unsigned char command;
 
-	if (!triton1)
+	if (!triton1 && !vsfx)
 		return 0;
 
-	if (bttv_verbose)
-		printk("bttv%d: enabling 430FX/VP3 compatibilty\n",btv->nr);
+	if (bttv_verbose) {
+		if (triton1)
+			printk("bttv%d: enabling ETBF (430FX/VP3 compatibilty)\n",btv->nr);
+		if (vsfx && btv->id >= 878)
+			printk("bttv%d: enabling VSFX\n",btv->nr);
+	}
 
 	if (btv->id < 878) {
-		/* bt848 (mis)uses a bit in the irq mask */
-		btv->triton1 = BT848_INT_ETBF;
+		/* bt848 (mis)uses a bit in the irq mask for etbf */
+		if (triton1)
+			btv->triton1 = BT848_INT_ETBF;
 	} else {
 		/* bt878 has a bit in the pci config space for it */
                 pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command);
-                command |= BT878_EN_TBFX;
+		if (triton1)
+			command |= BT878_EN_TBFX;
+		if (vsfx)
+			command |= BT878_EN_VSFX;
                 pci_write_config_byte(btv->dev, BT878_DEVCTRL, command);
-                pci_read_config_byte(btv->dev, BT878_DEVCTRL, &command);
-                if (!(command&BT878_EN_TBFX)) {
-                        printk("bttv: 430FX compatibility could not be enabled\n");
-			return -1;
-                }
         }
 	return 0;
 }
diff -urN linux-2.4.8-pre4/drivers/media/video/bttv-driver.c linux/drivers/media/video/bttv-driver.c
--- linux-2.4.8-pre4/drivers/media/video/bttv-driver.c	Mon Jul 16 15:13:32 2001
+++ linux/drivers/media/video/bttv-driver.c	Mon Dec  3 22:58:52 2001
@@ -69,6 +69,7 @@
 static unsigned int gbuffers = 2;
 static unsigned int gbufsize = BTTV_MAX_FBUF;
 static unsigned int combfilter = 0;
+static unsigned int lumafilter = 0;
 static int video_nr = -1;
 static int radio_nr = -1;
 static int vbi_nr = -1;
@@ -96,6 +97,7 @@
 MODULE_PARM(gbufsize,"i");
 MODULE_PARM_DESC(gbufsize,"size of the capture buffers, default is 0x208000");
 MODULE_PARM(combfilter,"i");
+MODULE_PARM(lumafilter,"i");
 
 MODULE_PARM(video_nr,"i");
 MODULE_PARM(radio_nr,"i");
@@ -699,7 +701,7 @@
 		 vadr+=bl;
 		 if((rcmd&(15<<28))==BT848_RISC_WRITE123)
 		 {
-		 	*((*rp)++)=(kvirt_to_bus(cbadr));
+		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cbadr));
 		 	cbadr+=blcb;
 		 	*((*rp)++)=cpu_to_le32(kvirt_to_bus(cradr));
 		 	cradr+=blcr;
@@ -1175,7 +1177,7 @@
 	if(btv->gbuf[mp->frame].stat != GBUFFER_UNUSED)
 		return -EBUSY;
 		
-	if(mp->height < 32 || mp->width < 32)
+	if(mp->height < 32 || mp->width < 48)
 		return -EINVAL;
 	if (mp->format >= PALETTEFMT_MAX)
 		return -EINVAL;
@@ -1391,10 +1393,16 @@
 {
 	struct bttv *btv=(struct bttv *)dev;
  	unsigned long irq_flags;
+	int need_wait;
 
 	down(&btv->lock);
 	btv->user--;
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
+	need_wait = (-1 != btv->gq_grab);
+	btv->gq_start = 0;
+	btv->gq_in = 0;
+	btv->gq_out = 0;
+	btv->gq_grab = -1;
 	btv->scr_on = 0;
 	btv->risc_cap_odd = 0;
 	btv->risc_cap_even = 0;
@@ -1410,7 +1418,7 @@
 
 	btread(BT848_I2C); 	/* This fixes the PCI posting delay */
 	
-	if (-1 != btv->gq_grab) {
+	if (need_wait) {
 		/*
 		 *	This is sucky but right now I can't find a good way to
 		 *	be sure its safe to free the buffer. We wait 5-6 fields
@@ -1504,7 +1512,7 @@
 		b.audios = bttv_tvcards[btv->type].audio_inputs;
 		b.maxwidth = tvnorms[btv->win.norm].swidth;
 		b.maxheight = tvnorms[btv->win.norm].sheight;
-		b.minwidth = 32;
+		b.minwidth = 48;
 		b.minheight = 32;
 		if(copy_to_user(arg,&b,sizeof(b)))
 			return -EFAULT;
@@ -1717,13 +1725,11 @@
 	case VIDIOCGWIN:
 	{
 		struct video_window vw;
-		/* Oh for a COBOL move corresponding .. */
+		memset(&vw,0,sizeof(vw));
 		vw.x=btv->win.x;
 		vw.y=btv->win.y;
 		vw.width=btv->win.width;
 		vw.height=btv->win.height;
-		vw.chromakey=0;
-		vw.flags=0;
 		if(btv->win.interlace)
 			vw.flags|=VIDEO_WINDOW_INTERLACE;
 		if(copy_to_user(arg,&vw,sizeof(vw)))
@@ -2196,6 +2202,10 @@
 	}
 	case VIDIOCGFREQ:
 	case VIDIOCSFREQ:
+	case VIDIOCGTUNER:
+	case VIDIOCSTUNER:
+	case VIDIOCGCHAN:
+	case VIDIOCSCHAN:
 	case BTTV_VERSION:
 		return bttv_ioctl(dev-2,cmd,arg);
 	case BTTV_VBISIZE:
@@ -2290,8 +2300,11 @@
 		if(v.tuner||btv->channel)	/* Only tuner 0 */
 			return -EINVAL;
 		strcpy(v.name, "Radio");
-		v.rangelow=(int)(76*16);	/* jp: 76.0MHz - 89.9MHz  */
-		v.rangehigh=(int)(108*16);	/* eu: 87.5MHz - 108.0MHz */
+		/* japan:          76.0 MHz -  89.9 MHz
+		   western europe: 87.5 MHz - 108.0 MHz
+		   russia:         65.0 MHz - 108.0 MHz */
+		v.rangelow=(int)(65*16);
+		v.rangehigh=(int)(108*16);
 		v.flags= 0; /* XXX */
 		v.mode = 0; /* XXX */
 		bttv_call_i2c_clients(btv,cmd,&v);
@@ -2441,20 +2454,22 @@
 		bt848_dma(btv, 0);
 }
 
+# define do_video_register(dev,type,nr) video_register_device(dev,type,nr)
+
 static int __devinit init_video_dev(struct bttv *btv)
 {
 	audio(btv, AUDIO_MUTE, 1);
         
-	if(video_register_device(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
+	if(do_video_register(&btv->video_dev,VFL_TYPE_GRABBER,video_nr)<0)
 		return -1;
-	if(video_register_device(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
+	if(do_video_register(&btv->vbi_dev,VFL_TYPE_VBI,vbi_nr)<0) 
         {
 	        video_unregister_device(&btv->video_dev);
 		return -1;
 	}
 	if (btv->has_radio)
 	{
-		if(video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
+		if(do_video_register(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr)<0) 
                 {
 		        video_unregister_device(&btv->vbi_dev);
 		        video_unregister_device(&btv->video_dev);
@@ -2491,8 +2506,8 @@
 	btv->win.interlace=1;
 	btv->win.x=0;
 	btv->win.y=0;
-	btv->win.width=768; /* 640 */
-	btv->win.height=576; /* 480 */
+	btv->win.width=320;
+	btv->win.height=240;
 	btv->win.bpp=2;
 	btv->win.depth=16;
 	btv->win.color_fmt=BT848_COLOR_FMT_RGB16;
@@ -2542,9 +2557,6 @@
 
 	btv->fbuffer=NULL;
 
-	bt848_muxsel(btv, 1);
-	bt848_set_winsize(btv);
-
 /*	btwrite(0, BT848_TDEC); */
         btwrite(0x10, BT848_COLOR_CTL);
 	btwrite(0x00, BT848_CAP_CTL);
@@ -2574,8 +2586,13 @@
 	btwrite(/*BT848_ADC_SYNC_T|*/
 		BT848_ADC_RESERVED|BT848_ADC_CRUSH, BT848_ADC);
 
-	btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
-	btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+	if (lumafilter) {
+		btwrite(0, BT848_E_CONTROL);
+		btwrite(0, BT848_O_CONTROL);
+	} else {
+		btwrite(BT848_CONTROL_LDEC, BT848_E_CONTROL);
+		btwrite(BT848_CONTROL_LDEC, BT848_O_CONTROL);
+	}
 
 	btv->picture.colour=254<<7;
 	btv->picture.brightness=128<<8;
@@ -2599,6 +2616,8 @@
 		BT848_INT_FMTCHG|BT848_INT_HLOCK,
 		BT848_INT_MASK);
 
+	bt848_muxsel(btv, 1);
+	bt848_set_winsize(btv);
 	make_vbitab(btv);
 	spin_lock_irqsave(&btv->s_lock, irq_flags);
 	bt848_set_risc_jmps(btv,-1);
@@ -2749,7 +2768,7 @@
 				wake_up_interruptible(&btv->capq);
 				break;
 			}
-			if (stat&(8<<28)) 
+			if (stat&(8<<28) && btv->gq_start) 
 			{
 				spin_lock(&btv->s_lock);
 				btv->gq_start = 0;
diff -urN linux-2.4.8-pre4/drivers/media/video/bttv.h linux/drivers/media/video/bttv.h
--- linux-2.4.8-pre4/drivers/media/video/bttv.h	Wed Apr 11 19:02:36 2001
+++ linux/drivers/media/video/bttv.h	Mon Dec  3 22:58:52 2001
@@ -72,9 +72,15 @@
 #define BTTV_EAGLE         0x33
 #define BTTV_PINNACLEPRO   0x34
 #define BTTV_TVIEW_RDS_FM  0x35
-#define BTTV_LIVETEC_9415  0x36
+#define BTTV_LIFETEC_9415  0x36
 #define BTTV_BESTBUY_EASYTV 0x37
 #define BTTV_FLYVIDEO_98FM 0x38
+#define BTTV_GMV1          0x3d
+#define BTTV_BESTBUY_EASYTV2 0x3e
+#define BTTV_ATI_TVWONDER  0x3f
+#define BTTV_ATI_TVWONDERVE 0x40
+#define BTTV_FLYVIDEO2000   0x41
+#define BTTV_TERRATVALUER   0x42
 
 /* i2c address list */
 #define I2C_TSA5522        0xc2
@@ -190,15 +196,12 @@
 
 /* i2c */
 #define I2C_CLIENTS_MAX 8
-extern struct i2c_algo_bit_data bttv_i2c_algo_template;
-extern struct i2c_adapter bttv_i2c_adap_template;
-extern struct i2c_client bttv_i2c_client_template;
 extern void bttv_bit_setscl(void *data, int state);
 extern void bttv_bit_setsda(void *data, int state);
 extern void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg);
 extern int bttv_I2CRead(struct bttv *btv, unsigned char addr, char *probe_for);
 extern int bttv_I2CWrite(struct bttv *btv, unsigned char addr, unsigned char b1,
-	     unsigned char b2, int both);
+			 unsigned char b2, int both);
 extern void bttv_readee(struct bttv *btv, unsigned char *eedata, int addr);
 
 #endif /* _BTTV_H_ */
diff -urN linux-2.4.8-pre4/drivers/media/video/bttvp.h linux/drivers/media/video/bttvp.h
--- linux-2.4.8-pre4/drivers/media/video/bttvp.h	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/bttvp.h	Mon Dec  3 22:58:52 2001
@@ -25,7 +25,7 @@
 #ifndef _BTTVP_H_
 #define _BTTVP_H_
 
-#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,57)
+#define BTTV_VERSION_CODE KERNEL_VERSION(0,7,72)
 
 
 #include <linux/types.h>
@@ -195,20 +195,8 @@
 };
 #endif
 
-#if defined(__powerpc__) /* big-endian */
-extern __inline__ void io_st_le32(volatile unsigned *addr, unsigned val)
-{
-        __asm__ __volatile__ ("stwbrx %1,0,%2" : \
-                            "=m" (*addr) : "r" (val), "r" (addr));
-      __asm__ __volatile__ ("eieio" : : : "memory");
-}
-
-#define btwrite(dat,adr)  io_st_le32((unsigned *)(btv->bt848_mem+(adr)),(dat))
-#define btread(adr)       ld_le32((unsigned *)(btv->bt848_mem+(adr)))
-#else
 #define btwrite(dat,adr)    writel((dat), (char *) (btv->bt848_mem+(adr)))
 #define btread(adr)         readl(btv->bt848_mem+(adr))
-#endif
 
 #define btand(dat,adr)      btwrite((dat) & btread(adr), adr)
 #define btor(dat,adr)       btwrite((dat) | btread(adr), adr)
diff -urN linux-2.4.8-pre4/drivers/media/video/msp3400.c linux/drivers/media/video/msp3400.c
--- linux-2.4.8-pre4/drivers/media/video/msp3400.c	Tue Mar  6 19:44:35 2001
+++ linux/drivers/media/video/msp3400.c	Mon Dec  3 22:58:52 2001
@@ -57,6 +57,7 @@
 #include <linux/unistd.h>
 
 #include "audiochip.h"
+#include "msp3400.h"
 
 /* Addresses to scan */
 static unsigned short normal_i2c[] = {I2C_CLIENT_END};
@@ -81,6 +82,12 @@
 static int simple  = -1;   /* use short programming (>= msp3410 only) */
 static int dolby   = 0;
 
+#define DFP_COUNT 0x41
+static const int bl_dfp[] = {
+	0x00, 0x01, 0x02, 0x03,  0x06, 0x08, 0x09, 0x0a,
+	0x0b, 0x0d, 0x0e, 0x10
+};
+
 struct msp3400c {
 	int simple;
 	int nicam;
@@ -90,12 +97,15 @@
 	int nicam_on;
 	int acb;
 	int main, second;	/* sound carrier */
-	int scart;              /* input is scart */
+	int scart;              /* input is scart (extern) */
 
 	int muted;
 	int left, right;	/* volume */
 	int bass, treble;
 
+	/* shadow register set */
+	int dfp_regs[DFP_COUNT];
+
 	/* thread */
 	struct task_struct  *thread;
 	wait_queue_head_t    wq;
@@ -525,6 +535,8 @@
 		src = 0x0010 | nicam;
 		break;
 	}
+	if (msp->scart)
+		src |= 0x0200;
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,0x0620);
@@ -534,6 +546,7 @@
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,src);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0009,src);
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000a,src);
+		msp3400c_write(client,I2C_MSP3400C_DFP, 0x000b,src);
 	}
 }
 
@@ -561,6 +574,19 @@
 	}
 }
 
+static void
+msp3400c_restore_dfp(struct i2c_client *client)
+{
+	struct msp3400c *msp = client->data;
+	int i;
+
+	for (i = 0; i < DFP_COUNT; i++) {
+		if (-1 == msp->dfp_regs[i])
+			continue;
+		msp3400c_write(client,I2C_MSP3400C_DFP, i, msp->dfp_regs[i]);
+	}
+}
+
 /* ----------------------------------------------------------------------- */
 
 struct REGISTER_DUMP {
@@ -901,8 +927,9 @@
 			break;
 		}
 
-		/* unmute */
+		/* unmute + restore dfp registers */
 		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_restore_dfp(client);
 
 		if (msp->watch_stereo)
 			mod_timer(&msp->wake_stereo, jiffies+5*HZ);
@@ -1139,10 +1166,11 @@
 			break;
 		}
 		
-		/* unmute */
+		/* unmute + restore dfp registers */
 		msp3400c_setbass(client, msp->bass);
 		msp3400c_settreble(client, msp->treble);
 		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
+		msp3400c_restore_dfp(client);
 
 		if (msp->watch_stereo)
 			mod_timer(&msp->wake_stereo, jiffies+HZ);
@@ -1189,7 +1217,7 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	struct msp3400c *msp;
         struct i2c_client *c;
-	int              rev1,rev2=0,i;
+	int              rev1,rev2,i;
 
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -1212,6 +1240,9 @@
 	msp->right  = 65535;
 	msp->bass   = 32768;
 	msp->treble = 32768;
+	for (i = 0; i < DFP_COUNT; i++)
+		msp->dfp_regs[i] = -1;
+
 	c->data = msp;
 	init_waitqueue_head(&msp->wq);
 
@@ -1331,18 +1362,25 @@
 	switch (cmd) {
 
 	case AUDC_SET_INPUT:
-#if 1
+		/* scart switching
+		     - IN1 is often used for external input
+		     - Hauppauge uses IN2 for the radio */
 		dprintk(KERN_DEBUG "msp34xx: AUDC_SET_INPUT(%d)\n",*sarg);
-		/* hauppauge 44xxx scart switching */
 		msp->scart = 0;
 		switch (*sarg) {
 		case AUDIO_RADIO:
 			msp3400c_set_scart(client,SCART_IN2,0);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+			msp3400c_setstereo(client,msp->stereo);
 			break;
 		case AUDIO_EXTERN:
-			msp->scart   = 1;
+			msp->scart = 1;
 			msp3400c_set_scart(client,SCART_IN1,0);
-			msp3400c_write(client,I2C_MSP3400C_DFP,0x0008,0x0220);
+			msp3400c_write(client,I2C_MSP3400C_DFP,0x000d,0x1900);
+			msp3400c_setstereo(client,msp->stereo);
+			break;
+		case AUDIO_TUNER:
+			msp3400c_setstereo(client,msp->stereo);
 			break;
 		default:
 			if (*sarg & AUDIO_MUTE)
@@ -1351,7 +1389,6 @@
 		}
 		if (msp->active)
 			msp->restart = 1;
-#endif
 		break;
 
 	case AUDC_SET_RADIO:
@@ -1373,6 +1410,33 @@
 			msp->restart = 1;
 		break;
 
+#if 1
+	/* work-in-progress:  hook to control the DFP registers */
+	case MSP_SET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+		int i;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		for (i = 0; i < sizeof(bl_dfp)/sizeof(int); i++)
+			if (r->reg == bl_dfp[i])
+				return -EINVAL;
+		msp->dfp_regs[r->reg] = r->value;
+		msp3400c_write(client,I2C_MSP3400C_DFP,r->reg,r->value);
+		return 0;
+	}
+	case MSP_GET_DFPREG:
+	{
+		struct msp_dfpreg *r = arg;
+
+		if (r->reg < 0 || r->reg >= DFP_COUNT)
+			return -EINVAL;
+		r->value = msp3400c_read(client,I2C_MSP3400C_DFP,r->reg);
+		return 0;
+	}
+#endif
+
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
 	   kernel pointer here... */
@@ -1443,82 +1507,9 @@
 		break;
 	}
 
-	/* --- v4l2 ioctls --- */
-	/* NOT YET */
-
-#if 0
-	/* --- old, obsolete interface --- */
-	case AUDC_SET_TVNORM:
-		msp->norm = *iarg;
-		break;
-	case AUDC_SWITCH_MUTE:
-		/* channels switching step one -- mute */
-		msp->watch_stereo=0;
-		del_timer(&msp->wake_stereo);
-		msp3400c_setvolume(client,0,0);
-		break;
-	case AUDC_NEWCHANNEL:
-		/* channels switching step two -- trigger sound carrier scan */
-		msp->watch_stereo=0;
-		del_timer(&msp->wake_stereo);
-		if (msp->active)
-			msp->restart = 1;
-		wake_up_interruptible(&msp->wq);
-		break;
-
-	case AUDC_GET_VOLUME_LEFT:
-		*sarg = msp->left;
-		break;
-	case AUDC_GET_VOLUME_RIGHT:
-		*sarg = msp->right;
-		break;
-	case AUDC_SET_VOLUME_LEFT:
-		msp->left = *sarg;
-		msp3400c_setvolume(client,msp->left, msp->right);
-		break;
-	case AUDC_SET_VOLUME_RIGHT:
-		msp->right = *sarg;
-		msp3400c_setvolume(client,msp->left, msp->right);
-		break;
-
-	case AUDC_GET_BASS:
-		*sarg = msp->bass;
-		break;
-	case AUDC_SET_BASS:
-		msp->bass = *sarg;
-		msp3400c_setbass(client,msp->bass);
-		break;
-
-	case AUDC_GET_TREBLE:
-		*sarg = msp->treble;
-		break;
-	case AUDC_SET_TREBLE:
-		msp->treble = *sarg;
-		msp3400c_settreble(client,msp->treble);
-		break;
-
-	case AUDC_GET_STEREO:	
-	        autodetect_stereo(client);
-	        *sarg = msp->stereo;		
-		break;
-	case AUDC_SET_STEREO:
-		if (*sarg) {
-			msp->watch_stereo=0;
-			del_timer(&msp->wake_stereo);
-			msp->stereo = *sarg;
-			msp3400c_setstereo(client,*sarg);
-		}
-		break;
-
-	case AUDC_GET_DC:
-		if (msp->simple)
-			break; /* fixme */
-		*sarg = ((int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1b) +
-			 (int)msp3400c_read(client, I2C_MSP3400C_DFP, 0x1c));
-		break;
-#endif
-	default:;
+	default:
 		/* nothing */
+		break;
 	}
 	return 0;
 }
diff -urN linux-2.4.8-pre4/drivers/media/video/msp3400.h linux/drivers/media/video/msp3400.h
--- linux-2.4.8-pre4/drivers/media/video/msp3400.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/media/video/msp3400.h	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,14 @@
+#ifndef MSP3400_H
+#define MSP3400_H
+
+/* ---------------------------------------------------------------------- */
+
+struct msp_dfpreg {
+    int reg;
+    int value;
+};
+
+#define MSP_SET_DFPREG     _IOW('m',15,struct msp_dfpreg)
+#define MSP_GET_DFPREG     _IOW('m',16,struct msp_dfpreg)
+
+#endif /* MSP3400_H */
diff -urN linux-2.4.8-pre4/drivers/media/video/tda7432.c linux/drivers/media/video/tda7432.c
--- linux-2.4.8-pre4/drivers/media/video/tda7432.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/media/video/tda7432.c	Mon Dec  3 22:58:52 2001
@@ -5,6 +5,8 @@
  * This driver will not complain if used with any 
  * other i2c device with the same address.
  *
+ * Muting and tone control by Jonathan Isom <jisom@ematic.com>
+ *
  * Copyright (c) 2000 Eric Sandeen <eric_sandeen@bigfoot.com>
  * This code is placed under the terms of the GNU General Public License
  * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
@@ -16,18 +18,21 @@
  *
  * loudness - set between 0 and 15 for varying degrees of loudness effect
  *
- * TODO:
- *  Implement tone controls
  *
+ *
+ *  Revision: 0.6 - added tone controls
+ *  Revision: 0.5 - Fixed odd balance problem
+ *  Revision: 0.4 - added muting
  *  Revision: 0.3 - Fixed silly reversed volume controls.  :)
  *  Revision: 0.2 - Cleaned up #defines
  *			fixed volume control
- *                  Added I2C_DRIVERID_TDA7432
+ *          Added I2C_DRIVERID_TDA7432
  *			added loudness insmod control
  *  Revision: 0.1 - initial version
  */
 
 #include <linux/module.h>
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -75,7 +80,7 @@
 	int addr;
 	int input;
 	int volume;
-	int tone;
+	int bass, treble;
 	int lf, lr, rf, rr;
 	int loud;
 	struct i2c_client c;
@@ -121,7 +126,7 @@
 /* Bits 0,1,2 control input:
  * 0x00 - Stereo input
  * 0x02 - Mono input
- * 0x03 - Mute
+ * 0x03 - Mute  (Using Attenuators Plays better with modules)
  * Mono probably isn't used - I'm guessing only the stereo
  * input is connected on most cards, so we'll set it to stereo.
  * 
@@ -133,7 +138,6 @@
  
 #define TDA7432_STEREO_IN	0
 #define TDA7432_MONO_IN		2	/* Probably won't be used */
-#define TDA7432_MUTE		3	/* Probably won't be used */
 #define TDA7432_BASS_SYM	1 << 3
 #define TDA7432_BASS_NORM	1 << 4
 
@@ -178,7 +182,7 @@
 #define TDA7432_TREBLE_0DB		0xf 
 #define TDA7432_TREBLE			7
 #define TDA7432_TREBLE_GAIN		1 << 3
-#define TDA7432_BASS_0DB		0xf << 4
+#define TDA7432_BASS_0DB		0xf
 #define TDA7432_BASS			7 << 4
 #define TDA7432_BASS_GAIN		1 << 7
 
@@ -200,6 +204,7 @@
  */
 
 #define TDA7432_ATTEN_0DB	0x00
+#define TDA7432_MUTE        0x1 << 5
 
 
 /* Subaddress 0x07 - Loudness Control */
@@ -257,18 +262,19 @@
 	d2printk("tda7432: In tda7432_set\n");
 	
 	dprintk(KERN_INFO 
-		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-		t->input,t->volume,t->tone,t->lf,t->lr,t->rf,t->rr,t->loud);
+		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
+		t->input,t->volume,t->bass,t->treble,t->lf,t->lr,t->rf,t->rr,t->loud);
 	buf[0]  = TDA7432_IN;
 	buf[1]  = t->input;
 	buf[2]  = t->volume;
-	buf[3]  = t->tone;
-	buf[4]  = t->lf;
-	buf[5]  = t->lr;
-	buf[6]  = t->rf;
-	buf[7]  = t->rr;
-	buf[8]  = t->loud;
-	if (9 != i2c_master_send(client,buf,9)) {
+	buf[3]  = t->bass;
+	buf[4]	= t->treble;
+	buf[5]  = t->lf;
+	buf[6]  = t->lr;
+	buf[7]  = t->rf;
+	buf[8]  = t->rr;
+	buf[9]  = t->loud;
+	if (10 != i2c_master_send(client,buf,10)) {
 		printk(KERN_WARNING "tda7432: I/O error, trying tda7432_set\n");
 		return -1;
 	}
@@ -287,8 +293,8 @@
 	t->volume = TDA7432_VOL_0DB;	 /* 0dB Volume            */
 	if (loudness)			 /* Turn loudness on?     */
 		t->volume |= TDA7432_LD_ON;	
-	t->tone   = TDA7432_TREBLE_0DB | /* 0dB Treble            */
-		    TDA7432_BASS_0DB; 	 /* 0dB Bass              */
+	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
+	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
 	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
 	t->lr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
 	t->rf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
@@ -353,9 +359,6 @@
 {
 	struct tda7432 *t = client->data;
 	d2printk("tda7432: In tda7432_command\n");
-#if 0
-	__u16 *sarg = arg;
-#endif
 
 	switch (cmd) {
 	/* --- v4l ioctls --- */
@@ -371,7 +374,7 @@
 		va->flags |= VIDEO_AUDIO_VOLUME |
 			VIDEO_AUDIO_BASS |
 			VIDEO_AUDIO_TREBLE;
-
+		va->mode |= VIDEO_SOUND_STEREO;
 		/* Master volume control
 		 * V4L volume is min 0, max 65535
 		 * TDA7432 Volume: 
@@ -389,18 +392,24 @@
 		 * attenuation exists for lf, lr, rf, rr
 		 * we use only lf and rf (front channels)
 		 */
-		 
+		
 		if ( (t->lf) < (t->rf) )
 			/* right is attenuated, balance shifted left */
 			va->balance = (32768 - 1057*(t->rf));
 		else
 			/* left is attenuated, balance shifted right */
 			va->balance = (32768 + 1057*(t->lf));
-
-		/* Bass/treble */
-		va->bass = 32768;   /* brain hurts... set to middle for now */
-		va->treble = 32768; /* brain hurts... set to middle for now */
 		
+		/* Bass/treble */	
+		va->bass=t->bass;
+		if(va->bass >= 0x8)
+				va->bass = ~(va->bass - 0x8) & 0xf;
+		va->bass = va->bass << 12;
+		va->treble=t->treble;
+		if(va->treble >= 0x8)
+				va->treble = ~(va->treble - 0x8) & 0xf;
+		va->treble = va->treble << 12;
+								
 		break; /* VIDIOCGAUDIO case */
 	}
 
@@ -415,26 +424,65 @@
 		if (loudness)		/* Turn on the loudness bit */
 			t->volume |= TDA7432_LD_ON;
 		
-		if (va->balance < 32768) {
+		if(va->flags & VIDEO_AUDIO_BASS)
+		{
+			t->bass = va->bass >> 12;
+			if(t->bass>= 0x8)
+					t->bass = (~t->bass & 0xf) + 0x8 ;
+			t->bass = t->bass | 0x10;
+		}
+		if(va->flags & VIDEO_AUDIO_TREBLE)
+		{
+			t->treble= va->treble >> 12;
+			if(t->treble>= 0x8)
+					t->treble = (~t->treble & 0xf) + 0x8 ;
+						
+		}
+		
+		if (va->balance < 32768) 
+		{
 			/* shifted to left, attenuate right */
 			t->rr = (32768 - va->balance)/1057;
 			t->rf = t->rr;
+			t->lr = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;	
 		}
-		else {
+		else if(va->balance > 32769)
+		{
 			/* shifted to right, attenuate left */
 			t->lf = (va->balance - 32768)/1057;
 			t->lr = t->lf;
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;		
 		}
-		
-		/* t->tone = 0xff; */ /* Brain hurts - no tone control for now... */
-
+		else 
+		{
+			/* centered */		
+			t->rr = TDA7432_ATTEN_0DB;
+			t->rf = TDA7432_ATTEN_0DB;
+			t->lf = TDA7432_ATTEN_0DB;
+			t->lr = TDA7432_ATTEN_0DB;
+		}
+					
+		tda7432_write(client,TDA7432_TN, (t->bass << 4)| t->treble );		
 		tda7432_write(client,TDA7432_VL, t->volume);
-		/* tda7432_write(client,TDA7432_TN, t->tone); */
-		tda7432_write(client,TDA7432_LF, t->lf);
-		tda7432_write(client,TDA7432_LR, t->lr);
-		tda7432_write(client,TDA7432_RF, t->rf);
-		tda7432_write(client,TDA7432_RR, t->rr);
-
+		
+		if (va->flags & VIDEO_AUDIO_MUTE)
+		{
+			/* Mute & update balance*/	
+			tda7432_write(client,TDA7432_LF, t->lf | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_LR, t->lr | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_RF, t->rf | TDA7432_MUTE);
+			tda7432_write(client,TDA7432_RR, t->rr | TDA7432_MUTE);
+		}
+		else
+		{	
+			tda7432_write(client,TDA7432_LF, t->lf);
+			tda7432_write(client,TDA7432_LR, t->lr);
+			tda7432_write(client,TDA7432_RF, t->rf);
+			tda7432_write(client,TDA7432_RR, t->rr);
+		}
+							
 		break;
 
 	} /* end of VIDEOCSAUDIO case */
@@ -469,11 +517,7 @@
         &driver
 };
 
-#ifdef MODULE
-int init_module(void)
-#else
 int tda7432_init(void)
-#endif
 {
 
 	if ( (loudness < 0) || (loudness > 15) )
@@ -482,17 +526,17 @@
 		return -EINVAL;
 	}
 
-
 	i2c_add_driver(&driver);
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+void tda7432_fini(void)
 {
 	i2c_del_driver(&driver);
 }
-#endif
+
+module_init(tda7432_init);
+module_exit(tda7432_fini);
 
 /*
  * Local variables:
diff -urN linux-2.4.8-pre4/drivers/media/video/tuner.c linux/drivers/media/video/tuner.c
--- linux-2.4.8-pre4/drivers/media/video/tuner.c	Tue Jun 12 11:06:54 2001
+++ linux/drivers/media/video/tuner.c	Mon Dec  3 22:58:52 2001
@@ -36,12 +36,16 @@
 static int addr  =  0;
 static char *pal =  "b";
 static int this_adap;
+static int tv_range[2]    = { 44, 958 };
+static int radio_range[2] = { 65, 108 };
 
 #define dprintk     if (debug) printk
 
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
+MODULE_PARM(tv_range,"2i");
+MODULE_PARM(radio_range,"2i");
 MODULE_PARM(pal,"s");
 
 struct tuner
@@ -173,7 +177,20 @@
 	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
 
 	{ "Philips PAL/SECAM multi (FQ1216ME)", Philips, PAL,
-	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623}
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I+FM (TAPC-I001D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_I (TAPC-I701D)", LGINNOTEK, PAL_I,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG NTSC+FM (TPI8NSR01F)", LGINNOTEK, NTSC,
+	  16*210.00,16*497.00,0xa0,0x90,0x30,0x8e,732},
+
+	{ "LG PAL_BG+FM (TPI8PSB01D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "LG PAL_BG (TPI8PSB11D)", LGINNOTEK, PAL,
+	  16*170.00,16*450.00,0xa0,0x90,0x30,0x8e,623},
+	{ "Temic PAL* auto + FM (4009 FN5)", TEMIC, PAL,
+	  16*141.00, 16*464.00, 0xa0,0x90,0x30,0x8e,623}
 };
 #define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
 
@@ -234,13 +251,13 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (freq < 45*16 || freq > 890*16) {
+	if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
 		/* FIXME: better do that chip-specific, but
 		   right now we don't have that in the config
 		   struct and this way is still better than no
 		   check at all */
-		printk("tuner: TV freq out of range\n");
-		return;
+		printk("tuner: TV freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
 	}
 
 	if (t->type == -1) {
@@ -357,8 +374,10 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (freq < 76*16 || freq > 108*16) {
-		printk("tuner: radio freq out of range\n");
+	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
+		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
+		       freq/16,freq%16*100/16,
+		       radio_range[0],radio_range[1]);
 		return;
 	}
 	if (t->type == -1) {
@@ -410,7 +429,7 @@
         client_template.adapter = adap;
         client_template.addr = addr;
 
-        printk("tuner: chip found @ 0x%x\n",addr);
+        printk("tuner: chip found @ 0x%x\n", addr<<1);
 
         if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
                 return -ENOMEM;
diff -urN linux-2.4.8-pre4/drivers/media/video/tuner.h linux/drivers/media/video/tuner.h
--- linux-2.4.8-pre4/drivers/media/video/tuner.h	Mon Feb 19 14:43:36 2001
+++ linux/drivers/media/video/tuner.h	Mon Dec  3 22:58:52 2001
@@ -47,10 +47,16 @@
 #define TUNER_TEMIC_4046FM5             22  /* you must actively select B/G, D/K, I, L, L` !  */
 #define TUNER_PHILIPS_PAL_DK		23
 #define TUNER_PHILIPS_FQ1216ME		24  /* you must actively select B/G/D/K, I, L, L` */
+#define TUNER_LG_PAL_I_FM	25
+#define TUNER_LG_PAL_I		26
+#define TUNER_LG_NTSC_FM	27
+#define TUNER_LG_PAL_FM		28
+#define TUNER_LG_PAL		29
+#define TUNER_TEMIC_4009FN5_MULTI_PAL_FM	30  /* B/G, I and D/K autodetected */
 
 
 #define NOTUNER 0
-#define PAL     1
+#define PAL     1	/* PAL_BG */
 #define PAL_I   2
 #define NTSC    3
 #define SECAM   4
@@ -60,6 +66,7 @@
 #define TEMIC   2
 #define Sony    3
 #define Alps    4
+#define LGINNOTEK 5
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
diff -urN linux-2.4.8-pre4/drivers/media/video/tvaudio.c linux/drivers/media/video/tvaudio.c
--- linux-2.4.8-pre4/drivers/media/video/tvaudio.c	Tue May  1 16:05:00 2001
+++ linux/drivers/media/video/tvaudio.c	Mon Dec  3 22:58:52 2001
@@ -98,6 +98,7 @@
 	int  inputreg;
 	int  inputmap[8];
 	int  inputmute;
+	int  inputmask;
 };
 static struct CHIPDESC chiplist[];
 
@@ -113,7 +114,7 @@
 
 	/* current settings */
 	__u16 left,right,treble,bass,mode;
-
+	int prevmode;
 	/* thread */
 	struct task_struct  *thread;
 	struct semaphore    *notify;
@@ -124,7 +125,7 @@
 
 
 /* ---------------------------------------------------------------------- */
-/* i2c addresses                                                           */
+/* i2c addresses                                                          */
 
 static unsigned short normal_i2c[] = {
 	I2C_TDA8425   >> 1,
@@ -182,6 +183,18 @@
 	return 0;
 }
 
+static int chip_write_masked(struct CHIPSTATE *chip, int subaddr, int val, int mask)
+{
+	if (mask != 0) {
+		if (-1 == subaddr) {
+			val = (chip->shadow.bytes[1] & ~mask) | (val & mask);
+		} else {
+			val = (chip->shadow.bytes[subaddr+1] & ~mask) | (val & mask);
+		}
+	}
+	return chip_write(chip, subaddr, val);
+}
+
 static int chip_read(struct CHIPSTATE *chip)
 {
 	unsigned char buffer;
@@ -283,7 +296,6 @@
 			continue;
 		
 		/* have a look what's going on */
-		dprintk("%s: thread checkmode\n", chip->c.name);
 		desc->checkmode(chip);
 		
 		/* schedule next check */
@@ -303,10 +315,16 @@
 	struct CHIPDESC  *desc = chiplist + chip->type;
 	int mode = desc->getmode(chip);
 
-	if (mode & VIDEO_SOUND_STEREO)
-		desc->setmode(chip,VIDEO_SOUND_STEREO);
-	else if (mode & VIDEO_SOUND_LANG1)
+	if (mode == chip->prevmode)
+	    return;
+
+	dprintk("%s: thread checkmode\n", chip->c.name);
+	chip->prevmode = mode;
+
+	if (mode & VIDEO_SOUND_LANG1)
 		desc->setmode(chip,VIDEO_SOUND_LANG1);
+	else if (mode & VIDEO_SOUND_STEREO)
+		desc->setmode(chip,VIDEO_SOUND_STEREO);
 	else
 		desc->setmode(chip,VIDEO_SOUND_MONO);
 }
@@ -331,6 +349,9 @@
 #define TDA9840_ST_STEREO  0x40 /* Stereo sound identified        */
 #define TDA9840_PONRES     0x80 /* Power-on reset detected if = 1 */
 
+#define TDA9840_TEST_INT1SN 0x1 /* Integration time 0.5s when set */
+#define TDA9840_TEST_INTFU 0x02 /* Disables integrator function */
+
 int  tda9840_getmode(struct CHIPSTATE *chip)
 {
 	int val, mode;
@@ -528,6 +549,7 @@
  *  1,  0  external stereo
  *  0,  1  external mono
  */
+#define TDA9873_INP_MASK    3
 #define TDA9873_INTERNAL    0
 #define TDA9873_EXT_STEREO  2
 #define TDA9873_EXT_MONO    1
@@ -543,6 +565,7 @@
  *  0, 1, 1   Dual BA
  */
 
+#define TDA9873_TR_MASK     (7 << 2)
 #define TDA9873_TR_MONO     4
 #define TDA9873_TR_STEREO   1 << 4
 #define TDA9873_TR_REVERSE  (1 << 3) & (1 << 2)
@@ -643,10 +666,10 @@
 
 void tda9873_setmode(struct CHIPSTATE *chip, int mode)
 {
-	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & 0xe3;
+	int sw_data  = chip->shadow.bytes[TDA9873_SW+1] & ~ TDA9873_TR_MASK;
 	/*	int adj_data = chip->shadow.bytes[TDA9873_AD+1] ; */
 
-	if (sw_data & 3) {
+	if ((sw_data & TDA9873_INP_MASK) != TDA9873_INTERNAL) {
 		dprintk("tda9873_setmode(): external input\n");
 		return;
 	}
@@ -667,9 +690,13 @@
 	case VIDEO_SOUND_LANG2:
 		sw_data |= TDA9873_TR_DUALB;
 		break;
+	default:
+		chip->mode = 0;
+		return;
 	}
-	dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n", mode, sw_data);
-	chip_write(chip,TDA9873_SW,sw_data);
+
+	dprintk("tda9873_setmode(): req. mode %d; chip_write: %d\n",
+		mode, sw_data);
 }
 
 int tda9873_checkit(struct CHIPSTATE *chip)
@@ -777,7 +804,8 @@
 		setmode:    tda9840_setmode,
 		checkmode:  generic_checkmode,
 
-		init:       { 2, { TDA9840_SW, 0x2a } }
+	        init:       { 2, { TDA9840_TEST, TDA9840_TEST_INT1SN
+				/* ,TDA9840_SW, TDA9840_MONO */} }
 	},
 	{
 		name:       "tda9873h",
@@ -795,8 +823,9 @@
 
 		init:       { 4, { TDA9873_SW, 0xa4, 0x06, 0x03 } },
 		inputreg:   TDA9873_SW,
-		inputmute:  0xc0,
-		inputmap:   {0xa4, 0xa2, 0xa4, 0xa4, 0xc0}
+		inputmute:  TDA9873_MUTE | TDA9873_AUTOMUTE,
+		inputmap:   {0xa0, 0xa2, 0xa0, 0xa0, 0xc0},
+		inputmask:  TDA9873_INP_MASK | TDA9873_MUTE | TDA9873_AUTOMUTE
 		
 	},
 	{
@@ -932,7 +961,7 @@
 	chip->c.data = chip;
 
 	/* find description for the chip */
-	dprintk("tvaudio: chip @ addr=0x%x\n",addr<<1);
+	dprintk("tvaudio: chip @ addr=0x%x\n", addr<<1);
 	for (desc = chiplist; desc->name != NULL; desc++) {
 		if (0 == *(desc->insmodopt))
 			continue;
@@ -956,7 +985,7 @@
 	strcpy(chip->c.name,desc->name);
 	chip->type = desc-chiplist;
 	chip->shadow.count = desc->registers+1;
-
+        chip->prevmode = -1;
 	/* register */
 	MOD_INC_USE_COUNT;
 	i2c_attach_client(&chip->c);
@@ -1002,6 +1031,7 @@
 {
 	struct CHIPSTATE *chip = client->data;
 
+	del_timer(&chip->wt);
 	if (NULL != chip->thread) {
 		/* shutdown async thread */
 		DECLARE_MUTEX_LOCKED(sem);
@@ -1034,9 +1064,9 @@
 	case AUDC_SET_INPUT:
 		if (desc->flags & CHIP_HAS_INPUTSEL) {
 			if (*sarg & 0x80)
-				chip_write(chip,desc->inputreg,desc->inputmute);
+				chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
 			else
-				chip_write(chip,desc->inputreg,desc->inputmap[*sarg]);
+				chip_write_masked(chip,desc->inputreg,desc->inputmap[*sarg],desc->inputmask);
 		}
 		break;
 	/* --- v4l ioctls --- */
@@ -1090,9 +1120,11 @@
 	}
 	case VIDIOCSFREQ:
 	{
-		chip->mode = 0; /* automatic */
+	    	chip->mode = 0; /* automatic */
 		if (desc->checkmode) {
 			desc->setmode(chip,VIDEO_SOUND_MONO);
+		    	if (chip->prevmode != VIDEO_SOUND_MONO)
+		    		chip->prevmode = -1; /* reset previous mode */
 			mod_timer(&chip->wt, jiffies+2*HZ);
 			/* the thread will call checkmode() later */
 		}
diff -urN linux-2.4.8-pre4/drivers/net/arlan.c linux/drivers/net/arlan.c
--- linux-2.4.8-pre4/drivers/net/arlan.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/net/arlan.c	Mon Dec  3 22:58:52 2001
@@ -1435,7 +1435,7 @@
 	ARLAN_DEBUG_EXIT("arlan_queue_retransmit");
 };
 
-extern inline void RetryOrFail(struct net_device *dev)
+static inline void RetryOrFail(struct net_device *dev)
 {
 	struct arlan_private *priv = ((struct arlan_private *) dev->priv);
 
diff -urN linux-2.4.8-pre4/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- linux-2.4.8-pre4/drivers/net/hamradio/scc.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/net/hamradio/scc.c	Mon Dec  3 22:58:52 2001
@@ -1775,8 +1775,8 @@
 					Ivec[hwcfg.irq].used = 1;
 			}
 
-			if (hwcfg.vector_latch) {
-				if (!request_region(Vector_Latch, 1, "scc vector latch"))
+			if (hwcfg.vector_latch && !Vector_Latch) {
+				if (!request_region(hwcfg.vector_latch, 1, "scc vector latch"))
 					printk(KERN_WARNING "z8530drv: warning, cannot reserve vector latch port 0x%lx\n, disabled.", hwcfg.vector_latch);
 				else
 					Vector_Latch = hwcfg.vector_latch;
diff -urN linux-2.4.8-pre4/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- linux-2.4.8-pre4/drivers/net/irda/ali-ircc.c	Wed Jul  4 11:50:38 2001
+++ linux/drivers/net/irda/ali-ircc.c	Mon Dec  3 22:58:52 2001
@@ -27,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/serial_reg.h>
@@ -331,8 +331,8 @@
 	self->tx_buff.head = (__u8 *) kmalloc(self->tx_buff.truesize, 
 					      GFP_KERNEL|GFP_DMA); 
 	if (self->tx_buff.head == NULL) {
-		kfree(self);
 		kfree(self->rx_buff.head);
+		kfree(self);
 		return -ENOMEM;
 	}
 	memset(self->tx_buff.head, 0, self->tx_buff.truesize);
diff -urN linux-2.4.8-pre4/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux-2.4.8-pre4/drivers/net/irda/irda-usb.c	Tue May  1 16:05:00 2001
+++ linux/drivers/net/irda/irda-usb.c	Mon Dec  3 22:58:52 2001
@@ -33,7 +33,7 @@
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/rtnetlink.h>
 #include <linux/usb.h>
 
diff -urN linux-2.4.8-pre4/drivers/net/ne2.c linux/drivers/net/ne2.c
--- linux-2.4.8-pre4/drivers/net/ne2.c	Wed Jun 20 11:10:53 2001
+++ linux/drivers/net/ne2.c	Mon Dec  3 22:58:52 2001
@@ -118,9 +118,9 @@
 static int irqs[4] __initdata = {3, 4, 5, 9};
 
 /* From the D-Link ADF file: */
-static unsigned int dlink_addresses[4]=
+static unsigned int dlink_addresses[4] __initdata =
                 {0x300, 0x320, 0x340, 0x360};
-static int dlink_irqs[8] = {3, 4, 5, 9, 10, 11, 14, 15};
+static int dlink_irqs[8] __initdata = {3, 4, 5, 9, 10, 11, 14, 15};
 
 struct ne2_adapters_t {
 	unsigned int	id;
@@ -165,7 +165,7 @@
  *
  */
 
-static void dlink_put_eeprom(unsigned char value, unsigned int addr)
+static void __init dlink_put_eeprom(unsigned char value, unsigned int addr)
 {
 	int z;
 	unsigned char v1, v2;
@@ -186,7 +186,7 @@
 	}
 }
 
-static void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
+static void __init dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
 {
 	/* shift data bit into correct position */
 
@@ -200,7 +200,7 @@
 	dlink_put_eeprom(0x09 | bit, addr);
 }
 
-static void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr)
+static void __init dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigned int addr)
 {
 	int z;
 
@@ -216,7 +216,7 @@
 	}
 }
 
-static unsigned int dlink_get_eeprom(unsigned int eeaddr, unsigned int addr)
+static unsigned int __init dlink_get_eeprom(unsigned int eeaddr, unsigned int addr)
 {
 	int z;
 	unsigned int value = 0;
diff -urN linux-2.4.8-pre4/drivers/net/pcmcia/3c574_cs.c linux/drivers/net/pcmcia/3c574_cs.c
--- linux-2.4.8-pre4/drivers/net/pcmcia/3c574_cs.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/net/pcmcia/3c574_cs.c	Mon Dec  3 22:58:52 2001
@@ -233,7 +233,7 @@
 static int mdio_read(ioaddr_t ioaddr, int phy_id, int location);
 static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value);
 static u_short read_eeprom(ioaddr_t ioaddr, int index);
-static void wait_for_completion(struct net_device *dev, int cmd);
+static void tc574_wait_for_completion(struct net_device *dev, int cmd);
 
 static void tc574_reset(struct net_device *dev);
 static void media_check(u_long arg);
@@ -515,8 +515,8 @@
 		outw(0x8040, ioaddr + Wn3_Options);
 		mdelay(1);
 		outw(0xc040, ioaddr + Wn3_Options);
-		wait_for_completion(dev, TxReset);
-		wait_for_completion(dev, RxReset);
+		tc574_wait_for_completion(dev, TxReset);
+		tc574_wait_for_completion(dev, RxReset);
 		mdelay(1);
 		outw(0x8040, ioaddr + Wn3_Options);
 		
@@ -656,7 +656,7 @@
 /*
   Use this for commands that may take time to finish
 */
-static void wait_for_completion(struct net_device *dev, int cmd)
+static void tc574_wait_for_completion(struct net_device *dev, int cmd)
 {
     int i = 1500;
     outw(cmd, dev->base_addr + EL3_CMD);
@@ -764,7 +764,7 @@
 	struct el3_private *lp = (struct el3_private *)dev->priv;
 	int i, ioaddr = dev->base_addr;
 
-	wait_for_completion(dev, TotalReset|0x10);
+	tc574_wait_for_completion(dev, TotalReset|0x10);
 
 	/* Clear any transactions in progress. */
 	outw(0, ioaddr + RunnerWrCtrl);
@@ -787,8 +787,8 @@
 	outw(0x8040, ioaddr + Wn3_Options);
 	mdelay(1);
 	outw(0xc040, ioaddr + Wn3_Options);
-	wait_for_completion(dev, TxReset);
-	wait_for_completion(dev, RxReset);
+	tc574_wait_for_completion(dev, TxReset);
+	tc574_wait_for_completion(dev, RxReset);
 	mdelay(1);
 	outw(0x8040, ioaddr + Wn3_Options);
 
@@ -859,7 +859,7 @@
 	lp->stats.tx_errors++;
 	dev->trans_start = jiffies;
 	/* Issue TX_RESET and TX_START commands. */
-	wait_for_completion(dev, TxReset);
+	tc574_wait_for_completion(dev, TxReset);
 	outw(TxEnable, ioaddr + EL3_CMD);
 	netif_wake_queue(dev);
 }
@@ -876,7 +876,7 @@
 		if (!(tx_status & 0x84)) break;
 		/* reset transmitter on jabber error or underrun */
 		if (tx_status & 0x30)
-			wait_for_completion(dev, TxReset);
+			tc574_wait_for_completion(dev, TxReset);
 		if (tx_status & 0x38) {
 			DEBUG(1, "%s: transmit error: status 0x%02x\n",
 				  dev->name, tx_status);
@@ -968,12 +968,12 @@
 					   " register %04x.\n", dev->name, fifo_diag);
 				if (fifo_diag & 0x0400) {
 					/* Tx overrun */
-					wait_for_completion(dev, TxReset);
+					tc574_wait_for_completion(dev, TxReset);
 					outw(TxEnable, ioaddr + EL3_CMD);
 				}
 				if (fifo_diag & 0x2000) {
 					/* Rx underrun */
-					wait_for_completion(dev, RxReset);
+					tc574_wait_for_completion(dev, RxReset);
 					set_rx_mode(dev);
 					outw(RxEnable, ioaddr + EL3_CMD);
 				}
@@ -1175,7 +1175,7 @@
 				lp->stats.rx_dropped++;
 			}
 		}
-		wait_for_completion(dev, RxDiscard);
+		tc574_wait_for_completion(dev, RxDiscard);
 	}
 
 	return worklimit;
diff -urN linux-2.4.8-pre4/drivers/net/pcmcia/3c589_cs.c linux/drivers/net/pcmcia/3c589_cs.c
--- linux-2.4.8-pre4/drivers/net/pcmcia/3c589_cs.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/net/pcmcia/3c589_cs.c	Mon Dec  3 22:58:52 2001
@@ -528,7 +528,7 @@
 /*
   Use this for commands that may take time to finish
 */
-static void wait_for_completion(struct net_device *dev, int cmd)
+static void tc589_wait_for_completion(struct net_device *dev, int cmd)
 {
     int i = 100;
     outw(cmd, dev->base_addr + EL3_CMD);
@@ -686,7 +686,7 @@
     lp->stats.tx_errors++;
     dev->trans_start = jiffies;
     /* Issue TX_RESET and TX_START commands. */
-    wait_for_completion(dev, TxReset);
+    tc589_wait_for_completion(dev, TxReset);
     outw(TxEnable, ioaddr + EL3_CMD);
     netif_wake_queue(dev);
 }
@@ -703,7 +703,7 @@
 	if (!(tx_status & 0x84)) break;
 	/* reset transmitter on jabber error or underrun */
 	if (tx_status & 0x30)
-	    wait_for_completion(dev, TxReset);
+	    tc589_wait_for_completion(dev, TxReset);
 	if (tx_status & 0x38) {
 	    DEBUG(1, "%s: transmit error: status 0x%02x\n",
 		  dev->name, tx_status);
@@ -796,12 +796,12 @@
 		       " register %04x.\n", dev->name, fifo_diag);
 		if (fifo_diag & 0x0400) {
 		    /* Tx overrun */
-		    wait_for_completion(dev, TxReset);
+		    tc589_wait_for_completion(dev, TxReset);
 		    outw(TxEnable, ioaddr + EL3_CMD);
 		}
 		if (fifo_diag & 0x2000) {
 		    /* Rx underrun */
-		    wait_for_completion(dev, RxReset);
+		    tc589_wait_for_completion(dev, RxReset);
 		    set_multicast_list(dev);
 		    outw(RxEnable, ioaddr + EL3_CMD);
 		}
@@ -1003,7 +1003,7 @@
 	    }
 	}
 	/* Pop the top of the Rx FIFO */
-	wait_for_completion(dev, RxDiscard);
+	tc589_wait_for_completion(dev, RxDiscard);
     }
     if (worklimit == 0)
 	printk(KERN_NOTICE "%s: too much work in el3_rx!\n", dev->name);
diff -urN linux-2.4.8-pre4/drivers/net/pcmcia/ibmtr_cs.c linux/drivers/net/pcmcia/ibmtr_cs.c
--- linux-2.4.8-pre4/drivers/net/pcmcia/ibmtr_cs.c	Wed Jul  4 11:50:39 2001
+++ linux/drivers/net/pcmcia/ibmtr_cs.c	Mon Dec  3 22:58:52 2001
@@ -49,7 +49,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/module.h>
@@ -361,7 +361,7 @@
     mem.CardOffset = mmiobase;
     mem.Page = 0;
     CS_CHECK(MapMemPage, link->win, &mem);
-    ti->mmio = (u_long)ioremap(req.Base, req.Size);
+    ti->mmio = ioremap(req.Base, req.Size);
 
     /* Allocate the SRAM memory window */
     req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
diff -urN linux-2.4.8-pre4/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- linux-2.4.8-pre4/drivers/net/tokenring/ibmtr.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Mon Dec  3 22:58:52 2001
@@ -228,7 +228,7 @@
 	printk("\n");
 }
 
-static void __devinit HWPrtChanID(__u32 pcid, short stride)
+static void __devinit HWPrtChanID(void * pcid, short stride)
 {
 	short i, j;
 	for (i = 0, j = 0; i < 24; i++, j += stride)
@@ -330,7 +330,6 @@
 	for (i = 0; ibmtr_portlist[i]; i++) {
 		int ioaddr = ibmtr_portlist[i];
 
-		if (check_region(ioaddr, IBMTR_IO_EXTENT)) continue;
 		if (!ibmtr_probe1(dev, ioaddr)) return 0;
 	}
 	return -ENODEV;
@@ -342,9 +341,9 @@
 {
 
 	unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0;
-	__u32 t_mmio = 0;
+	void * t_mmio = 0;
 	struct tok_info *ti = 0;
-	__u32 cd_chanid;
+	void *cd_chanid;
 	unsigned char *tchanid, ctemp;
 #ifndef PCMCIA
 	unsigned char t_irq=0;
@@ -355,6 +354,8 @@
 #ifndef MODULE
 #ifndef PCMCIA
 	dev = init_trdev(dev, 0);
+	if (!dev)
+		return -ENOMEM;
 #endif
 #endif
 
@@ -377,14 +378,14 @@
 	 *    Compute the linear base address of the MMIO area
 	 *    as LINUX doesn't care about segments
 	 */
-	t_mmio = (u32)ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
+	t_mmio = ioremap(((__u32) (segment & 0xfc) << 11) + 0x80000,2048);
 	if (!t_mmio) { 
 		DPRINTK("Cannot remap mmiobase memory area") ; 
 		return -ENODEV ; 
 	} 
 	intr = segment & 0x03;	/* low bits is coded interrupt # */
 	if (ibmtr_debug_trace & TRC_INIT)
-		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %08X intr: %d\n"
+		DPRINTK("PIOaddr: %4hx seg/intr: %2x mmio base: %p intr: %d\n"
 				, PIOaddr, (int) segment, t_mmio, (int) intr);
 
 	/*
@@ -392,8 +393,9 @@
 	 *    what we is there to learn of ISA/MCA or not TR card
 	 */
 #ifdef PCMCIA
+	iounmap(t_mmio);
 	ti = dev->priv;		/*BMS moved up here */
-	t_mmio = ti->mmio;	/*BMS to get virtual address */
+	t_mmio = (void *)ti->mmio;	/*BMS to get virtual address */
 	irq = ti->irq;		/*BMS to display the irq!   */
 #endif
 	cd_chanid = (CHANNEL_ID + t_mmio);	/* for efficiency */
@@ -424,7 +426,12 @@
 	if (cardpresent == TR_ISA && (readb(AIPFID + t_mmio) == 0x0e))
 		cardpresent = TR_ISAPNP;
 	if (cardpresent == NOTOK) {	/* "channel_id" did not match, report */
-		if (!(ibmtr_debug_trace & TRC_INIT)) return -ENODEV;
+		if (!(ibmtr_debug_trace & TRC_INIT)) {
+#ifndef PCMCIA
+			iounmap(t_mmio);
+#endif
+			return -ENODEV;
+		}
 		DPRINTK( "Channel ID string not found for PIOaddr: %4hx\n",
 								PIOaddr);
 		DPRINTK("Expected for ISA: ");
@@ -442,7 +449,10 @@
 	   waste the memory, just use the existing structure */
 #ifndef PCMCIA
 	ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL);
-	if (ti == NULL) return -ENOMEM;
+	if (ti == NULL) {
+		iounmap(t_mmio);
+		return -ENOMEM;
+	}
 	memset(ti, 0, sizeof(struct tok_info));
 	ti->mmio = t_mmio;
 	dev->priv = ti;		/* this seems like the logical use of the
@@ -459,7 +469,7 @@
 		ti->turbo=1;
 		t_irq=turbo_irq[i];
         }
-#endif
+#endif /* !PCMCIA */
 	ti->readlog_pending = 0;
 	init_waitqueue_head(&ti->wait_for_reset);
 
@@ -496,6 +506,7 @@
 		while (!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)){
 			if (!time_after(jiffies, timeout)) continue;
 			DPRINTK( "Hardware timeout during initialization.\n");
+			iounmap(t_mmio);
 			kfree(ti);
 			return -ENODEV;
 		}
@@ -510,7 +521,7 @@
 		DPRINTK("irq=%d", irq);
 		printk(", sram_virt=0x%x", ti->sram_virt);
 		if(ibmtr_debug_trace&TRC_INITV){ /* full chat in verbose only */
-			DPRINTK(", ti->mmio=%08X", ti->mmio);
+			DPRINTK(", ti->mmio=%p", ti->mmio);
 			printk(", segment=%02X", segment);
 		}
 		printk(".\n");
@@ -609,6 +620,7 @@
 		default:
 			DPRINTK("Unknown shared ram paging info %01X\n",
 							ti->shared_ram_paging);
+			iounmap(t_mmio); 
 			kfree(ti);
 			return -ENODEV;
 			break;
@@ -638,6 +650,7 @@
 			DPRINTK("Shared RAM for this adapter (%05x) exceeds "
 			"driver limit (%05x), adapter not started.\n",
 			chk_base, ibmtr_mem_base + IBMTR_SHARED_RAM_SIZE);
+			iounmap(t_mmio);
 			kfree(ti);
 			return -ENODEV;
 		} else { /* seems cool, record what we have figured out */
@@ -652,16 +665,24 @@
 	if (request_irq(dev->irq = irq, &tok_interrupt, 0, "ibmtr", dev) != 0) {
 		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",
 					irq);
+		iounmap(t_mmio);
 		kfree(ti);
 		return -ENODEV;
 	}
 	/*?? Now, allocate some of the PIO PORTs for this driver.. */
 	/* record PIOaddr range as busy */
-	request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr");
+	if (!request_region(PIOaddr, IBMTR_IO_EXTENT, "ibmtr")) {
+		DPRINTK("Could not grab PIO range. Halting driver.\n");
+		free_irq(dev->irq, dev);
+		iounmap(t_mmio);
+		kfree(ti);
+		return -EBUSY;
+	}
+
 	if (!version_printed++) {
 		printk(version);
 	}
-#endif
+#endif /* !PCMCIA */
 	DPRINTK("%s %s found\n",
 		channel_def[cardpresent - 1], adapter_def(ti->adapter_type));
 	DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n",
diff -urN linux-2.4.8-pre4/drivers/pci/quirks.c linux/drivers/pci/quirks.c
--- linux-2.4.8-pre4/drivers/pci/quirks.c	Wed Jun 20 11:16:01 2001
+++ linux/drivers/pci/quirks.c	Mon Dec  3 22:58:52 2001
@@ -92,42 +92,58 @@
  *	see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm
  *      Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for
  *      the info on which Mr Breese based his work.
+ *
+ *	Updated based on further information from the site and also on
+ *	information provided by VIA 
  */
 static void __init quirk_vialatency(struct pci_dev *dev)
 {
-	u8 r70;
+	struct pci_dev *p;
 	u8 rev;
-	struct pci_dev *vt82c686;
-   
-   
-	/* we want to look for a VT82C686 south bridge, and then apply the via latency
-	 * patch if we find that it's a 686B (by revision) <cpbotha@ieee.org>
+	u8 busarb;
+	/* Ok we have a potential problem chipset here. Now see if we have
+	   a buggy southbridge */
+	   
+	p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
+	if(p!=NULL)
+	{
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
+		/* Check for buggy part revisions */
+		if (rev < 0x40 || rev > 0x42) 
+			return;
+	}
+	else
+	{
+		p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL);
+		if(p==NULL)	/* No problem parts */
+			return;
+		pci_read_config_byte(p, PCI_CLASS_REVISION, &rev);
+		/* Check for buggy part revisions */
+		if (rev < 0x10 || rev > 0x12) 
+			return;
+	}
+	
+	/*
+	 *	Ok we have the problem. Now set the PCI master grant to 
+	 *	occur every master grant. The apparent bug is that under high
+	 *	PCI load (quite common in Linux of course) you can get data
+	 *	loss when the CPU is held off the bus for 3 bus master requests
+	 *	This happens to include the IDE controllers....
+	 *
+	 *	VIA only apply this fix when an SB Live! is present but under
+	 *	both Linux and Windows this isnt enough, and we have seen
+	 *	corruption without SB Live! but with things like 3 UDMA IDE
+	 *	controllers. So we ignore that bit of the VIA recommendation..
 	 */
-	vt82c686 = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL);
-	if (vt82c686)   
-     	{
-		pci_read_config_byte(vt82c686, PCI_CLASS_REVISION, &rev);
-        	/* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */
-		if (rev >= 0x40 && rev <= 0x4f)
-		{
-        		printk(KERN_INFO "Applying VIA PCI latency patch (found VT82C686B).\n");
-			/*
-	 		 *    In register 0x70, mask off bit 2 (PCI Master read caching)
-	 		 *    and 1 (Delay Transaction)
-	 		 */
-			pci_read_config_byte(dev, 0x70, &r70);
-			r70 &= 0xf9;
-			pci_write_config_byte(dev, 0x70, r70);
-			/*
-	 	 	 *    Turn off PCI Latency timeout (set to 0 clocks)
-	 	 	 */
-			pci_write_config_byte(dev, 0x75, 0x80);
-		}
-		else
-		{
-			printk(KERN_INFO "Found VT82C686A, not applying VIA latency patch.\n");
-		}
-	} /* if (vt82c686) ... */
+
+	pci_read_config_byte(dev, 0x76, &busarb);
+	/* Set bit 4 and bi 5 of byte 76 to 0x01 
+	   "Master priority rotation on every PCI master grant */
+	busarb &= ~(1<<5);
+	busarb |= (1<<4);
+	pci_write_config_byte(dev, 0x76, busarb);
+	printk(KERN_INFO "Applying VIA southbridge workaround.\n");
 }
 
 /*
@@ -416,6 +432,8 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8371_1,	quirk_vialatency },
+	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	0x3112	/* Not out yet ? */,	quirk_vialatency },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_viaetbf },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C597_0,	quirk_vt82c598_id },
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_82C586_3,	quirk_vt82c586_acpi },
diff -urN linux-2.4.8-pre4/drivers/s390/Config.in linux/drivers/s390/Config.in
--- linux-2.4.8-pre4/drivers/s390/Config.in	Mon Dec  3 22:58:44 2001
+++ linux/drivers/s390/Config.in	Mon Dec  3 22:58:52 2001
@@ -14,12 +14,21 @@
 
 tristate 'Support for DASD devices' CONFIG_DASD
 if [ "$CONFIG_DASD" != "n"  ]; then
-  bool '   Support for ECKD Disks' CONFIG_DASD_ECKD
-  bool '   Support for FBA  Disks' CONFIG_DASD_FBA
-#  bool '   Support for CKD  Disks' CONFIG_DASD_CKD
-  if [ "$CONFIG_ARCH_S390" = "y" ]; then
-    bool '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG
+  dep_tristate '   Support for ECKD Disks' CONFIG_DASD_ECKD $CONFIG_DASD
+  if [ "$CONFIG_DASD_ECKD" = "m" ]; then
+    bool     '   Automatic activation of ECKD module' CONFIG_DASD_AUTO_ECKD
   fi;
+  dep_tristate '   Support for FBA  Disks' CONFIG_DASD_FBA $CONFIG_DASD
+  if [ "$CONFIG_DASD_FBA" = "m" ]; then
+    bool     '   Automatic activation of FBA  module' CONFIG_DASD_AUTO_FBA
+  fi;
+#  dep_tristate '   Support for CKD  Disks' CONFIG_DASD_CKD $CONFIG_DASD
+  if [ "$CONFIG_ARCH_S390X" != "y" ]; then
+    dep_tristate '   Support for DIAG access to CMS reserved Disks' CONFIG_DASD_DIAG $CONFIG_DASD
+    if [ "$CONFIG_DASD_DIAG" = "m" ]; then
+      bool     '   Automatic activation of DIAG module' CONFIG_DASD_AUTO_DIAG
+    fi;
+  fi; 
 fi
 
 endmenu
diff -urN linux-2.4.8-pre4/drivers/s390/block/Makefile linux/drivers/s390/block/Makefile
--- linux-2.4.8-pre4/drivers/s390/block/Makefile	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/Makefile	Mon Dec  3 22:58:52 2001
@@ -4,19 +4,31 @@
 
 O_TARGET := s390-block.o
 
-list-multi := dasd_mod.o
+list-multi := dasd_mod.o dasd_eckd_mod.o dasd_fba_mod.o dasd_diag_mod.o
 export-objs := dasd.o
 
-dasd_mod-$(CONFIG_DASD_ECKD) += dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
-dasd_mod-$(CONFIG_DASD_FBA) += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
-dasd_mod-$(CONFIG_DASD_DIAG) += dasd_diag.o
-dasd_mod-objs := dasd.o $(dasd_mod-y)
+dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
+dasd_fba_mod-objs  := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
+dasd_diag_mod-objs := dasd_diag.o
+dasd_mod-objs      := dasd.o
 
 obj-$(CONFIG_DASD) += dasd_mod.o
+obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
+obj-$(CONFIG_DASD_FBA)  += dasd_fba_mod.o
+obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
 obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
 
 include $(TOPDIR)/Rules.make
 
 dasd_mod.o: $(dasd_mod-objs)
 	$(LD) -r -o $@ $(dasd_mod-objs)
+
+dasd_eckd_mod.o: $(dasd_eckd_mod-objs)
+	$(LD) -r -o $@ $(dasd_eckd_mod-objs)
+
+dasd_fba_mod.o: $(dasd_fba_mod-objs)
+	$(LD) -r -o $@ $(dasd_fba_mod-objs)
+
+dasd_diag_mod.o: $(dasd_diag_mod-objs)
+	$(LD) -r -o $@ $(dasd_diag_mod-objs)
 
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd.c linux/drivers/s390/block/dasd.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/s390/block/dasd.c	Mon Dec  3 22:58:52 2001
@@ -1,14 +1,13 @@
-/* 
+/*
  * File...........: linux/drivers/s390/block/dasd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                  Horst Hummel <Horst.Hummel@de.ibm.com>  
+ *                  Horst Hummel <Horst.Hummel@de.ibm.com> 
  *                  Carsten Otte <Cotte@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001
  *
  * History of changes (starts July 2000)
  * 11/09/00 complete redesign after code review
- * 02/01/01 removed some warnings
  * 02/01/01 added dynamic registration of ioctls
  *          fixed bug in registration of new majors
  *          fixed handling of request during dasd_end_request
@@ -18,13 +17,27 @@
  *          fixed some race conditions related to modules
  *          added devfs suupport
  * 03/06/01 refined dynamic attach/detach for leaving devices which are online.
- * 06/09/01 refined dynamic modifiaction of devices
- *          renewed debug feature exploitation
+ * 03/09/01 refined dynamic modifiaction of devices
+ * 03/12/01 moved policy in dasd_format to dasdfmt (renamed BIODASDFORMAT)
+ * 03/19/01 added BIODASDINFO-ioctl
+ *          removed 2.2 compatibility
+ * 04/27/01 fixed PL030119COT (dasd_disciplines does not work)
+ * 04/30/01 fixed PL030146HSM (module locking with dynamic ioctls)
+ *          fixed PL030130SBA (handling of invalid ranges)
+ * 05/02/01 fixed PL030145SBA (killing dasdmt)
+ *          fixed PL030149SBA (status of 'accepted' devices)
+ *          fixed PL030146SBA (BUG in ibm.c after adding device)
+ *          added BIODASDPRRD ioctl interface
+ * 05/11/01 fixed  PL030164MVE (trap in probeonly mode)
+ * 05/15/01 fixed devfs support for unformatted devices
+ * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA
+ * 07/09/01 fixed PL030324MSH (wrong statistics output)
+ * 07/16/01 merged in new fixes for handling low-mem situations
  */
 
-#include <linux/module.h>
 #include <linux/config.h>
 #include <linux/version.h>
+#include <linux/kmod.h>
 #include <linux/init.h>
 #include <linux/blkdev.h>
 #include <linux/stddef.h>
@@ -42,9 +55,9 @@
 #include <linux/spinlock.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/blkpg.h>
+#include <linux/wait.h>
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
 #include <asm/debug.h>
 
 #include <asm/atomic.h>
@@ -57,6 +70,9 @@
 #include <asm/s390_ext.h>
 #include <asm/s390dyn.h>
 #include <asm/idals.h>
+#include <asm/dasd.h>
+
+#include "dasd_int.h"
 
 #ifdef CONFIG_DASD_ECKD
 #include "dasd_eckd.h"
@@ -77,20 +93,31 @@
 		    " Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE ("dasd");
 MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");
-EXPORT_SYMBOL (dasd_discipline_enq);
-EXPORT_SYMBOL (dasd_discipline_deq);
+MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");
+EXPORT_SYMBOL (dasd_chanq_enq_head);
+EXPORT_SYMBOL (dasd_debug_area);
+EXPORT_SYMBOL (dasd_chanq_enq);
+EXPORT_SYMBOL (dasd_chanq_deq);
+EXPORT_SYMBOL (dasd_discipline_add);
+EXPORT_SYMBOL (dasd_discipline_del);
 EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_term_IO);
+EXPORT_SYMBOL (dasd_schedule_bh);
 EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_oper_handler);
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
-EXPORT_SYMBOL(dasd_ioctl_no_register);  
-EXPORT_SYMBOL(dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_ioctl_no_register);
+EXPORT_SYMBOL (dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_default_erp_action);
+EXPORT_SYMBOL (dasd_default_erp_postaction);
+EXPORT_SYMBOL (dasd_sleep_on_req);
+EXPORT_SYMBOL (dasd_set_normalized_cda);
 
 /* SECTION: Constant definitions to be used within this file */
 
-#define PRINTK_HEADER DASD_NAME": "
+#define PRINTK_HEADER DASD_NAME":"
 
-#define DASD_EMERGENCY_REQUESTS 16
 #define DASD_MIN_SIZE_FOR_QUEUE 32
 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
 #define DASD_CHANQ_MAX_SIZE 6
@@ -98,27 +125,36 @@
 /* SECTION: prototypes for static functions of dasd.c */
 
 static request_fn_proc do_dasd_request;
-static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
+static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int);
 static request_queue_t *dasd_get_queue (kdev_t kdev);
 static void cleanup_dasd (void);
-int dasd_fillgeo(int kdev,struct hd_geometry *geo);
-
+static void dasd_plug_device (dasd_device_t * device);
+static int dasd_fillgeo (int kdev, struct hd_geometry *geo);
+static void dasd_enable_ranges (dasd_range_t *, dasd_discipline_t *, int); 
+static void dasd_disable_ranges (dasd_range_t *, dasd_discipline_t *, int, int); 
+static void dasd_enable_single_device ( unsigned long);
+static inline int dasd_state_init_to_ready(dasd_device_t*);
+static inline void dasd_setup_partitions ( dasd_device_t *);
+static inline int dasd_setup_blkdev(dasd_device_t*);
+static inline int dasd_disable_blkdev(dasd_device_t*);
+static void dasd_flush_chanq ( dasd_device_t * device, int destroy ); 
+static void dasd_flush_request_queues ( dasd_device_t * device, int destroy );
 static struct block_device_operations dasd_device_operations;
-
+static inline dasd_device_t ** dasd_device_from_devno (int);
+static void dasd_process_queues (dasd_device_t * device);
 /* SECTION: static variables of dasd.c */
 
 static devfs_handle_t dasd_devfs_handle;
-
-/* SECTION: exported variables of dasd.c */
-
-debug_info_t *dasd_debug_area;
+static wait_queue_head_t dasd_init_waitq;
+static atomic_t dasd_init_pending = ATOMIC_INIT (0);
 
 #ifdef CONFIG_DASD_DYNAMIC
+
 /* SECTION: managing dynamic configuration of dasd_driver */
 
-static struct list_head dasd_devreg_head = LIST_HEAD_INIT(dasd_devreg_head);
+static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);
 
-/* 
+/*
  * function: dasd_create_devreg
  * creates a dasd_devreg_t related to a devno
  */
@@ -135,7 +171,7 @@
 	return r;
 }
 
-/* 
+/*
  * function: dasd_destroy_devreg
  * destroys the dasd_devreg_t given as argument
  */
@@ -153,44 +189,44 @@
 static int dasd_probeonly = 1;	/* is true, when probeonly mode is active */
 static int dasd_autodetect = 1;	/* is true, when autodetection is active */
 
-/* dasd_range_t are used for ordering the DASD devices */
-typedef struct dasd_range_t {
-	unsigned int from;	/* first DASD in range */
-	unsigned int to;	/* last DASD in range */
-	char discipline[4];	/* placeholder to force discipline */
-	struct dasd_range_t *next;	/* next one in linked list */
-} dasd_range_t;
-
-static dasd_range_t *dasd_range_head = NULL;	/* anchor for list of ranges */
+static dasd_range_t dasd_range_head =
+    { list:LIST_HEAD_INIT (dasd_range_head.list) };
 static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t dasd_open_count_lock;
 
-/* 
+/*
  * function: dasd_create_range
- * creates a dasd_range_t according to the arguments 
+ * creates a dasd_range_t according to the arguments
  * FIXME: no check is performed for reoccurrence of a devno
  */
 static inline dasd_range_t *
-dasd_create_range (int from, int to)
+dasd_create_range (int from, int to, int features)
 {
 	dasd_range_t *range = NULL;
+        int i;
+
+	if ( from > to ) {
+                printk (KERN_WARNING PRINTK_HEADER "Adding device range %04X-%04X: range invalid, ignoring.\n",from,to);
+		return NULL;
+	}
+	for (i=from;i<=to;i++) {
+                if (dasd_device_from_devno(i)) {
+                        printk (KERN_WARNING PRINTK_HEADER "device range %04X-%04X: device %04X is already in a range.\n",from,to,i);
+                }
+        }
 	range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL);
 	if (range == NULL)
 		return NULL;
 	memset (range, 0, sizeof (dasd_range_t));
 	range->from = from;
-	if (to == 0) {		/* single devno ? */
-		range->to = from;
-	} else {
-		range->to = to;
-	}
+        range->to = to;
+        range->features = features;
 	return range;
 }
 
-/* 
+/*
  * function dasd_destroy_range
  * destroy a range allocated wit dasd_crate_range
- * CAUTION: must not be callen in arunning sysztem, because it destroys 
+ * CAUTION: must not be callen in arunning sysztem, because it destroys
  * the mapping of DASDs
  */
 static inline void
@@ -199,68 +235,50 @@
 	kfree (range);
 }
 
-/* 
+/*
  * function: dasd_append_range
- * appends the range given as argument to the list anchored at dasd_range_head. 
+ * appends the range given as argument to the list anchored at dasd_range_head.
  */
 static inline void
 dasd_append_range (dasd_range_t * range)
 {
-	dasd_range_t *temp;
 	long flags;
 
 	spin_lock_irqsave (&range_lock, flags);
-	if (dasd_range_head == NULL) {
-		dasd_range_head = range;
-	} else {
-		for (temp = dasd_range_head;
-		     temp && temp->next;
-		     temp = temp->next) ;
-		temp->next = range;
-	}
+	list_add_tail (&range->list, &dasd_range_head.list);
 	spin_unlock_irqrestore (&range_lock, flags);
 }
 
 /*
  * function dasd_dechain_range
  * removes a range from the chain of ranges
- * CAUTION: must not be called in a running system because it destroys 
+ * CAUTION: must not be called in a running system because it destroys
  * the mapping of devices
  */
 static inline void
 dasd_dechain_range (dasd_range_t * range)
 {
-	dasd_range_t *temp, *prev = NULL;
 	unsigned long flags;
 
 	spin_lock_irqsave (&range_lock, flags);
-	for (temp = dasd_range_head; temp != NULL; temp = temp->next) {
-		if (temp == range)
-			break;
-		prev = temp;
-	}
-	if (!temp)
-		BUG ();
-	if (prev) {
-		prev->next = temp->next;
-	} else {
-		dasd_range_head = temp->next;
-	}
+	list_del (&range->list);
 	spin_unlock_irqrestore (&range_lock, flags);
 }
 
-/* 
+/*
  * function: dasd_add_range
  * creates a dasd_range_t according to the arguments and
  * appends it to the list of ranges
- * additionally a devreg_t is created and added to the list of devregs 
+ * additionally a devreg_t is created and added to the list of devregs
  */
-static inline dasd_range_t*
-dasd_add_range (int from, int to)
+static inline dasd_range_t *
+dasd_add_range (int from, int to, int features)
 {
 	dasd_range_t *range;
-	range = dasd_create_range (from, to);
-	if (!range) return NULL;
+
+	range = dasd_create_range (from, to, features);
+	if (!range)
+		return NULL;
 
 	dasd_append_range (range);
 #ifdef CONFIG_DASD_DYNAMIC
@@ -270,14 +288,14 @@
 		for (i = range->from; i <= range->to; i++) {
 			dasd_devreg_t *reg = dasd_create_devreg (i);
 			s390_device_register (&reg->devreg);
-                        list_add(&reg->list,&dasd_devreg_head);
+			list_add (&reg->list, &dasd_devreg_head);
 		}
 	}
 #endif				/* CONFIG_DASD_DYNAMIC */
 	return range;
 }
 
-/* 
+/*
  * function: dasd_remove_range
  * removes a range and the corresponding devregs from all of the chains
  * CAUTION: must not be called in a running system because it destroys
@@ -291,10 +309,10 @@
 	{
 		int i;
 		for (i = range->from; i <= range->to; i++) {
-                        struct list_head *l;
-                        dasd_devreg_t *reg = NULL;
+			struct list_head *l;
+			dasd_devreg_t *reg = NULL;
 			list_for_each (l, &dasd_devreg_head) {
-                                reg = list_entry(l,dasd_devreg_t,list);
+				reg = list_entry (l, dasd_devreg_t, list);
 				if (reg->devreg.flag == DEVREG_TYPE_DEVNO &&
 				    reg->devreg.ci.devno == i &&
 				    reg->devreg.oper_func == dasd_oper_handler)
@@ -323,9 +341,11 @@
 	dasd_range_t *temp;
 	int devindex = 0;
 	unsigned long flags;
+	struct list_head *l;
 
 	spin_lock_irqsave (&range_lock, flags);
-	for (temp = dasd_range_head; temp; temp = temp->next) {
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
 		if (devno >= temp->from && devno <= temp->to) {
 			spin_unlock_irqrestore (&range_lock, flags);
 			return devindex + devno - temp->from;
@@ -336,19 +356,43 @@
 	return -ENODEV;
 }
 
+/*
+ * function: dasd_devno_from_devindex
+ */
+static int
+dasd_devno_from_devindex (int devindex)
+{
+	dasd_range_t *temp;
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave (&range_lock, flags);
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
+                if ( devindex < temp->to - temp->from + 1) {
+			spin_unlock_irqrestore (&range_lock, flags);
+			return temp->from + devindex;
+		}
+		devindex -= temp->to - temp->from + 1;
+	}
+	spin_unlock_irqrestore (&range_lock, flags);
+	return -ENODEV;
+}
+
 /* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline */
 
-/* 
+/*
  * char *dasd[] is intended to hold the ranges supplied by the dasd= statement
  * it is named 'dasd' to directly be filled by insmod with the comma separated
  * strings when running as a module.
  * a maximum of 256 ranges can be supplied, as the parmline is limited to
  * <1024 Byte anyway.
  */
-char *dasd[256] = {NULL,};
+char *dasd[256];
+char *dasd_disciplines[8];
 
 #ifndef MODULE
-/* 
+/*
  * function: dasd_split_parm_string
  * splits the parmline given to the kernel into comma separated strings
  * which are filled into the 'dasd[]' array, to be parsed later on
@@ -358,7 +402,7 @@
 {
 	char *tmp = str;
 	int count = 0;
-	do {
+	while (tmp != NULL && *tmp != '\0') {
 		char *end;
 		int len;
 		end = strchr (tmp, ',');
@@ -370,27 +414,28 @@
 			end++;
 		}
 		dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
-		if (dasd == NULL) {
+		if (dasd[count] == NULL) {
 			printk (KERN_WARNING PRINTK_HEADER
-			    "can't store dasd= parameter no %d\n", count + 1);
+				"can't store dasd= parameter no %d\n",
+				count + 1);
 			break;
 		}
 		memset (dasd[count], 0, len * sizeof (char));
 		memcpy (dasd[count], tmp, len * sizeof (char));
 		count++;
 		tmp = end;
-	} while (tmp != NULL && *tmp != '\0');
+	};
 }
 
-/* 
+/*
  * dasd_parm_string holds a concatenated version of all 'dasd=' parameters
- * supplied in the parmline, which is later to be split by 
+ * supplied in the parmline, which is later to be split by
  * dasd_split_parm_string
  * FIXME: why first concatenate then split ?
  */
-static char dasd_parm_string[1024] __initdata = {0,};
+static char dasd_parm_string[1024] __initdata = { 0, };
 
-/* 
+/*
  * function: dasd_setup
  * is invoked for any single 'dasd=' parameter supplied in the parmline
  * it merges all the arguments into dasd_parm_string
@@ -404,44 +449,90 @@
 	}
 	strcat (dasd_parm_string, str);
 }
-/* 
- * function: dasd_call_setup 
+
+/*
+ * function: dasd_call_setup
  * is the 2.4 version of dasd_setup and
  * is invoked for any single 'dasd=' parameter supplied in the parmline
  */
 int __init
 dasd_call_setup (char *str)
 {
-        int dummy;
-        dasd_setup(str,&dummy);
+	int dummy;
+	dasd_setup (str, &dummy);
+	return 1;
+}
+
+int __init
+dasd_disciplines_setup (char *str)
+{
 	return 1;
 }
 
 __setup ("dasd=", dasd_call_setup);
+__setup ("dasd_disciplines=", dasd_disciplines_setup);
 
-#endif /* MODULE */
+#endif				/* MODULE */
 
-/* 
+/*
  * function: dasd_strtoul
  * provides a wrapper to simple_strtoul to strip leading '0x' and
  * interpret any argument to dasd=[range,...] as hexadecimal
  */
 static inline int
-dasd_strtoul (char *str, char **stra)
+dasd_strtoul (char *str, char **stra, int* features)
 {
-	char *temp = str;
-	int val;
-	if (*temp == '0') {
-		temp++;		/* strip leading zero */
-		if (*temp == 'x')
-			temp++;	/* strip leading x */
-	}
-	val = simple_strtoul (temp, &temp, 16);		/* interpret anything as hex */
-	*stra = temp;
-	return val;
+        char *temp=str;
+        char *buffer;
+        int val,i,start;
+
+        buffer=(char*)kmalloc((strlen(str)+1)*sizeof(char),GFP_ATOMIC);
+        if (buffer==NULL) {
+            printk (KERN_WARNING PRINTK_HEADER
+                    "can't parse dasd= parameter %s due to low memory\n",
+                    str);
+        }
+
+        /* remove leading '0x' */
+        if (*temp == '0') {
+                temp++;         /* strip leading zero */
+                if (*temp == 'x')
+                        temp++; /* strip leading x */
+        }
+
+        /* copy device no to buffer and convert to decimal */
+        for (i=0;isxdigit(temp[i]);i++)
+                buffer[i]=temp[i];
+        buffer[i]='\0';
+
+        val = simple_strtoul (buffer, &buffer, 16);
+
+        /* check for features - e.g. (ro) ; the '\0', ')' and '-' stops check */
+        if (temp[i]=='(') {
+
+                while (temp[i]!='\0' && temp[i]!=')'&&temp[i]!='-') { 
+                        start=++i;      
+        
+                        /* move next feature to buffer */
+                        for (;temp[i]!='\0'&&temp[i]!=':'&&temp[i]!=')'&&temp[i]!='-';i++)
+                                buffer[i-start]=temp[i];
+                        buffer[i-start]='\0';
+
+                        if (strlen(buffer)) { 
+                                if (!strcmp(buffer,"ro")) { /* handle 'ro' feature */
+                                        (*features) |= DASD_FEATURE_READONLY;
+                                        break;
+                                }
+                                printk (KERN_WARNING PRINTK_HEADER 
+                                        "unsupported feature: %s, ignoring setting",buffer);
+                        }
+                }
+        }
+        *stra = temp+i;
+        return val;
 }
 
-/* 
+/*
  * function: dasd_parse
  * examines the strings given in the string array str and
  * creates and adds the ranges to the apropriate lists
@@ -451,6 +542,7 @@
 {
 	char *temp;
 	int from, to;
+        int features = 0;
 
 	if (*str) {
 		/* turn off probeonly mode, if any dasd parameter is present */
@@ -472,12 +564,13 @@
 		} else {
 			/* turn off autodetect mode, if any range is present */
 			dasd_autodetect = 0;
-			from = dasd_strtoul (temp, &temp);
+			from = dasd_strtoul (temp, &temp, &features);
+                        to = from;
 			if (*temp == '-') {
 				temp++;
-				to = dasd_strtoul (temp, &temp);
+				to = dasd_strtoul (temp, &temp, &features);
 			}
-			dasd_add_range (from, to);
+			dasd_add_range (from, to ,features);
 		}
 		str++;
 	}
@@ -487,18 +580,16 @@
 
 static spinlock_t dasd_major_lock = SPIN_LOCK_UNLOCKED;
 
-static major_info_t dasd_major_info[] =
-{
+static major_info_t dasd_major_info[] = {
 	{
-		list: LIST_HEAD_INIT(dasd_major_info[1].list )
-	},
+	      list:LIST_HEAD_INIT (dasd_major_info[1].list)
+	 },
 	{
-		list: LIST_HEAD_INIT(dasd_major_info[0].list ),
-		gendisk: {
-                        INIT_GENDISK(94,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-		},
-		flags : DASD_MAJOR_INFO_IS_STATIC
-	}
+	      list:LIST_HEAD_INIT (dasd_major_info[0].list),
+	      gendisk:{
+	  INIT_GENDISK (94, DASD_NAME, DASD_PARTN_BITS, DASD_PER_MAJOR)
+	  },
+      flags:DASD_MAJOR_INFO_IS_STATIC}
 };
 
 static major_info_t *
@@ -508,17 +599,21 @@
 
 	major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
 	if (major_info) {
-		static major_info_t temp_major_info =
-		{
-			gendisk: {
-				INIT_GENDISK(0,DASD_NAME,DASD_PARTN_BITS,DASD_PER_MAJOR)
-			}
+		static major_info_t temp_major_info = {
+			gendisk:{
+				 INIT_GENDISK (0, DASD_NAME, DASD_PARTN_BITS,
+					       DASD_PER_MAJOR)}
 		};
 		memcpy (major_info, &temp_major_info, sizeof (major_info_t));
 	}
 	return major_info;
 }
 
+/*
+ * register major number
+ * is called with the 'static' major_info during init of the driver or 'NULL' to
+ * allocate an additional dynamic major.
+ */
 static int
 dasd_register_major (major_info_t * major_info)
 {
@@ -526,67 +621,86 @@
 	int major;
 	unsigned long flags;
 
+        /* allocate dynamic major */
 	if (major_info == NULL) {
 		major_info = get_new_major_info ();
 		if (!major_info) {
 			printk (KERN_WARNING PRINTK_HEADER
 				"Cannot get memory to allocate another major number\n");
 			return -ENOMEM;
-		} else {
-			printk (KERN_INFO PRINTK_HEADER
-				"Created another major number\n");
 		}
 	}
+
 	major = major_info->gendisk.major;
-	major_info->gendisk.de_arr = (devfs_handle_t*)
-		kmalloc(DASD_PER_MAJOR * sizeof(devfs_handle_t), GFP_KERNEL);
-	memset(major_info->gendisk.de_arr,0,DASD_PER_MAJOR * sizeof(devfs_handle_t));
-	major_info->gendisk.flags = (char*)
-		kmalloc(DASD_PER_MAJOR * sizeof(char), GFP_KERNEL);
-	memset(major_info->gendisk.flags,0,DASD_PER_MAJOR * sizeof(char));
 
+        /* init devfs array */
+	major_info->gendisk.de_arr = (devfs_handle_t *)
+	    kmalloc (DASD_PER_MAJOR * sizeof (devfs_handle_t), GFP_KERNEL);
+	memset (major_info->gendisk.de_arr, 0,
+		DASD_PER_MAJOR * sizeof (devfs_handle_t));
+
+        /* init flags */
+	major_info->gendisk.flags = (char *)
+	    kmalloc (DASD_PER_MAJOR * sizeof (char), GFP_KERNEL);
+	memset (major_info->gendisk.flags, 0, DASD_PER_MAJOR * sizeof (char));
+
+        /* register blockdevice */
 	rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
-		      "Cannot register to major no %d, rc = %d\n", major, rc);
-		return rc;
+			"Cannot register to major no %d, rc = %d\n", major, rc);
+		goto out_reg_blkdev; 
 	} else {
 		major_info->flags |= DASD_MAJOR_INFO_REGISTERED;
 	}
-        /* Insert the new major info into dasd_major_info if needed */
-        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC) ){
-                spin_lock_irqsave (&dasd_major_lock, flags);
-		list_add_tail(&major_info->list,&dasd_major_info[0].list);
+
+	/* Insert the new major info into dasd_major_info if needed (dynamic major) */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_add_tail (&major_info->list, &dasd_major_info[0].list);
 		spin_unlock_irqrestore (&dasd_major_lock, flags);
-        }
+	}
+
 	if (major == 0) {
 		major = rc;
 		rc = 0;
 	}
-	major_info->dasd_device = (dasd_device_t **) kmalloc (DASD_PER_MAJOR * sizeof (dasd_device_t *),
-							      GFP_ATOMIC);
+
+        /* init array of devices */
+	major_info->dasd_device =
+	    (dasd_device_t **) kmalloc (DASD_PER_MAJOR *
+					sizeof (dasd_device_t *), GFP_ATOMIC);
 	if (!major_info->dasd_device)
-		goto out_devfs;
-	memset (major_info->dasd_device, 0, DASD_PER_MAJOR * sizeof (dasd_device_t *));
+		goto out_devices;
+	memset (major_info->dasd_device, 0,
+		DASD_PER_MAJOR * sizeof (dasd_device_t *));
+
+        /* init blk_size */
 	blk_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!blk_size[major])
-		goto out_dasd_device;
+		goto out_blk_size;
 	memset (blk_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init blksize_size */
 	blksize_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!blksize_size[major])
-		goto out_blk_size;
+		goto out_blksize_size;
 	memset (blksize_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init_hardsect_size */
 	hardsect_size[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!hardsect_size[major])
-		goto out_blksize_size;
+		goto out_hardsect_size;
 	memset (hardsect_size[major], 0, (1 << MINORBITS) * sizeof (int));
+
+        /* init max_sectors */
 	max_sectors[major] =
 	    (int *) kmalloc ((1 << MINORBITS) * sizeof (int), GFP_ATOMIC);
 	if (!max_sectors[major])
-		goto out_hardsect_size;
+		goto out_max_sectors;
 	memset (max_sectors[major], 0, (1 << MINORBITS) * sizeof (int));
 
 	/* finally do the gendisk stuff */
@@ -594,29 +708,65 @@
 					    sizeof (struct hd_struct),
 					    GFP_ATOMIC);
 	if (!major_info->gendisk.part)
-		goto out_max_sectors;
+		goto out_gendisk;
 	memset (major_info->gendisk.part, 0, (1 << MINORBITS) *
 		sizeof (struct hd_struct));
 
-	INIT_BLK_DEV(major,do_dasd_request,dasd_get_queue,NULL);
+	INIT_BLK_DEV (major, do_dasd_request, dasd_get_queue, NULL);
 
 	major_info->gendisk.major = major;
 	major_info->gendisk.next = gendisk_head;
 	major_info->gendisk.sizes = blk_size[major];
 	gendisk_head = &major_info->gendisk;
 	return major;
-out_max_sectors:
-	kfree(max_sectors[major]);
-out_hardsect_size:
-	kfree(hardsect_size[major]);
-out_blksize_size:
-	kfree(blksize_size[major]);
-out_blk_size:
-	kfree(blk_size[major]);
-out_dasd_device:
-	kfree(major_info->dasd_device);
-out_devfs:
-	devfs_unregister_blkdev(major, DASD_NAME);
+
+        /* error handling - free the prior allocated memory */  
+      out_gendisk:
+	kfree (max_sectors[major]);
+	max_sectors[major] = NULL;
+
+      out_max_sectors:
+	kfree (hardsect_size[major]);
+	hardsect_size[major] = NULL;
+
+      out_hardsect_size:
+	kfree (blksize_size[major]);
+	blksize_size[major] = NULL;
+
+      out_blksize_size:
+	kfree (blk_size[major]);
+	blk_size[major] = NULL;
+
+      out_blk_size:
+	kfree (major_info->dasd_device);
+
+      out_devices:
+	/* Delete the new major info from dasd_major_info list if needed (dynamic) +*/
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_del (&major_info->list);
+		spin_unlock_irqrestore (&dasd_major_lock, flags);
+	}
+
+        /* unregister blockdevice */
+	rc = devfs_unregister_blkdev (major, DASD_NAME);
+	if (rc < 0) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"Unable to unregister from major no %d, rc = %d\n", major,
+			rc);
+	} else {
+		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
+	}
+
+      out_reg_blkdev:
+        kfree (major_info->gendisk.flags);
+        kfree (major_info->gendisk.de_arr);
+
+	/* Delete the new major info from dasd_major_info if needed */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		kfree (major_info);
+	}
+
 	return -ENOMEM;
 }
 
@@ -632,11 +782,7 @@
 		return -EINVAL;
 	}
 	major = major_info->gendisk.major;
-        INIT_BLK_DEV(major,NULL,NULL,NULL);
-	blk_size[major] = NULL;
-	blksize_size[major] = NULL;
-	hardsect_size[major] = NULL;
-	max_sectors[major] = NULL;
+	INIT_BLK_DEV (major, NULL, NULL, NULL);
 
 	/* do the gendisk stuff */
 	for (dd = gendisk_head; dd; dd = dd->next) {
@@ -652,34 +798,43 @@
 	if (dd == NULL) {
 		return -ENOENT;
 	}
-	kfree (major_info->gendisk.de_arr);
-	kfree (major_info->gendisk.flags);
 	kfree (major_info->dasd_device);
+	kfree (major_info->gendisk.part);
+
 	kfree (blk_size[major]);
 	kfree (blksize_size[major]);
 	kfree (hardsect_size[major]);
 	kfree (max_sectors[major]);
-	kfree (major_info->gendisk.part);
+
+	blk_size[major]      = NULL;
+	blksize_size[major]  = NULL;
+	hardsect_size[major] = NULL;
+	max_sectors[major]   = NULL;
 
 	rc = devfs_unregister_blkdev (major, DASD_NAME);
 	if (rc < 0) {
 		printk (KERN_WARNING PRINTK_HEADER
-		  "Cannot unregister from major no %d, rc = %d\n", major, rc);
+			"Cannot unregister from major no %d, rc = %d\n", major,
+			rc);
 		return rc;
 	} else {
 		major_info->flags &= ~DASD_MAJOR_INFO_REGISTERED;
 	}
-        /* Delete the new major info from dasd_major_info if needed */
-        if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
-                spin_lock_irqsave (&dasd_major_lock, flags);
-		list_del(&major_info->list);
+
+	kfree (major_info->gendisk.flags);
+	kfree (major_info->gendisk.de_arr);
+
+	/* Delete the new major info from dasd_major_info if needed */
+	if (!(major_info->flags & DASD_MAJOR_INFO_IS_STATIC)) {
+		spin_lock_irqsave (&dasd_major_lock, flags);
+		list_del (&major_info->list);
 		spin_unlock_irqrestore (&dasd_major_lock, flags);
 		kfree (major_info);
-        }
+	}
 	return rc;
 }
 
-/* 
+/*
  * function: dasd_device_from_kdev
  * finds the device structure corresponding to the kdev supplied as argument
  * in the major_info structures and returns it or NULL when not found
@@ -692,9 +847,9 @@
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info = list_entry(l,major_info_t,list);
-		if ( major_info->gendisk.major == MAJOR(kdev) )
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		if (major_info->gendisk.major == MAJOR (kdev))
 			break;
 	}
 	spin_unlock_irqrestore (&dasd_major_lock, flags);
@@ -703,10 +858,10 @@
 	return NULL;
 }
 
-/* 
+/*
  * function: dasd_device_from_devno
- * finds the address of the device structure corresponding to the devno 
- * supplied as argument in the major_info structures and returns 
+ * finds the address of the device structure corresponding to the devno
+ * supplied as argument in the major_info structures and returns
  * it or NULL when not found
  */
 static inline dasd_device_t **
@@ -718,8 +873,8 @@
 	unsigned long flags;
 
 	spin_lock_irqsave (&dasd_major_lock, flags);
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info = list_entry(l,major_info_t,list);
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		if (devindex < DASD_PER_MAJOR) {
 			spin_unlock_irqrestore (&dasd_major_lock, flags);
 			return &major_info->dasd_device[devindex];
@@ -730,70 +885,105 @@
 	return NULL;
 }
 
+/*
+ * function: dasd_features_from_devno
+ * finds the device range corresponding to the devno
+ * supplied as argument in the major_info structures and returns
+ * the features set for it
+ */
+
+static int
+dasd_features_from_devno (int devno)
+{
+	dasd_range_t *temp;
+	int devindex = 0;
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave (&range_lock, flags);
+	list_for_each (l, &dasd_range_head.list) {
+		temp = list_entry (l, dasd_range_t, list);
+		if (devno >= temp->from && devno <= temp->to) {
+			spin_unlock_irqrestore (&range_lock, flags);
+			return temp->features;
+		}
+		devindex += temp->to - temp->from + 1;
+	}
+	spin_unlock_irqrestore (&range_lock, flags);
+	return -ENODEV;
+}
+
+
+
 /* SECTION: managing dasd disciplines */
 
 /* anchor and spinlock for list of disciplines */
-static dasd_discipline_t *dasd_disciplines;
+static struct list_head dasd_disc_head = LIST_HEAD_INIT(dasd_disc_head);
 static spinlock_t discipline_lock = SPIN_LOCK_UNLOCKED;
 
-/* 
- * function dasd_discipline_enq 
+/*
+ * function dasd_discipline_enq
  * chains the discpline given as argument to the head of disiplines
  * head chaining policy is required to allow module disciplines to
  * be preferred against those, who are statically linked
  */
-void
+static inline void
 dasd_discipline_enq (dasd_discipline_t * d)
 {
-	spin_lock (&discipline_lock);
-	d->next = dasd_disciplines;
-	dasd_disciplines = d;
-	spin_unlock (&discipline_lock);
+    list_add(&d->list, &dasd_disc_head);
 }
 
-/* 
- * function dasd_discipline_deq 
+/*
+ * function dasd_discipline_deq
  * removes the discipline given as argument from the list of disciplines
  */
-int
+static inline void
 dasd_discipline_deq (dasd_discipline_t * d)
 {
-	int rc = 0;
-	spin_lock (&discipline_lock);
-	if (dasd_disciplines == d) {
-		dasd_disciplines = dasd_disciplines->next;
-	} else {
-		dasd_discipline_t *b;
-		b = dasd_disciplines;
-		while (b && b->next != d)
-			b = b->next;
-		if (b != NULL) {
-			b->next = b->next->next;
-		} else {
-			rc = -ENOENT;
-		}
-	}
-	spin_unlock (&discipline_lock);
-	return rc;
+        list_del(&d->list);
+}
+
+void
+dasd_discipline_add (dasd_discipline_t * d)
+{
+        unsigned long flags;
+        MOD_INC_USE_COUNT;
+	spin_lock_irqsave (&discipline_lock,flags);
+        dasd_discipline_enq (d);
+	spin_unlock_irqrestore (&discipline_lock,flags);
+        dasd_enable_ranges (&dasd_range_head, d, DASD_STATE_ONLINE);
+}
+
+void dasd_discipline_del (dasd_discipline_t * d)
+{
+        unsigned long flags;
+	spin_lock_irqsave (&discipline_lock,flags);
+        dasd_disable_ranges(&dasd_range_head, d, DASD_STATE_DEL, 1);
+        dasd_discipline_deq (d);
+	spin_unlock_irqrestore (&discipline_lock,flags);
+        MOD_DEC_USE_COUNT;
 }
 
 static inline dasd_discipline_t *
-dasd_find_discipline (dasd_device_t * device)
+dasd_find_disc (dasd_device_t * device, dasd_discipline_t *d)
 {
-	dasd_discipline_t *temp;
-	for (temp = dasd_disciplines; temp != NULL; temp = temp->next) {
-		if (temp->id_check)
-			if (temp->id_check (&device->devinfo)) {
-				continue;
-                        }
-		if (temp->check_characteristics) {
-			if (temp->check_characteristics (device)) {
-				continue;
-                        }
-		}
-		break;
-	}
-	return temp;
+        dasd_discipline_t *t;
+        struct list_head *l = d ? &d->list : dasd_disc_head.next;
+        do {
+                t = list_entry(l,dasd_discipline_t,list);
+                if ( ( t->id_check == NULL ||
+                       t->id_check (&device->devinfo) == 0 ) &&
+                     ( t->check_characteristics == NULL ||
+                       t->check_characteristics (device) == 0 ) )
+                        break;
+                l = l->next;
+                if ( d || 
+                     l == &dasd_disc_head ) {
+                        t = NULL;
+                        break;
+                }
+         } while ( 1 );
+	return t;
 }
 
 /* SECTION: profiling stuff */
@@ -817,9 +1007,9 @@
 }
 
 /*
- * function dasd_profile_add 
+ * function dasd_profile_add
  * adds the profiling information from the cqr given as argument to the
- * global and device specific profiling information 
+ * global and device specific profiling information
  */
 void
 dasd_profile_add (ccw_req_t * cqr)
@@ -844,8 +1034,10 @@
 		memset (&device->profile, 0, sizeof (dasd_profile_info_t));
 	};
 
-        dasd_global_profile.dasd_io_reqs++;
-        device->profile.dasd_io_reqs++;
+	dasd_global_profile.dasd_io_reqs++;
+	device->profile.dasd_io_reqs++;
+	dasd_global_profile.dasd_io_sects+=sectors;
+	device->profile.dasd_io_sects+=sectors;
 	dasd_profile_add_counter (sectors, dasd_io_secs, device);
 	dasd_profile_add_counter (tottime, dasd_io_times, device);
 	dasd_profile_add_counter (tottimeps, dasd_io_timps, device);
@@ -855,54 +1047,168 @@
 	dasd_profile_add_counter (endtime, dasd_io_time3, device);
 }
 
-/* SECTION: (de)queueing of requests to channel program queues */
 
-/* 
- * function dasd_chanq_enq 
- * appends the cqr given as argument to the queue
- * has to be called with the queue lock (namely the s390_irq_lock) acquired
+/* SECTION: All the gendisk stuff */
+
+
+/* SECTION: Managing wrappers for ccwcache */
+
+/*
+ * function dasd_alloc_request
+ * tries to return space for a channel program of length cplength with
+ * additional data of size datasize.
+ * If the ccwcache cannot fulfill the request it tries the emergeny requests
+ * before giving up finally
+ * FIXME: initialization of ccw_req_t should be done by function of ccwcache
  */
-static inline void
-dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize, dasd_device_t* device)
 {
-	if (q->head != NULL) {
-		q->tail->next = cqr;
-	} else
-		q->head = cqr;
-	cqr->next = NULL;
-	q->tail = cqr;
-	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+	ccw_req_t *rv = NULL;
+	int i;
+	unsigned long flags;
+
+	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
+		return rv;
+	}
+	if ((((sizeof (ccw_req_t) + 7) & -8) +
+	     cplength * sizeof (ccw1_t) + datasize) > PAGE_SIZE) {
+		BUG ();
+		}
+        if (device->lowmem_cqr==NULL) {
+                DASD_MESSAGE (KERN_WARNING, device, "Low memory! Using emergency request %p",device->lowmem_ccws);
+                device->lowmem_cqr=device->lowmem_ccws;
+                rv = device->lowmem_ccws;
+		memset (rv, 0, PAGE_SIZE);
+		strncpy ((char *) (&rv->magic), magic, 4);
+		ASCEBC ((char *) (&rv->magic), 4);
+		rv->cplength = cplength;
+		rv->datasize = datasize;
+		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
+		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
+        } else {
+                DASD_MESSAGE (KERN_WARNING, device,"Refusing emergency mem for request NULL, already in use at %p.",device->lowmem_ccws);
+	}
+	return rv;
 }
 
-/* 
+/*
+ * function dasd_free_request
+ * returns a ccw_req_t to the appropriate cache or emergeny request line
+ */
+void
+dasd_free_request (ccw_req_t * request, dasd_device_t* device)
+{
+#ifdef CONFIG_ARCH_S390X
+    ccw1_t* ccw;
+    /* clear any idals used for chain */
+    ccw=request->cpaddr-1;
+    do {
+            ccw++;
+            if ((ccw->cda < (unsigned long) device->lowmem_idals) || (ccw->cda >= (unsigned long) device->lowmem_idals+PAGE_SIZE))
+                    clear_normalized_cda (ccw);
+            else {
+                    if (device->lowmem_idal_ptr != device->lowmem_idals)
+                            DASD_MESSAGE (KERN_WARNING, device, "Freeing emergency idals from request at %p.",request);
+                    device->lowmem_idal_ptr = device->lowmem_idals;
+                    device->lowmem_cqr=NULL;
+            }
+    } while ((ccw->flags & CCW_FLAG_CC) || (ccw->flags & CCW_FLAG_DC));
+#endif
+    if (request != device->lowmem_ccws) { /* compare to lowmem_ccws to protect usage of lowmem_cqr for IDAL only ! */
+		ccw_free_request (request);
+    } else {
+            DASD_MESSAGE (KERN_WARNING, device,  "Freeing emergency request at %p",request);
+            device->lowmem_cqr=NULL;
+	}
+}
+
+int
+dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device )
+{
+#ifdef CONFIG_ARCH_S390X
+	int nridaws;
+        int count = cp->count;
+        
+        if (set_normalized_cda (cp, address)!=-ENOMEM) {
+            return 0;
+        }
+
+        if ((device->lowmem_cqr!=NULL) && (device->lowmem_cqr!=request)) {
+            DASD_MESSAGE (KERN_WARNING, device, "Refusing emergency idals for request %p, memory is already in use for request %p",request,device->lowmem_cqr);
+            return -ENOMEM;
+        }
+        device->lowmem_cqr=request;
+        if (device->lowmem_idal_ptr == device->lowmem_idals) {
+            DASD_MESSAGE (KERN_WARNING,device, "Low memory! Using emergency IDALs for request %p.\n",request);
+        }
+        nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
+		   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
+	if ( device->lowmem_idal_ptr>=device->lowmem_idals + PAGE_SIZE ) {
+		/* Ouch! No Idals left for emergency request */
+		BUG();
+	}
+	cp->flags |= CCW_FLAG_IDA;
+	cp->cda = (__u32)(unsigned long)device->lowmem_idal_ptr;
+        do {
+		*((long*)device->lowmem_idal_ptr) = address;
+		address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
+		nridaws --;
+                device->lowmem_idal_ptr += sizeof(unsigned long);
+        } while ( nridaws > 0 );
+#else 
+        cp -> cda = address;
+#endif
+	return 0;
+}
+
+
+/* SECTION: (de)queueing of requests to channel program queues */
+
+/*
+ * function dasd_chanq_enq
+ * appends the cqr given as argument to the queue
+ * has to be called with the queue lock (namely the s390_irq_lock) acquired
+ */
+inline void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+	if (q->head != NULL) {
+		q->tail->next = cqr;
+	} else
+		q->head = cqr;
+	cqr->next = NULL;
+	q->tail = cqr;
+	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+}
+
+/*
  * function dasd_chanq_enq_head
  * chains the cqr given as argument to the queue head
  * has to be called with the queue lock (namely the s390_irq_lock) acquired
  */
-static inline void
+inline void
 dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	cqr->next = q->head;
 	q->head = cqr;
 	if (q->tail == NULL)
 		q->tail = cqr;
-	check_then_set (&cqr->status,
-		       CQR_STATUS_FILLED,
-		       CQR_STATUS_QUEUED);
+	check_then_set (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
 }
 
-/* 
+/*
  * function dasd_chanq_deq
  * dechains the cqr given as argument from the queue
  * has to be called with the queue lock (namely the s390_irq_lock) acquired
  */
-int
+inline void
 dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
 	ccw_req_t *prev;
 
 	if (cqr == NULL)
-                BUG ();
+		BUG ();
 
 	if (cqr == q->head) {
 		q->head = cqr->next;
@@ -914,138 +1220,82 @@
 		while (prev && prev->next != cqr)
 			prev = prev->next;
 		if (prev == NULL)
-			return -ENOENT;
+			return;
 		prev->next = cqr->next;
 		if (prev->next == NULL)
 			q->tail = prev;
 	}
 	cqr->next = NULL;
-	return 0;
 }
 
-/* SECTION: All the gendisk stuff */
+/* SECTION: Managing the device queues etc. */
 
-/* 
- * function dasd_partn_detect
- * calls the function in genhd, which is appropriate to setup a partitioned disk
+/*
+ * function dasd_start_IO
+ * attempts to start the IO and returns an appropriate return code
  */
-static void
-dasd_partn_detect (dasd_device_t * dev)
+int
+dasd_term_IO (ccw_req_t * cqr)
 {
-	major_info_t *major_info = dev->major_info;
-	struct gendisk *dd = &major_info->gendisk;
-	int minor = MINOR (dev->kdev);
-
-	register_disk (dd,
-		       MKDEV (dd->major, minor),
-		       1 << DASD_PARTN_BITS,
-		       &dasd_device_operations,
-		       (dev->sizes.blocks << dev->sizes.s2b_shift));
-}
-
-/* SECTION: Managing wrappers for ccwcache */
-
-/* array and spinlock of emergency requests */
-static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS];
-static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+	int rc = 0;
+	dasd_device_t *device = cqr->device;
+	int irq;
+        int retries = 0;
 
-/* 
- * function dasd_init_emergeny_req
- * allocates emergeny requests
- */
-static inline void __init
-dasd_init_emergency_req (void)
-{
-	int i;
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		dasd_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL);
-		memset (dasd_emergency_req[i], 0, PAGE_SIZE);
+	if (!cqr) {
+		BUG ();
 	}
-}
-
-/* 
- * function dasd_cleanup_emergeny_req
- * tries to free emergeny requests skipping those, which are currently in use
- */
-static inline void
-dasd_cleanup_emergency_req (void)
-{
-	int i;
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		if (dasd_emergency_req[i])
-			free_page ((long) (dasd_emergency_req[i]));
-		else
-			printk (KERN_WARNING PRINTK_HEADER
-				"losing page for emergency request in use\n");
+	irq = device->devinfo.irq;
+	if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			      " ccw_req_t 0x%08X magic doesn't match"
+			      " discipline 0x%08X\n",
+			      cqr->magic,
+			      *(unsigned int *) device->discipline->name);
+		return -EINVAL;
 	}
-}
-
-/* 
- * function dasd_alloc_request
- * tries to return space for a channel program of length cplength with
- * additional data of size datasize. 
- * If the ccwcache cannot fulfill the request it tries the emergeny requests
- * before giving up finally
- * FIXME: initialization of ccw_req_t should be done by function of ccwcache
- */
-ccw_req_t *
-dasd_alloc_request (char *magic, int cplength, int datasize)
-{
-	ccw_req_t *rv = NULL;
-	int i;
-	unsigned long flags;
 
-	if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) {
-		return rv;
-	}
-	if ((((sizeof (ccw_req_t) + 7) & -8) + 
-             cplength*sizeof(ccw1_t) + datasize) > PAGE_SIZE) {
-            BUG();
+        while ( retries < 5 ) {
+            if ( retries < 2 )
+                rc = halt_IO(irq, (long)cqr, 
+                             cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+            else
+                rc = clear_IO(irq, (long)cqr, 
+                              cqr->options | DOIO_WAIT_FOR_INTERRUPT);
+            switch (rc) {
+            case 0:
+		break;
+            case -ENODEV:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device gone, retry\n");
+		break;
+            case -EIO:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "I/O error, retry\n");
+		break;
+            case -EBUSY:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device busy, retry later\n");
+		break;
+            default:
+		DASD_MESSAGE (KERN_ERR, device,
+			      "line %d unknown RC=%d, please report"
+			      " to linux390@de.ibm.com\n", __LINE__, rc);
+		BUG ();
+		break;
+            }
+            if (rc == 0) {
+		check_then_set (&cqr->status,
+				CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+                asm volatile ("STCK %0":"=m" (cqr->stopclk));
+                break;
+            }
+            retries ++;
         }
-	spin_lock_irqsave (&dasd_emergency_req_lock, flags);
-	for (i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
-		if (dasd_emergency_req[i] != NULL) {
-			rv = dasd_emergency_req[i];
-			dasd_emergency_req[i] = NULL;
-			break;
-		}
-	}
-	spin_unlock_irqrestore (&dasd_emergency_req_lock, flags);
-	if (rv) {
-		memset (rv, 0, PAGE_SIZE);
-		rv->cache = (kmem_cache_t *) (dasd_emergency_req + i);
-		strncpy ((char *) (&rv->magic), magic, 4);
-		ASCEBC ((char *) (&rv->magic), 4);
-		rv->cplength = cplength;
-		rv->datasize = datasize;
-		rv->data = (void *) ((long) rv + PAGE_SIZE - datasize);
-		rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t));
-	} else {
-		panic ("No way to fulfill request for I/O request\n");
-	}
-	return rv;
+	return rc;
 }
 
-/* 
- * function dasd_free_request
- * returns a ccw_req_t to the appropriate cache or emergeny request line
- */
-void
-dasd_free_request (ccw_req_t * request)
-{
-	if ((request->cache >= (kmem_cache_t *) dasd_emergency_req) &&
-	    (request->cache < (kmem_cache_t *) (dasd_emergency_req +
-						DASD_EMERGENCY_REQUESTS))) {
-		*((ccw_req_t **) (request->cache)) = request;
-	} else {
-		ccw_free_request (request);
-	}
-}			
-
-/* SECTION: Managing the device queues etc. */
-
-
-/* 
+/*
  * function dasd_start_IO
  * attempts to start the IO and returns an appropriate return code
  */
@@ -1055,7 +1305,7 @@
 	int rc = 0;
 	dasd_device_t *device = cqr->device;
 	int irq;
-        unsigned long long now;
+	unsigned long long now;
 
 	if (!cqr) {
 		BUG ();
@@ -1070,75 +1320,80 @@
 		return -EINVAL;
 	}
 
-        asm volatile ("STCK %0":"=m" (now));
-        rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
-        switch (rc) {
-        case 0:
-            break;
-        case -ENODEV:
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
-            break;
-        case -EIO:
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
-            break;
-        case -EBUSY:
-                DASD_MESSAGE (KERN_WARNING, device,"%s",
-                              "device busy, retry later\n");
-                break;
-        default:
-                DASD_MESSAGE (KERN_ERR, device,
-                              "line %d unknown RC=%d, please report"
-                              " to linux390@de.ibm.com\n",
-                              __LINE__, rc);
-                BUG();
-            break;
-        }
+	asm volatile ("STCK %0":"=m" (now));
+	rc = do_IO (irq, cqr->cpaddr, (long) cqr, cqr->lpm, cqr->options);
+	switch (rc) {
+	case 0:
+		break;
+	case -ENODEV:
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+		break;
+	case -EIO:
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+		break;
+	case -EBUSY:
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "device busy, retry later\n");
+		break;
+	default:
+		DASD_MESSAGE (KERN_ERR, device,
+			      "line %d unknown RC=%d, please report"
+			      " to linux390@de.ibm.com\n", __LINE__, rc);
+		BUG ();
+		break;
+	}
 	if (rc == 0) {
-                check_then_set (&cqr->status, 
-                               CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-                cqr->startclk = now;
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
+		cqr->startclk = now;
 	}
 	return rc;
 }
 
-/* 
- * function sleep_on_req
+/*
+ * function dasd_sleep_on_req
  * attempts to start the IO and waits for completion
  * FIXME: replace handmade sleeping by wait_event
  */
-static int
-sleep_on_req (ccw_req_t * req)
+int
+dasd_sleep_on_req (ccw_req_t * req)
 {
 	unsigned long flags;
 	int cs;
 	int rc = 0;
 	dasd_device_t *device = (dasd_device_t *) req->device;
 
+        if ( signal_pending(current) ) {
+                return -ERESTARTSYS;
+        }
 	s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
 	dasd_chanq_enq (&device->queue, req);
-        /* let the bh start the request to keep them in order */
-	dasd_schedule_bh (device); 
-        
+	/* let the bh start the request to keep them in order */
+	dasd_schedule_bh (device);
 	do {
 		s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-                wait_event (device->wait_q,
-                            (((cs=req->status)==CQR_STATUS_DONE)||
-                            (cs==CQR_STATUS_FAILED)));
+		wait_event ( device->wait_q,
+			     (((cs = req->status) == CQR_STATUS_DONE) ||
+			     (cs == CQR_STATUS_FAILED) ||
+                             signal_pending(current)));
 		s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
-		cs = req->status;
+                if ( signal_pending(current) ) {
+                        rc = -ERESTARTSYS;
+		     	if (req->status == CQR_STATUS_IN_IO ) 
+                        	device->discipline->term_IO(req);
+                        break;
+                } else if ( req->status == CQR_STATUS_FAILED) {
+                        rc = -EIO;
+                        break;
+                }
 	} while (cs != CQR_STATUS_DONE && cs != CQR_STATUS_FAILED);
-
 	s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
-	if (cs == CQR_STATUS_FAILED) {
-		rc = -EIO;
-	}
 	return rc;
+}				/* end dasd_sleep_on_req */
 
-}				/* end sleep_on_req */
-
-/* 
+/*
  * function dasd_end_request
  * posts the buffer_cache about a finalized request
  * FIXME: for requests splitted to serveral cqrs
@@ -1146,7 +1401,8 @@
 static inline void
 dasd_end_request (struct request *req, int uptodate)
 {
-	while (end_that_request_first (req, uptodate, DASD_NAME)) {}
+	while (end_that_request_first (req, uptodate, DASD_NAME)) {
+	}
 #ifndef DEVICE_NO_RANDOM
 	add_blkdev_randomness (MAJOR (req->rq_dev));
 #endif
@@ -1154,7 +1410,7 @@
 	return;
 }
 
-/* 
+/*
  * function dasd_get_queue
  * returns the queue corresponding to a device behind a kdev
  */
@@ -1162,10 +1418,10 @@
 dasd_get_queue (kdev_t kdev)
 {
 	dasd_device_t *device = dasd_device_from_kdev (kdev);
-	return &device->request_queue;
+	return device->request_queue;
 }
 
-/* 
+/*
  * function dasd_check_expire_time
  * check the request given as argument for expiration
  * and returns 0 if not yet expired, nonzero else
@@ -1177,18 +1433,17 @@
 	int rc = 0;
 
 	asm volatile ("STCK %0":"=m" (now));
-	if ( cqr->expires && 
-             cqr->expires + cqr->startclk <  now) {
-		DASD_MESSAGE (KERN_ERR, ((dasd_device_t*)cqr->device),
+	if (cqr->expires && cqr->expires + cqr->startclk < now) {
+		DASD_MESSAGE (KERN_ERR, ((dasd_device_t *) cqr->device),
 			      "IO timeout 0x%08lx%08lx usecs in req %p\n",
-			      (long) (cqr->expires >> 44), 
-                              (long) (cqr->expires >> 12), cqr);
-		cqr->expires <<=1;
+			      (long) (cqr->expires >> 44),
+			      (long) (cqr->expires >> 12), cqr);
+		cqr->expires <<= 1;
 	}
 	return rc;
 }
 
-/* 
+/*
  * function dasd_finalize_request
  * implemets the actions to perform, when a request is finally finished
  * namely in status CQR_STATUS_DONE || CQR_STATUS_FAILED
@@ -1196,190 +1451,226 @@
 static inline void
 dasd_finalize_request (ccw_req_t * cqr)
 {
-        dasd_device_t *device = cqr->device;
-        
+	dasd_device_t *device = cqr->device;
+
 	asm volatile ("STCK %0":"=m" (cqr->endclk));
 	if (cqr->req) {
-                dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
-                dasd_profile_add (cqr);
+		dasd_profile_add (cqr);
+		dasd_end_request (cqr->req, (cqr->status == CQR_STATUS_DONE));
 		/* free request if nobody is waiting on it */
-		dasd_free_request (cqr);
+		dasd_free_request (cqr, cqr->device);
 	} else {
-		/* during format we don't have the request structure */
+                if ( cqr == device->init_cqr && /* bring late devices online */
+                     device->level <= DASD_STATE_ONLINE ) { 
+                        device->timer.function = dasd_enable_single_device; 
+                        device->timer.data     = (unsigned long) device;
+                        device->timer.expires  = jiffies;
+                        add_timer(&device->timer);
+                }
 		/* notify sleeping task about finished postprocessing */
 		wake_up (&device->wait_q);
+                
 	}
 	return;
 }
 
-/* 
+/*
  * function dasd_process_queues
  * transfers the requests on the queue given as argument to the chanq
  * if possible, the request ist started on a fastpath
  */
 static void
-dasd_process_queues (dasd_device_t *device)
+dasd_process_queues (dasd_device_t * device)
 {
-        unsigned long flags;
-        struct request *req;
-        request_queue_t * queue = &device->request_queue;
+	unsigned long flags;
+	struct request *req;
+	request_queue_t *queue = device->request_queue;
 	dasd_chanq_t *qp = &device->queue;
-        int irq = device -> devinfo.irq;
-        ccw_req_t *final_requests= NULL;
-        static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
-        int chanq_max_size = DASD_CHANQ_MAX_SIZE;
-        ccw_req_t * cqr=NULL,*temp;
-        dasd_erp_postaction_fn_t erp_postaction;
-
-        s390irq_spin_lock_irqsave (irq, flags);
-        /* First we dechain the requests, processed with completed status */
-        while ( qp -> head && 
-                ((qp -> head -> status == CQR_STATUS_DONE) || 
-                 (qp -> head -> status == CQR_STATUS_FAILED) ||
-		 (qp -> head -> status == CQR_STATUS_ERROR) ) ) {
+	int irq = device->devinfo.irq;
+	ccw_req_t *final_requests = NULL;
+	static int chanq_min_size = DASD_MIN_SIZE_FOR_QUEUE;
+	int chanq_max_size = DASD_CHANQ_MAX_SIZE;
+	ccw_req_t *cqr = NULL, *temp;
+	dasd_erp_postaction_fn_t erp_postaction;
+
+
+	s390irq_spin_lock_irqsave (irq, flags);
+
+	/* First we dechain the requests, processed with completed status */
+	while (qp->head &&
+	       ((qp->head->status == CQR_STATUS_DONE  ) ||
+		(qp->head->status == CQR_STATUS_FAILED) ||
+		(qp->head->status == CQR_STATUS_ERROR )   )) {
+
 		dasd_erp_action_fn_t erp_action;
-		ccw_req_t *erp_cqr = NULL;
+		ccw_req_t            *erp_cqr = NULL;
+
 		/*  preprocess requests with CQR_STATUS_ERROR */
-		if (qp -> head -> status == CQR_STATUS_ERROR) {
-			if ((qp -> head -> dstat -> flag & DEVSTAT_HALT_FUNCTION) ||
-			    (qp->head->retries-- == 0 ) ||
-			    (device->discipline->erp_action==NULL) ||
-			    ((erp_action=device->discipline->erp_action(qp->head))==NULL)||
-			    ((erp_cqr = erp_action(qp->head))== NULL)) {
-				check_then_set (&qp->head->status,
+		if (qp->head->status == CQR_STATUS_ERROR) {
+
+                        qp->head->retries--; 
+
+			if (qp->head->dstat->flag & DEVSTAT_HALT_FUNCTION) {
+
+                                check_then_set (&qp->head->status,
                                                 CQR_STATUS_ERROR,
                                                 CQR_STATUS_FAILED);
-                                continue;
+
+                        } else if ((device->discipline->erp_action == NULL                          ) ||
+                                   ((erp_action = device->discipline->erp_action (qp->head)) == NULL)   ) {
+                                
+				erp_cqr = dasd_default_erp_action (qp->head);
+
+			} else { /* call discipline ERP action */
+
+                                erp_cqr = erp_action (qp->head);
+                        }
+                        continue;
+
+		} else if (qp->head->refers) {	/* we deal with a finished ERP */
+
+			if (qp->head->status == CQR_STATUS_DONE) {
+
+                                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                                              "ERP successful");
 			} else {
-                                if (erp_cqr != qp->head){
-                                        dasd_chanq_enq_head (qp, erp_cqr);
-                                }
-				/* chain of completed requests is now broken */
-				continue; 
+
+                                DASD_MESSAGE (KERN_ERR, device, "%s",
+                                              "ERP unsuccessful");
 			}
-		} else if ( qp -> head -> refers ) { /* we deal with an ERP */
-                        char *uptodatestr;
-                        if ( qp -> head -> status == CQR_STATUS_DONE) {
-                                uptodatestr = "ERP successful";
-                        } else {
-                                uptodatestr = "ERP unsuccessful";
-                        }
-                        
-                        if (device->discipline->erp_postaction == NULL ||
-                            ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)) {
-                                /* 
-                                                         * maybe we shoud set it to FAILED, 
-                                                         * because we are very paranoid ;) 
-                                                         */
-                                erp_postaction = default_erp_postaction;
+
+			if ((device->discipline->erp_postaction == NULL                              )||
+			    ((erp_postaction = device->discipline->erp_postaction (qp->head)) == NULL)  ) {
+
+                                dasd_default_erp_postaction (qp->head);
+
+			} else {  /* call ERP postaction of discipline */
+
+                                erp_postaction (qp->head);
                         }
-                        DASD_MESSAGE (KERN_INFO, device,
-                                      "%s: postaction [<%p>]\n",
-                                      uptodatestr, erp_postaction);
-                        erp_postaction (qp->head);
-                        continue;
-                }
-                
+
+			continue;
+		}
+
 		/* dechain request now */
-                if ( final_requests == NULL )
-                        final_requests = qp -> head;
-                cqr = qp -> head;
-                qp -> head = qp -> head -> next;
+		if (final_requests == NULL)
+			final_requests = qp->head;
+
+		cqr      = qp->head;
+		qp->head = qp->head->next;
+
 		if (qp->head == NULL)
 			qp->tail = NULL;
-        }
-        if ( cqr )
-            cqr -> next = NULL;
-        /* Now we try to fetch requests from the request queue */
-        for (temp = cqr; temp != NULL ;temp=temp-> next )
-                if ( temp ->status == CQR_STATUS_QUEUED)
-                        chanq_max_size --;
-	while ( (! queue->plugged) &&
-		(! list_empty(&queue->queue_head)) && 
-                (req=dasd_next_request(queue)) != NULL) {
-                /* queue empty or certain critera fulfilled -> transfer */
-                if ( qp -> head == NULL ||
-                     chanq_max_size > 0 ||
-                     (req->nr_sectors >= chanq_min_size)) {
-                        ccw_req_t *cqr;
-                        /* relocate request according to partition table */
-                        req->sector += device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
-                        cqr = device->discipline->build_cp_from_req (device, req);
-                        if (cqr == NULL) {
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "CCW creation failed on request %p\n", req);
-				/* revert relocation of request */
-                                req->sector -= device->major_info->gendisk.part[MINOR (req->rq_dev)].start_sect;
-                                break; /* terminate request queue loop */
-                                
-                        } 
+
+	} /* end while over completed requests */
+
+	if (cqr)
+		cqr->next = NULL;
+	/* Now clean the requests with final status */
+	while (final_requests) { 
+		temp = final_requests;
+		final_requests = temp->next;
+		dasd_finalize_request (temp);
+	}
+	/* Now we try to fetch requests from the request queue */
+	for (temp = cqr; temp != NULL; temp = temp->next)
+		if (temp->status == CQR_STATUS_QUEUED)
+			chanq_max_size--;
+	while ((atomic_read(&device->plugged) == 0) &&
+               (!queue->plugged) &&
+	       (!list_empty (&queue->queue_head)) &&
+	       (req = dasd_next_request (queue)) != NULL) {
+		/* queue empty or certain critera fulfilled -> transfer */
+		if (qp->head == NULL ||
+		    chanq_max_size > 0 || (req->nr_sectors >= chanq_min_size)) {
+			ccw_req_t *cqr = NULL;
+                        if (is_read_only(device->kdev) && req->cmd == WRITE) {
+                            DASD_MESSAGE (KERN_WARNING, device,
+                                          "rejecting write request %p\n",
+                                          req);
+                                dasd_end_request (req, 0);
+                                dasd_dequeue_request (queue,req);
+                        } else {
+                            /* relocate request according to partition table */
+                            req->sector +=
+                                device->major_info->gendisk.
+                                part[MINOR (req->rq_dev)].start_sect;
+                            cqr = device->discipline->build_cp_from_req (device, req);
+                            if (cqr == NULL) {
+				    DASD_MESSAGE (KERN_WARNING, device,
+                                                  "CCW creation failed on request %p\n",
+                                                  req);
+                                    /* revert relocation of request */
+                                    req->sector -=
+                                        device->major_info->gendisk.
+                                        part[MINOR (req->rq_dev)].start_sect;
+                                    break;	/* terminate request queue loop */
+                                    
+                            }
 #ifdef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
-                        chanq_min_size = (chanq_min_size + req->nr_sectors)>>1; 
-#endif /* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
-                        dasd_dequeue_request(queue,req);
-			dasd_chanq_enq (qp, cqr);
-                } else { /* queue not empty OR criteria not met */
-                        break; /* terminate request queue loop */
-                }
-        }
-        /* we process the requests with non-final status */
-        if ( qp -> head ) {
-                switch ( qp->head->status ) {
-                case CQR_STATUS_QUEUED:
-                        /* try to start the first I/O that can be started */
-                        if ( device->discipline->start_IO (qp->head) != 0) 
-                                BUG();
-                        break;
-                case CQR_STATUS_IN_IO:
-                        /* Check, if to invoke the missing interrupt handler */
-                        if ( dasd_check_expire_time (qp->head) ) {
-                                /* to be filled with MIH */
+                            chanq_min_size =
+                                (chanq_min_size + req->nr_sectors) >> 1;
+#endif				/* CONFIG_DYNAMIC_QUEUE_MIN_SIZE */
+                            dasd_dequeue_request (queue, req);
+                            dasd_chanq_enq (qp, cqr);
                         }
-                        break;
+		} else {	/* queue not empty OR criteria not met */
+			break;	/* terminate request queue loop */
+		}
+	}
+	/* we process the requests with non-final status */
+	if (qp->head) {
+		switch (qp->head->status) {
+		case CQR_STATUS_QUEUED:
+			/* try to start the first I/O that can be started */
+			if (device->discipline->start_IO == NULL)
+				BUG ();
+                        device->discipline->start_IO(qp->head);
+			break;
+		case CQR_STATUS_IN_IO:
+			/* Check, if to invoke the missing interrupt handler */
+			if (dasd_check_expire_time (qp->head)) {
+				/* to be filled with MIH */
+			}
+			break;
 
-                case CQR_STATUS_PENDING:
-                        /* just wait */
-                        break;
-                default: 
-                        BUG();
-                }
-        }
-        /* Now clean the requests with final status */
-        while ( final_requests ) {
-                cqr = final_requests;
-                final_requests = cqr-> next;
-                dasd_finalize_request( cqr );
-        }
-        s390irq_spin_unlock_irqrestore (irq, flags);
+		case CQR_STATUS_PENDING:
+			/* just wait */
+			break;
+		default:
+			BUG ();
+		}
+	}
+	s390irq_spin_unlock_irqrestore (irq, flags);
 }
 
-/* 
+/*
  * function dasd_run_bh
  * acquires the locks needed and then runs the bh
  */
 static void
-dasd_run_bh (dasd_device_t *device)
+dasd_run_bh (dasd_device_t * device)
 {
 	long flags;
 	spin_lock_irqsave (&io_request_lock, flags);
-	atomic_set(&device->bh_scheduled,0);
+	atomic_set (&device->bh_scheduled, 0);
 	dasd_process_queues (device);
 	spin_unlock_irqrestore (&io_request_lock, flags);
 }
 
-/* 
+/*
  * function dasd_schedule_bh
  * schedules the request_fn to run with next run_bh cycle
  */
 void
-dasd_schedule_bh (dasd_device_t *device)
+dasd_schedule_bh (dasd_device_t * device)
 {
 	/* Protect against rescheduling, when already running */
-        if (atomic_compare_and_swap(0,1,&device->bh_scheduled)) {
-                return;
-        }
+	if (atomic_compare_and_swap (0, 1, &device->bh_scheduled)) {
+		return;
+	}
 
-	INIT_LIST_HEAD(&device->bh_tq.list);
+	INIT_LIST_HEAD (&device->bh_tq.list);
 	device->bh_tq.sync = 0;
 	device->bh_tq.routine = (void *) (void *) dasd_run_bh;
 	device->bh_tq.data = device;
@@ -1389,46 +1680,24 @@
 	return;
 }
 
-/* 
+/*
  * function do_dasd_request
- * is called from ll_rw_blk.c and provides the caller of 
+ * is called from ll_rw_blk.c and provides the caller of
  * dasd_process_queues
  */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static void
 do_dasd_request (request_queue_t * queue)
 {
-        dasd_device_t *device = (dasd_device_t *)
-                ((long)queue-(long)offsetof (dasd_device_t, request_queue));
+        dasd_device_t *device = (dasd_device_t *)queue->queuedata;
 	dasd_process_queues (device);
 }
-#else
-static void
-do_dasd_request (void)
-{
-	major_info_t *major_info;
-	dasd_device_t *device;
-	int i;
-
-	for (major_info = dasd_major_info;
-	     major_info != NULL;
-	     major_info = major_info->next) {
-		for (i = 0; i < DASD_PER_MAJOR; i++) {
-			device = major_info->dasd_device[i];
-			if (!device)
-				continue;	/* remove indentation level */
-			dasd_process_queues (device);
-		}
-	}
-}
-#endif				/* LINUX_IS_24 */
 
 /*
- * DASD_HANDLE_STATE_CHANGE_PENDING 
+ * DASD_HANDLE_STATE_CHANGE_PENDING
  *
  * DESCRIPTION
  *   Handles the state change pending interrupt.
- *   Search for the device related request queue and check if the first 
+ *   Search for the device related request queue and check if the first
  *   cqr in queue in in status 'CQR_STATUE_PENDING'.
  *   If so the status is set to 'CQR_STATUS_QUEUED' to reactivate
  *   the device.
@@ -1436,43 +1705,42 @@
  *  PARAMETER
  *   stat               device status of state change pending interrupt.
  */
-void 
-dasd_handle_state_change_pending (devstat_t *stat)
+void
+dasd_handle_state_change_pending (devstat_t * stat)
 {
-        dasd_device_t **device_addr;
-        ccw_req_t     *cqr;
+	dasd_device_t **device_addr;
+	ccw_req_t *cqr;
 
 	device_addr = dasd_device_from_devno (stat->devno);
 
-        if (device_addr == NULL) {
-		printk (KERN_INFO PRINTK_HEADER
-                        "unable to find device for state change pending "
-                        "interrupt: devno%04X\n",
-                        stat->devno);
-        } else {
-                /* re-activate first request in queue */
-                cqr = (*device_addr)->queue.head;
+	if (device_addr == NULL) {
 
-                if (cqr->status == CQR_STATUS_PENDING) {
+		printk (KERN_DEBUG PRINTK_HEADER
+			"unable to find device for state change pending "
+			"interrupt: devno%04X\n", stat->devno);
+	} else {
+		/* re-activate first request in queue */
+		cqr = (*device_addr)->queue.head;
 
-                        DASD_MESSAGE (KERN_INFO, (*device_addr),
-                                      "%s",
-                                      "device request queue restarted by "
-                                      "state change pending interrupt\n");
+		if (cqr->status == CQR_STATUS_PENDING) {
 
-                        del_timer(&(*device_addr)->timer);
+			DASD_MESSAGE (KERN_DEBUG, (*device_addr),
+				      "%s",
+				      "device request queue restarted by "
+				      "state change pending interrupt\n");
 
-                        check_then_set(&cqr->status, 
-                                       CQR_STATUS_PENDING, 
-                                       CQR_STATUS_QUEUED);
+			del_timer (&(*device_addr)->timer);
 
-                        dasd_schedule_bh(*device_addr);
+			check_then_set (&cqr->status,
+					CQR_STATUS_PENDING, CQR_STATUS_QUEUED);
 
-                }
-        }
-} /* end dasd_handle_state_change_pending */
+			dasd_schedule_bh (*device_addr);
 
-/* 
+		}
+	}
+}				/* end dasd_handle_state_change_pending */
+
+/*
  * function dasd_int_handler
  * is the DASD driver's default interrupt handler for SSCH-IO
  */
@@ -1480,16 +1748,14 @@
 dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
 	int ip;
-        int devno;
 	ccw_req_t *cqr;
 	dasd_device_t *device;
         unsigned long long now;
-#ifdef ERP_DEBUG
-	static int counter = 0;
-#endif
 	dasd_era_t era = dasd_era_none; /* default is everything is okay */
 	devstat_t *stat = (devstat_t *)ds;
 
+        DASD_DRIVER_DEBUG_EVENT (4, dasd_int_handler,
+                                 "Interrupt: IRQ 0x%x",irq);
         asm volatile ("STCK %0":"=m" (now));
         if (stat == NULL) {
                 BUG();
@@ -1499,145 +1765,148 @@
         if (stat->dstat & (DEV_STAT_ATTENTION | 
                            DEV_STAT_DEV_END   |
                            DEV_STAT_UNIT_EXCEP )) {
-
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "State change Interrupt: %04X",
+                                         stat->devno);
                 dasd_handle_state_change_pending (stat);
                 //return; /* TBD */
         }
 
 	ip = stat->intparm;
 	if (!ip) {		/* no intparm: unsolicited interrupt */
-		printk (KERN_INFO PRINTK_HEADER
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "Unsolicited Interrupt: %04X",
+                                         stat->devno);
+		printk (KERN_DEBUG PRINTK_HEADER
                         "unsolicited interrupt: irq0x%x devno%04X\n",
                         irq,stat->devno);
 		return;
 	}
 	if (ip & 0x80000001) {
-		printk (KERN_INFO PRINTK_HEADER
+                DASD_DRIVER_DEBUG_EVENT (2, dasd_int_handler,
+                                         "spurious Interrupt: %04X",
+                                         stat->devno);
+		printk (KERN_DEBUG PRINTK_HEADER
                         "spurious interrupt: irq0x%x devno%04X, parm %08x\n",
                         irq,stat->devno,ip);
 		return;
 	}
 	cqr = (ccw_req_t *)(long)ip;
 	device = (dasd_device_t *) cqr->device;
-	if (device == NULL || device != ds-offsetof(dasd_device_t,dev_status)) {
+	if (device == NULL || 
+            device != ds-offsetof(dasd_device_t,dev_status)) {
                 BUG();
 	}
-	devno = device->devinfo.devno;
 	if (device->devinfo.irq != irq) {
                 BUG();
 	}
 	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
                 BUG();
 	}
-#ifdef ERP_DEBUG
-                if ((++counter % 937 >= 0) &&
-                    (  counter % 937 <= 10) &&
-                    (  counter < 5000    ) &&
-                    (  counter > 2000    )   ){
-                        static int fake_count = 0;
-                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
-                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from; cntr=%i / %02X\n",counter,++fake_count);
-                        printk ( KERN_INFO PRINTK_HEADER "***********************************************\n");
+#ifdef ERP_FAKE
+        {
+                static int counter    = 0;
+                static int fake_count = 0;
+
+                if ((++counter % 937 >=   0) &&
+                    (  counter % 937 <=  10) && 
+                    (  counter       < 5000) && 
+                    (  counter       > 2000)   ) {
+
+                        char *sense = stat->ii.sense.data;
+                        
+                        printk (KERN_INFO PRINTK_HEADER
+                                "***********************************************\n");
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Faking I/O error to recover from; cntr=%i / %02X\n",
+                                counter, ++fake_count);
+                        printk (KERN_INFO PRINTK_HEADER
+                                "***********************************************\n");
+
                         era = dasd_era_recover;
-                        stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+                        stat->flag  |= DEVSTAT_FLAG_SENSE_AVAIL;
                         stat->dstat |= 0x02;
-// sense 32
-                        {
-                                char *sense = stat->ii.sense.data;
-                                sense [25] = 0x1D;
-                                sense [27] = 0x00;
-                                //sense [25] = (fake_count % 256); //0x1B;
-                                //sense [27] = 0x00;
-                        }
-// sense 24
-//                        {
-//                                char *sense = stat->ii.sense.data;
-//                                sense [0] = (counter % 0xFF); //0x1B;
-//                                sense [1] = ((counter * 7) % 0xFF); //0x1B;
-//                                sense [2] = (fake_count % 0xFF); //0x1B;
-//                                sense [27] = 0x80;
-//                        }
-
-/*
-                memset(stat->ii.sense.data,0,32);
-                stat->ii.sense.data[2] = 0x06;
-                stat->ii.sense.data[4] = 0x04;
-                stat->ii.sense.data[5] = 0x60;
-                stat->ii.sense.data[6] = 0x41;
-                stat->ii.sense.data[8] = 0xff;
-                stat->ii.sense.data[9] = 0xff;
-                stat->ii.sense.data[15] = 0x05;
-                stat->ii.sense.data[16] = 0x21;
-                stat->ii.sense.data[18] = 0x60;
-                stat->ii.sense.data[19] = 0x3b;
-                stat->ii.sense.data[20] = 0x24;
-                stat->ii.sense.data[21] = 0x61;
-                stat->ii.sense.data[22] = 0x65;
-                stat->ii.sense.data[23] = 0x03;
-                stat->ii.sense.data[24] = 0x04;
-                stat->ii.sense.data[25] = 0x10;
-                stat->ii.sense.data[26] = 0x4e;
-*/
-        }
-#endif
-        /* first of all lets try to find out the appropriate era_action */
-        if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
-             stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END) ) {
-                /* anything abnormal ? */
-                if ( device->discipline->examine_error == NULL ||
-                     stat->flag & DEVSTAT_HALT_FUNCTION ) {
-                        era = dasd_era_fatal;
-                } else {
-                        era = device->discipline->examine_error (cqr, stat);
+                        memset(sense,0,32);
+
+                        /* 32 byte sense (byte 27 bit 1 = 0)*/
+                        sense[25] = 0x1D;
+//                        sense [25] = (fake_count % 256); //0x1B;
+
+                        /* 24 byte sense (byte 27 bit 1 = 1)*/
+//                        sense [0] = (counter % 0xFF); //0x1B;
+//                        sense [1] = ((counter * 7) % 0xFF); //0x1B;
+//                        sense [2] = (fake_count % 0xFF); //0x1B;
+//                        sense [27] = 0x80;
                 }
         }
+#endif /* ERP_FAKE */
+        /* first of all lets try to find out the appropriate era_action */
+        DASD_DEVICE_DEBUG_EVENT (4, device," Int: CS/DS 0x%04X",
+                                 ((stat->cstat<<8)|stat->dstat));
+	/* first of all lets try to find out the appropriate era_action */
+	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ||
+	    stat->dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
+		/* anything abnormal ? */
+		if (device->discipline->examine_error == NULL ||
+		    stat->flag & DEVSTAT_HALT_FUNCTION) {
+			era = dasd_era_fatal;
+		} else {
+			era = device->discipline->examine_error (cqr, stat);
+		}
+                DASD_DRIVER_DEBUG_EVENT (1, dasd_int_handler," era_code %d",
+                                         era);
+	}
         if ( era == dasd_era_none ) {
-		if (device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-			device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED;
                 check_then_set(&cqr->status, 
                                CQR_STATUS_IN_IO, CQR_STATUS_DONE);
                 cqr->stopclk=now;
-                cqr=cqr->next;
 		/* start the next queued request if possible -> fast_io */
-                if (cqr->status == CQR_STATUS_QUEUED) {
-                        if (device->discipline->start_IO (cqr) != 0) {
+                if (cqr->next &&
+                    cqr->next->status == CQR_STATUS_QUEUED) {
+                        if (device->discipline->start_IO (cqr->next) != 0) {
                                 printk (KERN_WARNING PRINTK_HEADER
                                         "Interrupt fastpath failed!\n");
                         } 
                 }
         } else { /* error */
-                if (cqr->dstat == NULL)
-                        cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
-                if (cqr->dstat) {
-                        memcpy (cqr->dstat, stat, sizeof (devstat_t));
-                } else {
-                        PRINT_ERR ("no memory for dstat...ignoring\n");
-                }
-                /* dump sense data */
-                if (device->discipline &&
-                    device->discipline->dump_sense) {
-                        char *errmsg = device->discipline->dump_sense (device, cqr);
-                        if (errmsg != NULL) {
-                                printk ("Sense data:\n%s", errmsg);
-                                free_page ((unsigned long) errmsg);
-                        } else {
-                                printk (KERN_WARNING PRINTK_HEADER
-                                        "No memory to dump error message\n");
-                        }
-                }
-                switch(era) {
-                case dasd_era_fatal:
-                        check_then_set (&cqr->status,CQR_STATUS_IN_IO,
-                                        CQR_STATUS_FAILED);
-                        break;
-                case dasd_era_recover:
-                        check_then_set (&cqr->status,CQR_STATUS_IN_IO,
-                                        CQR_STATUS_ERROR);
-                        break;
-                default:
-                        BUG();
-                }
-        }                
+		if (cqr->dstat == NULL)
+			cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
+		if (cqr->dstat) {
+			memcpy (cqr->dstat, stat, sizeof (devstat_t));
+		} else {
+			PRINT_ERR ("no memory for dstat...ignoring\n");
+		}
+
+#ifdef ERP_DEBUG
+		/* dump sense data */
+		if (device->discipline            && 
+                    device->discipline->dump_sense  ) {
+
+                        device->discipline->dump_sense (device, 
+                                                        cqr);
+		}
+#endif
+
+		switch (era) {
+		case dasd_era_fatal:
+			check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+					CQR_STATUS_FAILED);
+			break;
+		case dasd_era_recover:
+			check_then_set (&cqr->status, CQR_STATUS_IN_IO,
+					CQR_STATUS_ERROR);
+			break;
+		default:
+			BUG ();
+		}
+	}
+        if ( cqr == device->init_cqr &&
+             ( cqr->status == CQR_STATUS_DONE ||
+               cqr->status == CQR_STATUS_FAILED )){
+                dasd_state_init_to_ready(device);
+                if ( atomic_read(&dasd_init_pending) == 0)
+                        wake_up (&dasd_init_waitq);
+        }
 	dasd_schedule_bh (device);
 }
 
@@ -1657,26 +1926,39 @@
  *   erp                CQR performing the ERP
  */
 ccw_req_t *
-default_erp_action (ccw_req_t * cqr)
+dasd_default_erp_action (ccw_req_t * cqr)
 {
-	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
 
-	printk (KERN_WARNING PRINTK_HEADER
-		"Default ERP called... \n");
+        dasd_device_t *device = cqr->device;
+	ccw_req_t     *erp    = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
+
+	printk (KERN_DEBUG PRINTK_HEADER "Default ERP called... \n");
+
+	if (!erp) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP request");
+                
+                check_then_set (&cqr->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
 
-        if (erp == NULL)
-               return NULL;
+                return cqr;
+	}
 
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda = (__u32)(void *)cqr->cpaddr;
-	erp->function = default_erp_action;
-	erp->refers = cqr;
+	erp->cpaddr->cda = (__u32) (void *) cqr->cpaddr;
+	erp->function = dasd_default_erp_action;
+	erp->refers = (unsigned int) (unsigned long) cqr;
 	erp->device = cqr->device;
 	erp->magic = cqr->magic;
 	erp->retries = 16;
 
 	erp->status = CQR_STATUS_FILLED;
 
+        dasd_chanq_enq_head (&device->queue,
+                             erp);
+
 	return erp;
 }
 
@@ -1687,6 +1969,8 @@
  *   Frees all ERPs of the current ERP Chain and set the status
  *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
  *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *   NOTE: This function is only called if no discipline postaction
+ *         is available
  *
  * PARAMETER
  *   erp                current erp_head
@@ -1695,96 +1979,63 @@
  *   cqr                pointer to the original CQR
  */
 ccw_req_t *
-default_erp_postaction (ccw_req_t * erp)
+dasd_default_erp_postaction (ccw_req_t *erp)
 {
-	ccw_req_t *cqr = NULL, *free_erp = NULL;
-	dasd_device_t *device = NULL;
-        int success;
-        
-	device = (dasd_device_t *) (erp->device);
+
+	ccw_req_t     *cqr      = NULL, 
+                      *free_erp = NULL;
+	dasd_device_t *device   = erp->device;
+	int           success;
+
+	if (erp->refers   == NULL || 
+            erp->function == NULL   ) {
+
+		BUG ();
+	}
 
 	if (erp->status == CQR_STATUS_DONE)
 		success = 1;
 	else
 		success = 0;
 
-#ifdef ERP_DEBUG
-
-	/* print current erp_chain */
-        printk (KERN_WARNING PRINTK_HEADER
-                "default ERP postaction called for erp chain:\n");
-        {
-                ccw_req_t *temp_erp = NULL;
-                for (temp_erp = erp; temp_erp != NULL; temp_erp = temp_erp->refers){
-                        printk(KERN_WARNING PRINTK_HEADER 
-                               "       erp %p refers to %p with erp function %p\n",
-                               temp_erp,
-                               temp_erp->refers,
-                               temp_erp->function );
-                }
-        }
-
-#endif /* ERP_DEBUG*/
-
-	if (erp->refers == NULL || erp->function == NULL) {
-                BUG();
-	}
-	if (erp->function != default_erp_action) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "default ERP postaction called ERP action [<%p>]\n",
-                        erp->function);
-	}
 	/* free all ERPs - but NOT the original cqr */
-        
 	while (erp->refers != NULL) {
-                free_erp = erp;
-		erp = erp->refers;
+
+		free_erp = erp;
+		erp      = erp->refers;
+
 		/* remove the request from the device queue */
-		dasd_chanq_deq (&device->queue,	free_erp);
+		dasd_chanq_deq (&device->queue,
+                                free_erp);
+
 		/* free the finished erp request */
-		dasd_free_request (free_erp);
+		dasd_free_request (free_erp, free_erp->device);
 	}
-        
+
 	/* save ptr to original cqr */
 	cqr = erp;
 
-#ifdef ERP_DEBUG
-	printk (KERN_INFO PRINTK_HEADER
-		"default_erp_postaction - left original request = %p \n",cqr);
-#endif /* ERP_DEBUG */
-
 	/* set corresponding status to original cqr */
 	if (success) {
+
 		check_then_set (&cqr->status, 
-                                CQR_STATUS_ERROR, 
-                                CQR_STATUS_DONE);
+                                CQR_STATUS_ERROR,
+				CQR_STATUS_DONE);
 	} else {
+
 		check_then_set (&cqr->status,
-                                CQR_STATUS_ERROR,
+				CQR_STATUS_ERROR, 
                                 CQR_STATUS_FAILED);
 	}
 
-#ifdef ERP_DEBUG
-	/* print current erp_chain */
-	printk (KERN_WARNING PRINTK_HEADER
-		"default ERP postaction finished with remaining chain:\n");
-	{
-		ccw_req_t *temp_erp = NULL;
-		for (temp_erp = cqr; temp_erp != NULL; temp_erp = temp_erp->refers) {
-			printk (KERN_WARNING PRINTK_HEADER
-				" erp %p refers to %p \n",
-				temp_erp, temp_erp->refers);
-		}
-	}
-#endif /* ERP_DEBUG */
-
 	return cqr;
-}				/* end default_erp_postaction */
+
+} /* end default_erp_postaction */
 
 /* SECTION: The helpers of the struct file_operations */
 
-/* 
- * function dasd_format 
+/*
+ * function dasd_format
  * performs formatting of _device_ according to _fdata_
  * Note: The discipline's format_function is assumed to deliver formatting
  * commands to format a single unit of the device. In terms of the ECKD
@@ -1795,196 +2046,114 @@
 dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
 	int rc = 0;
-        int format_done = 0;
-	ccw_req_t *req = NULL;
-	format_data_t temp =
-	{
-		fdata->start_unit,
-		fdata->stop_unit,
-		fdata->blksize,
-		fdata->intensity
-	};
-        
-        spin_lock (&dasd_open_count_lock);
-	if (device->open_count != 1) {
-		DASD_MESSAGE (KERN_INFO, device,
-			      "device is already open %d times",
-			      device->open_count);
-                spin_unlock(&dasd_open_count_lock);
-		return -EINVAL;
-	}
-	if (!device->discipline->format_device) {
-                spin_unlock(&dasd_open_count_lock);
-		return -EINVAL;
-	}
-        device->open_count = -1;
-        spin_unlock (&dasd_open_count_lock);
-	/* downgrade state of the device */
-	dasd_set_device_level (device->devinfo.irq,
-			       DASD_DEVICE_LEVEL_RECOGNIZED,
-			       device->discipline,
-			       0);
-	DASD_MESSAGE (KERN_INFO, device, 
-                      "Starting format from %d to %d (%d B blocks flags %d",
-                      fdata->start_unit,
-                      fdata->stop_unit,
-                      fdata->blksize,
-                      fdata->intensity);
-	/* Invalidate first track */
-	if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-	    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
-	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
-		format_data_t temp2 =
-		{0, 0, fdata->blksize, 0x04};
-		DASD_MESSAGE (KERN_INFO, device, 
-                              "%s", 
-                              "Invalidating first track...");
-		req = device->discipline->format_device (device, &temp2);
-		if (req) {
-			rc = sleep_on_req (req);
-			dasd_free_request (req);	/* request is no longer used */
-		} else {
-			rc = -EINVAL;
-		}
-		if (rc) {
-                        DASD_MESSAGE (KERN_WARNING, device, 
-                                      "%s",
-                                      "Can't invalidate Track 0\n");
-		} else {
-                        DASD_MESSAGE (KERN_INFO, device, 
-                                      "%s", 
-                                      "...Invalidation complete");
-                }
-		temp.start_unit++;
-	}
-	/* format remainnig tracks of device */
-	while (!rc                                                                 &&
-	       ((req = device->discipline->format_device (device, &temp)) != NULL)   ) {
-                                format_done=1;
-		if ((rc = sleep_on_req (req)) != 0) {
-
+	int openct = atomic_read (&device->open_count);
 
-			DASD_MESSAGE (KERN_WARNING, device,
-				      " Formatting failed with rc = %d\n",
-				      rc);
+	if (openct > 1) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "dasd_format: device is open! expect errors.");
+	}
+	DASD_MESSAGE (KERN_INFO, device,
+		      "formatting units %d to %d (%d B blocks) flags %d",
+		      fdata->start_unit, fdata->stop_unit,
+		      fdata->blksize, fdata->intensity);
+	while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) {
+                ccw_req_t *req;
+                dasd_format_fn_t ffn = device->discipline->format_device;
+		ffn = device->discipline->format_device;
+		if (ffn == NULL)
+			break;
+		req = ffn (device, fdata);
+		if (req == NULL) {
+			rc = -ENOMEM;
 			break;
 		}
-                
-		dasd_free_request (req);	/* request is no longer used */
-		temp.start_unit++;
+		if ((rc = dasd_sleep_on_req (req)) != 0) {
+			DASD_MESSAGE (KERN_WARNING, device,
+				      " Formatting of unit %d failed with rc = %d\n",
+				      fdata->start_unit, rc);
+			break;
+		} 
+		dasd_free_request (req, device);	/* request is no longer used */
+	        if ( signal_pending(current) )
+			break;		
+		fdata->start_unit++;
 	}
-
-	if (!rc         &&
-	    req == NULL   ) {
-		if (fdata->start_unit == DASD_FORMAT_DEFAULT_START_UNIT &&
-		    fdata->stop_unit  == DASD_FORMAT_DEFAULT_STOP_UNIT  &&
-	    	    fdata->intensity  == DASD_FORMAT_DEFAULT_INTENSITY    ) {
-			format_data_t temp2 =
-			{0, 0, fdata->blksize, fdata->intensity};
-			DASD_MESSAGE (KERN_INFO, device, 
-                                      "%s", 
-                                      "Revalidating first track...");
-			req = device->discipline->format_device (device, &temp2);
-			if (req) {
-				rc = sleep_on_req (req);
-				dasd_free_request (req);	/* request is no longer used */
-			} else {
-				rc = -EINVAL;
-			}
-			if (rc) {
-				DASD_MESSAGE (KERN_WARNING, device,
-                                              "%s",
-                                              "Can't revalidate Track 0\n");
-			} else {
-                                DASD_MESSAGE (KERN_INFO, device, 
-                                              "%s", 
-                                              "...Revalidation complete");
-                        }
-		}
-	}			/* end if no more requests */
-
-        /* check if at least one format cp was build in discipline */
-        if (!format_done) {
-                rc = -EINVAL;
-        }
-
-	if (rc)
-		DASD_MESSAGE (KERN_WARNING, device,
-			      "%s", " Formatting finished unsuccessfully");
-	else
-		DASD_MESSAGE (KERN_INFO, device,
-			      "%s", " Formatting finished successfully");
-
-        /* 
-         * re-analyse device
-         */
-        dasd_set_device_level (device->devinfo.irq,
-                               DASD_DEVICE_LEVEL_ONLINE,
-                               device->discipline,
-                               0);
-        udelay (1500000);
-                
-        dasd_set_device_level (device->devinfo.irq,
-                               DASD_DEVICE_LEVEL_ONLINE,
-                               device->discipline,
-                               0);
-
-        spin_lock (&dasd_open_count_lock);
-        device->open_count=1;
-        spin_unlock (&dasd_open_count_lock);
 	return rc;
 }				/* end dasd_format */
 
-static struct list_head dasd_ioctls = LIST_HEAD_INIT(dasd_ioctls);
+static struct list_head dasd_ioctls = LIST_HEAD_INIT (dasd_ioctls);
 
 static dasd_ioctl_list_t *
-dasd_find_ioctl( int no )
+dasd_find_ioctl (int no)
 {
 	struct list_head *curr;
-	list_for_each(curr,&dasd_ioctls){
-		if (list_entry(curr,dasd_ioctl_list_t,list)->no == no ){
-			return list_entry(curr,dasd_ioctl_list_t,list);
+	list_for_each (curr, &dasd_ioctls) {
+		if (list_entry (curr, dasd_ioctl_list_t, list)->no == no) {
+			return list_entry (curr, dasd_ioctl_list_t, list);
 		}
 	}
 	return NULL;
 }
 
 int
-dasd_ioctl_no_register ( int no, dasd_ioctl_fn_t handler )
+dasd_ioctl_no_register (struct module *owner, int no, dasd_ioctl_fn_t handler)
 {
 	dasd_ioctl_list_t *new;
-	if (dasd_find_ioctl(no))
+	if (dasd_find_ioctl (no))
 		return -EBUSY;
-	new = kmalloc(sizeof(dasd_ioctl_list_t),GFP_KERNEL);
- 	if ( new ==  NULL )
+	new = kmalloc (sizeof (dasd_ioctl_list_t), GFP_KERNEL);
+	if (new == NULL)
 		return -ENOMEM;
-	new -> no = no;
-	new -> handler = handler;
-	list_add(&new->list,&dasd_ioctls);
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
+	new->owner = owner;
+	new->no = no;
+	new->handler = handler;
+	list_add (&new->list, &dasd_ioctls);
+	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 int
-dasd_ioctl_no_unregister ( int no, dasd_ioctl_fn_t handler )
-{	
-	dasd_ioctl_list_t *old = dasd_find_ioctl(no);
-	if ( old == NULL )
+dasd_ioctl_no_unregister (struct module *owner, int no, dasd_ioctl_fn_t handler)
+{
+	dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+	if (old == NULL)
 		return -ENOENT;
-	if ( old->no != no ||
-	     old->handler != handler )
+	if (old->no != no || old->handler != handler || owner != old->owner )
 		return -EINVAL;
-	list_del(&old->list);
-	kfree(old);
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
+	list_del (&old->list);
+	kfree (old);
+	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static int
+dasd_revalidate (dasd_device_t * device)
+{
+        int rc = 0;
+	int i;
+	kdev_t kdev = device->kdev;
+	int openct = atomic_read (&device->open_count);
+	int start = MINOR (kdev);
+	if (openct != 1) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s",
+			      "BLKRRPART: device is open! expect errors.");
+	}
+	for (i = (1 << DASD_PARTN_BITS) - 1; i >= 0; i--) {
+                int major = device->major_info->gendisk.major;
+		int minor = start + i;
+		kdev_t devi = MKDEV (major, minor);
+		struct super_block *sb = get_super (devi);
+		sync_dev (devi);
+		if (sb)
+			invalidate_inodes (sb);
+		invalidate_buffers (devi);
+	}
+        dasd_destroy_partitions(device);
+        dasd_setup_partitions(device);
+        return rc;
+
+}
+static int
 do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
 	int rc = 0;
@@ -2013,31 +2182,37 @@
 		_IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
 		_IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
 		device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev),
-		device->devinfo.devno, device->devinfo.irq,
-		data);
+		device->devinfo.devno, device->devinfo.irq, data);
 #endif
 	switch (no) {
+        case DASDAPIVER: {
+                       int ver = DASD_API_VERSION;
+                       rc = copy_to_user ((int *) data, &ver, sizeof (int));
+                       if (rc)
+                               rc = -EFAULT;
+                       break;
+        }
 	case BLKGETSIZE:{	/* Return device size */
-			long blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1;
-			rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+			long blocks = major_info->gendisk.sizes 
+                                      [MINOR (inp->i_rdev)] << 1;
+			rc =
+			    copy_to_user ((long *) data, &blocks,
+					  sizeof (long));
 			if (rc)
 				rc = -EFAULT;
 			break;
 		}
 	case BLKRRPART:{
-                        if (!capable(CAP_SYS_ADMIN)) {
-                            rc = -EACCES;
-                            break;
-                        }
-			fsync_dev(inp->i_rdev);
-			dasd_partn_detect (device);
-			invalidate_buffers(inp->i_rdev);
-			rc = 0;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			rc = dasd_revalidate (device);
 			break;
 		}
 	case HDIO_GETGEO:{
-			struct hd_geometry geo = {0,};
-			rc = dasd_fillgeo(inp->i_rdev, &geo);
+			struct hd_geometry geo = { 0, };
+			rc = dasd_fillgeo (inp->i_rdev, &geo);
 			if (rc)
 				break;
 
@@ -2047,148 +2222,208 @@
 				rc = -EFAULT;
 			break;
 		}
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-        case BLKSSZGET:
-        case BLKROSET:
-        case BLKROGET:
-        case BLKRASET:
-        case BLKRAGET:
-        case BLKFLSBUF:
-        case BLKPG: 
-        case BLKELVGET:
-        case BLKELVSET:
-                return blk_ioctl(inp->i_rdev, no, data);
-                break;
-#else
-        case BLKRASET:
-                if(!capable(CAP_SYS_ADMIN))
-                        return -EACCES;
-                if(!dev || arg > 0xff)
-                        return -EINVAL;
-                read_ahead[MAJOR(dev)] = arg;
-                rc = 0;
-                break;
-        case BLKRAGET:
-                if (!arg)
-                        return -EINVAL;
-                rc = put_user(read_ahead[MAJOR(dev)], (long *) arg);
-                break;
-        case BLKSSZGET: {
-            /* Block size of media */
-            rc = copy_to_user((int *)data,
-                              &blksize_size[MAJOR(device->kdev)]
-                              [MINOR(device->kdev)],
-                              sizeof(int)) ? -EFAULT : 0;
-        }
-        RO_IOCTLS (inp->i_rdev, data);
-	case BLKFLSBUF:{
-                if (!capable(CAP_SYS_ADMIN)) 
-                        return -EACCES;
-                fsync_dev(inp->i_rdev);
-                invalidate_buffers(inp->i_rdev);
-                rc = 0;
-                break;
+	case BIODASDDISABLE:{
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+                        if ( device->level > DASD_STATE_ACCEPT) {
+                                if ( device->request_queue)
+                                        dasd_flush_request_queues(device,0);
+                                dasd_flush_chanq(device,0);
+                                dasd_disable_blkdev(device);
+                                dasd_set_device_level (device->devinfo.devno, 
+                                                       device->discipline, 
+                                                       DASD_STATE_ACCEPT);
+                        }
+                        break;
         }
-#endif				/* LINUX_IS_24 */
-	case BIODASDRSID:{
-			rc = copy_to_user ((void *) data,
-					   &(device->devinfo.sid_data),
-					   sizeof (senseid_t)) ? -EFAULT : 0;
-			break;
-		}
-	case BIODASDRWTB:{
-			int offset = 0;
-			int xlt;
-			rc = copy_from_user (&xlt, (void *) data,
-					     sizeof (int)) ? -EFAULT : 0;
-			if (rc)
+	case BIODASDENABLE:{
+                        dasd_range_t range = { 
+                                from: device->devinfo.devno,
+                                to: device->devinfo.devno 
+                        };
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
 				break;
-			offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
-			    device->sizes.s2b_shift;
-			xlt += offset;
-			rc = copy_to_user ((void *) data, &xlt,
-					   sizeof (int)) ? -EFAULT : 0;
-			break;
-		}
-	case BIODASDFORMAT:{
-			/* fdata == NULL is a valid arg to dasd_format ! */
-			int partn;
-			format_data_t fdata =
-			{
-				DASD_FORMAT_DEFAULT_START_UNIT,
-				DASD_FORMAT_DEFAULT_STOP_UNIT,
-				DASD_FORMAT_DEFAULT_BLOCKSIZE,
-				DASD_FORMAT_DEFAULT_INTENSITY};
-
-                        if (!capable(CAP_SYS_ADMIN)) {
-                            rc = -EACCES;
-                            break;
+			}
+                        dasd_enable_ranges (&range, device->discipline, 0);
+                        break;
+        }
+	case BIODASDFMT:{
+			/* fdata == NULL is no longer a valid arg to dasd_format ! */
+			int partn = MINOR (inp->i_rdev) &
+			    ((1 << major_info->gendisk.minor_shift) - 1);
+			format_data_t fdata;
+
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+                        if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+                                rc = -EROFS;
+                                break;
                         }
-			if (data) {
-				rc = copy_from_user (&fdata, (void *) data,
-						     sizeof (format_data_t));
-				if (rc) {
-					rc = -EFAULT;
-					break;
-				}
+			if (!data) {
+				rc = -EINVAL;
+				break;
+			}
+			rc = copy_from_user (&fdata, (void *) data,
+					     sizeof (format_data_t));
+			if (rc) {
+				rc = -EFAULT;
+				break;
 			}
-			partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
 			if (partn != 0) {
-				printk (KERN_WARNING PRINTK_HEADER
-					" devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-				     " Cannot low-level format a partition\n",
-					device->devinfo.devno, device->devinfo.irq, device->name,
-				    MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+				DASD_MESSAGE (KERN_WARNING, device, "%s",
+					      "Cannot low-level format a partition");
 				return -EINVAL;
 			}
 			rc = dasd_format (device, &fdata);
 			break;
 		}
+	case BIODASDPRRST:{
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			memset (&device->profile, 0,
+				sizeof (dasd_profile_info_t));
+			break;
+		}
+	case BIODASDPRRD:{
+			rc = copy_to_user((long *)data,
+					  (long *)&device->profile,
+					  sizeof(dasd_profile_info_t));
+			if (rc)
+				rc = -EFAULT;
+			break;
+		}
 	case BIODASDRSRV:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->reserve (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+			ccw_req_t *req;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			req = device->discipline->reserve (device);
+			rc = dasd_sleep_on_req (req);
+			dasd_free_request (req, device);
+			break;
+		}
 	case BIODASDRLSE:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->release (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+			ccw_req_t *req;
+			if (!capable (CAP_SYS_ADMIN)) {
+				rc = -EACCES;
+				break;
+			}
+			req = device->discipline->release (device);
+			rc = dasd_sleep_on_req (req);
+			dasd_free_request (req, device);
+			break;
+		}
 	case BIODASDSLCK:{
 			printk (KERN_WARNING PRINTK_HEADER
 				"Unsupported ioctl BIODASDSLCK\n");
 			break;
 		}
+	case BIODASDINFO:{
+			dasd_information_t dasd_info;
+			unsigned long flags;
+			rc = device->discipline->fill_info (device, &dasd_info);
+                        dasd_info.label_block = device->sizes.pt_block;
+			dasd_info.devno = device->devinfo.devno;
+			dasd_info.schid = device->devinfo.irq;
+			dasd_info.cu_type = device->devinfo.sid_data.cu_type;
+			dasd_info.cu_model = device->devinfo.sid_data.cu_model;
+			dasd_info.dev_type = device->devinfo.sid_data.dev_type;
+			dasd_info.dev_model = device->devinfo.sid_data.dev_model;
+			dasd_info.open_count =
+			    atomic_read (&device->open_count);
+			dasd_info.status = device->level;
+			if (device->discipline) {
+				memcpy (dasd_info.type,
+					device->discipline->name, 4);
+			} else {
+				memcpy (dasd_info.type, "none", 4);
+			}
+			dasd_info.req_queue_len = 0;
+			dasd_info.chanq_len = 0;
+			if (device->request_queue->request_fn) {
+				struct list_head *l;
+				ccw_req_t *cqr = device->queue.head;
+				spin_lock_irqsave (&io_request_lock, flags);
+				list_for_each (l,
+					       &device->request_queue->
+					       queue_head) {
+					dasd_info.req_queue_len++;
+				}
+				spin_unlock_irqrestore (&io_request_lock,
+							flags);
+				s390irq_spin_lock_irqsave (device->devinfo.irq,
+							   flags);
+				while (cqr) {
+					cqr = cqr->next;
+					dasd_info.chanq_len++;
+				}
+				s390irq_spin_unlock_irqrestore (device->devinfo.
+								irq, flags);
+			}
+			rc =
+			    copy_to_user ((long *) data, (long *) &dasd_info,
+					  sizeof (dasd_information_t));
+			if (rc)
+				rc = -EFAULT;
+			break;
+		}
+#if 0 /* needed for XFS */
+	case BLKBSZSET:{
+		int bsz;
+		rc = copy_from_user ((long *)&bsz,(long *)data,sizeof(int));
+		if ( rc ) {
+			rc = -EFAULT;
+		} else {
+			if ( bsz >= device->sizes.bp_block )
+				rc = blk_ioctl (inp->i_rdev, no, data);
+			else
+				rc = -EINVAL; 
+		}
+		break;
+		}
+#endif /* 0 */
+	case BLKSSZGET:
+	case BLKROSET:
+	case BLKROGET:
+	case BLKRASET:
+	case BLKRAGET:
+	case BLKFLSBUF:
+	case BLKPG:
+	case BLKELVGET:
+	case BLKELVSET:
+		return blk_ioctl (inp->i_rdev, no, data);
+		break;
 	default:{
 
-			dasd_ioctl_list_t *old = dasd_find_ioctl(no);
-			if ( old ) {
-				rc = old->handler(inp,no,data);
+			dasd_ioctl_list_t *old = dasd_find_ioctl (no);
+			if (old) {
+				if ( old->owner )
+					__MOD_INC_USE_COUNT(old->owner);
+				rc = old->handler (inp, no, data);
+				if ( old->owner )
+					__MOD_DEC_USE_COUNT(old->owner);
 			} else {
 				DASD_MESSAGE (KERN_INFO, device,
-					    "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
+					      "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
 					      no,
 					      _IOC_DIR (no) == _IOC_NONE ? "0" :
 					      _IOC_DIR (no) == _IOC_READ ? "r" :
-					      _IOC_DIR (no) == _IOC_WRITE ? "w" :
-					   _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
-					      "rw" : "u",
-					 _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+					      _IOC_DIR (no) ==
+					      _IOC_WRITE ? "w" : _IOC_DIR (no)
+					      == (_IOC_READ | _IOC_WRITE) ? "rw"
+					      : "u", _IOC_TYPE (no),
+					      _IOC_NR (no), _IOC_SIZE (no),
 					      data);
-				rc = -EINVAL;
-			}	
+				rc = -ENOTTY;
+			}
 			break;
 		}
 	}
@@ -2213,37 +2448,46 @@
 dasd_open (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
+        unsigned long flags;
 	dasd_device_t *device;
 
+        MOD_INC_USE_COUNT;
 	if ((!inp) || !(inp->i_rdev)) {
-		return -EINVAL;
+		rc = -EINVAL;
+                goto fail;
 	}
 	if (dasd_probeonly) {
-		printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -EPERM;
+		printk ("\n" KERN_INFO PRINTK_HEADER
+			"No access to device (%d:%d) due to probeonly mode\n",
+			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+		rc = -EPERM;
+                goto fail;
 	}
+        spin_lock_irqsave(&discipline_lock,flags);
 	device = dasd_device_from_kdev (inp->i_rdev);
-	if (device == NULL) {
+	if (device == NULL ) {
 		printk (KERN_WARNING PRINTK_HEADER
-			"No device registered as (%d:%d)\n", MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -ENODEV;
+			"No device registered as (%d:%d)\n",
+			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+		rc = -ENODEV;
+                goto unlock;
 	}
-	if (device->level < DASD_DEVICE_LEVEL_RECOGNIZED ||
-	    device->discipline == NULL) {
+	if (device->level < DASD_STATE_ACCEPT ) {
 		DASD_MESSAGE (KERN_WARNING, device,
 			      " %s", " Cannot open unrecognized device\n");
-		return -EINVAL;
+		rc = -ENODEV;
+                goto unlock;
 	}
-        spin_lock(&dasd_open_count_lock);
-        if (device->open_count == -1) {
-            spin_unlock (&dasd_open_count_lock);
-            return -EBUSY;
+	if (atomic_inc_return (&device->open_count) == 1 ) {
+                if ( device->discipline->owner )
+                        __MOD_INC_USE_COUNT(device->discipline->owner);
+        } else {
+                MOD_DEC_USE_COUNT;
         }
-#ifdef MODULE
-	MOD_INC_USE_COUNT;
-#endif				/* MODULE */
-	device->open_count++;
-        spin_unlock (&dasd_open_count_lock);
+ unlock:
+        spin_unlock_irqrestore(&discipline_lock,flags);
+ fail:
+        if (rc) MOD_DEC_USE_COUNT;
 	return rc;
 }
 
@@ -2251,28 +2495,41 @@
 dasd_release (struct inode *inp, struct file *filp)
 {
 	int rc = 0;
+        int count;
 	dasd_device_t *device;
 
 	if ((!inp) || !(inp->i_rdev)) {
-		return -EINVAL;
+		rc = -EINVAL;
+                goto out;
 	}
 	device = dasd_device_from_kdev (inp->i_rdev);
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No device registered as %d:%d\n",
 			MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
-		return -EINVAL;
+		rc = -EINVAL;
+                goto out;
 	}
-        spin_lock(&dasd_open_count_lock);
-	if (device->open_count--) {
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif				/* MODULE */
-	} 
-	fsync_dev(inp->i_rdev); /* sync the device */
-	if (device->open_count == 0) /* finally invalidate buffers */
-		invalidate_buffers(inp->i_rdev);
-        spin_unlock(&dasd_open_count_lock);
+
+	if (device->level < DASD_STATE_ACCEPT ) {
+		DASD_MESSAGE (KERN_WARNING, device,
+			      " %s", " Cannot release unrecognized device\n");
+		rc = -ENODEV;
+                goto out;
+	}
+	fsync_dev (inp->i_rdev);	/* sync the device */
+        count = atomic_dec_return (&device->open_count);
+        if ( count == 0) {
+                invalidate_buffers (inp->i_rdev);
+                if ( device->discipline->owner )
+                        __MOD_DEC_USE_COUNT(device->discipline->owner);
+                MOD_DEC_USE_COUNT;
+	} else if ( count == -1 ) { /* paranoia only */
+                atomic_set (&device->open_count,0);
+                printk (KERN_WARNING PRINTK_HEADER
+                        "release called with open count==0\n");
+        }
+ out:
 	return rc;
 }
 
@@ -2282,11 +2539,6 @@
 	open:dasd_open,
 	release:dasd_release,
 	ioctl:dasd_ioctl,
-#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	read:block_read,
-	write:block_write,
-	fsync:block_fsync,
-#endif				/* LINUX_IS_24 */
 };
 
 /* SECTION: Management of device list */
@@ -2298,16 +2550,9 @@
 		return -EINVAL;
 
 	device->discipline->fill_geometry (device, geo);
-	geo->start = device->major_info->
-			gendisk.part[MINOR(kdev)].start_sect;
-
-	/* This is a hack.  dasdfmt and ibm.c expect geo.start 
-	   to contain the block number of the label block when
-	   it calls HDIO_GETGEO on the first partition. */
-	if (geo->start == 0)
-                geo->start = device->sizes.pt_block;
-
-	return 0;
+	geo->start = device->major_info->gendisk.part[MINOR(kdev)].start_sect 
+		     >> device->sizes.s2b_shift;;
+        return 0;
 } 
 
 
@@ -2319,11 +2564,11 @@
 	char first, second, third;
 
 	if (hd) {
-		major_info_t *major_info=NULL;
+		major_info_t *major_info = NULL;
 		struct list_head *l;
 
-		list_for_each(l,&dasd_major_info[0].list) {
-			major_info = list_entry(l,major_info_t,list); 
+		list_for_each (l, &dasd_major_info[0].list) {
+			major_info = list_entry (l, major_info_t, list);
 			if (&major_info->gendisk == hd) {
 				break;
 			}
@@ -2334,14 +2579,14 @@
 		}
 	}
 	third = index % 26;
-	second = ((index-26) / 26) % 26;
-	first = (((index-702) / 26) / 26) % 26;
+	second = ((index - 26) / 26) % 26;
+	first = (((index - 702) / 26) / 26) % 26;
 
 	len = sprintf (str, "dasd");
-	if (index>701) {
+	if (index > 701) {
 		len += sprintf (str + len, "%c", first + 'a');
 	}
-	if (index>25) {
+	if (index > 25) {
 		len += sprintf (str + len, "%c", second + 'a');
 	}
 	len += sprintf (str + len, "%c", third + 'a');
@@ -2356,20 +2601,215 @@
 	return 0;
 }
 
-#ifdef CONFIG_DASD_DYNAMIC
 static void
-dasd_plug_device (dasd_device_t *device)
+dasd_plug_device (dasd_device_t * device)
+{
+	atomic_set(&device->plugged,1);	
+}
+
+static void
+dasd_unplug_device (dasd_device_t * device)
+{
+	atomic_set(&device->plugged,0);	
+        dasd_schedule_bh(device);
+}
+
+static void
+dasd_flush_chanq ( dasd_device_t * device, int destroy ) 
 {
-        device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+        ccw_req_t *cqr;
+        unsigned long flags;
+        if ( destroy ) {
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                cqr = device->queue.head;
+                while ( cqr != NULL ) {
+                        if ( cqr -> status == CQR_STATUS_IN_IO )
+                                device->discipline->term_IO (cqr);
+                        if ( cqr->status != CQR_STATUS_DONE ||
+                             cqr->status != CQR_STATUS_FAILED ) {
+                                cqr->status = CQR_STATUS_FAILED;
+                        }
+                        dasd_schedule_bh(device);
+                        cqr = cqr->next;
+                }
+                s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+        }
+        wait_event( device->wait_q, device->queue.head == NULL );
 }
 
 static void
-dasd_unplug_device (dasd_device_t *device)
+dasd_flush_request_queues ( dasd_device_t * device, int destroy )
+{
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+        for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) {
+                if ( destroy )
+                        destroy_buffers(MKDEV(major,minor+i)); 
+                else
+                        invalidate_buffers(MKDEV(major,minor+i)); 
+        } 
+}
+
+static int
+dasd_disable_volume ( dasd_device_t * device, int force ) 
 {
-        generic_unplug_device(&device->request_queue);
+        int rc = 0;
+        int target  = DASD_STATE_KNOWN;
+        int count = atomic_read (&device->open_count);
+        int part;
+        
+	if ( count ) {
+		DASD_MESSAGE (KERN_EMERG, device, "%s",
+			      "device has vanished although it was open!");
+        }
+        if ( force ) {
+                dasd_flush_chanq(device,force);
+                dasd_flush_request_queues(device,force);
+                dasd_disable_blkdev(device);
+                target = DASD_STATE_DEL;
+        }
+
+#if 0
+        /* unregister devfs entries */
+        for (part = 0; part < (1 << DASD_PARTN_BITS); part++) {
+                devfs_unregister(device->major_info->gendisk.part[MINOR(device->kdev)+part].de);
+                device->major_info->gendisk.part[MINOR(device->kdev)+part].de = NULL;
+        }                        
+#endif
+        
+        DASD_MESSAGE (KERN_WARNING, device, 
+                      "disabling device, target state:%d",target);
+        dasd_set_device_level (device->devinfo.devno, 
+                               device->discipline, 
+                               target);
+        return rc;
 }
 
 static void
+dasd_disable_ranges (dasd_range_t *range, 
+                     dasd_discipline_t *d,
+                     int all, int force ) 
+{
+        dasd_range_t *rrange;
+        int j;
+
+        if (range == &dasd_range_head) {
+                rrange = list_entry (range->list.next, 
+                                     dasd_range_t, list);
+        } else {
+                rrange = range;
+        }
+        do {
+                for (j = rrange->from; j <= rrange->to; j++) {
+                        dasd_device_t **dptr;
+                        dasd_device_t *device;
+                        dptr = dasd_device_from_devno(j);
+                        if ( dptr == NULL ) {
+                            continue;
+                        }
+                        device = *dptr;
+                        if (device == NULL ||
+                            (d != NULL &&
+                             device -> discipline != d))
+                                continue;
+                        
+                        dasd_disable_volume(device, force);
+                }
+                rrange = list_entry (rrange->list.next, dasd_range_t, list);
+        } while ( all && rrange && rrange != range );
+}
+
+static void 
+dasd_enable_single_device ( unsigned long arg ) {
+        dasd_device_t * device =(dasd_device_t *) arg;
+        int devno = device->devinfo.devno;
+        dasd_range_t range = { from: devno, to:devno };
+        dasd_enable_ranges (&range,NULL,0);
+}
+
+static void
+dasd_enable_ranges (dasd_range_t *range, dasd_discipline_t *d, int all ) 
+{
+        int retries = 0;
+	int j;
+        kdev_t tempdev;
+	dasd_range_t *rrange;
+
+	if (range == NULL)
+		return;
+        
+        do {
+                if (range == &dasd_range_head) {
+                        rrange = list_entry (range->list.next, 
+                                             dasd_range_t, list);
+                } else {
+                        rrange = range;
+                }
+                do {
+                        for (j = rrange->from; j <= rrange->to; j++) {
+                                if ( dasd_devindex_from_devno(j) < 0 )
+                                        continue;
+                                dasd_set_device_level (j, d, DASD_STATE_ONLINE);
+                        }
+                        rrange = list_entry (rrange->list.next, dasd_range_t, list);
+                } while ( all && rrange && rrange != range );
+
+                if (atomic_read (&dasd_init_pending) == 0) /* we are done, exit loop */
+                        break;
+
+                if ( retries == 0 ) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "waiting for responses...\n");
+                } else if ( retries < 5 ) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "waiting a little bit longer...\n");
+                } else {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "giving up, enable late devices manually!\n");
+                        break;
+                }
+                interruptible_sleep_on_timeout (&dasd_init_waitq, (1 * HZ));
+                retries ++;
+        } while (1);
+        /* now setup block devices */
+
+        /* Now do block device and partition setup */
+        if (range == &dasd_range_head) {
+                rrange = list_entry (range->list.next, 
+                                     dasd_range_t, list);
+        } else {
+                rrange = range;
+        }
+        do {
+                for (j = rrange->from; j <= rrange->to; j++) {
+                        dasd_device_t **dptr;
+                        dasd_device_t *device;
+                        if ( dasd_devindex_from_devno(j) < 0 )
+                                continue;
+                        dptr = dasd_device_from_devno(j);
+                        device = *dptr;
+                        if (device == NULL )
+                                continue;
+                        if ( ((d == NULL && device->discipline != NULL) ||
+                              (device->discipline == d )) &&
+                             device->level >= DASD_STATE_READY &&
+                             device->request_queue == NULL ) {
+                                if (dasd_features_from_devno(j)&DASD_FEATURE_READONLY) {
+                                    for (tempdev=device->kdev;tempdev<(device->kdev +(1 << DASD_PARTN_BITS));tempdev++)
+                                        set_device_ro (tempdev, 1);
+                                     printk (KERN_WARNING PRINTK_HEADER "setting read-only mode for device /dev/%s\n",device->name);
+                                }
+                                dasd_setup_blkdev(device);
+                                dasd_setup_partitions(device);
+                        }
+                }
+                rrange = list_entry (rrange->list.next, dasd_range_t, list);
+        } while ( all && rrange && rrange != range );
+}
+
+#ifdef CONFIG_DASD_DYNAMIC
+static void
 dasd_not_oper_handler (int irq, int status)
 {
 	dasd_device_t *device = NULL;
@@ -2377,13 +2817,12 @@
 	struct list_head *l;
 	int i, devno = -ENODEV;
 
-        /* find out devno of leaving device: CIO has already deleted this information ! */
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l, major_info_t,list);	
+	/* find out devno of leaving device: CIO has already deleted this information ! */
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			device = major_info->dasd_device[i];
-			if (device &&
-			    device->devinfo.irq == irq) {
+			if (device && device->devinfo.irq == irq) {
 				devno = device->devinfo.devno;
 				break;
 			}
@@ -2396,360 +2835,561 @@
 			"not_oper_handler called on irq %d no devno!\n", irq);
 		return;
 	}
-
-	if (device->open_count != 0) {
-                DASD_MESSAGE(KERN_ALERT,device,"%s",
-                             "open device has gone. please repair!");
-                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED, 
-                                       NULL, 0);
-	} else {
-                DASD_MESSAGE(KERN_INFO,device,"%s","device has gone");
-                dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN, 
-                                       NULL, 0);
-        }
+        dasd_disable_volume(device, 0);
 }
 
-static int
-dasd_enable_single_volume (int irq)
+int
+dasd_oper_handler (int irq, devreg_t * devreg)
 {
+	int devno;
 	int rc = 0;
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-			       NULL, 0);
-	printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
-	{
-		static wait_queue_head_t wait_queue;
-		init_waitqueue_head (&wait_queue);
-		interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1);
+	major_info_t *major_info = NULL;
+        dasd_range_t *rptr,range;
+        dasd_device_t *device = NULL;
+	struct list_head *l;
+        int i;
+
+	devno = get_devno_by_irq (irq);
+	if (devno == -ENODEV) {
+		rc = -ENODEV;
+                goto out;
 	}
-	dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
+	/* find out devno of leaving device: CIO has already deleted this information ! */
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		for (i = 0; i < DASD_PER_MAJOR; i++) {
+			device = major_info->dasd_device[i];
+			if (device && device->devinfo.irq == irq) {
+				devno = device->devinfo.devno;
+				break;
+			}
+		}
+		if (devno != -ENODEV)
+			break;
+	}
+	if (devno < 0) {
+                BUG();
+	}
+        if ( device &&
+             device->level == DASD_STATE_READY ) {
+            dasd_set_device_level (device->devinfo.devno, 
+                                   device->discipline, DASD_STATE_ONLINE);
+
+        } else {
+            if (dasd_autodetect) {
+		rptr = dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+                if ( rptr == NULL ) {
+                    rc = -ENOMEM;
+                    goto out;
+                }
+            } else {
+                range.from = devno;
+                range.to = devno;
+                rptr = &range;
+            }
+            dasd_enable_ranges (rptr, NULL, 0);
+        }
+ out:
 	return rc;
 }
+#endif				/* CONFIG_DASD_DYNAMIC */
+
+static inline dasd_device_t **
+dasd_find_device_addr ( int devno ) 
+{
+        dasd_device_t **device_addr;
+
+	DASD_DRIVER_DEBUG_EVENT (1, dasd_find_device_addr, 
+                                 "devno %04X", devno);
+	if ( dasd_devindex_from_devno (devno) < 0 ) {
+                DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
+                                             "no dasd: devno %04X",
+                                             devno);
+		return NULL;
+	}
+        /* allocate major numbers on demand  for new devices */
+	while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
+                int rc;
+
+		if ((rc = dasd_register_major (NULL)) <= 0) {
+
+                        DASD_DRIVER_DEBUG_EXCEPTION (1, dasd_find_device_addr, 
+                                                     "%s",
+                                                     "out of major numbers!");
+                        break;
+		}
+	}
+        return device_addr;
+}
+
+static inline int
+dasd_state_del_to_new (dasd_device_t **addr ) 
+{
+        dasd_device_t* device;
+        int rc = 0;
+	if (*addr == NULL) { /* allocate device descriptor on demand for new device */
+                device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+		if (device == NULL ) {
+			rc = -ENOMEM;
+                        goto out;
+		}
+		memset (device, 0, sizeof (dasd_device_t));
+                *addr = device;
+                device->lowmem_ccws = (void*)get_free_page (GFP_ATOMIC|GFP_DMA);
+                if (device->lowmem_ccws == NULL) {
+                        rc = -ENOMEM;
+                        goto noccw;
+	}
+#ifdef CONFIG_ARCH_S390X
+                device->lowmem_idals =
+                    device->lowmem_idal_ptr = (void*) get_free_page (GFP_ATOMIC|GFP_DMA);
+                if (device->lowmem_idals == NULL) {
+                        rc = -ENOMEM;
+                        goto noidal;
+                }                
+#endif
+}
+        goto out;
+ noidal:
+        free_page ((long) device->lowmem_ccws);
+ noccw:
+        kfree(device);
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_new_to_del (dasd_device_t **addr )
+{
+        dasd_device_t *device = *addr;
+        if (device && device->private) {
+                kfree(device->private);
+                device->private = NULL;
+        }
+#ifdef CONFIG_ARCH_S390X
+        free_page ((long)(device->lowmem_idals));
+#endif
+        free_page((long)(device->lowmem_ccws));
+        kfree(device);
+        *addr = NULL; 
+        return 0;
+}
+
+static inline int
+dasd_state_new_to_known (dasd_device_t **dptr, int devno, dasd_discipline_t *disc) 
+{
+        int rc = 0;
+	umode_t devfs_perm  = S_IFBLK | S_IRUSR | S_IWUSR;
+        struct list_head *l;
+        major_info_t *major_info = NULL;
+        int i;
+        dasd_device_t *device = *dptr;
+        devfs_handle_t dir;
+        char buffer[5];
+        
+
+	list_for_each (l, &dasd_major_info[0].list) {
+                major_info = list_entry (l, major_info_t, list);
+		for (i = 0; i < DASD_PER_MAJOR; i++) {
+			if (major_info->dasd_device[i] == device) {
+				device->kdev = MKDEV (major_info->gendisk.major,
+                                                      i << DASD_PARTN_BITS);
+				break;
+			}
+		}
+		if (i < DASD_PER_MAJOR) /* we found one */
+			break;
+	}
+        if ( major_info == NULL || major_info == &dasd_major_info[0] ) 
+                BUG();
+
+        device->major_info = major_info;
+        dasd_device_name (device->name,
+                          (((long)dptr -
+                            (long)device->major_info->dasd_device) /
+                           sizeof (dasd_device_t *)),
+                          0, &device->major_info->gendisk);
+        init_waitqueue_head (&device->wait_q);
+        
+        rc = get_dev_info_by_devno (devno, &device->devinfo);
+        if ( rc ) {
+                goto out;
+        }
+        if ( devno != device->devinfo.devno )
+                BUG();
+        device->discipline = dasd_find_disc (device, disc);
+        if ( device->discipline == NULL ) {
+                rc = -ENODEV;
+                goto out;
+        }
+        sprintf (buffer, "%04x", device->devinfo.devno);
+        dir = devfs_mk_dir (dasd_devfs_handle, buffer, device);
+        device->major_info->gendisk.de_arr[MINOR(device->kdev)
+                                          >> DASD_PARTN_BITS] = dir;
+	if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+	        devfs_perm &= ~(S_IWUSR);
+	}
+        device->devfs_entry = devfs_register (dir,"device",DEVFS_FL_DEFAULT,
+                                              MAJOR(device->kdev),
+                                              MINOR(device->kdev),
+                                              devfs_perm,
+                                              &dasd_device_operations,NULL);
+        device->level = DASD_STATE_KNOWN;
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_known_to_new (dasd_device_t *device ) 
+{
+        int rc = 0;
+        /* don't reset to zeros because of persistent data durich detach/attach! */
+        devfs_unregister(device->devfs_entry);
+        devfs_unregister(device->major_info->gendisk.de_arr[MINOR(device->kdev) >> DASD_PARTN_BITS]);
+
+        return rc;
+}
+
+static inline int
+dasd_state_known_to_accept (dasd_device_t *device) 
+{
+        int rc = 0;
+        device->debug_area = debug_register (device->name, 0, 2, 
+                                             3 * sizeof (long));
+        debug_register_view (device->debug_area, &debug_sprintf_view);
+        debug_register_view (device->debug_area, &debug_hex_ascii_view);
+        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area created",device);
+        
+        if (device->discipline->int_handler) {
+                rc = s390_request_irq_special (device->devinfo.irq,
+                                               device->discipline->int_handler,
+                                               dasd_not_oper_handler,
+                                               0, DASD_NAME,
+                                               &device->dev_status);
+                if ( rc ) {
+                        printk("No request IRQ\n");
+                        goto out;
+                }
+        }
+        device->level = DASD_STATE_ACCEPT;
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_accept_to_known (dasd_device_t *device ) 
+{
+        if ( device->discipline == NULL )
+                goto out;
+        if (device->discipline->int_handler) {
+                free_irq (device->devinfo.irq, &device->dev_status);
+        }
+        DASD_DEVICE_DEBUG_EVENT (0, device,"%p debug area deleted",device);
+        if ( device->debug_area != NULL )
+                debug_unregister (device->debug_area);
+        device->discipline = NULL;
+        device->level = DASD_STATE_KNOWN;
+ out:
+        return 0;
+}
+
+static inline int
+dasd_state_accept_to_init (dasd_device_t *device) 
+{
+        int rc = 0;
+        unsigned long flags;
+
+        if ( device->discipline->init_analysis ) {
+                device->init_cqr=device->discipline->init_analysis (device);
+                if ( device->init_cqr != NULL ) {
+                        if ( device->discipline->start_IO == NULL )
+                                BUG();
+                        atomic_inc (&dasd_init_pending);
+                        s390irq_spin_lock_irqsave (device->devinfo.irq, 
+                                                   flags);
+                        rc = device->discipline->start_IO (device->init_cqr);
+                        s390irq_spin_unlock_irqrestore(device->devinfo.irq, 
+                                                       flags);
+                        if ( rc )
+                                goto out;
+                        device->level = DASD_STATE_INIT;
+                } else {
+                        rc = -ENOMEM;
+                }
+        } else {
+                rc = dasd_state_init_to_ready ( device ); 
+        }
+ out:
+        return rc;
+}
+
+static inline int
+dasd_state_init_to_ready (dasd_device_t *device ) 
+{
+        int rc = 0;    
+        if (device->discipline->do_analysis != NULL)
+                if ( device->discipline->do_analysis (device) == 0 ) 
+                        switch (device->sizes.bp_block) {
+                        case 512:
+                        case 1024:
+                        case 2048:
+                        case 4096:
+                                break;
+                        default:
+                                rc = -EMEDIUMTYPE;
+                        }
+        if ( device->init_cqr ) {
+                atomic_dec(&dasd_init_pending);
+                device->init_cqr = NULL; /* This one is no longer needed */
+        }
+        device->level = DASD_STATE_READY;
+        return rc;
+}
+
+static inline int
+dasd_state_ready_to_accept (dasd_device_t *device ) 
+{
+        int rc = 0;
+        unsigned long flags;
+
+        if ( device->init_cqr != NULL ) {
+                if ( device->discipline->term_IO == NULL )
+                        BUG();
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                device->discipline->term_IO (device->init_cqr);
+                s390irq_spin_unlock_irqrestore(device->devinfo.irq, flags);
+                atomic_dec (&dasd_init_pending);
+                dasd_free_request (device->init_cqr, device);
+                device->init_cqr = NULL;
+        }
+        memset(&device->sizes,0,sizeof(dasd_sizes_t));
+        device->level = DASD_STATE_ACCEPT;
+        return rc;
+}
+
+static inline int
+dasd_state_ready_to_online (dasd_device_t *device ) 
+{
+        int rc = 0;
+        dasd_unplug_device (device);
+        device->level = DASD_STATE_ONLINE;
+        return rc;
+}
+
+static inline int
+dasd_state_online_to_ready (dasd_device_t *device ) 
+{
+        int rc = 0;
+        dasd_plug_device (device);
+        device->level = DASD_STATE_READY;
+        return rc;
+}
+
+static inline int
+dasd_setup_blkdev (dasd_device_t *device ) 
+{
+        int rc = 0;
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                if (i == 0)
+                        device->major_info->gendisk.sizes[minor] =
+                                (device->sizes.blocks << device->
+                                 sizes.s2b_shift) >> 1;
+                else
+                        device->major_info->gendisk.sizes[minor + i] = 0;
+                hardsect_size[major][minor + i] = device->sizes.bp_block;
+                blksize_size[major][minor + i] = device->sizes.bp_block;
+                max_sectors[major][minor + i] =
+                        device->discipline->max_blocks << 
+                        device->sizes.s2b_shift;
+		device->major_info->gendisk.part[minor+i].start_sect = 0;
+		device->major_info->gendisk.part[minor+i].nr_sects = 0;
+        }
+        device->request_queue = kmalloc(sizeof(request_queue_t),GFP_KERNEL);
+        device->request_queue->queuedata = device;
+        blk_init_queue (device->request_queue, do_dasd_request);
+        blk_queue_headactive (device->request_queue, 0);
+        elevator_init (&(device->request_queue->elevator),ELEVATOR_NOOP);
+        return rc;
+}
+
+static inline int
+dasd_disable_blkdev (dasd_device_t *device ) 
+{
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                destroy_buffers(MKDEV(major,minor+i));
+                device->major_info->gendisk.sizes[minor + i] = 0;
+                hardsect_size[major][minor + i] = 0;
+                blksize_size[major][minor + i] = 0;
+                max_sectors[major][minor + i] = 0;
+        }
+        if (device->request_queue) {
+            blk_cleanup_queue (device->request_queue);
+            kfree(device->request_queue);
+            device->request_queue = NULL;
+        }
+        return 0;
+}
+
+
+/*
+ * function dasd_setup_partitions
+ * calls the function in genhd, which is appropriate to setup a partitioned disk
+ */
+static inline void
+dasd_setup_partitions ( dasd_device_t * device ) 
+{
+	register_disk (&device->major_info->gendisk,
+                       device->kdev,
+		       1 << DASD_PARTN_BITS,
+		       &dasd_device_operations,
+		       (device->sizes.blocks << device->sizes.s2b_shift));
+}
 
-int
-dasd_oper_handler (int irq, devreg_t * devreg)
+static inline void
+dasd_destroy_partitions ( dasd_device_t * device ) 
 {
-	int devno;
-	int rc;
-	devno = get_devno_by_irq (irq);
-        printk (KERN_WARNING PRINTK_HEADER "Oper handler called\n");
-	if (devno == -ENODEV) {
-          printk (KERN_WARNING PRINTK_HEADER "NODEV\n");
-		return -ENODEV;
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+        
+        for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                device->major_info->gendisk.part[minor+i].start_sect = 0;
+                device->major_info->gendisk.part[minor+i].nr_sects   = 0;
         }
-	if (dasd_autodetect) {
-		dasd_add_range (devno, 0);
-	}
-	rc = dasd_enable_single_volume (irq);
-	return rc;
+        devfs_register_partitions(&device->major_info->gendisk,
+                                  MINOR(device->kdev),1);
 }
-#endif	/* CONFIG_DASD_DYNAMIC */
 
-/* 
- * function dasd_set_device_level 
+static inline void
+dasd_resetup_partitions ( dasd_device_t * device ) 
+{
+    BUG();
+    dasd_destroy_partitions ( device ) ;
+    dasd_setup_partitions ( device ) ;
+}
+
+/*
+ * function dasd_set_device_level
  */
 static int
-dasd_set_device_level (unsigned int irq, int desired_level,
-		       dasd_discipline_t * discipline, int flags)
+dasd_set_device_level (unsigned int devno, 
+                       dasd_discipline_t * discipline,
+                       int to_state)
 {
 	int rc = 0;
-	int devno;
-	dasd_device_t **device_addr, *device;
-	int current_level;
-	major_info_t *major_info = NULL;
-	struct list_head *l;
-	int i, minor, major;
-	ccw_req_t *cqr = NULL;
-	struct gendisk *dd;
+        dasd_device_t **device_addr;
+        dasd_device_t *device;
+        int from_state;
 
-	devno = get_devno_by_irq (irq);
-	if (devno < 0) { /* e.g. when device has been detached before */
-		/* search in device list */
-		list_for_each(l,&dasd_major_info[0].list) {
-			major_info = list_entry(l,major_info_t,list);	
-			for (i = 0; i < DASD_PER_MAJOR; i++) {
-				device = major_info->dasd_device[i];
-				if (device && device->devinfo.irq == irq) {
-					devno = device->devinfo.devno;
-					break;
-				}
-			}
-			if (devno == -ENODEV)
-				return -ENODEV;
-		}
-	}
-	if (dasd_devindex_from_devno (devno) < 0) {
-		return -ENODEV;
-	}
-	while ((device_addr = dasd_device_from_devno (devno)) == NULL) {
-		if ((rc = dasd_register_major (NULL)) > 0) {
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered to major number: %u\n", rc);
-		} else {
-			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register to another major no\n");
-			return -ERANGE;
-		}
-	}
-	device = *device_addr;
-	if (!device) {		/* allocate device descriptor */
-		device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
-		if (!device) {
-			printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n");
-			goto nomem;
-		}
-		memset (device, 0, sizeof (dasd_device_t));
-		*device_addr = device;
-	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		int i;
-		major_info = list_entry(l,major_info_t,list);	
-		for (i = 0; i < DASD_PER_MAJOR; i++) {
-			if (major_info->dasd_device[i] == device) {
-				device->kdev = MKDEV (major_info->gendisk.major, i << DASD_PARTN_BITS);
-				break;
-			}
-		}
-		if (i < DASD_PER_MAJOR)
-			break;
-	}
-	if (major_info == &dasd_major_info[0]) {
-		return -ENODEV;
-	}
-	minor = MINOR (device->kdev);
-	major = MAJOR (device->kdev);
-	current_level = device->level;
-	if (desired_level > current_level) {
-		switch (current_level) {
-		case DASD_DEVICE_LEVEL_UNKNOWN:	/* Find a discipline */
-                        device->major_info = major_info;
-                        dasd_device_name (device->name,
-                                          ((long) device_addr -
-                                           (long) device->major_info->dasd_device) /
-                                          sizeof (dasd_device_t *),
-                                          0, &major_info->gendisk);
-			rc = get_dev_info_by_irq (irq, &device->devinfo);
-			if (rc < 0) {
-				break;
-			}
-			discipline = dasd_find_discipline (device);
-			if (discipline && !rc) {
-                                DASD_MESSAGE (KERN_INFO, device,
-                                              "%s", " ");
-			} else {
-                                break;
-			}
-			device->discipline = discipline;
-                        device->debug_area = debug_register(device->name,0,2,3*sizeof(long));
-                        debug_register_view(device->debug_area,&debug_sprintf_view);
-                        debug_register_view(device->debug_area,&debug_hex_ascii_view);
-			if (device->discipline->int_handler) {
-#ifdef CONFIG_DASD_DYNAMIC
-				s390_request_irq_special (irq,
-                                                          device->discipline->int_handler,
-                                                          dasd_not_oper_handler,
-							  0,
-							  DASD_NAME,
-							  &device->dev_status);
-#else				/* !defined(CONFIG_DASD_DYNAMIC) */
-				request_irq (irq,
-					     device->discipline->int_handler,
-					     0,
-					     DASD_NAME,
-					     &device->dev_status);
-#endif				/* CONFIG_DASD_DYNAMIC */
-			}
-			device->proc_dir = (struct proc_dir_entry *)
-			    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-			if (device->proc_dir) {
-				memset (device->proc_dir, 0, sizeof (struct proc_dir_entry));
-				device->proc_info = (struct proc_dir_entry *)
-				    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-				if (device->proc_info) {
-					memset (device->proc_info, 0,
-					      sizeof (struct proc_dir_entry));
-				}
-				device->proc_stats = (struct proc_dir_entry *)
-				    kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL);
-				if (device->proc_stats) {
-					memset (device->proc_stats, 0,
-					      sizeof (struct proc_dir_entry));
-				}
-			}
-			init_waitqueue_head (&device->wait_q);
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_UNKNOWN,
-				       DASD_DEVICE_LEVEL_RECOGNIZED);
-			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
-				break;
-		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
-			if (device->discipline->init_analysis) {
-				cqr = device->discipline->init_analysis (device);
-				if (cqr != NULL) {
-					dasd_chanq_enq (&device->queue, cqr);
-					if (device->discipline->start_IO) {
-						long flags;
-						s390irq_spin_lock_irqsave (irq, flags);
-						device->discipline->start_IO (cqr);
-						check_then_set (&device->level,
-                                                                DASD_DEVICE_LEVEL_RECOGNIZED,
-                                                                DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
-						s390irq_spin_unlock_irqrestore (irq, flags);
-					}
-				}
-			} else {
-				check_then_set (&device->level, DASD_DEVICE_LEVEL_RECOGNIZED,
-                                                DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
-			}
-			if (desired_level >= DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
-			return -EAGAIN;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:	/* Re-entering here ! */
-			if (device->discipline->do_analysis)
-                                if (device->discipline->do_analysis (device))
-                                        return -ENODEV;
-			switch (device->sizes.bp_block) {
-			case 512:
-			case 1024:
-			case 2048:
-			case 4096:
-				break;
-			default:
-				{
-					printk (KERN_INFO PRINTK_HEADER
-						"/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
-						" Did you format the drive?\n",
-						device->name, devno, device->sizes.bp_block);
-					return -EMEDIUMTYPE;
-				}
-			}
-			blk_init_queue (&device->request_queue, do_dasd_request);
-			blk_queue_headactive (&device->request_queue, 0);
-			elevator_init(&device->request_queue.elevator, ELEVATOR_NOOP);
-			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                                if (i == 0)
-                                        blk_size[major][minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
-				else
-					blk_size[major][minor + i] = 0;
-				hardsect_size[major][minor + i] = device->sizes.bp_block;
-				blksize_size[major][minor + i] = device->sizes.bp_block;
-				if (blksize_size[major][minor + i] < 1024)
-					blksize_size[major][minor + i] = 1024;
-
-				max_sectors[major][minor + i] =
-                                        device->discipline->max_blocks << device->sizes.s2b_shift;
-			}
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-				       DASD_DEVICE_LEVEL_ANALYSED);
-			dd = &major_info->gendisk;
-			dd->sizes[minor] = (device->sizes.blocks <<
-					    device->sizes.s2b_shift) >> 1;
-                        dd->part[minor].start_sect = 0;
-			{
-				char buffer[5];
-				sprintf(buffer,"%04X",device->devinfo.devno);
-				dd->de_arr[minor>>DASD_PARTN_BITS] = devfs_mk_dir(dasd_devfs_handle,buffer,NULL);
-			}
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#ifndef MODULE
-			if (flags & 0x80)
+        device_addr = dasd_find_device_addr ( devno );
+        if ( device_addr == NULL ) {
+                rc = -ENODEV;
+                goto out;
+        }
+        device = *device_addr;
+
+        if ( device == NULL ) {
+                from_state = DASD_STATE_DEL;
+                if ( to_state == DASD_STATE_DEL )
+                        goto out;
+        } else {
+                from_state = device->level;
+        }
+
+        if ( from_state == to_state )
+                goto out;
+
+        if ( to_state < from_state )
+                goto shutdown;
+
+        /* First check for bringup */
+        if ( from_state <= DASD_STATE_DEL &&
+             to_state >= DASD_STATE_NEW ) { 
+                rc = dasd_state_del_to_new(device_addr);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+                device = *device_addr;
+        }
+        if ( from_state <= DASD_STATE_NEW &&
+             to_state >= DASD_STATE_KNOWN ) { 
+                rc = dasd_state_new_to_known( device_addr, devno, discipline );
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( from_state <= DASD_STATE_KNOWN &&
+             to_state >= DASD_STATE_ACCEPT ) { 
+                rc = dasd_state_known_to_accept(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( dasd_probeonly ) {
+            goto out;
+        }
+        if ( from_state <= DASD_STATE_ACCEPT &&
+             to_state >= DASD_STATE_INIT ) { 
+                rc = dasd_state_accept_to_init(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        if ( from_state <= DASD_STATE_INIT &&
+             to_state >= DASD_STATE_READY ) { 
+                rc = -EAGAIN;
+                goto out;
+        }
+        if ( from_state <= DASD_STATE_READY &&
+             to_state >= DASD_STATE_ONLINE ) { 
+                rc = dasd_state_ready_to_online(device);
+                if ( rc ) {
+                        goto bringup_fail;
+                }
+        }
+        goto out;
+ bringup_fail:   /* revert changes */
+#if 0
+        printk (KERN_DEBUG PRINTK_HEADER
+                "failed to set device from state %d to %d at level %d rc %d. Reverting...\n",
+                from_state,to_state,device->level,rc);
 #endif
-#endif				/* KERNEL_VERSION */
-				dasd_partn_detect (device);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
-                        dasd_unplug_device(device);
-			check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ANALYSED,
-                                        DASD_DEVICE_LEVEL_ONLINE);
-                        
-			if (desired_level == DASD_DEVICE_LEVEL_ONLINE)
-                                break;
-		case DASD_DEVICE_LEVEL_ONLINE:	
-                        break;
-		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"Internal error in " __FILE__ " on line %d."
-				" validate_dasd called from %p with "
-				" desired_level = %d, current_level =%d"
-				" Pls send this message and your System.map to"
-				" linux390@de.ibm.com\n",
-				__LINE__, __builtin_return_address (0),
-				desired_level, current_level);
-			break;
-		}
-	} else if (desired_level < current_level) {	/* donwgrade device status */
-		switch (current_level) {
-		case DASD_DEVICE_LEVEL_ONLINE:	/* Fallthrough ?? */
-                        dasd_plug_device(device); 
-			check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ONLINE,
-                                        DASD_DEVICE_LEVEL_ANALYSED);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
-                                break;
-                case DASD_DEVICE_LEVEL_ANALYSED:	/* Fallthrough ?? */
-			for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
-                                __invalidate_buffers(MKDEV(major,minor),1);
-                                blk_size[major][minor] = 0;
-				hardsect_size[major][minor + i] = 0;
-				blksize_size[major][minor + i] = 0;
-				max_sectors[major][minor + i] = 0;
-			}
-			memset (&device->sizes, 0, sizeof (dasd_sizes_t));
-			blk_cleanup_queue (&device->request_queue);
-                        check_then_set (&device->level,
-                                        DASD_DEVICE_LEVEL_ANALYSED,
-                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
-                        if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
-                                break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
-			if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-				break;
-		case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:	/* Fallthrough ?? */
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
-				       DASD_DEVICE_LEVEL_RECOGNIZED);
-			if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
-				break;
-		case DASD_DEVICE_LEVEL_RECOGNIZED:	/* Fallthrough ?? */
-			if (device->discipline->int_handler) {
-				free_irq (irq, &device->dev_status);
-			}
-			device->discipline = NULL;
-                        debug_unregister(device->debug_area);
-			check_then_set (&device->level,
-				       DASD_DEVICE_LEVEL_RECOGNIZED,
-				       DASD_DEVICE_LEVEL_UNKNOWN);
-                        *device_addr = NULL;
-                        kfree(device);
-			if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
-				break;
-		case DASD_DEVICE_LEVEL_UNKNOWN:
-			break;
-		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"Internal error in " __FILE__ " on line %d."
-				" validate_dasd called from %p with "
-				" desired_level = %d, current_level =%d"
-				" Pls send this message and your System.map to"
-				" linux390@de.ibm.com\n",
-				__LINE__, __builtin_return_address (0),
-				desired_level, current_level);
-			break;
-		}
-	}
-	if (rc) {
-		goto exit;
-	}
-      nomem:
-	rc = -ENOMEM;
-      exit:
-	return 0;
+        to_state = from_state;
+        from_state = device->level;
+        
+        /* now do a shutdown */
+ shutdown: 
+        if ( from_state >= DASD_STATE_ONLINE &&
+             to_state <= DASD_STATE_READY ) 
+                if (dasd_state_online_to_ready(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_READY &&
+                      to_state <= DASD_STATE_ACCEPT ) 
+                if ( dasd_state_ready_to_accept(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_ACCEPT &&
+             to_state <= DASD_STATE_KNOWN ) 
+                if ( dasd_state_accept_to_known(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_KNOWN &&
+             to_state <= DASD_STATE_NEW ) 
+                if ( dasd_state_known_to_new(device))
+                        BUG();
+        if ( from_state >= DASD_STATE_NEW &&
+             to_state <= DASD_STATE_DEL) 
+                if (dasd_state_new_to_del(device_addr))
+                        BUG();
+        goto out;
+ out:
+        return rc;
 }
 
 /* SECTION: Procfs stuff */
@@ -2758,29 +3398,16 @@
 	int len;
 } tempinfo_t;
 
-void dasd_fill_inode (struct inode* inode, int fill) {
-    if (fill)
-        MOD_INC_USE_COUNT;
-    else
-        MOD_DEC_USE_COUNT;
+void
+dasd_fill_inode (struct inode *inode, int fill)
+{
+	if (fill)
+		MOD_INC_USE_COUNT;
+	else
+		MOD_DEC_USE_COUNT;
 }
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 static struct proc_dir_entry *dasd_proc_root_entry = NULL;
-#else
-static struct proc_dir_entry dasd_proc_root_entry =
-{
-	low_ino:0,
-	namelen:4,
-	name:"dasd",
-	mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-	nlink:1,
-	uid:0,
-	gid:0,
-	size:0,
-        fill_inode:dasd_fill_inode
-};
-#endif				/* KERNEL_VERSION */
 static struct proc_dir_entry *dasd_devices_entry;
 static struct proc_dir_entry *dasd_statistics_entry;
 
@@ -2790,94 +3417,138 @@
 	int rc = 0;
 	int size = 1;
 	int len = 0;
-	major_info_t *temp = dasd_major_info;
+	major_info_t *temp = NULL;
 	struct list_head *l;
 	tempinfo_t *info;
 	int i;
+        unsigned long flags;
+        int index = 0;
 
+        MOD_INC_USE_COUNT;
+        spin_lock_irqsave(&discipline_lock,flags);
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
-		printk (KERN_WARNING "No memory available for data\n");
-		return -ENOMEM;
+                printk (KERN_WARNING "No memory available for data\n");
+                MOD_DEC_USE_COUNT;
+                return -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
 	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		temp = list_entry(l,major_info_t,list);	
-		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
-			dasd_device_t *device = temp->dasd_device[i];
-			if (device) {
-				size += 128;
-			}
-		}
+	list_for_each (l, &dasd_major_info[0].list) {
+                size += 128 * 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
-	temp = dasd_major_info;
-	info->data = (char *) vmalloc (size);	/* FIXME! determine space needed in a better way */
+	info->data = (char *) vmalloc (size);	
+	DASD_DRIVER_DEBUG_EVENT (1, dasd_devices_open, "area: %p, size 0x%x",
+				 info->data, size);
 	if (size && info->data == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
 		vfree (info);
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
-	list_for_each(l,&dasd_major_info[0].list) {
-		temp = list_entry(l,major_info_t,list);	
+	list_for_each (l, &dasd_major_info[0].list) {
+		temp = list_entry (l, major_info_t, list);
 		for (i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i++) {
-			dasd_device_t *device = temp->dasd_device[i];
+			dasd_device_t *device;
+                        int devno = dasd_devno_from_devindex(index+i);
+                        if ( devno == -ENODEV )
+                                continue;
+                        device = temp->dasd_device[i];
 			if (device) {
 				len += sprintf (info->data + len,
-						"%04X(%s) at (%d:%d) is %7s:",
+						"%04X(%s) at (%3d:%3d) is %7s:",
 						device->devinfo.devno,
-						device->discipline ? device->discipline->name : "none",
-				    temp->gendisk.major, i << DASD_PARTN_BITS,
+						device->discipline ?
+						device->
+						discipline->name : "none",
+						temp->gendisk.major,
+						i << DASD_PARTN_BITS,
 						device->name);
 				switch (device->level) {
-				case DASD_DEVICE_LEVEL_UNKNOWN:
-					len += sprintf (info->data + len, "unknown\n");
-					break;
-				case DASD_DEVICE_LEVEL_RECOGNIZED:
-					len += sprintf (info->data + len, "passive");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+				case DASD_STATE_NEW:
+                                        len +=
+					    sprintf (info->data + len,
+						     "new");
+                                        break;
+				case DASD_STATE_KNOWN:
+					len +=
+					    sprintf (info->data + len,
+						     "detected");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
-					len += sprintf (info->data + len, "busy   \n");
+				case DASD_STATE_ACCEPT:
+                                        len += sprintf (info->data + len,"accepted");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
-					len += sprintf (info->data + len, "n/f    \n");
+				case DASD_STATE_INIT:
+					len +=
+					    sprintf (info->data + len,
+						     "busy   ");
 					break;
-				case DASD_DEVICE_LEVEL_ANALYSED:
-					len += sprintf (info->data + len, "active ");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
-					break;
-				case DASD_DEVICE_LEVEL_ONLINE:
-					len += sprintf (info->data + len, "active ");
-					len += sprintf (info->data + len, " at blocksize: %d, %ld blocks, %ld MB\n",
-							device->sizes.bp_block,
-							device->sizes.blocks,
-							((device->sizes.bp_block >> 9) * device->sizes.blocks) >> 11);
+				case DASD_STATE_READY:
+				case DASD_STATE_ONLINE:
+                                    if ( atomic_read(&device->plugged) )
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "fenced ");
+                                    else
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "active ");
+                                    if ( device->sizes.bp_block == 512 ||
+                                         device->sizes.bp_block == 1024 ||
+                                         device->sizes.bp_block == 2048 ||
+                                         device->sizes.bp_block == 4096 )
+					len +=
+					    sprintf (info->data + len,
+						     "at blocksize: %d, %ld blocks, %ld MB",
+						     device->sizes.bp_block,
+						     device->sizes.blocks,
+						     ((device->
+						       sizes.bp_block >> 9) *
+						      device->sizes.
+						      blocks) >> 11);
+                                    else
+                                        len +=
+                                            sprintf (info->data + len,
+                                                     "n/f    ");
 					break;
 				default:
-					len += sprintf (info->data + len, "no stat\n");
+					len +=
+					    sprintf (info->data + len,
+						     "no stat");
 					break;
 				}
-			}
+			} else {
+                                char buffer[7];
+                                dasd_device_name (buffer, i, 0, &temp->gendisk);
+                                if ( devno < 0  ) {
+                                        len += sprintf (info->data + len,
+                                                        "none");
+                                } else {
+                                        len += sprintf (info->data + len,
+                                                        "%04X",devno);
+                                }
+                                len += sprintf (info->data + len,
+                                                "(none) at (%3d:%3d) is %7s: unknown",
+						temp->gendisk.major,
+						i << DASD_PARTN_BITS,
+						buffer);
+                        }
+                        if ( dasd_probeonly )
+                            len += sprintf(info->data + len,"(probeonly)");
+                        len += sprintf(info->data + len,"\n");
 		}
+                index += 1 << (MINORBITS - DASD_PARTN_BITS);
 	}
 	info->len = len;
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
+        spin_unlock_irqrestore(&discipline_lock,flags);
 	return rc;
 }
 
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 static ssize_t
-dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+dasd_generic_read (struct file *file, char *user_buf, size_t user_len,
+		   loff_t * offset)
 {
 	loff_t len;
 	tempinfo_t *p_info = (tempinfo_t *) file->private_data;
@@ -2894,85 +3565,68 @@
 }
 
 static ssize_t
-dasd_devices_write (struct file *file, const char *user_buf, size_t user_len, loff_t * offset)
+dasd_devices_write (struct file *file, const char *user_buf,
+		    size_t user_len, loff_t * offset)
 {
 	char *buffer = vmalloc (user_len+1);
 	int off = 0;
 	char *temp;
-        int irq;
-        int j,target;
-        dasd_range_t *rptr, range;
+	dasd_range_t range;
+        int features = 0;
 
 	if (buffer == NULL)
 		return -ENOMEM;
 	if (copy_from_user (buffer, user_buf, user_len)) {
-		vfree(buffer);
+		vfree (buffer);
 		return -EFAULT;
 	}
 	buffer[user_len] = 0;
-	printk (KERN_INFO PRINTK_HEADER "Now executing %s\n", buffer);
-        if (strncmp ( buffer, "set ",4) &&
-            strncmp ( buffer, "add ",4)){
-                printk (KERN_WARNING PRINTK_HEADER 
-                        "/proc/dasd/devices: only 'set' and 'add' are supported verbs");
-                return -EINVAL;
-        }
-        off += 4;
-        while (!isalnum(buffer[off])) off++;
+	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/devices: '%s'\n", buffer);
+	if (strncmp (buffer, "set ", 4) && strncmp (buffer, "add ", 4)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"/proc/dasd/devices: only 'set' and 'add' are supported verbs\n");
+		return -EINVAL;
+	}
+	off += 4;
+	while (buffer[off] && !isalnum (buffer[off]))
+		off++;
 	if (!strncmp (buffer + off, "device", strlen ("device"))) {
-		off += strlen("device");
-		while (!isalnum(buffer[off])) off++;
-        }
+		off += strlen ("device");
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+	}
 	if (!strncmp (buffer + off, "range=", strlen ("range="))) {
-		off += strlen("range=");
-		while (!isalnum(buffer[off])) off++;
-        }
-        temp = buffer+off;
-        range.from = dasd_strtoul (temp, &temp);
-        range.to = range.from;
-        if (*temp == '-') {
-                temp++;
-                range.to = dasd_strtoul (temp, &temp);
-        }
-        off = (long)temp - (long)buffer;
-        if ( !strncmp ( buffer, "add",strlen("add"))) {
-                rptr = dasd_add_range (range.from, range.to);
-        } else {
-                rptr = &range;
-        }
-        while (!isalnum(buffer[off])) off++;
-        printk (KERN_INFO PRINTK_HEADER 
-                "varying device range %04X-%04X\n", rptr->from, rptr->to);
-        if ( !strncmp ( buffer, "add",strlen("add")) ||
-             !strncmp ( buffer+off, "on",strlen("on")) ) {
-                target = DASD_DEVICE_LEVEL_ONLINE;
-                for (j = rptr->from; j <= rptr->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE, NULL, 0);
-			}
-		}
-		printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-		{
-			static wait_queue_head_t wait_queue;
-			init_waitqueue_head (&wait_queue);
-			interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) );
+		off += strlen ("range=");
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+	}
+	
+	temp = buffer + off;
+	range.from = dasd_strtoul (temp, &temp, &features);
+	range.to = range.from;
+
+	if (*temp == '-') {
+		temp++;
+		range.to = dasd_strtoul (temp, &temp, &features);
+	}
+
+	off = (long) temp - (long) buffer;
+	if (!strncmp (buffer, "add", strlen ("add"))) {
+		dasd_add_range (range.from, range.to, features);
+                dasd_enable_ranges (&range, NULL, 0);
+	} else { 
+		while (buffer[off] && !isalnum (buffer[off]))
+			off++;
+		if (!strncmp (buffer + off, "on", strlen ("on"))) {
+        	        dasd_enable_ranges (&range, NULL, 0);
+		} else if (!strncmp (buffer + off, "off", strlen ("off"))) {
+        	        dasd_disable_ranges (&range, NULL, 0, 1);
+		} else {
+			printk (KERN_WARNING PRINTK_HEADER
+			"/proc/dasd/devices: parse error in '%s'", buffer);
 		}
-        } else if ( !strncmp ( buffer+off, "off",strlen("off"))) {
-                target = DASD_DEVICE_LEVEL_UNKNOWN;
-        } else {
-                printk (KERN_WARNING PRINTK_HEADER 
-                        "/proc/dasd/devices: parse error in '%s'", buffer);
-                vfree (buffer);
-                return -EINVAL;
-                
-        }
-        for (j = rptr->from; j <= rptr->to; j++) {
-                irq = get_irq_by_devno (j);
-                if (irq >= 0) {
-                        dasd_set_device_level (irq, target, NULL, 0);
-                }
-        }
+	}
+	vfree (buffer);
 	return user_len;
 }
 
@@ -2986,25 +3640,18 @@
 			vfree (p_info->data);
 		vfree (p_info);
 	}
-#ifdef MODULE
-        MOD_DEC_USE_COUNT;
-#endif
+	MOD_DEC_USE_COUNT;
 	return rc;
 }
 
-static struct file_operations dasd_devices_file_ops =
-{
-	read:dasd_devices_read,	/* read */
+static struct file_operations dasd_devices_file_ops = {
+	read:dasd_generic_read,	/* read */
 	write:dasd_devices_write,	/* write */
 	open:dasd_devices_open,	/* open */
 	release:dasd_devices_close,	/* close */
 };
 
-static struct inode_operations dasd_devices_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	default_file_ops:&dasd_devices_file_ops		/* file ops */
-#endif				/* LINUX_IS_24 */
+static struct inode_operations dasd_devices_inode_ops = {
 };
 
 static int
@@ -3015,9 +3662,11 @@
 	tempinfo_t *info;
 	int shift, i, help = 0;
 
+        MOD_INC_USE_COUNT;
 	info = (tempinfo_t *) vmalloc (sizeof (tempinfo_t));
 	if (info == NULL) {
 		printk (KERN_WARNING "No memory available for data\n");
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	} else {
 		file->private_data = (void *) info;
@@ -3027,99 +3676,154 @@
 		printk (KERN_WARNING "No memory available for data\n");
 		vfree (info);
 		file->private_data = NULL;
+                MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 	for (shift = 0, help = dasd_global_profile.dasd_io_reqs;
-	     help > 8192;
-	     help = help >> 1, shift++) ;
-	len = sprintf (info->data, "%ld dasd I/O requests\n", dasd_global_profile.dasd_io_reqs);
-	len += sprintf (info->data + len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
-	len += sprintf (info->data + len, "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
+	     help > 8192; help = help >> 1, shift++) ;
+	len =
+	    sprintf (info->data, "%d dasd I/O requests\n",
+		     dasd_global_profile.dasd_io_reqs);
+	len +=
+	    sprintf (info->data + len, "with %d sectors(512B each)\n",
+		     dasd_global_profile.dasd_io_sects);
+	len +=
+	    sprintf (info->data + len,
+		     "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k 128k\n");
+	len +=
+	    sprintf (info->data + len,
+		     "_256 _512 __1M __2M __4M __8M _16M _32M _64M 128M 256M 512M __1G __2G __4G _>4G\n");
 	len += sprintf (info->data + len, "Histogram of sizes (512B secs)\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_secs[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_secs[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	len += sprintf (info->data + len, "Histogram of I/O times\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_times[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_times[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_times[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O times per sector\n");
+	len +=
+	    sprintf (info->data + len, "Histogram of I/O times per sector\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_timps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_timps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_timps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	len += sprintf (info->data + len, "Histogram of I/O time till ssch\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time1[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time1[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time1[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between ssch and irq\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between ssch and irq per sector\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between ssch and irq per sector\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2ps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time2ps[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time2ps[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
-	len += sprintf (info->data + len, "Histogram of I/O time between irq and end\n");
+	len +=
+	    sprintf (info->data + len,
+		     "Histogram of I/O time between irq and end\n");
 	for (i = 0; i < 16; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time3[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	for (; i < 32; i++) {
-		len += sprintf (info->data + len, "%4ld ", dasd_global_profile.dasd_io_time3[i] >> shift);
+		len +=
+		    sprintf (info->data + len, "%4d ",
+			     dasd_global_profile.dasd_io_time3[i] >> shift);
 	}
 	len += sprintf (info->data + len, "\n");
 	info->len = len;
-#ifdef MODULE
-        MOD_INC_USE_COUNT;
-#endif
 	return rc;
 }
 
-static struct file_operations dasd_statistics_file_ops =
+static ssize_t
+dasd_statistics_write (struct file *file, const char *user_buf,
+		       size_t user_len, loff_t * offset)
 {
-	read:dasd_devices_read,	/* read */
+	char *buffer = vmalloc (user_len);
+
+	if (buffer == NULL)
+		return -ENOMEM;
+	if (copy_from_user (buffer, user_buf, user_len)) {
+		vfree (buffer);
+		return -EFAULT;
+	}
+	buffer[user_len] = 0;
+	printk (KERN_INFO PRINTK_HEADER "/proc/dasd/statictics: '%s'\n",
+		buffer);
+	if (strncmp (buffer, "reset", 4)) {
+		memset (&dasd_global_profile, 0, sizeof (dasd_profile_info_t));
+	}
+	return user_len;
+}
+
+static struct file_operations dasd_statistics_file_ops = {
+	read:dasd_generic_read,	/* read */
 	open:dasd_statistics_open,	/* open */
+	write:dasd_statistics_write,	/* write */
 	release:dasd_devices_close,	/* close */
 };
 
-static struct inode_operations dasd_statistics_inode_ops =
-{
-#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-	default_file_ops:&dasd_statistics_file_ops	/* file ops */
-#endif				/* LINUX_IS_24 */
+static struct inode_operations dasd_statistics_inode_ops = {
 };
 
 int
 dasd_proc_init (void)
 {
 	int rc = 0;
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	dasd_proc_root_entry = proc_mkdir ("dasd", &proc_root);
 	dasd_devices_entry = create_proc_entry ("devices",
 						S_IFREG | S_IRUGO | S_IWUSR,
@@ -3131,204 +3835,175 @@
 						   dasd_proc_root_entry);
 	dasd_statistics_entry->proc_fops = &dasd_statistics_file_ops;
 	dasd_statistics_entry->proc_iops = &dasd_statistics_inode_ops;
-#else
-	proc_register (&proc_root, &dasd_proc_root_entry);
-	dasd_devices_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
-	if (dasd_devices_entry) {
-		memset (dasd_devices_entry, 0, sizeof (struct proc_dir_entry));
-		dasd_devices_entry->name = "devices";
-		dasd_devices_entry->namelen = strlen ("devices");
-		dasd_devices_entry->low_ino = 0;
-		dasd_devices_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
-		dasd_devices_entry->nlink = 1;
-		dasd_devices_entry->uid = 0;
-		dasd_devices_entry->gid = 0;
-		dasd_devices_entry->size = 0;
-		dasd_devices_entry->get_info = NULL;
-		dasd_devices_entry->ops = &dasd_devices_inode_ops;
-		proc_register (&dasd_proc_root_entry, dasd_devices_entry);
-	}
-	dasd_statistics_entry = (struct proc_dir_entry *) kmalloc (sizeof (struct proc_dir_entry), GFP_ATOMIC);
-	if (dasd_statistics_entry) {
-		memset (dasd_statistics_entry, 0, sizeof (struct proc_dir_entry));
-		dasd_statistics_entry->name = "statistics";
-		dasd_statistics_entry->namelen = strlen ("statistics");
-		dasd_statistics_entry->low_ino = 0;
-		dasd_statistics_entry->mode = (S_IFREG | S_IRUGO | S_IWUSR);
-		dasd_statistics_entry->nlink = 1;
-		dasd_statistics_entry->uid = 0;
-		dasd_statistics_entry->gid = 0;
-		dasd_statistics_entry->size = 0;
-		dasd_statistics_entry->get_info = NULL;
-		dasd_statistics_entry->ops = &dasd_statistics_inode_ops;
-		proc_register (&dasd_proc_root_entry, dasd_statistics_entry);
-	}
-#endif				/* LINUX_IS_24 */
 	return rc;
 }
 
 void
 dasd_proc_cleanup (void)
 {
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 	remove_proc_entry ("devices", dasd_proc_root_entry);
 	remove_proc_entry ("statistics", dasd_proc_root_entry);
 	remove_proc_entry ("dasd", &proc_root);
-#else
-	proc_unregister (&dasd_proc_root_entry, dasd_statistics_entry->low_ino);
-	kfree (dasd_statistics_entry);
-	proc_unregister (&dasd_proc_root_entry, dasd_devices_entry->low_ino);
-	kfree (dasd_devices_entry);
-	proc_unregister (&proc_root, dasd_proc_root_entry.low_ino);
-#endif				/* LINUX_IS_24 */
 }
 
+int
+dasd_request_module ( void *name ) {
+	int rc = -ERESTARTSYS;
+    	strcpy(current->comm, name);
+   	daemonize();
+   	while ( current->fs->root == NULL ) { /* wait for root-FS */
+        	DECLARE_WAIT_QUEUE_HEAD(wait);
+        	sleep_on_timeout(&wait,HZ); /* wait in steps of one second */
+	} 
+	while ( (rc=request_module(name)) != 0 ) {
+        	DECLARE_WAIT_QUEUE_HEAD(wait);
+		printk ( KERN_INFO "request_module returned %d for %s\n",rc,(char*)name);
+        	sleep_on_timeout(&wait,5* HZ); /* wait in steps of 5 seconds */
+    	}
+    	return rc;
+}
+
+
 /* SECTION: Initializing the driver */
 int __init
 dasd_init (void)
 {
 	int rc = 0;
 	int irq;
-	int j;
-	major_info_t *major_info=NULL;
+	major_info_t *major_info = NULL;
 	struct list_head *l;
-	dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "initializing...\n");
-        dasd_debug_area = debug_register(DASD_NAME,0,2,3*sizeof(long));
-        debug_register_view(dasd_debug_area,&debug_sprintf_view);
-        debug_register_view(dasd_debug_area,&debug_hex_ascii_view);
-        
-        if ( dasd_debug_area == NULL ) {
-                goto failed;
-        }
-        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","ENTRY");
-	dasd_devfs_handle = devfs_mk_dir(NULL,DASD_NAME,NULL);
-        if ( dasd_devfs_handle < 0 ) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,"%s","no devfs");
-                goto failed;
-        }
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l,major_info_t,list);
-                if ((rc = dasd_register_major (major_info)) > 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "major %d: success",major_info->gendisk.major);
-                        printk (KERN_INFO PRINTK_HEADER
-                                "Registered successfully to major no %u\n", major_info->gendisk.major);
+	dasd_debug_area = debug_register (DASD_NAME, 0, 2, 4 * sizeof (long));
+	debug_register_view (dasd_debug_area, &debug_sprintf_view);
+	debug_register_view (dasd_debug_area, &debug_hex_ascii_view);
+
+	init_waitqueue_head (&dasd_init_waitq);
+
+	if (dasd_debug_area == NULL) {
+		goto failed;
+	}
+	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "ENTRY");
+	dasd_devfs_handle = devfs_mk_dir (NULL, DASD_NAME, NULL);
+	if (dasd_devfs_handle < 0) {
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no devfs");
+		goto failed;
+	}
+	list_for_each (l, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
+		if ((rc = dasd_register_major (major_info)) > 0) {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "major %d: success",
+						 major_info->gendisk.major);
+			printk (KERN_INFO PRINTK_HEADER
+				"Registered successfully to major no %u\n",
+				major_info->gendisk.major);
 		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "major %d: failed",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "major %d: failed",
+						 major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't register successfully to major no %d\n", major_info->gendisk.major);
+				"Couldn't register successfully to major no %d\n",
+				major_info->gendisk.major);
 			/* revert registration of major infos */
-                        goto failed;
+			goto failed;
 		}
 	}
 #ifndef MODULE
 	dasd_split_parm_string (dasd_parm_string);
 #endif				/* ! MODULE */
 	dasd_parse (dasd);
-	dasd_init_emergency_req ();
 
 	rc = dasd_proc_init ();
 	if (rc) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "%s","no proc-FS");
-                goto failed;
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init, "%s", "no proc-FS");
+		goto failed;
 	}
 	genhd_dasd_name = dasd_device_name;
-	genhd_dasd_fillgeo = dasd_fillgeo;
 
+	if (dasd_autodetect) {	/* update device range to all devices */
+		for (irq = get_irq_first (); irq != -ENODEV;
+		     irq = get_irq_next (irq)) {
+			int devno = get_devno_by_irq (irq);
+			int index = dasd_devindex_from_devno (devno);
+			if (index == -ENODEV) {	/* not included in ranges */
+				DASD_DRIVER_DEBUG_EVENT (2, dasd_init,
+							 "add %04X to range",
+							 devno);
+				dasd_add_range (devno, devno, DASD_DEFAULT_FEATURES);
+			}
+		}
+	}
+
+	if (MACHINE_IS_VM) {
+#ifdef CONFIG_DASD_DIAG
+		rc = dasd_diag_init ();
+		if (rc == 0) {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "DIAG discipline %s",
+						 "success");
+			printk (KERN_INFO PRINTK_HEADER
+				"Registered DIAG discipline successfully\n");
+		} else {
+			DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+						 "DIAG discipline %s",
+						 "failed");
+			goto failed;
+		}
+#endif /* CONFIG_DASD_DIAG */
+#if defined(CONFIG_DASD_DIAG_MODULE) && defined(CONFIG_DASD_AUTO_DIAG)
+                kernel_thread(dasd_request_module,"dasd_diag_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_DIAG */
+	}
 #ifdef CONFIG_DASD_ECKD
 	rc = dasd_eckd_init ();
 	if (rc == 0) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "ECKD discipline %s","success");
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "ECKD discipline %s", "success");
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered ECKD discipline successfully\n");
 	} else {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "ECKD discipline %s","failed");
-                goto failed;
-	}
-#endif				/* CONFIG_DASD_ECKD */
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "ECKD discipline %s", "failed");
+		goto failed;
+	}
+#endif /* CONFIG_DASD_ECKD */
+#if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD)
+        kernel_thread(dasd_request_module,"dasd_eckd_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_ECKD */
 #ifdef CONFIG_DASD_FBA
 	rc = dasd_fba_init ();
 	if (rc == 0) {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "FBA discipline %s","success");
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "FBA discipline %s", "success");
 
 		printk (KERN_INFO PRINTK_HEADER
 			"Registered FBA discipline successfully\n");
 	} else {
-                DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                        "FBA discipline %s","failed");
-                goto failed;
-	}
-#endif				/* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_DIAG
-	if (MACHINE_IS_VM) {
-		rc = dasd_diag_init ();
-		if (rc == 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "DIAG discipline %s","success");
-			printk (KERN_INFO PRINTK_HEADER
-				"Registered DIAG discipline successfully\n");
-		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,dasd_init,
-                                                "DIAG discipline %s","failed");
-                        goto failed;
-		}
-	}
-#endif				/* CONFIG_DASD_DIAG */
-	rc = 0;
-	if (dasd_autodetect) { /* update device range to all devices */
-		for (irq = get_irq_first (); irq != -ENODEV; 
-                     irq = get_irq_next (irq)) {
-			int devno = get_devno_by_irq (irq);
-			int index = dasd_devindex_from_devno (devno);
-			if (index == -ENODEV) {		/* not included in ranges */
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "add %04X to range",
-                                                        devno);
-				dasd_add_range (devno, 0);
-                        }
+		DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+					 "FBA discipline %s", "failed");
+		goto failed;
+	}
+#endif /* CONFIG_DASD_FBA */
+#if defined(CONFIG_DASD_FBA_MODULE) && defined(CONFIG_DASD_AUTO_FBA)
+        kernel_thread(dasd_request_module,"dasd_fba_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_FBA */
+        {
+                char **disc=dasd_disciplines;
+                while (*disc) {
+                        kernel_thread(dasd_request_module,*disc,SIGCHLD);
+                        disc++;
                 }
         }
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-                        if (irq >= 0)
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "1st step in initialization irq 0x%x",irq);
-                        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-                                               NULL, 0);
-		}
-	}
-	printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
-	{
-		static wait_queue_head_t wait_queue;
-		init_waitqueue_head (&wait_queue);
-		interruptible_sleep_on_timeout (&wait_queue,
-						(5 * HZ) );
-	}
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-                                DASD_DRIVER_DEBUG_EVENT(2,dasd_init,
-                                                        "2nd step in initialization irq 0x%x",irq);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ONLINE,
-						       NULL, 0);
-			}
-		}
-	}
-        goto out;
- failed:
-	printk (KERN_INFO PRINTK_HEADER "initialization not performed due to errors\n");
-        cleanup_dasd();
- out:
-        DASD_DRIVER_DEBUG_EVENT(0,dasd_init,"%s","LEAVE");
+
+	rc = 0;
+	goto out;
+      failed:
+	printk (KERN_INFO PRINTK_HEADER
+		"initialization not performed due to errors\n");
+	cleanup_dasd ();
+      out:
+	DASD_DRIVER_DEBUG_EVENT (0, dasd_init, "%s", "LEAVE");
 	printk (KERN_INFO PRINTK_HEADER "initialization finished\n");
 	return rc;
 }
@@ -3336,95 +4011,78 @@
 static void
 cleanup_dasd (void)
 {
-	int i,j,rc;
-	int irq;
-	major_info_t *major_info=NULL;
-	struct list_head *l;
-	dasd_range_t *range, *next;
+	int i,rc=0;
+	major_info_t *major_info = NULL;
+	struct list_head *l,*n;
+	dasd_range_t *range;
 
 	printk (KERN_INFO PRINTK_HEADER "shutting down\n");
         DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","ENTRY");
-	for (range = dasd_range_head; range; range = range->next) {
-		for (j = range->from; j <= range->to; j++) {
-			irq = get_irq_by_devno (j);
-			if (irq >= 0) {
-                                DASD_DRIVER_DEBUG_EVENT(2,"cleanup_dasd",
-                                                        "shutdown irq 0x%x",irq);
-				dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
-						       NULL, 0);
-			}
-		}
-	}
+	dasd_disable_ranges (&dasd_range_head, NULL, 1, 1);
+        if (MACHINE_IS_VM) {
 #ifdef CONFIG_DASD_DIAG
-	if (MACHINE_IS_VM) {
-		dasd_diag_cleanup ();
-                DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                        "DIAG discipline %s","success");
+                dasd_diag_cleanup ();
+                DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+                                         "DIAG discipline %s", "success");
                 printk (KERN_INFO PRINTK_HEADER
-                        "De-Registered DIAG discipline successfully\n");
+			"De-Registered DIAG discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
 	}
-#endif				/* CONFIG_DASD_DIAG */
 #ifdef CONFIG_DASD_FBA
 	dasd_fba_cleanup ();
-        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                "FBA discipline %s","success");
-        printk (KERN_INFO PRINTK_HEADER
-                "De-Registered FBA discipline successfully\n");
-#endif				/* CONFIG_DASD_FBA */
+	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+				 "FBA discipline %s", "success");
+	printk (KERN_INFO PRINTK_HEADER
+		"De-Registered FBA discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
 #ifdef CONFIG_DASD_ECKD
 	dasd_eckd_cleanup ();
-        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                "ECKD discipline %s","success");
-        printk (KERN_INFO PRINTK_HEADER
-                "De-Registered ECKD discipline successfully\n");
-#endif				/* CONFIG_DASD_ECKD */
+	DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+				 "ECKD discipline %s", "success");
+	printk (KERN_INFO PRINTK_HEADER
+		"De-Registered ECKD discipline successfully\n");
+#endif /* CONFIG_DASD_ECKD_BUILTIN */
         
 	dasd_proc_cleanup ();
-	dasd_cleanup_emergency_req ();
-
-	list_for_each(l,&dasd_major_info[0].list) {
-		major_info=list_entry(l,major_info_t,list);	
+        
+	list_for_each_safe (l, n, &dasd_major_info[0].list) {
+		major_info = list_entry (l, major_info_t, list);
 		for (i = 0; i < DASD_PER_MAJOR; i++) {
 			kfree (major_info->dasd_device[i]);
 		}
-		if ((major_info -> flags & DASD_MAJOR_INFO_REGISTERED) &&
+		if ((major_info->flags & DASD_MAJOR_INFO_REGISTERED) &&
 		    (rc = dasd_unregister_major (major_info)) == 0) {
-                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                                "major %d: success",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+						 "major %d: success",
+						 major_info->gendisk.major);
 			printk (KERN_INFO PRINTK_HEADER
-				"Unregistered successfully from major no %u\n", major_info->gendisk.major);
+				"Unregistered successfully from major no %u\n",
+				major_info->gendisk.major);
 		} else {
-                        DASD_DRIVER_DEBUG_EVENT(1,"cleanup_dasd",
-                                                "major %d: failed",major_info->gendisk.major);
+			DASD_DRIVER_DEBUG_EVENT (1, "cleanup_dasd",
+						 "major %d: failed",
+						 major_info->gendisk.major);
 			printk (KERN_WARNING PRINTK_HEADER
-				"Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major, rc);
-		}
-	}
-
+				"Couldn't unregister successfully from major no %d rc = %d\n",
+				major_info->gendisk.major, rc);
+  		}
+  	}
+	list_for_each_safe (l, n, &dasd_range_head.list) {
+		range = list_entry (l, dasd_range_t, list);
+                dasd_remove_range(range);
+        }
 
-	range = dasd_range_head;
-	while (range) {
-		next = range->next;
-                dasd_remove_range (range);
-		if (next == NULL)
-			break;
-		else
-			range = next;
-	}
-	dasd_range_head = NULL;
-        
 #ifndef MODULE
-        for( j = 0; j < 256; j++ )
-                if ( dasd[j] ) {
-                        kfree(dasd[j]);
-                        dasd[j] = NULL;
+        for( i = 0; i < 256; i++ )
+                if ( dasd[i] ) {
+                        kfree(dasd[i]);
+                        dasd[i] = NULL;
                 }
 #endif /* MODULE */
         if (dasd_devfs_handle) 
                 devfs_unregister(dasd_devfs_handle);
         if (dasd_debug_area != NULL )
                 debug_unregister(dasd_debug_area);
-
 	printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
         DASD_DRIVER_DEBUG_EVENT(0,"cleanup_dasd","%s","LEAVE");
 }
@@ -3434,7 +4092,7 @@
 init_module (void)
 {
 	int rc = 0;
-	return dasd_init ();
+	rc = dasd_init ();
 	return rc;
 }
 
@@ -3453,7 +4111,7 @@
  * of the file.
  * ---------------------------------------------------------------------------
  * Local variables:
- * c-indent-level: 4 
+ * c-indent-level: 4
  * c-brace-imaginary-offset: 0
  * c-brace-offset: -4
  * c-argdecl-indent: 4
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_3370_erp.c linux/drivers/s390/block/dasd_3370_erp.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_3370_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_3370_erp.c	Mon Dec  3 22:58:52 2001
@@ -6,8 +6,9 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
 
+#include "dasd_int.h"
+#include "dasd_3370_erp.h"
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(3370)"
@@ -29,7 +30,7 @@
  *   dasd_era_fatal     for all fatal (unrecoverable errors)
  *   dasd_era_recover   for all others.
  */
-dasd_era_t
+dasd_era_t 
 dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 	char *sense = stat->ii.sense.data;
@@ -37,7 +38,7 @@
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 	if (sense[0] & 0x80) {	/* CMD reject */
 		return dasd_era_fatal;
 	}
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_3370_erp.h linux/drivers/s390/block/dasd_3370_erp.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_3370_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_3370_erp.h	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,15 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3370_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_3370_ERP_H
+#define DASD_3370_ERP_H
+
+dasd_era_t dasd_3370_erp_examine (ccw_req_t *, devstat_t *);
+
+#endif				/* DASD_3990_ERP_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_3990_erp.c linux/drivers/s390/block/dasd_3990_erp.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_3990_erp.c	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_3990_erp.c	Mon Dec  3 22:58:52 2001
@@ -4,13 +4,17 @@
  *                  Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
+ *
+ * History of changes:
+ * 05/14/01 fixed PL030160GTO (BUG() in erp_action_5)
  */
 
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
 #include <asm/s390io.h>
 #include <linux/timer.h>
+
+#include "dasd_int.h"
 #include "dasd_eckd.h"
 #include "dasd_3990_erp.h"
 
@@ -24,7 +28,6 @@
  * SECTION DEBUG ROUTINES
  ***************************************************************************** 
  */
-#ifdef ERP_DEBUG
 void
 log_erp_chain (ccw_req_t *cqr,
                int       caller,
@@ -34,104 +37,100 @@
         ccw_req_t     *loop_cqr = cqr;
 	dasd_device_t *device   = cqr->device;
 
-        char    *page = (char *)get_free_page(GFP_ATOMIC);
-        int     len = 0;
         int     i;
         char    *nl, 
                 *end_cqr,
                 *begin, 
                 *end;
+        
+        /* dump sense data */
+        if (device->discipline            && 
+            device->discipline->dump_sense  ) {
 
-        if ( page == NULL ) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "No memory to dump ERP chain\n");
-                return;
-        }        
-                        
+                device->discipline->dump_sense (device, 
+                                                cqr);
+        }
+
+        /* log the channel program */
         while (loop_cqr != NULL) {
                 
-                memset (page, 0, 4096);
-                len = 0;
-
-                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                 "device %04X on irq %d: (%s) ERP chain report for req: %p\n",
-                                 device->devinfo.devno,
-                                 device->devinfo.irq,
-                                 caller == 0 ? "EXAMINE" : "ACTION",
-                                 loop_cqr);
+                DASD_MESSAGE (KERN_ERR, device, 
+                              "(%s) ERP chain report for req: %p\n",
+                              caller == 0 ? "EXAMINE" : "ACTION",
+                              loop_cqr);
                 
                 nl      = (char *) loop_cqr;
                 end_cqr = nl + sizeof (ccw_req_t); 
-
+                
                 while (nl < end_cqr) {
-
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                         nl,
-                                         nl[0], nl[1], nl[2], nl[3],
-                                         nl[4], nl[5], nl[6], nl[7],
-                                         nl[8], nl[9], nl[10], nl[11],
-                                         nl[12], nl[13], nl[14], nl[15]);
+                        
+                        DASD_MESSAGE (KERN_ERR, device, 
+                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                      "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                      nl,
+                                      nl[0], nl[1], nl[2], nl[3],
+                                      nl[4], nl[5], nl[6], nl[7],
+                                      nl[8], nl[9], nl[10], nl[11],
+                                      nl[12], nl[13], nl[14], nl[15]);
                         nl +=16;
                 }        
                 
                 nl  = (char *) loop_cqr->cpaddr;
+                
+                if (loop_cqr->cplength > 40) { /* log only parts of the CP */
 
-                if (loop_cqr->cplength > 40 ) { /* log only parts of the CP */
-
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "Start of channel program:\n");
-
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Start of channel program:\n");
+                        
                         for (i = 0; i < 20; i += 2) { 
-
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
                         
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "End of channel program:\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "End of channel program:\n");
                         
                         nl  = (char *) loop_cqr->cpaddr;
                         nl  += ((loop_cqr->cplength - 10) * 8);
                         
                         for (i = 0; i < 20; i += 2) { 
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
                         
                 } else { /* log the whole CP */
                         
-                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                         "Channel program (complete):\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Channel program (complete):\n");
                         
                         for (i = 0; i < (loop_cqr->cplength + 4); i += 2) { 
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                 "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                 nl,
-                                                 nl[0], nl[1], nl[2], nl[3],
-                                                 nl[4], nl[5], nl[6], nl[7],
-                                                 nl[8], nl[9], nl[10], nl[11],
-                                                 nl[12], nl[13], nl[14], nl[15]);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                              "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                              nl,
+                                              nl[0], nl[1], nl[2], nl[3],
+                                              nl[4], nl[5], nl[6], nl[7],
+                                              nl[8], nl[9], nl[10], nl[11],
+                                              nl[12], nl[13], nl[14], nl[15]);
                                 
                                 nl += 16;
                         }
@@ -140,51 +139,47 @@
                 /* log bytes arround failed CCW if not already done */ 
                 begin = (char *) loop_cqr->cpaddr;
                 end   = begin + ((loop_cqr->cplength+4) * 8);
-                nl = (void *)cpa;
+                nl = (void *)(long)cpa;
 
                 if (loop_cqr == cqr) {  /* log only once */
  
-                        if ((loop_cqr->cplength > 40) ||     /* not whole CP was logged or */
-                            ((nl < begin ) &&                /* CCW is outside logged CP   */
-                             (nl > end   )          )   ) {
+                        /* if not whole CP logged OR CCW outside logged CP */
+                        if ((loop_cqr->cplength > 40) ||   
+                            ((nl < begin        ) &&
+                             (nl > end          )   )   ) {
                         
-                                nl -= 10*8;     /* start some bytes before */          
+                                nl -= 10*8;     /* start some bytes before */
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "Failed CCW (%p) (area):\n",
-                                                 (void *)cpa);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                                "Failed CCW (%p) (area):\n",
+                                                (void *)(long)cpa);
                                 
                                 for (i = 0; i < 20; i += 2) { 
                                         
-                                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                         "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
-                                                         "%02x%02x%02x%02x %02x%02x%02x%02x\n",
-                                                         nl,
-                                                         nl[0], nl[1], nl[2], nl[3],
-                                                         nl[4], nl[5], nl[6], nl[7],
-                                                         nl[8], nl[9], nl[10], nl[11],
-                                                         nl[12], nl[13], nl[14], nl[15]);
+                                        DASD_MESSAGE (KERN_ERR, device, 
+                                                      "%p: %02x%02x%02x%02x %02x%02x%02x%02x "
+                                                      "%02x%02x%02x%02x %02x%02x%02x%02x\n",
+                                                      nl,
+                                                      nl[0], nl[1], nl[2], nl[3],
+                                                      nl[4], nl[5], nl[6], nl[7],
+                                                      nl[8], nl[9], nl[10], nl[11],
+                                                      nl[12], nl[13], nl[14], nl[15]);
                                         
                                         nl += 16;
                                 }
                                 
                         } else {
                                 
-                                len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
-                                                 "Failed CCW (%p) already logged\n",
-                                                 (void *)cpa);
+                                DASD_MESSAGE (KERN_ERR, device, 
+                                              "Failed CCW (%p) already logged\n",
+                                              (void *)(long)cpa);
                         }
                 }
-
-                printk ("%s", page);
+                
                 loop_cqr = loop_cqr->refers;
         }
         
-        free_page ((unsigned long) page);
-
 } /* end log_erp_chain */
-#endif /* ERP_DEBUG */
-
 
 /*
  ***************************************************************************** 
@@ -211,32 +206,46 @@
  *   dasd_era_recover   for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine_24 (char *sense)
+dasd_3990_erp_examine_24 (ccw_req_t *cqr,
+                          char      *sense)
 {
 
-	/* check for 'Command Recejct' which is always a fatal error  */
-	if (sense[0] & SNS0_CMD_REJECT) {
-		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-			return dasd_era_recover;
-		} else {
-			return dasd_era_fatal;
-		}
+        dasd_device_t *device = cqr->device;
+        
+	/* check for 'Command Reject' */
+	if ((  sense[0] & SNS0_CMD_REJECT       ) &&
+	    (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: Command Reject detected - "
+                              "fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* check for 'Invalid Track Format'                           */
-	if (sense[1] & SNS1_INV_TRACK_FORMAT) {
-		if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-			return dasd_era_recover;
-		} else {
-			return dasd_era_fatal;
-		}
+
+	/* check for 'Invalid Track Format' */
+	if ((  sense[1] & SNS1_INV_TRACK_FORMAT ) &&
+            (!(sense[2] & SNS2_ENV_DATA_PRESENT))   ) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: Invalid Track Format detected "
+                              "- fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* check for 'No Record Found'                                */
+
+	/* check for 'No Record Found' */
 	if (sense[1] & SNS1_NO_REC_FOUND) {
-            return dasd_era_fatal;
+                
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 24: No Record Found detected "
+                              "- fatal error");
+
+                return dasd_era_fatal;
 	}
-	/* return recoverable for all others                          */
-	return dasd_era_recover;
 
+	/* return recoverable for all others */
+  	return dasd_era_recover;
 } /* END dasd_3990_erp_examine_24 */
 
 /*
@@ -253,19 +262,27 @@
  *   dasd_era_recover   for recoverable others.
  */
 dasd_era_t
-dasd_3990_erp_examine_32 (char *sense)
+dasd_3990_erp_examine_32 (ccw_req_t *cqr,
+                          char      *sense)
 {
 
+        dasd_device_t *device = cqr->device;
+
 	switch (sense[25]) {
 	case 0x00:
 		return dasd_era_none;
+
 	case 0x01:
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "EXAMINE 32: fatal error");
 		return dasd_era_fatal;
+
 	default:
+
 		return dasd_era_recover;
 	}
 
-}				/* end dasd_3990_erp_examine_32 */
+} /* end dasd_3990_erp_examine_32 */
 
 /*
  * DASD_3990_ERP_EXAMINE 
@@ -292,31 +309,30 @@
         dasd_era_t era    = dasd_era_recover;
 
 	/* check for successful execution first */
-	if (stat->cstat == 0x00 &&
-	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+	if (stat->cstat == 0x00                                 &&
+	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)  )
 		return dasd_era_none;
 
 	/* distinguish between 24 and 32 byte sense data */
 	if (sense[27] & DASD_SENSE_BIT_0) {
 
-		/* examine the 24 byte sense data */
-		era = dasd_3990_erp_examine_24 (sense);
+		era = dasd_3990_erp_examine_24 (cqr,
+                                                sense);
 
 	} else {
 
-		/* examine the 32 byte sense data */
-		era = dasd_3990_erp_examine_32 (sense);
+		era = dasd_3990_erp_examine_32 (cqr,
+                                                sense);
 
-	} /* end distinguish between 24 and 32 byte sense data */
+	} 
 
-#ifdef ERP_DEBUG
+        /* log the erp chain if fatal error occurred */
         if (era == dasd_era_fatal) {
 
                 log_erp_chain (cqr, 
                                0, 
                                stat->cpa);
         }
-#endif /* ERP_DEBUG */
         
         return era;
 
@@ -334,6 +350,37 @@
  */
 
 /*
+ * DASD_3990_ERP_CLEANUP 
+ *
+ * DESCRIPTION
+ *   Removes the already build but not neccessary ERP request and sets
+ *   the status of the original cqr / erp to the given (final) status
+ *
+ *  PARAMETER
+ *   erp                request to be blocked
+ *   final_status       either CQR_STATUS_DONE or CQR_STATUS_FAILED 
+ *
+ * RETURN VALUES
+ *   cqr                original cqr               
+ */
+ccw_req_t *
+dasd_3990_erp_cleanup (ccw_req_t *erp,
+                       char      final_status)
+{
+
+        ccw_req_t *cqr = erp->refers;
+        
+        dasd_free_request (erp, erp->device);
+
+        check_then_set (&cqr->status,
+                        CQR_STATUS_ERROR,
+                        final_status);
+
+        return cqr;
+
+} /* end dasd_3990_erp_cleanup */ 
+
+/*
  * DASD_3990_ERP_BLOCK_QUEUE 
  *
  * DESCRIPTION
@@ -365,8 +412,9 @@
 
         /* restart queue after some time */
         device->timer.function = dasd_3990_erp_restart_queue; 
-        device->timer.data = (unsigned long) erp;
-        device->timer.expires = jiffies + (expires * HZ);
+        device->timer.data     = (unsigned long) erp;
+        device->timer.expires  = jiffies + (expires * HZ);
+
         add_timer(&device->timer); 
 
 } /* end dasd_3990_erp_block_queue */ 
@@ -390,6 +438,7 @@
 void
 dasd_3990_erp_restart_queue (unsigned long erp)
 {
+
         ccw_req_t     *cqr    = (void *) erp;
 	dasd_device_t *device = cqr->device;
 	unsigned long flags;
@@ -399,10 +448,9 @@
                                    flags);
 
         /* 'restart' the device queue */
-        if (cqr->status == CQR_STATUS_PENDING){
+        if (cqr->status == CQR_STATUS_PENDING) {
                 
-                DASD_MESSAGE (KERN_INFO, device,
-                              "%s",
+                DASD_MESSAGE (KERN_INFO, device, "%s",
                               "request queue restarted by MIH");
 
                 check_then_set (&cqr->status,
@@ -414,11 +462,10 @@
         s390irq_spin_unlock_irqrestore (device->devinfo.irq, 
                                         flags);
 
-        dasd_schedule_bh(device);
+        dasd_schedule_bh (device);
 
 } /* end dasd_3990_erp_restart_queue */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_INT_REQ 
  *
@@ -434,27 +481,31 @@
 ccw_req_t *
 dasd_3990_erp_int_req (ccw_req_t *erp)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function */
+        /* and retry once without blocking queue                 */
+        /* (this enables easier enqueing of the cqr)             */
         if (erp->function != dasd_3990_erp_int_req) {
+
                 erp->retries  = 256;
                 erp->function = dasd_3990_erp_int_req;
-        }
 
-        /* issue a message and wait for 'device ready' interrupt */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "is offline or not installed - "
-                      "INTERVENTION REQUIRED!!\n");
+        } else {
 
-        dasd_3990_erp_block_queue (erp,
-                                   60);
+                /* issue a message and wait for 'device ready' interrupt */
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "is offline or not installed - "
+                              "INTERVENTION REQUIRED!!");
+                
+                dasd_3990_erp_block_queue (erp,
+                                           60);
+        }
 
 	return erp;
 
 } /* end dasd_3990_erp_int_req */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_ALTERNATE_PATH 
@@ -478,22 +529,17 @@
 	dasd_device_t *device = erp->device;
         int irq = device->devinfo.irq;
 
-	/* dissable current channel path - this causes the use of an other 
-	   channel path if there is one.. */
-
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "disable lpu %x",
-                      erp->dstat->lpum);
-
         /* try alternate valid path */
         erp->lpm     &= ~(erp->dstat->lpum);
         erp->options |= DOIO_VALID_LPM;		/* use LPM for DO_IO */
 
 	if ((erp->lpm & ioinfo[irq]->opm) != 0x00) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "try alternate lpm %x",
-                              erp->lpm);
+		DASD_MESSAGE (KERN_DEBUG, device,
+                              "try alternate lpm=%x (lpum=%x / opm=%x)",
+                              erp->lpm,
+                              erp->dstat->lpum,
+                              ioinfo[irq]->opm);
 
 		/* reset status to queued to handle the request again... */
 		check_then_set (&erp->status,
@@ -504,10 +550,11 @@
                 
 	} else {
          
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",      
-                              "No alternate channel path left -> "
-                              "permanent error");
+                DASD_MESSAGE (KERN_ERR, device,
+                              "No alternate channel path left (lpum=%x / "
+                              "opm=%x) -> permanent error",
+                              erp->dstat->lpum,
+                              ioinfo[irq]->opm);
                 
                 /* post request with permanent error */
                 check_then_set (&erp->status,
@@ -518,7 +565,6 @@
         
 } /* end dasd_3990_erp_alternate_path */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_DCTL
  *
@@ -527,7 +573,7 @@
  *   Inhibit Write subcommand (0x20) and the given modifier.
  *
  *  PARAMETER
- *   erp                pointer to the current ERP
+ *   erp                pointer to the current (failed) ERP
  *   modifier           subcommand modifier
  *   
  * RETURN VALUES
@@ -538,14 +584,25 @@
 dasd_3990_erp_DCTL (ccw_req_t *erp,
                     char      modifier)
 {
-	DCTL_data_t *DCTL_data;
-        ccw1_t      *ccw;
-        ccw_req_t   *dctl_cqr = dasd_alloc_request ((char *) &erp->magic,
-                                                    1,
-                                                    sizeof(DCTL_data_t));
+
+	dasd_device_t *device = erp->device;
+	DCTL_data_t   *DCTL_data;
+        ccw1_t        *ccw;
+        ccw_req_t     *dctl_cqr = dasd_alloc_request ((char *) &erp->magic,
+                                                      1,
+                                                      sizeof(DCTL_data_t),
+                                                      erp->device);
         
-	if (dctl_cqr == NULL) {
-		BUG();
+	if (!dctl_cqr) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate DCTL-CQR");
+                
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+
+		return erp;
         }
 
 	DCTL_data = dctl_cqr->data;
@@ -557,15 +614,24 @@
 	memset (ccw, 0, sizeof (ccw1_t));
         ccw->cmd_code = CCW_CMD_DCTL;
         ccw->count    = 4;
-        set_normalized_cda(ccw, __pa (DCTL_data));
+        if (dasd_set_normalized_cda(ccw, 
+                                    __pa (DCTL_data), dctl_cqr, erp->device)) {
+                dasd_free_request (dctl_cqr, erp->device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate DCTL-CQR");
 
+                check_then_set (&erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+		return erp;
+        }
         dctl_cqr->function = dasd_3990_erp_DCTL;
-        dctl_cqr->refers = erp;
-        dctl_cqr->device = erp->device;
-        dctl_cqr->magic = erp->magic;
-        dctl_cqr->lpm = LPM_ANYPATH;
-        dctl_cqr->expires = 5 * TOD_MIN;
-        dctl_cqr->retries = 2;
+        dctl_cqr->refers   = erp;
+        dctl_cqr->device   = erp->device;
+        dctl_cqr->magic    = erp->magic;
+        dctl_cqr->lpm      = LPM_ANYPATH;
+        dctl_cqr->expires  = 5 * TOD_MIN;
+        dctl_cqr->retries  = 2;
 	asm volatile ("STCK %0":"=m" (dctl_cqr->buildclk));
 
         dctl_cqr->status = CQR_STATUS_FILLED;
@@ -573,7 +639,6 @@
 	return dctl_cqr;
 
 } /* end dasd_3990_erp_DCTL */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ACTION_1 
@@ -595,6 +660,7 @@
 ccw_req_t *
 dasd_3990_erp_action_1 (ccw_req_t *erp)
 {
+
         erp->function = dasd_3990_erp_action_1;
 
         dasd_3990_erp_alternate_path (erp);
@@ -624,21 +690,22 @@
 dasd_3990_erp_action_4 (ccw_req_t *erp,
 			char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function    */
         /* and retry once without waiting for state change pending  */
         /* interrupt (this enables easier enqueing of the cqr)      */
         if (erp->function != dasd_3990_erp_action_4) {
-                erp->retries  = 255; 
+
+                erp->retries  = 256; 
                 erp->function = dasd_3990_erp_action_4;
 
         } else {
 
                 if (sense[25] & 0x1D) {	/* state change pending */
                         
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
+                        DASD_MESSAGE (KERN_INFO, device, "%s",
                                       "waiting for state change pending "
                                       "int");
                         
@@ -646,11 +713,8 @@
                                                    30);
                         
                 } else {
+
                         /* no state change pending - retry */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "no state change pending - retry");
-                        
                         check_then_set (&erp->status,
                                         CQR_STATUS_ERROR,
                                         CQR_STATUS_QUEUED);
@@ -667,12 +731,12 @@
  ***************************************************************************** 
  */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_ACTION_5 
  *
  * DESCRIPTION
  *   Setup ERP to do the ERP action 5 (see Reference manual).
+ *   NOTE: Further handling is done in xxx_further_erp after the retries.
  *
  *  PARAMETER
  *   erp                pointer to the current ERP
@@ -684,16 +748,11 @@
 ccw_req_t *
 dasd_3990_erp_action_5 (ccw_req_t *erp)
 {
+
         /* first of all retry */
         erp->retries = 10;
         erp->function = dasd_3990_erp_action_5;
 
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_QUEUED);
-
-        /* further handling is done in xxx_further_erp after the retries */
-
         return erp;
 
 } /* end dasd_3990_erp_action_5 */
@@ -713,15 +772,17 @@
  *   void
  */
 void
-dasd_3990_handle_env_data (char *sense)
+dasd_3990_handle_env_data (ccw_req_t *erp,
+                           char      *sense)
 {
-	/* check bytes 7-23 for further information */
 
-	char msg_format = (sense[7] & 0xF0);
-	char msg_no = (sense[7] & 0x0F);
+        dasd_device_t *device = erp->device;
+	char msg_format       = (sense[7] & 0xF0);
+	char msg_no           = (sense[7] & 0x0F);
+        
 
 	switch (msg_format) {
-	case 0x00:		/* Format 0 - Program or System Checks */
+	case 0x00:	/* Format 0 - Program or System Checks */
 
 		if (sense[1] & 0x10) {	/* check message to operator bit */
 
@@ -729,579 +790,595 @@
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Invalid Command\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Command");
 				break;
 			case 0x02:
-				printk (KERN_WARNING PRINTK_HEADER
-				     "FORMAT 0 - Invalid Command Sequence\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Command "
+                                              "Sequence");
 				break;
 			case 0x03:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - CCW Count less than "
-					"required\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - CCW Count less than "
+                                              "required");
 				break;
 			case 0x04:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Invalid Parameter\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Parameter");
 				break;
 			case 0x05:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Diagnostic of Sepecial "
-					"Command Violates File Mask\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Diagnostic of Sepecial"
+                                              " Command Violates File Mask");
 				break;
 			case 0x07:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Channel Returned with "
-					"Incorrect retry CCW\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Channel Returned with "
+                                              "Incorrect retry CCW");
 				break;
 			case 0x08:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reset Notification\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reset Notification");
 				break;
 			case 0x09:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Storage Path Restart\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Storage Path Restart");
 				break;
 			case 0x0A:
-				printk (KERN_WARNING PRINTK_HEADER
-				    "FORMAT 0 - Channel requested ... %02x\n",
-					sense[8]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Channel requested "
+                                              "... %02x",
+                                              sense[8]);
 				break;
 			case 0x0B:
-				printk (KERN_WARNING PRINTK_HEADER
-				     "FORMAT 0 - Invalid Defective/Alternate "
-					"Track Pointer\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Invalid Defective/"
+                                              "Alternate Track Pointer");
 				break;
 			case 0x0C:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - DPS Installation Check\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - DPS Installation "
+                                              "Check");
 				break;
 			case 0x0E:
-				printk (KERN_WARNING PRINTK_HEADER
-				    "FORMAT 0 - Command Invalid on Secondary "
-					"Address\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Command Invalid on "
+                                              "Secondary Address");
 				break;
 			case 0x0F:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Status Not As Required: "
-					"reason %02x\n",
-					sense[8]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Status Not As "
+                                              "Required: reason %02x",
+                                              sense[8]);
 				break;
 			default:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reseved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reseved");
 			}
 		} else {
 			switch (msg_no) {
 			case 0x00:	/* No Message */
 				break;
 			case 0x01:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Device Error Source\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Device Error Source");
 				break;
 			case 0x02:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reserved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reserved");
 				break;
 			case 0x03:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Device Fenced - device = "
-					"%02x\n",
-					sense[4]);
+                                DASD_MESSAGE (KERN_WARNING, device,
+                                              "FORMAT 0 - Device Fenced - "
+                                              "device = %02x",
+                                              sense[4]);
 				break;
 			case 0x04:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Data Pinned for Device\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Data Pinned for "
+                                              "Device");
 				break;
 			default:
-				printk (KERN_WARNING PRINTK_HEADER
-					"FORMAT 0 - Reserved\n");
+                                DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                              "FORMAT 0 - Reserved");
 			}
                 }
                 break;
 		
-	case 0x10:		/* Format 1 - Device Equipment Checks */
+	case 0x10:	/* Format 1 - Device Equipment Checks */
 		switch (msg_no) {
 		case 0x00:	/* No Message */
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device Status 1 not as "
-				"expected\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device Status 1 not as "
+                                      "expected");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Index missing\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Index missing");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Interruption cannot be reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Interruption cannot be reset");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device did not respond to "
-				"selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device did not respond to "
+                                      "selection");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device check-2 error or Set "
-				"Sector is not complete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device check-2 error or Set "
+                                      "Sector is not complete");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Head address does not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Head address does not "
+                                      "compare");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device status 1 not valid\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device status 1 not valid");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Device not ready\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Device not ready");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Track physical address did "
-				"not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Track physical address did "
+                                      "not compare");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Missing device address bit\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Missing device address bit");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Drive motor switch is off\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Drive motor switch is off");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Seek incomplete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Seek incomplete");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Cylinder address did not "
-				"compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Cylinder address did not "
+                                      "compare");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Offset active cannot be reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Offset active cannot be "
+                                      "reset");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 1 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 1 - Reserved");
 		}
                 break;		
                         
-	case 0x20:		/* Format 2 - 3990 Equipment Checks */
+	case 0x20:	/* Format 2 - 3990 Equipment Checks */
 		switch (msg_no) {
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - 3990 check-2 error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - 3990 check-2 error");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Support facility errors\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - Support facility errors");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Microcode detected error %02x\n",
-				sense[8]);
+                        DASD_MESSAGE (KERN_WARNING, device,
+                                      "FORMAT 2 - Microcode detected error %02x",
+                                      sense[8]);
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 2 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 2 - Reserved");
 		}
                 break;		
 
-	case 0x30:		/* Format 3 - 3990 Control Checks */
+	case 0x30:	/* Format 3 - 3990 Control Checks */
 		switch (msg_no) {
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 3 - Allegiance terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 3 - Allegiance terminated");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 3 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 3 - Reserved");
 		}
                 break;		
 
-	case 0x40:		/* Format 4 - Data Checks */
+	case 0x40:	/* Format 4 - Data Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Home address area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Home address area error");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Count area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Count area error");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Key area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Key area error");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Data area error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Data area error");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 4 - No sync byte in home address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in home address "
+                                      "area");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 4 - No syn byte in count address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in count address "
+                                      "area");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No sync byte in key area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in key area");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No syn byte in data area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in data area");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Home address area error; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Home address area error; "
+                                      "offset active");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - Count area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Count area error; offset "
+                                      "active");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Key area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Key area error; offset "
+                                      "active");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Data area error; offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Data area error; "
+                                      "offset active");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - No sync byte in home address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in home "
+                                      "address area; offset active");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 4 - No syn byte in count address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No syn byte in count "
+                                      "address area; offset active");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No sync byte in key area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No sync byte in key area; "
+                                      "offset active");
 			break;
 		case 0x0F:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - No syn byte in data area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - No syn byte in data area; "
+                                      "offset active");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 4 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 4 - Reserved");
 		}
                 break;		
 
-	case 0x50:		/* Format 5 - Data Check with displacement information */
+	case 0x50:	/* Format 5 - Data Check with displacement information */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-			  "FORMAT 5 - Data Check in the home address area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the "
+                                      "home address area");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the count area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the count area");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the key area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the key area");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the data area\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the data area");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-			    "FORMAT 5 - Data Check in the home address area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the "
+                                      "home address area; offset active");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the count area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the count area; "
+                                      "offset active");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the key area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the key area; "
+                                      "offset active");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Data Check in the data area; "
-				"offset active\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Data Check in the data area; "
+                                      "offset active");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 5 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 5 - Reserved");
 		}
                 break;		
 
-	case 0x60:		/* Format 6 - Usage Statistics/Overrun Errors */
+	case 0x60:	/* Format 6 - Usage Statistics/Overrun Errors */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel A\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel A");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel B\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel B");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel C\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel C");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel D\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel D");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel E\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel E");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel F\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel F");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel G\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel G");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Overrun on channel H\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Overrun on channel H");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 6 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 6 - Reserved");
 		}
                 break;		
 
-	case 0x70:		/* Format 7 - Device Connection Control Checks */
+	case 0x70:	/* Format 7 - Device Connection Control Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC initiated by a connection "
-				"check alert\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC initiated by a connection "
+                                      "check alert");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC 1 sequence not successful\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC 1 sequence not "
+                                      "successful");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - RCC 1 and RCC 2 sequences not "
-				"successful\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - RCC 1 and RCC 2 sequences not "
+                                      "successful");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in during selection "
-				"sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in during "
+                                      "selection sequence");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - extra RCC required\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - extra RCC required");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid DCC selection response "
-				"or timeout\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid DCC selection "
+                                      "response or timeout");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Missing end operation; device "
-				"transfer complete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Missing end operation; device "
+                                      "transfer complete");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Missing end operation; device "
-				"transfer incomplete\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Missing end operation; device "
+                                      "transfer incomplete");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in for an immediate "
-				"command sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in for an "
+                                      "immediate command sequence");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Invalid tag-in for an extended "
-				"command sequence\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Invalid tag-in for an "
+                                      "extended command sequence");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - 3990 microcode time out when "
-				"stopping selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - 3990 microcode time out when "
+                                      "stopping selection");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - No response to selection after "
-				"a poll interruption\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - No response to selection "
+                                      "after a poll interruption");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Permanent path error (DASD "
-				"controller not available)\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Permanent path error (DASD "
+                                      "controller not available)");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - DASD controller not available on "
-				"disconnected command chain\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - DASD controller not available"
+                                      " on disconnected command chain");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 7 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 7 - Reserved");
 		}
                 break;		
 
-	case 0x80:		/* Format 8 - Additional Device Equipment Checks */
+	case 0x80:	/* Format 8 - Additional Device Equipment Checks */
 		switch (msg_no) {
 		case 0x00:	/* No Message */
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Error correction code hardware "
-				"fault\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Error correction code "
+                                      "hardware fault");
 			break;
 		case 0x03:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Unexpected end operation response "
-				"code\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Unexpected end operation "
+                                      "response code");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - End operation with transfer count "
-				"not zero\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - End operation with transfer "
+                                      "count not zero");
 			break;
 		case 0x05:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - End operation with transfer "
-				"count zero\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - End operation with transfer "
+                                      "count zero");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 8 - DPS checks after a system reset or "
-				"selective reset\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DPS checks after a system "
+                                      "reset or selective reset");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - DPS cannot be filled\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DPS cannot be filled");
 			break;
 		case 0x08:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Short busy time-out during device "
-				"selection\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Short busy time-out during "
+                                      "device selection");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - DASD controller failed to set or "
-				"reset the long busy latch\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - DASD controller failed to "
+                                      "set or reset the long busy latch");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT 8 - No interruption from device during "
-				"a command chain\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - No interruption from device "
+                                      "during a command chain");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 8 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 8 - Reserved");
 		}
                 break;		
 
-	case 0x90:		/* Format 9 - Device Read, Write, and Seek Checks */
+	case 0x90:	/* Format 9 - Device Read, Write, and Seek Checks */
 		switch (msg_no) {
 		case 0x00:
 			break;	/* No Message */
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Device check-2 error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Device check-2 error");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Head address did not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Head address did not compare");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Track physical address did not "
-				"compare while oriented\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Track physical address did "
+                                      "not compare while oriented");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-			     "FORMAT 9 - Cylinder address did not compare\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Cylinder address did not "
+                                      "compare");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT 9 - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT 9 - Reserved");
 		}
                 break;		
 
 	case 0xF0:		/* Format F - Cache Storage Checks */
 		switch (msg_no) {
 		case 0x00:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Operation Terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Operation Terminated");
 			break;
 		case 0x01:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Subsystem Processing Error\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Subsystem Processing Error");
 			break;
 		case 0x02:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Cache or nonvolatile storage "
-				"equipment failure\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Cache or nonvolatile storage "
+                                      "equipment failure");
 			break;
 		case 0x04:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Caching terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching terminated");
 			break;
 		case 0x06:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Cache fast write access not "
-				"authorized\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Cache fast write access not "
+                                      "authorized");
 			break;
 		case 0x07:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Track format incorrect\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Track format incorrect");
 			break;
 		case 0x09:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Caching reinitiated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching reinitiated");
 			break;
 		case 0x0A:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Nonvolatile storage terminated\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Nonvolatile storage "
+                                      "terminated");
 			break;
 		case 0x0B:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Volume is suspended duplex\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Volume is suspended duplex");
 			break;
 		case 0x0C:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - Subsystem status connot be "
-				"determined\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Subsystem status connot be "
+                                      "determined");
 			break;
 		case 0x0D:
-			printk (KERN_WARNING PRINTK_HEADER
-			      "FORMAT F - Caching status reset to default\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - Caching status reset to "
+                                      "default");
 			break;
 		case 0x0E:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT F - DASD Fast Write inhibited\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT F - DASD Fast Write inhibited");
 			break;
 		default:
-			printk (KERN_WARNING PRINTK_HEADER
-				"FORMAT D - Reserved\n");
+                        DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                      "FORMAT D - Reserved");
 		}
                 break;		
 
-	default:		/* unknown message format - should not happen */
+	default:	/* unknown message format - should not happen */
 
 	} /* end switch message format */
 
@@ -1324,38 +1401,29 @@
 dasd_3990_erp_com_rej (ccw_req_t *erp,
 		       char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
-        ccw_req_t     *cqr    = NULL;
 
         erp->function = dasd_3990_erp_com_rej;
 
 	/* env data present (ACTION 10 - retry should work) */
 	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Command Reject - environmental data present\n");
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Command Reject - environmental data present");
 
-		dasd_3990_handle_env_data (sense);
+		dasd_3990_handle_env_data (erp,
+                                           sense);
 
 		erp->retries = 5;
 
 	} else {
 		/* fatal error -  set status to FAILED */
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Command Reject - Fatal error\n");
-
-                cqr = erp->refers;
-
-                dasd_free_request (erp);
-
-                erp = cqr;
-
- 		check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Command Reject - Fatal error");
 
+                erp = dasd_3990_erp_cleanup (erp,
+                                             CQR_STATUS_FAILED);
 	}
 
 	return erp;
@@ -1376,27 +1444,31 @@
 ccw_req_t *
 dasd_3990_erp_bus_out (ccw_req_t *erp)
 {
+
 	dasd_device_t *device = erp->device;
 
         /* first time set initial retry counter and erp_function */
+        /* and retry once without blocking queue                 */
+        /* (this enables easier enqueing of the cqr)             */
         if (erp->function != dasd_3990_erp_bus_out) {
                 erp->retries  = 256;
                 erp->function = dasd_3990_erp_bus_out;
-        }
-
-        /* issue a message and wait for 'device ready' interrupt */
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "bus out parity error or BOPC requested by channel\n");
+        } else {
 
-        dasd_3990_erp_block_queue (erp,
-                                   60);
+                /* issue a message and wait for 'device ready' interrupt */
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "bus out parity error or BOPC requested by "
+                              "channel");
+                
+                dasd_3990_erp_block_queue (erp,
+                                           60);
+                
+        }
 
 	return erp;
 
 } /* end dasd_3990_erp_bus_out */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_EQUIP_CHECK
@@ -1413,60 +1485,51 @@
 dasd_3990_erp_equip_check (ccw_req_t *erp,
 			   char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_equip_check;
 
-#ifdef ERP_FULL_ERP
 	if (sense[1] & SNS1_WRITE_INHIBITED) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Write inhibited path encountered");
 
 		/* vary path offline */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Path should be varied off-line. "
-                              "This is not implemented yet \n - please report to "
-                              "linux390@de.ibm.com");
+                              "This is not implemented yet \n - please report "
+                              "to linux390@de.ibm.com");
 
 		erp = dasd_3990_erp_action_1 (erp);
 
-	} else 
-#endif /* ERP_FULL_ERP */
-                if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-                        
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment Check - "
-                                      "environmental data present");
-#ifdef ERP_FULL_ERP
-                        dasd_3990_handle_env_data (sense);
-#endif /* ERP_FULL_ERP */
-                        
-                        erp = dasd_3990_erp_action_4 (erp,
-                                                      sense);
-
-#ifdef ERP_FULL_ERP
-                } else if (sense[1] & SNS1_PERM_ERR) {
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment Check - retry exhausted or "
-                                      "undesirable\n");
-                        
-                        erp = dasd_3990_erp_action_1 (erp);
-                        
-                } else {
-                        /* all other equipment checks - Action 5 */
-                        /* rest is done when retries == 0 */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Equipment check or processing error\n");
-                        
-                        erp = dasd_3990_erp_action_5 (erp);
-#endif /* ERP_FULL_ERP */
-                }
+	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
+                
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment Check - "
+                              "environmental data present");
+                
+                dasd_3990_handle_env_data (erp,
+                                           sense);
+                
+                erp = dasd_3990_erp_action_4 (erp,
+                                              sense);
+                
+        } else if (sense[1] & SNS1_PERM_ERR) {
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment Check - retry exhausted or "
+                              "undesirable");
+                
+                erp = dasd_3990_erp_action_1 (erp);
+                
+        } else {
+                /* all other equipment checks - Action 5 */
+                /* rest is done when retries == 0 */
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                              "Equipment check or processing error");
+                
+                erp = dasd_3990_erp_action_5 (erp);
+        }
         
         return erp;
         
@@ -1487,18 +1550,17 @@
 dasd_3990_erp_data_check (ccw_req_t *erp,
 			  char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_data_check;
 
-#ifdef ERP_FULL_ERP
 	if (sense[2] & SNS2_CORRECTABLE) {	/* correctable data check */
 
 		/* issue message that the data has been corrected */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_EMERG, device, "%s",
                               "Data recovered during retry with PCI "
-                              "fetch mode active\n");
+                              "fetch mode active");
 
                 /* not possible to handle this situation in Linux */    
                 panic("No way to inform appliction about the possibly "
@@ -1506,8 +1568,7 @@
 
 	} else if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check recovered secondary "
                               "addr of duplex pair");
 
@@ -1516,41 +1577,25 @@
 
 	} else if (sense[1] & SNS1_PERM_ERR) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check with internal "
-                              "retry exhausted\n");
+                              "retry exhausted");
 
 		erp = dasd_3990_erp_action_1 (erp);
 
 	} else {
 		/* all other data checks */
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Uncorrectable data check with retry count "
-                              "exhausted...\n");
+                              "exhausted...");
 
 		erp = dasd_3990_erp_action_5 (erp);
 	}
 
-#else
-	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
-                
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "Uncorrectable data check recovered secondary "
-                              "addr of duplex pair");
-
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
-	}
-#endif /* ERP_FULL_ERP */
-
 	return erp;
 
 } /* end dasd_3990_erp_data_check */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_OVERRUN
  *
@@ -1566,21 +1611,20 @@
 dasd_3990_erp_overrun (ccw_req_t *erp,
 		       char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_overrun;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "Overrun - service overrun or overrun"
-                      " error requested by channel\n");
+                      " error requested by channel");
 
         erp = dasd_3990_erp_action_5 (erp);
 
 	return erp;
 
 } /* end dasd_3990_erp_overrun */
-#endif /* ERP_FULL_ERP */
 
 /*
  * DASD_3990_ERP_INV_FORMAT
@@ -1597,44 +1641,36 @@
 dasd_3990_erp_inv_format (ccw_req_t *erp,
 			  char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_inv_format;
 
 	if (sense[2] & SNS2_ENV_DATA_PRESENT) {
 
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Track format error when destaging or "
                               "staging data");
 
-#ifdef ERP_FULL_ERP
-		dasd_3990_handle_env_data (sense);
+		dasd_3990_handle_env_data (erp,
+                                           sense);
 
 		erp = dasd_3990_erp_action_4 (erp,
 					      sense);
 
 	} else {
-		DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+		DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Invalid Track Format - Fatal error should have "
-                              "been handled within the interrupt handler\n");
+                              "been handled within the interrupt handler");
 
-		check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_FAILED);
+                erp= dasd_3990_erp_cleanup (erp,
+                                            CQR_STATUS_FAILED);
         }
-#else
-		erp = dasd_3990_erp_action_4 (erp,
-					      sense);
-	}
-#endif /* ERP_FULL_ERP */
 
 	return erp;
 
 } /* end dasd_3990_erp_inv_format */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_EOC
  *
@@ -1642,30 +1678,25 @@
  *   Handles 24 byte 'End-of-Cylinder' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp                already added default erp
  * RETURN VALUES
- *   erp                new erp_head - pointer to new ERP
+ *   erp                pointer to original (failed) cqr.
  */
 ccw_req_t *
-dasd_3990_erp_EOC (ccw_req_t *erp,
+dasd_3990_erp_EOC (ccw_req_t *default_erp,
 		   char      *sense)
 {
 
-	dasd_device_t *device = erp->device;
-
-	erp->function = dasd_3990_erp_EOC;
+	dasd_device_t *device = default_erp->device;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "End-of-Cylinder - must never happen\n");
+        DASD_MESSAGE (KERN_ERR, device, "%s",
+                      "End-of-Cylinder - must never happen");
 
-        /* implement action 7 */
-        BUG();
-
-	return erp;
+        /* implement action 7 - BUG */
+        return dasd_3990_erp_cleanup (default_erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_EOC */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ENV_DATA
@@ -1682,16 +1713,16 @@
 dasd_3990_erp_env_data (ccw_req_t *erp,
 			char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_env_data;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "Environmental data present");
-#ifdef ERP_FULL_ERP
-        dasd_3990_handle_env_data (sense);
-#endif /* ERP_FULL_ERP */  
+
+        dasd_3990_handle_env_data (erp,
+                                   sense);
 
 	erp = dasd_3990_erp_action_4 (erp,
 				      sense);
@@ -1700,7 +1731,6 @@
 
 } /* end dasd_3990_erp_env_data */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_NO_REC
  *
@@ -1708,28 +1738,24 @@
  *   Handles 24 byte 'No Record Found' error.
  *
  * PARAMETER
- *   erp                current erp_head
+ *   erp                already added default ERP
+ *              
  * RETURN VALUES
  *   erp                new erp_head - pointer to new ERP
  */
 ccw_req_t *
-dasd_3990_erp_no_rec (ccw_req_t *erp,
+dasd_3990_erp_no_rec (ccw_req_t *default_erp,
 		      char      *sense)
 {
-	dasd_device_t *device = erp->device;
 
-	erp->function = dasd_3990_erp_no_rec;
-        
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+	dasd_device_t *device = default_erp->device;
+
+        DASD_MESSAGE (KERN_ERR, device, "%s",
                       "No Record Found - Fatal error should "
-                      "have been handled within the interrupt handler\n");
-        
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_FAILED);
+                      "have been handled within the interrupt handler");
 
-	return erp;
+        return dasd_3990_erp_cleanup (default_erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_no_rec */
 
@@ -1749,22 +1775,16 @@
 ccw_req_t *
 dasd_3990_erp_file_prot (ccw_req_t *erp)
 {
-	dasd_device_t *device = erp->device;
 
-	erp->function = dasd_3990_erp_file_prot;
+	dasd_device_t *device = erp->device;
 
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "File Protected\n");
+        DASD_MESSAGE (KERN_ERR, device, "%s",
+                      "File Protected");
 
-        check_then_set (&erp->status,
-                        CQR_STATUS_ERROR,
-                        CQR_STATUS_FAILED);
-
-	return erp;
+        return dasd_3990_erp_cleanup (erp,
+                                      CQR_STATUS_FAILED);
 
 } /* end dasd_3990_erp_file_prot */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_INSPECT_24 
@@ -1781,14 +1801,13 @@
  *   erp                pointer to the (addtitional) ERP
  */
 ccw_req_t *
-dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
-                           char      *sense)
+dasd_3990_erp_inspect_24 (ccw_req_t *erp,
+                          char      *sense)
 {
+
 	ccw_req_t *erp_filled = NULL;
-	dasd_device_t *device = erp->device;
 
 	/* Check sense for ....    */
-#ifdef ERP_FULL_ERP
 	/* 'Command Reject'        */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_CMD_REJECT)) {
@@ -1805,7 +1824,6 @@
 	    (sense[0] & SNS0_BUS_OUT_CHECK)) {
 		erp_filled = dasd_3990_erp_bus_out (erp);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Equipment Check'       */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_EQUIPMENT_CHECK)) {
@@ -1818,35 +1836,30 @@
 		erp_filled = dasd_3990_erp_data_check (erp,
 						       sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'Overrun'               */
 	if ((erp_filled == NULL) &&
 	    (sense[0] & SNS0_OVERRUN)) {
 		erp_filled = dasd_3990_erp_overrun (erp,
 						    sense);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Invalid Track Format'  */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_INV_TRACK_FORMAT)) {
 		erp_filled = dasd_3990_erp_inv_format (erp,
 						       sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'End-of-Cylinder'       */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_EOC)) {
 		erp_filled = dasd_3990_erp_EOC (erp,
 						sense);
 	}
-#endif /* ERP_FULL_ERP */  
 	/* 'Environmental Data'    */
 	if ((erp_filled == NULL) &&
 	    (sense[2] & SNS2_ENV_DATA_PRESENT)) {
 		erp_filled = dasd_3990_erp_env_data (erp,
 						     sense);
 	}
-#ifdef ERP_FULL_ERP
 	/* 'No Record Found'       */
 	if ((erp_filled == NULL) &&
 	    (sense[1] & SNS1_NO_REC_FOUND)) {
@@ -1858,15 +1871,9 @@
 	    (sense[1] & SNS1_FILE_PROTECTED)) {
 		erp_filled = dasd_3990_erp_file_prot (erp);
 	}
-#endif /* ERP_FULL_ERP */  
-
-	/* other (unknown) error - do default ERP                     */
+	/* other (unknown) error - do default ERP */
 	if (erp_filled == NULL) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "default ERP taken");
-
 		erp_filled = erp;	
 	}
 
@@ -1880,7 +1887,6 @@
  ***************************************************************************** 
  */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERPACTION_10_32 
  *
@@ -1898,19 +1904,18 @@
 dasd_3990_erp_action_10_32 (ccw_req_t *erp,
                             char      *sense)
 {
+
 	dasd_device_t *device = erp->device;
 
         erp->retries  = 256;
         erp->function = dasd_3990_erp_action_10_32;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Perform logging requested\n");
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Perform logging requested");
 
 	return erp;
 
 } /* end dasd_3990_erp_action_10_32 */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ACTION_1B_32
@@ -1924,8 +1929,9 @@
  *   action because it contains no DE/LO data space.
  *
  * PARAMETER
- *   default_erp        already created default erp.
+ *   default_erp        already added default erp.
  *   sense              current sense data 
+ *
  * RETURN VALUES
  *   erp                new erp or 
  *                      default_erp in case of imprecise ending or error
@@ -1934,6 +1940,7 @@
 dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
                             char      *sense)
 {
+
 	dasd_device_t  *device = default_erp->device;
         __u32          cpa     = 0;
         ccw_req_t      *cqr;
@@ -1942,14 +1949,14 @@
 	char           *LO_data;   /* LO_eckd_data_t */
         ccw1_t         *ccw;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Write not finsihed because of unexpected condition");
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Write not finished because of unexpected condition");
         
         default_erp->function = dasd_3990_erp_action_1B_32;
 
         /* determine the original cqr */
         cqr = default_erp; 
+
         while (cqr->refers != NULL){
                 cqr = cqr->refers;
         }
@@ -1957,8 +1964,7 @@
         /* for imprecise ending just do default erp */
         if (sense[1] & 0x01) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Imprecise ending is set - just retry");
 
                 return default_erp;
@@ -1970,34 +1976,28 @@
         
         if (cpa == 0) {
                 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Unable to determine address of the CCW "
                               "to be restarted");
                 
-                check_then_set (&default_erp->status,
-                                CQR_STATUS_FILLED,
-                                CQR_STATUS_FAILED);
-                
-                return default_erp;
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
         }
         
 	/* Build new ERP request including DE/LO */
 	erp = dasd_alloc_request ((char *) &cqr->magic,
                                   2 + 1,                    /* DE/LO + TIC */
                                   sizeof (DE_eckd_data_t) +
-                                  sizeof (LO_eckd_data_t));
+                                  sizeof (LO_eckd_data_t),
+                                  device);
+
+	if (!erp) {
 
-	if ( !erp ) {
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "Unable to allocate ERP");
                 
-                check_then_set (&default_erp->status,
-                                               CQR_STATUS_FILLED,
-                                               CQR_STATUS_FAILED);
-                
-                return default_erp;
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
 	}
         
         /* use original DE */
@@ -2012,10 +2012,11 @@
         if ((sense[3]  == 0x01) &&
             (LO_data[1] & 0x01)   ){
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "BUG - this should not happen");
-                //BUG();    /* check for read count suffixing n.a. */
+
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
         }
 
         if ((sense[7] & 0x3F) == 0x01) {
@@ -2043,22 +2044,38 @@
         ccw = erp->cpaddr;
 	memset (ccw, 0, sizeof (ccw1_t));
 	ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (DE_data));
+	ccw->flags    = CCW_FLAG_CC;
+	ccw->count    = 16;
+	if (dasd_set_normalized_cda (ccw,
+                                     __pa (DE_data), erp, device)) {
+                dasd_free_request (erp, device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP");
+
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
+        }
 
         /* create LO ccw */    
         ccw++;
 	memset (ccw, 0, sizeof (ccw1_t));
 	ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
-	ccw->flags = CCW_FLAG_CC;
-	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (LO_data));
+	ccw->flags    = CCW_FLAG_CC;
+	ccw->count    = 16;
+	if (dasd_set_normalized_cda (ccw, 
+                                     __pa (LO_data), erp, device)){
+                dasd_free_request (erp, device);
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP");
+                
+                return dasd_3990_erp_cleanup (default_erp,
+                                              CQR_STATUS_FAILED);
+        }
         
         /* TIC to the failed ccw */
         ccw++;
 	ccw->cmd_code = CCW_CMD_TIC;
-	ccw->cda = cpa;
+	ccw->cda      = cpa;
 
         /* fill erp related fields */
         erp->function = dasd_3990_erp_action_1B_32;
@@ -2067,11 +2084,11 @@
 	erp->magic    = default_erp->magic;
 	erp->lpm      = 0xFF;
 	erp->expires  = 0;
-	erp->retries  = 255;
+	erp->retries  = 256;
 	erp->status   = CQR_STATUS_FILLED;
         
         /* remove the default erp */
-        dasd_free_request (default_erp);
+        dasd_free_request (default_erp, device);
         
 	return erp;
         
@@ -2096,6 +2113,7 @@
 dasd_3990_update_1B (ccw_req_t *previous_erp,
                      char      *sense)
 {
+
 	dasd_device_t  *device = previous_erp->device;
         __u32          cpa     = 0;
         ccw_req_t      *cqr;
@@ -2103,13 +2121,13 @@
 	char           *LO_data;   /* LO_eckd_data_t */
         ccw1_t         *ccw;
 
-	DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "Write not finsihed because of unexpected condition"
+	DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                      "Write not finished because of unexpected condition"
                       " - follow on");
         
         /* determine the original cqr */
-        cqr = previous_erp; 
+        cqr = previous_erp;
+
         while (cqr->refers != NULL){
                 cqr = cqr->refers;
         }
@@ -2117,13 +2135,12 @@
         /* for imprecise ending just do default erp */
         if (sense[1] & 0x01) {
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Imprecise ending is set - just retry");
 
                 check_then_set (&previous_erp->status,
-                                               CQR_STATUS_ERROR,
-                                               CQR_STATUS_QUEUED);
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_QUEUED);
 
                 return previous_erp;
         } 
@@ -2133,16 +2150,8 @@
         cpa = previous_erp->dstat->cpa;    
         
         if (cpa == 0) {
-                ccw = cqr->cpaddr;   /* addr of first data transfer */
-                ccw++;               /* command in domain           */
-                ccw++;
-                cpa = (__u32) ccw; 
-        }
-        
-        if (cpa == 0) {
                 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_DEBUG, device, "%s",
                               "Unable to determine address of the CCW "
                               "to be restarted");
                 
@@ -2161,10 +2170,14 @@
         if ((sense[3]  == 0x01) &&
             (LO_data[1] & 0x01)   ){
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+                DASD_MESSAGE (KERN_ERR, device, "%s",
                               "BUG - this should not happen");
-                //BUG();    /* check for read count suffixing n.a. */
+
+                check_then_set (&previous_erp->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+                
+                return previous_erp;
         }
 
         if ((sense[7] & 0x3F) == 0x01) {
@@ -2202,12 +2215,14 @@
         
 } /* end dasd_3990_update_1B */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_COMPOUND_RETRY 
  *
  * DESCRIPTION
  *   Handles the compound ERP action retry code.
+ *   NOTE: At least one retry is done even if zero is specified
+ *         by the sense data. This makes enqueueing of the request
+ *         easier.
  *
  * PARAMETER
  *   sense              sense data of the actual error
@@ -2221,41 +2236,30 @@
 dasd_3990_erp_compound_retry (ccw_req_t *erp,
                               char      *sense)
 {
+
         switch (sense[25] & 0x03) { 
         case 0x00:	/* no not retry */
-                erp->retries = 0;
-                break;
+                erp->retries = 1; 
+                break;            
                 
         case 0x01:	/* retry 2 times */
                 erp->retries = 2;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
                 break;
                 
         case 0x02:	/* retry 10 times */
                 erp->retries = 10;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
                 break;
                 
-        case 0x03:	/* retry 255 times */
-                erp->retries = 255;
-
-                check_then_set (&erp->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_QUEUED);
+        case 0x03:	/* retry 256 times */
+                erp->retries = 256;
                 break;
                 
         default:
                 BUG();
         }
-
+        
         erp->function = dasd_3990_erp_compound_retry;
-
+        
 } /* end dasd_3990_erp_compound_retry */
 
 /*
@@ -2277,14 +2281,14 @@
 dasd_3990_erp_compound_path (ccw_req_t *erp,
                              char      *sense)
 {
-
+        
         if (sense[25] & DASD_SENSE_BIT_3) {
                 dasd_3990_erp_alternate_path (erp);
                 
                 if (erp->status == CQR_STATUS_FAILED) {
                         /* reset the lpm and the status to be able to 
                          * try further actions. */
-        
+                        
                         erp->lpm = LPM_ANYPATH;
                         
                         check_then_set (&erp->status,
@@ -2316,7 +2320,6 @@
 dasd_3990_erp_compound_code (ccw_req_t *erp,
                              char      *sense)
 {
-
         
         if (sense[25] & DASD_SENSE_BIT_2) {
 
@@ -2337,7 +2340,8 @@
                         break;
                         
                 default:
-                        BUG();
+                        /* should not happen - continue */
+
                 }
         }
 
@@ -2367,16 +2371,17 @@
 dasd_3990_erp_compound_config (ccw_req_t *erp,
                                char      *sense)
 {
+
         if ((sense[25] & DASD_SENSE_BIT_1) && 
             (sense[26] & DASD_SENSE_BIT_2)   ) {	
 
                 /* set to suspended duplex state then restart */
                 dasd_device_t *device  = erp->device;
 
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",      
-                              "Set device to suspended duplex state should be done!\n"
-                              "This is not implemented yet (for compound ERP)\n"
+                DASD_MESSAGE (KERN_ERR, device, "%s",      
+                              "Set device to suspended duplex state should be "
+                              "done!\n"
+                              "This is not implemented yet (for compound ERP)"
                               " - please report to linux390@de.ibm.com");
                 
         }
@@ -2389,12 +2394,12 @@
  * DASD_3990_ERP_COMPOUND 
  *
  * DESCRIPTION
- *   Does a detailed inspection of the 32 byte sense data
- *   and sets up a related error recovery action.  
+ *   Does the further compound program action if 
+ *   compound retry was not successful.
  *
  * PARAMETER
  *   sense              sense data of the actual error
- *   erp                pointer to the currently created ERP
+ *   erp                pointer to the current (failed) ERP
  *
  * RETURN VALUES
  *   erp                (additional) ERP pointer
@@ -2404,33 +2409,23 @@
 dasd_3990_erp_compound (ccw_req_t *erp,
                         char      *sense)
 {
-        if ((erp->function != dasd_3990_erp_compound_retry ) &&
-            (erp->function != dasd_3990_erp_compound_path  ) &&
-            (erp->function != dasd_3990_erp_compound_code  ) &&
-            (erp->function != dasd_3990_erp_compound_config)   ) {
 
-                /* called first time */
-                dasd_3990_erp_compound_retry (erp,
-                                              sense);
-        }
-        
-        /* do further action if no retry is specified / left */
         if ((erp->function == dasd_3990_erp_compound_retry) &&
-            (erp->status   == CQR_STATUS_ERROR            )   ){
+            (erp->status   == CQR_STATUS_ERROR            )   ) {
                 
                 dasd_3990_erp_compound_path (erp,
                                              sense);
         }
 
         if ((erp->function == dasd_3990_erp_compound_path) &&
-            (erp->status   == CQR_STATUS_ERROR           )   ){
+            (erp->status   == CQR_STATUS_ERROR           )    ){
 
                 erp = dasd_3990_erp_compound_code (erp,
                                                    sense);
         }
 
         if ((erp->function == dasd_3990_erp_compound_code) && 
-            (erp->status   == CQR_STATUS_ERROR           )   ){
+            (erp->status   == CQR_STATUS_ERROR           )   ) {
                 
                 dasd_3990_erp_compound_config (erp,
                                                sense);
@@ -2447,7 +2442,6 @@
         return erp;
         
 } /* end dasd_3990_erp_compound */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_INSPECT_32 
@@ -2468,6 +2462,7 @@
 dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                            char      *sense )
 {
+
 	dasd_device_t *device = erp->device;
 
 	erp->function = dasd_3990_erp_inspect_32;
@@ -2475,40 +2470,32 @@
 	if (sense[25] & DASD_SENSE_BIT_0) {
 
 		/* compound program action codes (byte25 bit 0 == '1') */
-#ifdef ERP_FULL_ERP
-                erp = dasd_3990_erp_compound (erp,
+                dasd_3990_erp_compound_retry (erp,
                                               sense);
-#else
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
-                              "default ERP taken");
-#endif /* ERP_FULL_ERP */  
 
 	} else {
 
 		/* single program action codes (byte25 bit 0 == '0') */
 		switch (sense[25]) {
-#ifdef ERP_FULL_ERP
+
 		case 0x00:	/* success */
-                        DASD_MESSAGE (KERN_WARNING, device,
+                        DASD_MESSAGE (KERN_DEBUG, device,
                                       "ERP called for successful request %p"
                                       " - NO ERP necessary",
                                       erp);
+                        
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_DONE);
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_DONE);
                         break;
                         
 		case 0x01:	/* fatal error */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "Fatal error should "
-                                      "have been handled within the interrupt handler\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Fatal error should have been "
+                                      "handled within the interrupt handler");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_FAILED);
                         break;
 
 		case 0x02:	/* intervention required */
@@ -2517,15 +2504,15 @@
                         break;
 
 		case 0x0F:	/* length mismatch during update write command */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "update write command error - should not happen; "
-                                      "Please send this message together with the above "
-                                      "sense data to linux390@de.ibm.com\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "update write command error - should not "
+                                      "happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_FAILED);
                         break;
 
 		case 0x10:	/* logging required for other channel program */
@@ -2534,17 +2521,16 @@
                         break;
 
 		case 0x15:	/* next track outside defined extend */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "next track outside defined extend - should not happen; "
-                                      "Please send this message together with the above "
-                                      "sense data to linux390@de.ibm.com\n");
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "next track outside defined extend - "
+                                      "should not happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
 
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        erp= dasd_3990_erp_cleanup (erp,
+                                                    CQR_STATUS_FAILED);
                         break;
-#endif /* ERP_FULL_ERP */  
 
 		case 0x1B:	/* unexpected condition during write */
 
@@ -2552,22 +2538,18 @@
                                                           sense);
                         break;
 
-#ifdef ERP_FULL_ERP
 		case 0x1C:	/* invalid data */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
+                        DASD_MESSAGE (KERN_EMERG, device, "%s",
                                       "Data recovered during retry with PCI "
-                                      "fetch mode active\n");
+                                      "fetch mode active");
                         
                         /* not possible to handle this situation in Linux */    
-                        panic("No way to inform appliction about the possibly "
-                              "incorret data");
+                        panic("Invalid data - No way to inform appliction about "
+                              "the possibly incorret data");
 			break;
-#endif /* ERP_FULL_ERP */  
 
 		case 0x1D:	/* state-change pending */
-                        DASD_MESSAGE (KERN_WARNING, device, 
-                                      "%s",
+                        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                                       "A State change pending condition exists "
                                       "for the subsystem or device");
 
@@ -2575,10 +2557,8 @@
                                                       sense);
 			break;
 
-		default:	/* all others errors */
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "%s",
-                                      "default ERP taken");
+		default:	/* all others errors - default erp  */
+                        
 		}
 	}
 
@@ -2607,6 +2587,7 @@
 ccw_req_t *
 dasd_3990_erp_inspect (ccw_req_t *erp)
 {
+
 	ccw_req_t *erp_new = NULL;
 	/* sense data are located in the refers record of the */
 	/* already set up new ERP !                           */
@@ -2648,24 +2629,34 @@
 ccw_req_t *
 dasd_3990_erp_add_erp (ccw_req_t *cqr)
 {
+
+	dasd_device_t *device = cqr->device;
+
 	/* allocate additional request block */
-	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0);
-	if ( !erp ) {
-		printk( KERN_WARNING PRINTK_HEADER
-			"unable to allocate ERP request\n" );
-                return NULL;
+	ccw_req_t *erp = dasd_alloc_request ((char *) &cqr->magic, 1, 0, cqr->device);
+
+	if (!erp) {
+
+                DASD_MESSAGE (KERN_ERR, device, "%s",
+                              "Unable to allocate ERP request");
+                
+                check_then_set (&cqr->status,
+                                CQR_STATUS_ERROR,
+                                CQR_STATUS_FAILED);
+
+                return cqr;
 	}
 
 	/* initialize request with default TIC to current ERP/CQR */
 	erp->cpaddr->cmd_code = CCW_CMD_TIC;
-	erp->cpaddr->cda      = ((__u32) cqr->cpaddr);
+	erp->cpaddr->cda      = (long)(cqr->cpaddr);
 	erp->function = dasd_3990_erp_add_erp;
 	erp->refers   = cqr;
 	erp->device   = cqr->device;
 	erp->magic    = cqr->magic;
 	erp->lpm      = 0xFF;
 	erp->expires  = 0;
-	erp->retries  = 255;
+	erp->retries  = 256;
 
 	erp->status = CQR_STATUS_FILLED;
 
@@ -2697,7 +2688,8 @@
 	erp = dasd_3990_erp_add_erp (cqr);
 
 	/* inspect sense, determine specific ERP if possible */
-        if (erp != NULL) {
+        if (erp != cqr) {
+
                 erp = dasd_3990_erp_inspect (erp);
         }
 
@@ -2727,13 +2719,13 @@
 dasd_3990_erp_error_match (ccw_req_t *cqr1,
 			   ccw_req_t *cqr2)
 {
+
 	/* check failed CCW */
 	if (cqr1->dstat->cpa !=
 	    cqr2->dstat->cpa) {
 	//	return 0;	/* CCW doesn't match */
-                printk(KERN_WARNING PRINTK_HEADER 
-                       "_error_match: CCW doesn't match -> ignore\n");
 	}
+
 	/* check sense data; byte 0-2,25,27 */
 	if (!((strncmp (cqr1->dstat->ii.sense.data,
 			cqr2->dstat->ii.sense.data,
@@ -2745,9 +2737,10 @@
 
 		return 0;	/* sense doesn't match */
 	}
+
 	return 1;		/* match */
 
-}				/* end dasd_3990_erp_error_match */
+} /* end dasd_3990_erp_error_match */
 
 /*
  * DASD_3990_ERP_IN_ERP
@@ -2760,35 +2753,38 @@
  *   cqr                failed cqr (either original cqr or already an erp)
  *
  * RETURN VALUES
- *   erp                erp-pointer to the already defined error recovery procedure OR
+ *   erp                erp-pointer to the already defined error 
+ *                      recovery procedure OR
  *                      NULL if a 'new' error occurred.
  */
 ccw_req_t *
 dasd_3990_erp_in_erp (ccw_req_t *cqr)
 {
-	ccw_req_t *erp_head = cqr,	/* save erp chain head */
-	         *erp_match = NULL;	/* save erp chain head */
+
+	ccw_req_t *erp_head  = cqr,	/* save erp chain head */
+                  *erp_match = NULL;	/* save erp chain head */
 	int match = 0;		/* 'boolean' for matching error found */
 
 	if (cqr->refers == NULL) {	/* return if not in erp */
 		return NULL;
 	}
+
 	/* check the erp/cqr chain for current error */
 	do {
 		match = dasd_3990_erp_error_match (erp_head,
 						   cqr->refers);
-		erp_match = cqr;	/* save possible matching erp  */
-		cqr = cqr->refers;	/* check next erp/cqr in queue */
+		erp_match = cqr;	 /* save possible matching erp  */
+		cqr       = cqr->refers; /* check next erp/cqr in queue */
+
 	} while ((cqr->refers != NULL) &&
-		 (match == 0));
+		 (!match             )   );
 
-	if (match) {
-		return erp_match;	/* return address of matching erp */
-	} else {
-		return NULL;	/* return NULL to indicate that no match
-				   was found */
+	if (!match) {
+		return NULL; 	/* no match was found */
 	}
 
+        return erp_match;	/* return address of matching erp */
+
 } /* END dasd_3990_erp_in_erp */
 
 /*
@@ -2810,9 +2806,10 @@
 ccw_req_t *
 dasd_3990_erp_further_erp (ccw_req_t *erp)
 {
-        dasd_device_t     *device = erp->device;
+
+        dasd_device_t *device = erp->device;
+        char          *sense  = erp->dstat->ii.sense.data;
         
-#ifdef ERP_FULL_ERP
         /* check for 24 byte sense ERP */
 	if ((erp->function == dasd_3990_erp_bus_out ) ||
             (erp->function == dasd_3990_erp_action_1) ||
@@ -2823,8 +2820,6 @@
 	} else if (erp->function == dasd_3990_erp_action_5) {
                 
                 /* retries have not been successful */
-                char *sense = erp->dstat->ii.sense.data;
-                
                 /* prepare erp for retry on different channel path */
                 erp = dasd_3990_erp_action_1 (erp);
                 
@@ -2853,26 +2848,25 @@
                                 break;
                         }
                         default:
-                                DASD_MESSAGE (KERN_WARNING, device,
-                                              "invalid subcommand modifier 0x%x for "
-                                              "Diagnostic Control Command",
+                                DASD_MESSAGE (KERN_DEBUG, device,
+                                              "invalid subcommand modifier 0x%x "
+                                              "for Diagnostic Control Command",
                                               sense[25]);
                         }
                 } 
 
-//        /* check for 32 byte sense ERP */
-//	} else if ((erp->function == dasd_3990_erp_xxx){
-#else
-        /* check for 24 byte sense ERP */
-	if ((erp->function == dasd_3990_erp_action_1) ||
-            (erp->function == dasd_3990_erp_action_4)   ){
-                
-                erp = dasd_3990_erp_action_1 (erp);
-#endif /* ERP_FULL_ERP */  
+        /* check for 32 byte sense ERP */
+	} else if ((erp->function == dasd_3990_erp_compound_retry ) ||
+                   (erp->function == dasd_3990_erp_compound_path  ) ||
+                   (erp->function == dasd_3990_erp_compound_code  ) ||
+                   (erp->function == dasd_3990_erp_compound_config)   ) {
                 
+                erp = dasd_3990_erp_compound (erp,
+                                              sense);
+
 	} else {
                 /* no retry left and no additional special handling necessary */
-                DASD_MESSAGE (KERN_WARNING, device,
+                DASD_MESSAGE (KERN_ERR, device,
                               "no retries left for erp %p - "
                               "set status to FAILED",
                               erp);
@@ -2892,102 +2886,87 @@
  * DESCRIPTION
  *   An error occurred again and an ERP has been detected which is already
  *   used to handle this error (e.g. retries). 
- *   All prior ERP's are set to status DONE and the retry counter is
- *   decremented.
- *   If retry counter is already 0, it has to checked if further action
- *   is needed (besides retry) or if the ERP has failed.
+ *   All prior ERP's are asumed to be successful and therefore removed
+ *   from queue.
+ *   If retry counter of matching erp is already 0, it is checked if further 
+ *   action is needed (besides retry) or if the ERP has failed.
  *
  * PARAMETER
  *   erp_head           first ERP in ERP-chain
- *   erp_match          ERP that handles the actual error.
+ *   erp                ERP that handles the actual error.
+ *                      (matching erp)
  *
  * RETURN VALUES
- *   none                
+ *   erp                modified/additional ERP
  */
-void
+ccw_req_t *
 dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head,
-				ccw_req_t *erp_match)
+				ccw_req_t *erp)
 {
 
 	dasd_device_t *device   = erp_head->device;
-	ccw_req_t     *erp_done = erp_head;
+	ccw_req_t     *erp_done = erp_head;  /* finished req */
         ccw_req_t     *erp_free = NULL;      /* req to be freed */    
-
+        
 	/* loop over successful ERPs and remove them from chanq */
-	while ((erp_done != erp_match) &&
-	       (erp_done != NULL)) {
-
-#ifdef ERP_DEBUG
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "successful ERP - dequeue and free request %p",
-                              (void *) erp_done);
-#endif /* ERP_DEBUG */
+	while (erp_done != erp) {
 
-		check_then_set (&erp_done->status,
-                                CQR_STATUS_ERROR,
-                                CQR_STATUS_DONE);
+                if (erp_done == NULL) 	/* end of chain reached */
+                        panic (PRINTK_HEADER "Programming error in ERP! The "
+                               "original request was lost\n");
 
 		/* remove the request from the device queue */
 		dasd_chanq_deq (&device->queue,
 				erp_done);
-
+                
                 erp_free = erp_done;
 		erp_done = erp_done->refers;
                 
 		/* free the finished erp request */
-		dasd_free_request (erp_free);
+		dasd_free_request (erp_free, erp_free->device);
 
-	}
+	} /* end while */
 
-	if (erp_done == NULL) 	/* erp_done should never be NULL! */
-		panic (PRINTK_HEADER "Programming error in ERP! The original "
-                       "request was lost\n");
-
-#ifdef ERP_DEBUG
-	/* handle matching ERP */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "handle matching erp %p",
-                      (void *) erp_done);
-#endif
-        
-        if (erp_done->retries > 0) {
+        if (erp->retries > 0) {
+                
+                char *sense = erp->dstat->ii.sense.data;
                 
                 /* check for special retries */
-                if (erp_done->function == dasd_3990_erp_action_4) {
-                        char *sense = erp_done->dstat->ii.sense.data;
-                        erp_done = dasd_3990_erp_action_4 (erp_done,
-                                                           sense);
-                        
-                } else if (erp_done->function == dasd_3990_erp_action_1B_32) {
-                        char *sense = erp_done->dstat->ii.sense.data;
-                        erp_done = dasd_3990_update_1B (erp_done,
-                                                        sense);
-
-#ifdef ERP_FULL_ERP
-                } else if (erp_done->function == dasd_3990_erp_int_req) {
-                        erp_done = dasd_3990_erp_int_req (erp_done);
-#endif /* ERP_FULL_ERP */  
+                if (erp->function == dasd_3990_erp_action_4) {
+                        
+                        erp = dasd_3990_erp_action_4 (erp,
+                                                      sense);
+                        
+                } else if (erp->function == dasd_3990_erp_action_1B_32) {
+                        
+                        erp = dasd_3990_update_1B (erp,
+                                                   sense);
+
+                } else if (erp->function == dasd_3990_erp_int_req) {
+
+                        erp = dasd_3990_erp_int_req (erp);
                         
                 } else {
                         /* simple retry   */
-                        DASD_MESSAGE (KERN_WARNING, device,
+                        DASD_MESSAGE (KERN_DEBUG, device,
                                       "%i retries left for erp %p",
-                                      erp_done->retries,
-                                      (void *) erp_done);
+                                      erp->retries,
+                                      erp);
                         
                         /* handle the request again... */
-                        check_then_set (&erp_done->status,
+                        check_then_set (&erp->status,
                                         CQR_STATUS_ERROR,
                                         CQR_STATUS_QUEUED);
                 }
+                
         } else {
                 /* no retry left - check for further necessary action    */
                 /* if no further actions, handle rest as permanent error */
-                erp_done = dasd_3990_erp_further_erp (erp_done);
+                erp = dasd_3990_erp_further_erp (erp);
 	}
 
-        erp_head = erp_done;
-
+        return erp;
+        
 } /* end dasd_3990_erp_handle_match_erp */
 
 /*
@@ -3004,30 +2983,27 @@
  *   erp                erp-pointer to the head of the ERP action chain.
  *                      This means:
  *                       - either a ptr to an additional ERP cqr or
- *                       - the original given cqr (which's status might be modified)
+ *                       - the original given cqr (which's status might 
+ *                         be modified)
  */
 ccw_req_t *
 dasd_3990_erp_action (ccw_req_t *cqr)
 {
+
 	ccw_req_t     *erp    = NULL;
 	dasd_device_t *device = cqr->device;
+        __u32         cpa     = cqr->dstat->cpa;    
 
 #ifdef ERP_DEBUG 
-        __u32 cpa = cqr->dstat->cpa;    
-#endif /* ERP_DEBUG */
-
-#ifdef ERP_DEBUG 
-
-	printk (KERN_WARNING PRINTK_HEADER
-		"entering 3990 ERP for "
-		"0x%04X on sch %d = /dev/%s \n",
-		device->devinfo.devno,
-		device->devinfo.irq,
-		device->name);
+        DASD_MESSAGE (KERN_DEBUG, device,
+                      "entering 3990 ERP for "
+                      "0x%04X on sch %d = /dev/%s ",
+                      device->devinfo.devno,
+                      device->devinfo.irq,
+                      device->name);
 
 	/* print current erp_chain */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "ERP chain at BEGINNING of ERP-ACTION");
         {
                 ccw_req_t *temp_erp = NULL;
@@ -3035,23 +3011,24 @@
                      temp_erp != NULL; 
                      temp_erp = temp_erp->refers){
 
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "      erp %p refers to %p \n",
+                        DASD_MESSAGE (KERN_DEBUG, device,
+                                      "      erp %p refers to %p",
                                       temp_erp,
                                       temp_erp->refers);
                 }
         } 
-#endif
+#endif /* ERP_DEBUG */
 
 	/* double-check if current erp/cqr was successfull */
-	if ((cqr->dstat->cstat == 0x00) &&
-	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) {
-                DASD_MESSAGE (KERN_WARNING, device,
+	if ((cqr->dstat->cstat == 0x00                                 ) &&
+	    (cqr->dstat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))   ) {
+
+                DASD_MESSAGE (KERN_DEBUG, device,
                               "ERP called for successful request %p"
                               " - NO ERP necessary",
                               cqr);
                 
-                check_then_set (&erp->status,
+                check_then_set (&cqr->status,
                                 CQR_STATUS_ERROR,
                                 CQR_STATUS_DONE);
 
@@ -3059,12 +3036,12 @@
 	}
 	/* check if sense data are available */
 	if (!cqr->dstat->ii.sense.data) {
-		DASD_MESSAGE (KERN_WARNING, device,
+		DASD_MESSAGE (KERN_DEBUG, device,
 			"ERP called witout sense data avail ..."
 			"request %p - NO ERP possible",
 			cqr);
 
-                check_then_set (&erp->status,
+                check_then_set (&cqr->status,
                                 CQR_STATUS_ERROR,
                                 CQR_STATUS_FAILED);
 
@@ -3080,38 +3057,178 @@
 		erp = dasd_3990_erp_additional_erp (cqr);
 	} else {
 		/* matching erp found - set all leading erp's to DONE */
-		dasd_3990_erp_handle_match_erp (cqr, erp);
-		erp = cqr;
+		erp = dasd_3990_erp_handle_match_erp (cqr, 
+                                                      erp);
 	}
 
 #ifdef ERP_DEBUG
 	/* print current erp_chain */
-        DASD_MESSAGE (KERN_WARNING, device,
-                      "%s",
+        DASD_MESSAGE (KERN_DEBUG, device, "%s",
                       "ERP chain at END of ERP-ACTION");
         {
                 ccw_req_t *temp_erp = NULL;
                 for (temp_erp = erp; 
                      temp_erp != NULL; 
-                     temp_erp = temp_erp->refers){
+                     temp_erp = temp_erp->refers) {
 
-                        DASD_MESSAGE (KERN_WARNING, device,
-                                      "      erp %p refers to %p \n",
+                        DASD_MESSAGE (KERN_DEBUG, device,
+                                      "      erp %p refers to %p",
                                       temp_erp,
                                       temp_erp->refers);
                 }
         }
 #endif /* ERP_DEBUG */
 
-#ifdef ERP_DEBUG
         if (erp->status == CQR_STATUS_FAILED) {
-                log_erp_chain (erp, 1, cpa);
+
+                log_erp_chain (erp,
+                               1,
+                               cpa);
+        }
+
+        /* enqueue added ERP request */
+        if ((erp != cqr                      ) &&
+            (erp->status == CQR_STATUS_FILLED)   ){
+
+                dasd_chanq_enq_head (&device->queue,
+                                     erp);
+        } else {
+                if ((erp->status == CQR_STATUS_FILLED )||
+                    (erp != cqr                       )  ){
+                        /* something strange happened - log the error and throw a BUG() */
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "Problems with ERP chain!!! BUG");
+
+                        /* print current erp_chain */
+                        DASD_MESSAGE (KERN_DEBUG, device, "%s",
+                                      "ERP chain at END of ERP-ACTION");
+                        {
+                                ccw_req_t *temp_erp = NULL;
+                                for (temp_erp = erp; 
+                                     temp_erp != NULL; 
+                                     temp_erp = temp_erp->refers) {
+
+                                        DASD_MESSAGE (KERN_DEBUG, device,
+                                                      "      erp %p (function %p) refers to %p",
+                                                      temp_erp,
+                                                      temp_erp->function,
+                                                      temp_erp->refers);
+                                }
+                        }
+                        BUG();
+                }
+
         }
-#endif /* ERP_DEBUG */
 
 	return erp;
 
 } /* end dasd_3990_erp_action */
+
+/*
+ * DASD_3990_ERP_POSTACTION
+ *
+ * DESCRIPTION
+ *   Frees all ERPs of the current ERP Chain and set the status
+ *   of the original CQR either to CQR_STATUS_DONE if ERP was successful
+ *   or to CQR_STATUS_FAILED if ERP was NOT successful.
+ *
+ * PARAMETER
+ *   erp                current erp_head
+ *
+ * RETURN VALUES
+ *   cqr                pointer to the original CQR
+ */
+ccw_req_t *
+dasd_3990_erp_postaction (ccw_req_t *erp)
+{
+
+	ccw_req_t     *cqr      = NULL, 
+                      *free_erp = NULL;
+	dasd_device_t *device   = erp->device;
+	int           success;
+
+	if (erp->refers   == NULL || 
+            erp->function == NULL   ) {
+
+		BUG ();
+	}
+
+	if (erp->status == CQR_STATUS_DONE)
+		success = 1;
+	else
+		success = 0;
+
+#ifdef ERP_DEBUG
+
+	/* print current erp_chain */
+	printk (KERN_DEBUG PRINTK_HEADER
+		"3990 ERP postaction called for erp chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+
+		for (temp_erp = erp; 
+                     temp_erp != NULL;
+		     temp_erp = temp_erp->refers) {
+
+			printk (KERN_DEBUG PRINTK_HEADER
+				"       erp %p refers to %p with erp function %p\n",
+				temp_erp, temp_erp->refers, temp_erp->function);
+		}
+	}
+
+#endif /* ERP_DEBUG */
+
+	/* free all ERPs - but NOT the original cqr */
+	while (erp->refers != NULL) {
+
+		free_erp = erp;
+		erp      = erp->refers;
+
+		/* remove the request from the device queue */
+		dasd_chanq_deq (&device->queue,
+                                free_erp);
+
+		/* free the finished erp request */
+		dasd_free_request (free_erp, free_erp->device);
+	}
+
+	/* save ptr to original cqr */
+	cqr = erp;
+
+	/* set corresponding status to original cqr */
+	if (success) {
+
+		check_then_set (&cqr->status, 
+                                CQR_STATUS_ERROR,
+				CQR_STATUS_DONE);
+	} else {
+
+		check_then_set (&cqr->status,
+				CQR_STATUS_ERROR, 
+                                CQR_STATUS_FAILED);
+	}
+
+#ifdef ERP_DEBUG
+	/* print current erp_chain */
+	printk (KERN_DEBUG PRINTK_HEADER
+		"3990 ERP postaction finished with remaining chain:\n");
+	{
+		ccw_req_t *temp_erp = NULL;
+
+		for (temp_erp = cqr; 
+                     temp_erp != NULL;
+		     temp_erp = temp_erp->refers) {
+
+			printk (KERN_DEBUG PRINTK_HEADER
+				" erp %p refers to %p \n", temp_erp,
+				temp_erp->refers);
+		}
+	}
+#endif /* ERP_DEBUG */
+
+	return cqr;
+
+} /* end dasd_3990_erp_postaction */
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_3990_erp.h linux/drivers/s390/block/dasd_3990_erp.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_3990_erp.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_3990_erp.h	Mon Dec  3 22:58:52 2001
@@ -10,7 +10,6 @@
 #ifndef DASD_3990_ERP_H
 #define DASD_3990_ERP_H
 
-
 dasd_era_t dasd_3990_erp_examine (ccw_req_t *, devstat_t *);
 
 ccw_req_t *dasd_3990_erp_action (ccw_req_t *);
@@ -19,10 +18,9 @@
 void dasd_3990_erp_restart_queue (unsigned long);
 
 typedef struct DCTL_data_t {
-	unsigned char  subcommand;  /* e.g Inhibit Write, Enable Write,... */
-	unsigned char  modifier;    /* Subcommand modifier                 */
-	unsigned short res;	    /* reserved */
+	unsigned char subcommand;	/* e.g Inhibit Write, Enable Write,... */
+	unsigned char modifier;	/* Subcommand modifier                 */
+	unsigned short res;	/* reserved */
 } __attribute__ ((packed)) DCTL_data_t;
 
-
-#endif /* DASD_3990_ERP_H */
+#endif				/* DASD_3990_ERP_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_9336_erp.c linux/drivers/s390/block/dasd_9336_erp.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_9336_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_9336_erp.c	Mon Dec  3 22:58:52 2001
@@ -6,7 +6,8 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include "dasd_int.h"
+#include "dasd_9336_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -29,15 +30,12 @@
  *   dasd_era_fatal     for all fatal (unrecoverable errors)
  *   dasd_era_recover   for all others.
  */
-dasd_era_t
-dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_era_t dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
-	char *sense = stat->ii.sense.data;
-
 	/* check for successful execution first */
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	/* examine the 24 byte sense data */
 	return dasd_era_recover;
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_9336_erp.h linux/drivers/s390/block/dasd_9336_erp.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_9336_erp.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_9336_erp.h	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,15 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9336_erp.h
+ * Author(s)......: Horst Hummel <Horst Hummel@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ *
+ * History of changes (starts July 2000)
+ */
+
+#ifndef DASD_9336_ERP_H
+#define DASD_9336_ERP_H
+
+dasd_era_t dasd_9336_erp_examine (ccw_req_t *, devstat_t *);
+
+#endif				/* DASD_3990_ERP_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_9343_erp.c linux/drivers/s390/block/dasd_9343_erp.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_9343_erp.c	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_9343_erp.c	Mon Dec  3 22:58:52 2001
@@ -6,18 +6,17 @@
  */
 
 #include <asm/ccwcache.h>
-#include <asm/dasd.h>
+#include "dasd_int.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(9343)"
 #endif				/* PRINTK_HEADER */
 
-dasd_era_t
-dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+dasd_era_t dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 	return dasd_era_recover;
 }
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_9343_erp.h linux/drivers/s390/block/dasd_9343_erp.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_9343_erp.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_9343_erp.h	Mon Dec  3 22:58:52 2001
@@ -10,9 +10,8 @@
 #ifndef DASD_9343_ERP_H
 #define DASD_9343_ERP_H
 
-
 dasd_era_t dasd_9343_erp_examine (ccw_req_t *, devstat_t *);
 
 ccw_req_t *dasd_9343_erp_action (ccw_req_t *);
 
-#endif /* DASD_9343_ERP_H */
+#endif				/* DASD_9343_ERP_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_diag.c linux/drivers/s390/block/dasd_diag.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_diag.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/s390/block/dasd_diag.c	Mon Dec  3 22:58:52 2001
@@ -14,6 +14,7 @@
  *          fixed partition handling and HDIO_GETGEO
  */
 
+#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <asm/debug.h>
@@ -29,6 +30,7 @@
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_diag.h"
 
 #ifdef PRINTK_HEADER
@@ -39,7 +41,7 @@
 dasd_discipline_t dasd_diag_discipline;
 
 typedef struct
-dasd_diag_private_t {
+    dasd_diag_private_t {
 	dasd_diag_characteristics_t rdc_data;
 	diag_rw_io_t iob;
 	diag_init_io_t iib;
@@ -64,10 +66,8 @@
 			      ".previous\n"
 			      ".section __ex_table,\"a\"\n"
 			      "    .align 4\n"
-			      "    .long 0b,2b\n"
-			      ".previous\n"
-			      :"=d"   (rc)
-			      :"d"    ((void *) __pa (devchar))
+			      "    .long 0b,2b\n" ".previous\n":"=d" (rc)
+			      :"d" ((void *) __pa (devchar))
 			      :"1");
 	return rc;
 }
@@ -75,11 +75,11 @@
 static __inline__ int
 dia250 (void *iob, int cmd)
 {
- 	__asm__ __volatile__ ("    lr    0,%1\n"
-                              "    diag  0,%0,0x250\n"
-                              "0:  ipm   %0\n"
-                              "    srl   %0,28\n"
- 			      "    or    %0,1\n"
+	__asm__ __volatile__ ("    lr    0,%1\n"
+			      "    diag  0,%0,0x250\n"
+			      "0:  ipm   %0\n"
+			      "    srl   %0,28\n"
+			      "    or    %0,1\n"
 			      "1:\n"
 			      ".section .fixup,\"ax\"\n"
 			      "2:  lhi   %0,3\n"
@@ -90,12 +90,10 @@
 			      ".previous\n"
 			      ".section __ex_table,\"a\"\n"
 			      "    .align 4\n"
-                              "    .long 0b,2b\n"
-                              ".previous\n"
-                              : "+d" (cmd)
-                              : "d" ((void *) __pa (iob))
-                              : "0", "1", "cc" );
- 	return cmd;
+			      "    .long 0b,2b\n" ".previous\n":"+d" (cmd)
+			      :"d" ((void *) __pa (iob))
+			      :"0", "1", "cc");
+	return cmd;
 }
 
 static __inline__ int
@@ -115,7 +113,7 @@
 
 	rc = dia250 (iib, INIT_BIO);
 
-	return rc&3;
+	return rc & 3;
 }
 
 static __inline__ int
@@ -128,7 +126,7 @@
 	memset (iib, 0, sizeof (diag_init_io_t));
 	iib->dev_nr = device->devinfo.devno;
 	rc = dia250 (iib, TERM_BIO);
-	return rc&3;
+	return rc & 3;
 }
 
 int
@@ -154,20 +152,17 @@
 	if (rc > 8) {
 		PRINT_WARN ("dia250 returned CC %d\n", rc);
 		check_then_set (&cqr->status,
-					       CQR_STATUS_QUEUED,
-					       CQR_STATUS_ERROR);
-        } else if (rc == 0 ) {                                     
-               check_then_set(&cqr->status,        
-                                             CQR_STATUS_QUEUED,   
-                                             CQR_STATUS_DONE);    
-               dasd_schedule_bh(device);                                
-	 } else {
+				CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
+	} else if (rc == 0) {
+		check_then_set (&cqr->status,
+				CQR_STATUS_QUEUED, CQR_STATUS_DONE);
+		dasd_schedule_bh (device);
+	} else {
 		if (cqr->expires) {
 			cqr->expires += cqr->startclk;
 		}
 		check_then_set (&cqr->status,
-					       CQR_STATUS_QUEUED,
-					       CQR_STATUS_IN_IO);
+				CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
 		rc = 0;
 	}
 	return rc;
@@ -176,22 +171,26 @@
 void
 dasd_ext_handler (struct pt_regs *regs, __u16 code)
 {
+    	int cpu = smp_processor_id();
 	ccw_req_t *cqr;
 	int ip = S390_lowcore.ext_params;
-	char status = *((char *) S390_lowcore.ext_params + 5);
+	char status = *((char *) &S390_lowcore.ext_params + 5);
 	dasd_device_t *device;
 	int done_fast_io = 0;
 	int devno;
 
+	irq_enter(cpu, -1);
+
 	if (!ip) {		/* no intparm: unsolicited interrupt */
 		printk (KERN_WARNING PRINTK_HEADER
 			"caught unsolicited interrupt\n");
+		irq_exit(cpu, -1);
 		return;
 	}
 	if (ip & 0x80000001) {
 		printk (KERN_WARNING PRINTK_HEADER
-			"caught spurious interrupt with parm %08x\n",
-			ip);
+			"caught spurious interrupt with parm %08x\n", ip);
+		irq_exit(cpu, -1);
 		return;
 	}
 	cqr = (ccw_req_t *) ip;
@@ -201,7 +200,8 @@
 		printk (KERN_WARNING PRINTK_HEADER
 			" INT on devno 0x%04X  = /dev/%s (%d:%d)"
 			" belongs to NULL device\n",
-			devno, device->name, MAJOR (device->kdev), MINOR (device->kdev));
+			devno, device->name, MAJOR (device->kdev),
+			MINOR (device->kdev));
 	}
 	if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
 		printk (KERN_WARNING PRINTK_HEADER
@@ -211,18 +211,15 @@
 			devno, device->name,
 			MAJOR (device->kdev), MINOR (device->kdev),
 			cqr->magic, *(int *) (&device->discipline->name));
+		irq_exit(cpu, -1);
 		return;
 	}
 	asm volatile ("STCK %0":"=m" (cqr->stopclk));
 	switch (status) {
 	case 0x00:
 		check_then_set (&cqr->status,
-					       CQR_STATUS_IN_IO,
-					       CQR_STATUS_DONE);
-		if ( device->level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
-					device->level = DASD_DEVICE_LEVEL_ANALYSIS_PREPARED;
-		if (cqr->next &&
-		    (cqr->next->status == CQR_STATUS_QUEUED)) {
+				CQR_STATUS_IN_IO, CQR_STATUS_DONE);
+		if (cqr->next && (cqr->next->status == CQR_STATUS_QUEUED)) {
 			if (dasd_start_diag (cqr->next) == 0) {
 				done_fast_io = 1;
 			}
@@ -233,12 +230,12 @@
 	case 0x03:
 	default:
 		check_then_set (&cqr->status,
-					       CQR_STATUS_IN_IO,
-					       CQR_STATUS_FAILED);
+				CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
 		break;
 	}
 	wake_up (&device->wait_q);
 	dasd_schedule_bh (device);
+	irq_exit(cpu, -1);
 }
 
 static int
@@ -255,47 +252,46 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
+			"Null device pointer passed to characteristics checker\n");
 		return -ENODEV;
 	}
-	if (device->private != NULL) {
-                kfree (device->private);
-        } 
-        device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
-        if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
+	device->private = kmalloc (sizeof (dasd_diag_private_t), GFP_KERNEL);
+	if (device->private == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+		rc = -ENOMEM;
+                goto fail;
 	}
 	private = (dasd_diag_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
-        
+
 	rdc_data->dev_nr = device->devinfo.devno;
 	rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
-        
-	if (dia210 (rdc_data) != 0) {
-                goto nodiag;
+
+        rc = dia210 (rdc_data);
+	if ( rc != 0) {
+		goto fail;
 	}
 	if (rdc_data->vdev_class != DEV_CLASS_FBA &&
 	    rdc_data->vdev_class != DEV_CLASS_ECKD &&
 	    rdc_data->vdev_class != DEV_CLASS_CKD) {
-                goto nodiag;
+                rc = -ENOTSUPP;
+		goto fail;
 	}
 #if 0
 	printk (KERN_INFO PRINTK_HEADER
 		"%04X: %04X on real %04X/%02X\n",
 		rdc_data->dev_nr,
-		rdc_data->vdev_type,
-		rdc_data->rdev_type, rdc_data->rdev_model);
+		rdc_data->vdev_type, rdc_data->rdev_type, rdc_data->rdev_model);
 #endif
 	/* Figure out position of label block */
 	if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
-		label_block = 1;
+		device->sizes.pt_block = 1;
 	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
 		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
-		label_block = 2;
+		device->sizes.pt_block = 2;
 	} else {
-                goto nodiag;
+                BUG();
 	}
 	private->label = (long *) get_free_page (GFP_KERNEL);
 	label = private->label;
@@ -304,86 +300,69 @@
 	for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
 		diag_bio_t *bio;
 		diag_rw_io_t *iob = &private->iob;
-                
+
 		rc = mdsk_init_io (device, bsize, 0, 64);
 		if (rc > 4) {
 			continue;
 		}
-		cqr = ccw_alloc_request (dasd_diag_discipline.name, sizeof(diag_bio_t)/sizeof(ccw1_t), 0);
+		cqr = dasd_alloc_request (dasd_diag_discipline.name,
+                                         sizeof (diag_bio_t) / sizeof (ccw1_t),
+                                         0, device);
 		if (cqr == NULL) {
 			printk (KERN_WARNING PRINTK_HEADER
-                                "No memory to allocate initialization request\n");
-                        free_page((long)private->label);
-                        kfree(private);
-                        device->private = NULL;
-                        return -ENOMEM;
+				"No memory to allocate initialization request\n");
+			free_page ((long) private->label);
+                        rc = -ENOMEM;
+                        goto fail;
 		}
 		bio = (diag_bio_t *) (cqr->cpaddr);
 		memset (bio, 0, sizeof (diag_bio_t));
 		bio->type = MDSK_READ_REQ;
-		bio->block_number = label_block + 1;
+		bio->block_number = device->sizes.pt_block + 1;
 		bio->buffer = __pa (private->label);
 		cqr->device = device;
-		cqr->status= CQR_STATUS_FILLED;
+		cqr->status = CQR_STATUS_FILLED;
 		memset (iob, 0, sizeof (diag_rw_io_t));
 		iob->dev_nr = rdc_data->dev_nr;
 		iob->block_count = 1;
-		iob->interrupt_params = (u32)cqr;
+		iob->interrupt_params = (u32) cqr;
 		iob->bio_list = __pa (bio);
 		rc = dia250 (iob, RW_BIO);
 		if (rc == 0) {
-			if (label[3] != bsize) {
-                                goto nodiag;
-			}
-			if (label[0] != 0xc3d4e2f1) {	/* != CMS1 */
-                                goto nodiag;
-			}
-			if (label[13] == 0) {
-                                goto nodiag;
+			if (label[3] != bsize ||
+                            label[0] != 0xc3d4e2f1 ||	/* != CMS1 */
+                            label[13] == 0 ){
+                                rc = -EMEDIUMTYPE;
+				goto fail;
 			}
 			break;
 		}
 		mdsk_term_io (device);
 	}
-        if ( bsize > PAGE_SIZE )
-                goto nodiag;
+        if (bsize > PAGE_SIZE) {
+                rc = -EMEDIUMTYPE;
+		goto fail;
+        }
+	device->sizes.blocks = label[7];
 	device->sizes.bp_block = bsize;
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
 	for (sb = 512; sb < bsize; sb = sb << 1)
 		device->sizes.s2b_shift++;
-        goto good;
- nodiag:
-        kfree(private);
-        device -> private = NULL;
-        rc = -ENODEV;
- good:
-	return rc;
-}
-
-static int
-dasd_diag_do_analysis (struct dasd_device_t *device)
-{
-	dasd_diag_private_t *private = (dasd_diag_private_t *) device->private;
-
-	long *label = private->label;
-
-	/* real size of the volume */
-	device->sizes.blocks = label[7];
-        if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
-		device->sizes.pt_block = 1;
-	} else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
-		   private->rdc_data.vdev_class == DEV_CLASS_CKD) {
-		device->sizes.pt_block = 2;
-	} else {
-		return -EINVAL;
-        }
 	printk (KERN_INFO PRINTK_HEADER
 		"/dev/%s (%04X): capacity (%dkB blks): %ldkB\n",
 		device->name, device->devinfo.devno,
 		(device->sizes.bp_block >> 10),
 		(device->sizes.blocks << device->sizes.s2b_shift) >> 1);
-        free_page((long)private->label);
-	return 0;
+	free_page ((long) private->label);
+        rc = 0;
+	goto out;
+ fail:
+        if ( rc ) {
+                kfree (device->private);
+                device->private = NULL;
+        }
+ out:
+	return rc;
 }
 
 static int
@@ -418,23 +397,6 @@
 	return dasd_era_fatal;
 }
 
-static dasd_erp_action_fn_t
-dasd_diag_erp_action (ccw_req_t * cqr)
-{
-	return default_erp_action;
-}
-
-static dasd_erp_postaction_fn_t
-dasd_diag_erp_postaction (ccw_req_t * cqr)
-{
-	if (cqr->function == default_erp_action)
-		return default_erp_postaction;
-	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n",
-		cqr->function);
-	return NULL;
-}
-
 static ccw_req_t *
 dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
 {
@@ -459,14 +421,12 @@
 	}
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
+		if (bh->b_size < byt_per_blk)
+                        BUG();
+                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
 	}
 	/* Build the request */
-	rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0);
+	rw_cp = dasd_alloc_request (dasd_diag_discipline.name, bhct << 1, 0, device);
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -474,28 +434,36 @@
 
 	block = req->sector >> device->sizes.s2b_shift;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size >= byt_per_blk) {
-			memset (bio, 0, sizeof (diag_bio_t));
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-				bio->type = rw_cmd;
-				bio->block_number = block + 1;
-				bio->buffer = __pa (bh->b_data + size);
-				bio++;
-				block++;
-			}
-		} else {
-			PRINT_WARN ("Cannot fulfill request smaller than block\n");
-			ccw_free_request (rw_cp);
-			return NULL;
-		}
+                memset (bio, 0, sizeof (diag_bio_t));
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        bio->type = rw_cmd;
+                        bio->block_number = block + 1;
+                        bio->buffer = __pa (bh->b_data + size);
+                        bio++;
+                        block++;
+                }
 	}
+	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
 	rw_cp->device = device;
-	rw_cp->expires = 50 * TOD_SEC;		/* 50 seconds */
+	rw_cp->expires = 50 * TOD_SEC;	/* 50 seconds */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
 	return rw_cp;
 }
 
+static int
+dasd_diag_fill_info (dasd_device_t * device, dasd_information_t * info)
+{
+	int rc = 0;
+	info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_diag_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_diag_private_t *) device->private)->rdc_data,
+		sizeof (dasd_diag_characteristics_t));
+	info->confdata_size = 0;
+	return rc;
+}
+
 static char *
 dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 {
@@ -511,21 +479,19 @@
 	return page;
 }
 
-dasd_discipline_t dasd_diag_discipline =
-{
+dasd_discipline_t dasd_diag_discipline = {
+        owner: THIS_MODULE,
 	name:"DIAG",
 	ebcname:"DIAG",
-	max_blocks:PAGE_SIZE/sizeof(diag_bio_t),
+	max_blocks:PAGE_SIZE / sizeof (diag_bio_t),
 	check_characteristics:dasd_diag_check_characteristics,
-	do_analysis:dasd_diag_do_analysis,
 	fill_geometry:dasd_diag_fill_geometry,
 	start_IO:dasd_start_diag,
 	examine_error:dasd_diag_examine_error,
-	erp_action:dasd_diag_erp_action,
-	erp_postaction:dasd_diag_erp_postaction,
 	build_cp_from_req:dasd_diag_build_cp_from_req,
 	dump_sense:dasd_diag_dump_sense,
-	int_handler:dasd_ext_handler
+	int_handler:dasd_ext_handler,
+	fill_info:dasd_diag_fill_info,
 };
 
 int
@@ -534,32 +500,55 @@
 	int rc = 0;
 	if (MACHINE_IS_VM) {
 		printk (KERN_INFO PRINTK_HEADER
-		   "%s discipline initializing\n", dasd_diag_discipline.name);
+			"%s discipline initializing\n",
+			dasd_diag_discipline.name);
 		ASCEBC (dasd_diag_discipline.ebcname, 4);
 		ctl_set_bit (0, 9);
 		register_external_interrupt (0x2603, dasd_ext_handler);
-		dasd_discipline_enq (&dasd_diag_discipline);
+		dasd_discipline_add (&dasd_diag_discipline);
 	} else {
 		printk (KERN_INFO PRINTK_HEADER
-			"Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+			"Machine is not VM: %s discipline not initializing\n",
+			dasd_diag_discipline.name);
 		rc = -EINVAL;
 	}
 	return rc;
 }
 
 void
-dasd_diag_cleanup( void ) {
-        if ( MACHINE_IS_VM ) {
-          printk ( KERN_INFO PRINTK_HEADER
-                   "%s discipline cleaning up\n", dasd_diag_discipline.name);
-          dasd_discipline_deq(&dasd_diag_discipline);
-          unregister_external_interrupt (0x2603, dasd_ext_handler);
-          ctl_clear_bit (0, 9);
-        } else {
-          printk ( KERN_INFO PRINTK_HEADER
-                   "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
-        }
+dasd_diag_cleanup (void)
+{
+	if (MACHINE_IS_VM) {
+		printk (KERN_INFO PRINTK_HEADER
+			"%s discipline cleaning up\n",
+			dasd_diag_discipline.name);
+		dasd_discipline_del (&dasd_diag_discipline);
+		unregister_external_interrupt (0x2603, dasd_ext_handler);
+		ctl_clear_bit (0, 9);
+	} else {
+		printk (KERN_INFO PRINTK_HEADER
+			"Machine is not VM: %s discipline not initializing\n",
+			dasd_diag_discipline.name);
+	}
 }
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_diag_init ();
+	return rc;
+}
+
+void
+cleanup_module (void)
+{
+	dasd_diag_cleanup ();
+	return;
+}
+#endif
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_diag.h linux/drivers/s390/block/dasd_diag.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_diag.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_diag.h	Mon Dec  3 22:58:52 2001
@@ -29,9 +29,9 @@
 	u8 rdev_type;
 	u8 rdev_model;
 	u8 rdev_features;
-} __attribute__             ((packed, aligned (4))) 
+} __attribute__ ((packed, aligned (4)))
 
-dasd_diag_characteristics_t;
+    dasd_diag_characteristics_t;
 
 typedef struct diag_bio_t {
 	u8 type;
@@ -40,9 +40,9 @@
 	u32 block_number;
 	u32 alet;
 	u32 buffer;
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_bio_t;
+    diag_bio_t;
 
 typedef struct diag_init_io_t {
 	u16 dev_nr;
@@ -52,9 +52,9 @@
 	u32 start_block;
 	u32 end_block;
 	u32 spare2[6];
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_init_io_t;
+    diag_init_io_t;
 
 typedef struct diag_rw_io_t {
 	u16 dev_nr;
@@ -67,9 +67,9 @@
 	u32 bio_list;
 	u32 interrupt_params;
 	u32 spare3[5];
-} __attribute__ ((packed, aligned (8))) 
+} __attribute__ ((packed, aligned (8)))
 
-diag_rw_io_t;
+    diag_rw_io_t;
 
 int dasd_diag_init (void);
-void dasd_diag_cleanup(void);
+void dasd_diag_cleanup (void);
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_eckd.c linux/drivers/s390/block/dasd_eckd.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_eckd.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/s390/block/dasd_eckd.c	Mon Dec  3 22:58:52 2001
@@ -1,6 +1,7 @@
 /* 
  * File...........: linux/drivers/s390/block/dasd_eckd.c
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+                    Carsten Otte <Cotte@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
 
@@ -22,27 +23,25 @@
 #include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <asm/debug.h>
-
 #include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
+
+#include <asm/debug.h>
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
-
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_eckd.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif				/* PRINTK_HEADER */
-#define PRINTK_HEADER DASD_NAME"(eckd): "
-#undef DASD_CDL // Support compatible disk layout
+#define PRINTK_HEADER DASD_NAME"(eckd):"
 #undef CDL_PRINTK
 
 #define ECKD_C0(i) (i->home_bytes)
@@ -62,55 +61,39 @@
 dasd_eckd_private_t {
 	dasd_eckd_characteristics_t rdc_data;
 	dasd_eckd_confdata_t conf_data;
-#ifdef DASD_CDL
-        eckd_count_t count_area[5];
-#else
-	eckd_count_t count_area;
-#endif
-	ccw_req_t *init_cqr;
-#ifdef DASD_CDL
-        int uses_cdl; 
-#endif
+	eckd_count_t count_area[5];
+	int uses_cdl;
 } dasd_eckd_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
-devreg_t dasd_eckd_known_devices[] =
-{
-	{
-		ci:
-		{hc:
-		 {ctype:0x3990}},
-		flag: (DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+devreg_t dasd_eckd_known_devices[] = {
+        {
+                ci: { hc: {ctype:0x3880, dtype: 3390}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_MATCH_DEV_TYPE | 
+                      DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
+        {
+                ci: { hc: {ctype:0x3990}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x2105}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+                ci: { hc: {ctype:0x2105}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x9343}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                       DEVREG_NO_DEV_INFO| 
-                       DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	}
+                ci: { hc: {ctype:0x9343}},
+                flag:(DEVREG_MATCH_CU_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        }
 };
 #endif
 
-#ifdef DASD_CDL
-int sizes_trk0[]={28,148,84};
+int sizes_trk0[] = { 28, 148, 84 };
 #define LABEL_SIZE 140
-#endif
 
 static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
@@ -126,8 +109,7 @@
 }
 
 static inline int
-bytes_per_record (dasd_eckd_characteristics_t * rdc,
-		  int kl,	/* key length */
+bytes_per_record (dasd_eckd_characteristics_t * rdc, int kl,	/* key length */
 		  int dl /* data length */ )
 {
 	int bpr = 0;
@@ -194,8 +176,7 @@
 				       9 + ceil_quot (kl + 6 * kn, 34) +
 				       9 + ceil_quot (dl + 6 * dn, 34));
 		} else
-			return 1729 / (10 +
-				       9 + ceil_quot (dl + 6 * dn, 34));
+			return 1729 / (10 + 9 + ceil_quot (dl + 6 * dn, 34));
 	case 0x9345:
 		dn = ceil_quot (dl + 6, 232) + 1;
 		if (kl) {
@@ -204,21 +185,17 @@
 				       7 + ceil_quot (kl + 6 * kn, 34) +
 				       ceil_quot (dl + 6 * dn, 34));
 		} else
-			return 1420 / (18 +
-				       7 + ceil_quot (dl + 6 * dn, 34));
+			return 1420 / (18 + 7 + ceil_quot (dl + 6 * dn, 34));
 	}
 	return rpt;
 }
 
-
-static inline void
+static inline int
 define_extent (ccw1_t * de_ccw,
 	       DE_eckd_data_t * data,
-	       int trk,
-	       int totrk,
-	       int cmd,
-	       dasd_device_t * device)
+	       int trk, int totrk, int cmd, dasd_device_t * device, ccw_req_t* cqr)
 {
+        int rc=0;
 	ch_t geo, beg, end;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
 
@@ -232,7 +209,8 @@
 	memset (de_ccw, 0, sizeof (ccw1_t));
 	de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
 	de_ccw->count = 16;
-	set_normalized_cda (de_ccw, __pa (data));
+	if (rc=dasd_set_normalized_cda (de_ccw, __pa (data), cqr, device)) 
+                return rc;
 
 	memset (data, 0, sizeof (DE_eckd_data_t));
 	switch (cmd) {
@@ -259,6 +237,7 @@
 	case DASD_ECKD_CCW_WRITE_CKD_MT:
 		data->attributes.operation = 0x1;	/* format through cache */
 		break;
+	case DASD_ECKD_CCW_ERASE:
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
 	case DASD_ECKD_CCW_WRITE_RECORD_ZERO:
 		data->mask.perm = 0x3;
@@ -270,46 +249,66 @@
 		break;
 	}
 	data->attributes.mode = 0x3;
-	if (private->rdc_data.cu_type == 0x2105 
-#ifdef DASD_CDL
-            && !(private->uses_cdl && trk < 2)
-#endif
-            ) {
+	if (private->rdc_data.cu_type == 0x2105
+	    && !(private->uses_cdl && trk < 2)
+	    ) {
 		data->reserved |= 0x40;
 	}
 	data->beg_ext.cyl = beg.cyl;
 	data->beg_ext.head = beg.head;
 	data->end_ext.cyl = end.cyl;
 	data->end_ext.head = end.head;
+        return rc;
 }
 
-static inline void
+static inline int
 locate_record (ccw1_t * lo_ccw,
 	       LO_eckd_data_t * data,
 	       int trk,
 	       int rec_on_trk,
-	       int no_rec,
-	       int cmd,
-	       dasd_device_t * device,
-	       int reclen)
+	       int no_rec, int cmd, dasd_device_t * device, int reclen, ccw_req_t* cqr)
 {
+        int rc=0;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	ch_t geo =
-	{private->rdc_data.no_cyl,
-	 private->rdc_data.trk_per_cyl};
-	ch_t seek =
-	{trk / (geo.head), trk % (geo.head)};
-	int sector;
+	ch_t geo = { private->rdc_data.no_cyl,
+		private->rdc_data.trk_per_cyl
+	};
+	ch_t seek = { trk / (geo.head), trk % (geo.head) };
+	int sector = 0;
 
 #ifdef CDL_PRINTK
-        printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n",trk,rec_on_trk,no_rec,cmd,reclen);
+	printk ("Locate: trk %d, rec %d, no_rec %d, cmd %d, reclen %d\n", trk,
+		rec_on_trk, no_rec, cmd, reclen);
 #endif
 	memset (lo_ccw, 0, sizeof (ccw1_t));
 	lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
 	lo_ccw->count = 16;
-	set_normalized_cda (lo_ccw, __pa (data));
+	if (rc=dasd_set_normalized_cda (lo_ccw, __pa (data), cqr, device))
+                return rc;
 
 	memset (data, 0, sizeof (LO_eckd_data_t));
+        if (rec_on_trk) {
+                switch (private->rdc_data.dev_type) {
+                case 0x3390:{
+                        int dn, d;
+                        dn = ceil_quot (reclen + 6, 232);
+                        d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
+                        sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
+                        break;
+                }
+                case 0x3380:{
+                        int d;
+                        d = 7 + ceil_quot (reclen + 12, 32);
+                        sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
+                        break;
+                }
+                case 0x9345:
+                default:
+                        sector = 0;
+                }
+        }
+        data->sector = sector;
+	data->count = no_rec;
 	switch (cmd) {
 	case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
 		data->operation.orientation = 0x3;
@@ -360,32 +359,18 @@
 	case DASD_ECKD_CCW_READ_COUNT:
 		data->operation.operation = 0x06;
 		break;
+	case DASD_ECKD_CCW_ERASE:
+                data->length = reclen;
+                data->auxiliary.last_bytes_used = 0x1;
+		data->operation.operation = 0x0b;
+		break;
 	default:
 		INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
 	}
-	switch (private->rdc_data.dev_type) {
-	case 0x3390:{
-			int dn, d;
-			dn = ceil_quot (reclen + 6, 232);
-			d = 9 + ceil_quot (reclen + 6 * (dn + 1), 34);
-			sector = (49 + (rec_on_trk - 1) * (10 + d)) / 8;
-			break;
-		}
-	case 0x3380:{
-			int d;
-			d = 7 + ceil_quot (reclen + 12, 32);
-			sector = (39 + (rec_on_trk - 1) * (8 + d)) / 7;
-			break;
-		}
-	case 0x9345:
-	default:
-		sector = 0;
-	}
-	data->sector = sector;
 	memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
 	memcpy (&(data->search_arg), &seek, sizeof (ch_t));
 	data->search_arg.record = rec_on_trk;
-	data->count += no_rec;
+        return rc;
 }
 
 static int
@@ -393,12 +378,10 @@
 {
 	if (info->sid_data.cu_type == 0x3990 ||
 	    info->sid_data.cu_type == 0x2105)
-		if (info->sid_data.dev_type == 0x3390)
-			return 0;
+		    if (info->sid_data.dev_type == 0x3390) return 0;
 	if (info->sid_data.cu_type == 0x3990 ||
 	    info->sid_data.cu_type == 0x2105)
-		if (info->sid_data.dev_type == 0x3380)
-			return 0;
+		    if (info->sid_data.dev_type == 0x3380) return 0;
 	if (info->sid_data.cu_type == 0x9343)
 		if (info->sid_data.dev_type == 0x9345)
 			return 0;
@@ -408,7 +391,7 @@
 static int
 dasd_eckd_check_characteristics (struct dasd_device_t *device)
 {
-	int rc = -ENODEV;
+	int rc = 0;
 	void *conf_data;
 	void *rdc_data;
 	int conf_len;
@@ -416,82 +399,89 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
+			"Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+	}
+	device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
+	if (device->private == NULL) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+		rc = -ENOMEM;
+                goto fail;
 	}
-        if (device->private != NULL) {
-                kfree(device->private);
-        }
-        device->private = kmalloc (sizeof (dasd_eckd_private_t), GFP_KERNEL);
-        if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
-        }
 	private = (dasd_eckd_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
 	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 64);
 	if (rc) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"Read device characteristics returned error %d\n", rc);
-		return rc;
-	}
+                goto fail;
+        }
 	printk (KERN_INFO PRINTK_HEADER
-	    "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n",
+		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) "
+                "Cyl:%d Head:%d Sec:%d\n",
 		device->devinfo.devno, device->devinfo.irq,
 		private->rdc_data.dev_type, private->rdc_data.dev_model,
 		private->rdc_data.cu_type, private->rdc_data.cu_model.model,
 		private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,
 		private->rdc_data.sec_per_trk);
-	rc = 0 ? 0 : read_conf_data (device->devinfo.irq, &conf_data, &conf_len, LPM_ANYPATH);
+	rc = read_conf_data (device->devinfo.irq, &conf_data, &conf_len,
+                             LPM_ANYPATH);
+
+        if (rc == -EOPNOTSUPP) {
+                rc = 0; /* this one is ok */
+        }
 	if (rc) {
-		if (rc == -EOPNOTSUPP)
-			return 0;
 		printk (KERN_WARNING PRINTK_HEADER
 			"Read configuration data returned error %d\n", rc);
-		return rc;
-	}
-	if (conf_len != sizeof (dasd_eckd_confdata_t)) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
-			conf_len, sizeof (dasd_eckd_confdata_t));
-		return rc;
+                goto fail;
 	}
-	if (conf_data == NULL) {
+        if (conf_data == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No configuration data retrieved\n");
-		return -ENOMEM;
-	}
-	memcpy (&private->conf_data, conf_data, sizeof (dasd_eckd_confdata_t));
-	printk (KERN_INFO PRINTK_HEADER
-                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): Configuration data read\n",
-		device->devinfo.devno, device->devinfo.irq,
-		private->rdc_data.dev_type, private->rdc_data.dev_model,
-		private->rdc_data.cu_type, private->rdc_data.cu_model.model);
-	device->sizes.bp_block = 4096;
-	device->sizes.s2b_shift = 3;
-	device->sizes.blocks = (private->rdc_data.no_cyl *
-				private->rdc_data.trk_per_cyl *
-				recs_per_track (&private->rdc_data,
-						0, device->sizes.bp_block));
-	return 0;
+                goto out; /* no errror */
+	} 
+        if (conf_len != sizeof (dasd_eckd_confdata_t)) {
+		printk (KERN_WARNING PRINTK_HEADER
+			"sizes of configuration data mismatch"
+                        "%d (read) vs %ld (expected)\n",
+			conf_len, sizeof (dasd_eckd_confdata_t));
+                goto out; /* no errror */
+	} 
+        memcpy (&private->conf_data, conf_data, 
+                sizeof (dasd_eckd_confdata_t));
+        printk (KERN_INFO PRINTK_HEADER
+                "%04X on sch %d: %04X/%02X(CU:%04X/%02X): "
+                "Configuration data read\n",
+                device->devinfo.devno, device->devinfo.irq,
+                private->rdc_data.dev_type, 
+                private->rdc_data.dev_model,
+                private->rdc_data.cu_type, 
+                private->rdc_data.cu_model.model);
+        goto out;
+ fail:
+        if ( rc ) {
+                kfree (device->private);
+                device->private = NULL;
+        }
+ out:
+	return rc;
 }
 
-#ifdef DASD_CDL
 static inline int
-dasd_eckd_cdl_reclen (dasd_device_t* device,int recid) {
-        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-        int byt_per_blk = device->sizes.bp_block;
-        int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
-        if (recid < 3) 
-                return sizes_trk0[recid];
-        if (recid < blk_per_trk)
-                return byt_per_blk;
-        if (recid < 2*blk_per_trk )
-                return LABEL_SIZE;
-        return byt_per_blk;
+dasd_eckd_cdl_reclen (dasd_device_t * device, int recid)
+{
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+	int byt_per_blk = device->sizes.bp_block;
+	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+	if (recid < 3)
+		return sizes_trk0[recid];
+	if (recid < blk_per_trk)
+		return byt_per_blk;
+	if (recid < 2 * blk_per_trk)
+		return LABEL_SIZE;
+	return byt_per_blk;
 }
-#endif
 
 static ccw_req_t *
 dasd_eckd_init_analysis (struct dasd_device_t *device)
@@ -500,76 +490,82 @@
 	ccw1_t *ccw;
 	DE_eckd_data_t *DE_data;
 	LO_eckd_data_t *LO_data;
-	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-#ifdef DASD_CDL
-        eckd_count_t *count_data = private->count_area;
-#else
-	eckd_count_t *count_data = &(private->count_area);
-#endif
-#ifdef DASD_CDL
-        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 8 + 1, 
-                                 sizeof (DE_eckd_data_t) + 
-                                 2*sizeof (LO_eckd_data_t));
-#else
-	cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3 + 1, 
-                                 sizeof (DE_eckd_data_t) + 
-                                 sizeof (LO_eckd_data_t));
-#endif
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+	eckd_count_t *count_data = private->count_area;
+
+	cqr = dasd_alloc_request (dasd_eckd_discipline.name, 8 + 1,
+				 sizeof (DE_eckd_data_t) +
+				 2 * sizeof (LO_eckd_data_t),
+                                 device);
 	if (cqr == NULL) {
-		printk (KERN_WARNING PRINTK_HEADER
-			"No memory to allocate initialization request\n");
-		return NULL;
-	} else {
-		private->init_cqr = cqr;
+                printk (KERN_WARNING PRINTK_HEADER
+                        "No memory to allocate initialization request\n");
+                goto out;
 	}
 	DE_data = cqr->data;
 	LO_data = cqr->data + sizeof (DE_eckd_data_t);
 	ccw = cqr->cpaddr;
-#ifdef DASD_CDL
-        define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device);
-#else
-	define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
-#endif
+	if (define_extent (ccw, DE_data, 0, 2, DASD_ECKD_CCW_READ_COUNT, device, cqr)) {
+                goto clear_cqr;
+        }        
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
-#ifdef DASD_CDL
-        locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#else
-	locate_record (ccw, LO_data, 0, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#endif
-#ifdef DASD_CDL
+	if (locate_record (ccw, LO_data++, 0, 0, 4, DASD_ECKD_CCW_READ_COUNT,
+                           device, 0, cqr)) {
+                goto clear_cqr;
+        }       
 	ccw->flags |= CCW_FLAG_CC;
 	ccw++;
 	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
 	ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data++));
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT, device, 0);
-#endif
-        ccw->flags |= CCW_FLAG_CC;
-        ccw++;
-        ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-        ccw->count = 8;
-        set_normalized_cda (ccw, __pa (count_data));
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data++), cqr, device)) {
+                goto clear_cqr;
+        }
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	if (locate_record (ccw, LO_data++, 2, 0, 1, DASD_ECKD_CCW_READ_COUNT,
+                           device, 0, cqr)) {
+                goto clear_cqr;
+        }       
+	ccw->flags |= CCW_FLAG_CC;
+	ccw++;
+	ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+	ccw->count = 8;
+	if (dasd_set_normalized_cda (ccw, __pa (count_data), cqr, device)) {
+                goto clear_cqr;
+        }
 	cqr->device = device;
 	cqr->retries = 0;
 	cqr->status = CQR_STATUS_FILLED;
+        dasd_chanq_enq (&device->queue, cqr);
+        goto out;
+ clear_cqr:
+        dasd_free_request (cqr,device);
+        printk (KERN_WARNING PRINTK_HEADER
+                "No memory to allocate initialization request\n");
+        cqr=NULL;
+ out:
 	return cqr;
 }
 
@@ -578,105 +574,91 @@
 {
 	int sb, rpt;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-        eckd_count_t *count_area = NULL;
-        char *cdl_msg;
-#ifdef DASD_CDL /* BAD HACK SO FIX ME UP */
-        int i;
-        private -> uses_cdl = 1;
-
-        /* Free the cqr and cleanup device->sizes */
-        dasd_chanq_deq (&device->queue, private->init_cqr);
-        ccw_free_request (private->init_cqr);
-        private->init_cqr = NULL;
-        memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-        /* Check Track 0 for Compatible Disk Layout */
-        for (i = 0; i < 3; i++) { 
-                if ((i < 3) &&
-                    ((private->count_area[i].kl != 4) ||
-                     (private->count_area[i].dl != 
-                      dasd_eckd_cdl_reclen (device,i) - 4))) {
-                        private -> uses_cdl = 0;
-                        break;
-                } 
-        }
-        if ( i == 3 ) {
-                count_area = &private->count_area[4];
-        }
-        if (private->uses_cdl == 0) { 
-                for (i = 0; i < 5; i++) {
-                        if ((private->count_area[i].kl != 0) ||
-                            (private->count_area[i].dl != 
-                             private->count_area[0].dl)) {
-                                break;
-                        }
-                }
-                if ( i == 5 ) {
-                        count_area = &private->count_area[0];
-                }
-        } else {
-                if (private->count_area[3].record == 1) {
-                        DASD_MESSAGE(KERN_WARNING,device,"%s",
-                                     "Trk 0: no records after VTOC!");
-                }
+	eckd_count_t *count_area = NULL;
+	char *cdl_msg;
+        int status;
+	int i;
+	private->uses_cdl = 1;
+        status = device->init_cqr->status;
+	dasd_chanq_deq (&device->queue, device->init_cqr);
+	dasd_free_request (device->init_cqr, device);
+	/* Free the cqr and cleanup device->sizes */
+        if ( status != CQR_STATUS_DONE ) {
+                DASD_MESSAGE (KERN_WARNING,device,"%s",
+                              "volume analysis returned fatal error");
+                return -EMEDIUMTYPE;
         }
-        if (count_area != NULL && /* we found notthing violating our disk layout */
-            count_area ->kl == 0) { 
+	/* Check Track 0 for Compatible Disk Layout */
+	for (i = 0; i < 3; i++) {
+		if ((i < 3) &&
+		    ((private->count_area[i].kl != 4) ||
+		     (private->count_area[i].dl !=
+		      dasd_eckd_cdl_reclen (device, i) - 4))) {
+			private->uses_cdl = 0;
+			break;
+		}
+	}
+	if (i == 3) {
+		count_area = &private->count_area[4];
+	}
+	if (private->uses_cdl == 0) {
+		for (i = 0; i < 5; i++) {
+			if ((private->count_area[i].kl != 0) ||
+			    (private->count_area[i].dl !=
+			     private->count_area[0].dl)) {
+				break;
+			}
+		}
+		if (i == 5) {
+			count_area = &private->count_area[0];
+		}
+	} else {
+		if (private->count_area[3].record == 1) {
+			DASD_MESSAGE (KERN_WARNING, device, "%s",
+				      "Trk 0: no records after VTOC!");
+		}
+	}
+	if (count_area != NULL &&	/* we found notthing violating our disk layout */
+	    count_area->kl == 0) {
                 /* find out blocksize */
                 switch (count_area->dl) {
                 case 512:
-                case 1024:
-                case 2048:
-                case 4096:
-                        device->sizes.bp_block = count_area->dl;
-                        break;
-                }
-        }
-#else
-	dasd_chanq_deq (&device->queue, private->init_cqr);
-	ccw_free_request (private->init_cqr);
-	private->init_cqr = NULL;
-	memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
-	switch (private->count_area.dl) {
-	case 512:
-	case 1024:
-	case 2048:
-	case 4096:
-		device->sizes.bp_block = private->count_area.dl;
-		break;
+		case 1024:
+		case 2048:
+		case 4096:
+			device->sizes.bp_block = count_area->dl;
+			break;
+		}
+	}
+	if (device->sizes.bp_block == 0) {
+		DASD_MESSAGE (KERN_WARNING, device, "%s\n",
+			      "Volume has incompatible disk layout");
+		return -EMEDIUMTYPE;
 	}
-#endif
-        if ( device->sizes.bp_block == 0 ) {
-                DASD_MESSAGE(KERN_WARNING, device,"%s\n",
-                             "Volume has incompatible disk layout");
-                return -EMEDIUMTYPE;
-        }
 	device->sizes.s2b_shift = 0;	/* bits to shift 512 to get a block */
-        device->sizes.pt_block = 2;
+	device->sizes.pt_block = 2;
 	for (sb = 512; sb < device->sizes.bp_block; sb = sb << 1)
 		device->sizes.s2b_shift++;
 
 	rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
-	device->sizes.blocks = (private->rdc_data.no_cyl * 
-                                private->rdc_data.trk_per_cyl *
-                                recs_per_track (&private->rdc_data, 0, 
-                                                device->sizes.bp_block));
-#ifdef DASD_CDL
-        cdl_msg = private->uses_cdl?"compatible disk layout":"classic disk layout";
-#else
-        cdl_msg = "classic disk layout";
-#endif           
-                  
-        DASD_MESSAGE(KERN_INFO,device,"(%dkB blks): %dkB at %dkB/trk %s",
-                     (device->sizes.bp_block >> 10),
-                     (private->rdc_data.no_cyl * 
-                      private->rdc_data.trk_per_cyl *
-                      recs_per_track (&private->rdc_data, 0, 
-                                      device->sizes.bp_block) *
-                      (device->sizes.bp_block >> 9)) >> 1,
-                     (recs_per_track (&private->rdc_data, 0, 
-                                      device->sizes.bp_block) * 
-                      device->sizes.bp_block) >> 10,
-                     cdl_msg);
+	device->sizes.blocks = (private->rdc_data.no_cyl *
+				private->rdc_data.trk_per_cyl *
+				recs_per_track (&private->rdc_data, 0,
+						device->sizes.bp_block));
+	cdl_msg =
+	    private->
+	    uses_cdl ? "compatible disk layout" : "classic disk layout";
+
+	DASD_MESSAGE (KERN_INFO, device, "(%dkB blks): %dkB at %dkB/trk %s",
+		      (device->sizes.bp_block >> 10),
+		      (private->rdc_data.no_cyl *
+		       private->rdc_data.trk_per_cyl *
+		       recs_per_track (&private->rdc_data, 0,
+				       device->sizes.bp_block) *
+		       (device->sizes.bp_block >> 9)) >> 1,
+		      (recs_per_track (&private->rdc_data, 0,
+				       device->sizes.bp_block) *
+		       device->sizes.bp_block) >> 10, cdl_msg);
 	return 0;
 }
 
@@ -690,13 +672,14 @@
 	case 1024:
 	case 2048:
 	case 4096:
-		break;
+            geo->sectors = recs_per_track (&(private->rdc_data), 
+                                           0, device->sizes.bp_block);
+            break;
 	default:
-		return -EINVAL;
+            break;
 	}
 	geo->cylinders = private->rdc_data.no_cyl;
 	geo->heads = private->rdc_data.trk_per_cyl;
-	geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block);
 	return rc;
 }
 
@@ -713,95 +696,89 @@
 	ccw1_t *last_ccw = NULL;
 	void *last_data = NULL;
 	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-	int trk = fdata->start_unit;
-	int bs = fdata->blksize == DASD_FORMAT_DEFAULT_BLOCKSIZE ? 4096 : fdata->blksize;
-	int flags = fdata->intensity == DASD_FORMAT_DEFAULT_INTENSITY ? 0 : fdata->intensity;
-
-	int rpt = recs_per_track (&(private->rdc_data), 0, bs);
-	int cyl = trk / private->rdc_data.trk_per_cyl;
-	int head = trk % private->rdc_data.trk_per_cyl;
+
+	int rpt = recs_per_track (&(private->rdc_data), 0, fdata->blksize);
+	int cyl = fdata->start_unit / private->rdc_data.trk_per_cyl;
+	int head = fdata->start_unit % private->rdc_data.trk_per_cyl;
 	int wrccws = rpt;
 	int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
-#ifdef DASD_CDL
-        int formatCDL=0;
-#endif
-
-	if (((fdata->stop_unit == DASD_FORMAT_DEFAULT_STOP_UNIT) &&
-	 trk >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)) ||
-	    ((fdata->stop_unit != DASD_FORMAT_DEFAULT_STOP_UNIT) &&
-	     trk > fdata->stop_unit)) {
-		DASD_MESSAGE(KERN_INFO, device,"Track %d reached! ending.", trk);
+        
+	if (fdata->start_unit >= (private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl)){
+                DASD_MESSAGE (KERN_INFO, device, "Track no %d too big!", fdata->start_unit);
+                return NULL;
+        }
+        if ( fdata->start_unit > fdata->stop_unit) {
+                DASD_MESSAGE (KERN_INFO, device, "Track %d reached! ending.",
+                              fdata->start_unit);
 		return NULL;
 	}
-	switch (bs) {
+	switch (fdata->blksize) {
 	case 512:
 	case 1024:
 	case 2048:
 	case 4096:
 		break;
 	default:
-		printk (KERN_WARNING PRINTK_HEADER "Invalid blocksize %d...terminating!\n", bs);
+		printk (KERN_WARNING PRINTK_HEADER
+			"Invalid blocksize %d...terminating!\n", fdata->blksize);
 		return NULL;
 	}
-	switch (flags) {
+	switch (fdata->intensity) {
 	case 0x00:
 	case 0x01:
 	case 0x03:
 	case 0x04:		/* make track invalid */
-                break;
-#ifdef DASD_CDL /* Format compatible disk Layout */
-        case 0x08:
-        case 0x09:
-        case 0x0b:
-        case 0x0c:
-                formatCDL=1;
+	case 0x08:
+	case 0x09:
+	case 0x0b:
+	case 0x0c:
 		break;
-#endif
 	default:
-		printk (KERN_WARNING PRINTK_HEADER "Invalid flags 0x%x...terminating!\n", flags);
+		printk (KERN_WARNING PRINTK_HEADER
+			"Invalid flags 0x%x...terminating!\n", fdata->intensity);
 		return NULL;
 	}
 
 	/* print status line */
 	if ((private->rdc_data.no_cyl < 20) ?
-	    (trk % private->rdc_data.no_cyl == 0) :
-	    (trk % private->rdc_data.no_cyl == 0 &&
-	     (trk / private->rdc_data.no_cyl) %
+	    (fdata->start_unit % private->rdc_data.no_cyl == 0) :
+	    (fdata->start_unit % private->rdc_data.no_cyl == 0 &&
+	     (fdata->start_unit / private->rdc_data.no_cyl) %
 	     (private->rdc_data.no_cyl / 20))) {
-		DASD_MESSAGE(KERN_INFO, device, "Format Cylinder: %d Flags: %d\n",
-			trk / private->rdc_data.trk_per_cyl,
-			flags);
+		DASD_MESSAGE (KERN_INFO, device,
+			      "Format Cylinder: %d Flags: %d\n",
+			      fdata->start_unit / private->rdc_data.trk_per_cyl, fdata->intensity);
 	}
-	if (flags & 0x04) {
-                rpt = 1;
+	if ((fdata->intensity & ~0x8) & 0x04) {
 		wrccws = 1;
-                bs = 8;
+		rpt = 1;
 	} else {
-		if (flags & 0x1) {
+		if (fdata->intensity & 0x1) {
 			wrccws++;
 			datasize += sizeof (eckd_count_t);
 		}
-		if (flags & 0x2) {
+		if (fdata->intensity & 0x2) {
 			wrccws++;
 			datasize += sizeof (eckd_home_t);
 		}
 	}
-	fcp = ccw_alloc_request (dasd_eckd_discipline.name,
+	fcp = dasd_alloc_request (dasd_eckd_discipline.name,
 				 wrccws + 2 + 1,
-				 datasize + rpt * sizeof (eckd_count_t));
+				 datasize + rpt * sizeof (eckd_count_t),
+                                 device );
 	if (fcp != NULL) {
 		fcp->device = device;
-                fcp->retries = 2;       /* set retry counter to enable ERP */
+		fcp->retries = 2;	/* set retry counter to enable ERP */
 		last_data = fcp->data;
 		DE_data = (DE_eckd_data_t *) last_data;
 		last_data = (void *) (DE_data + 1);
 		LO_data = (LO_eckd_data_t *) last_data;
 		last_data = (void *) (LO_data + 1);
-		if (flags & 0x2) {
+		if (fdata->intensity & 0x2) {
 			ha_data = (eckd_home_t *) last_data;
 			last_data = (void *) (ha_data + 1);
 		}
-		if (flags & 0x1) {
+		if (fdata->intensity & 0x1) {
 			r0_data = (eckd_count_t *) last_data;
 			last_data = (void *) (r0_data + 1);
 		}
@@ -809,63 +786,65 @@
 
 		last_ccw = fcp->cpaddr;
 
-		switch (flags) {
+		switch (fdata->intensity & ~0x08) {
 		case 0x03:
-                case 0x0b:
-			define_extent (last_ccw, DE_data, trk, trk,
-				    DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS,
+                                           device, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device, device->sizes.bp_block);
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+				       DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device,
+                                           device->sizes.bp_block, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			break;
 		case 0x01:
-                case 0x09:
-			define_extent (last_ccw, DE_data, trk, trk,
-				     DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+                                           DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device, device->sizes.bp_block);
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+				       DASD_ECKD_CCW_WRITE_RECORD_ZERO, device,
+                                           device->sizes.bp_block, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			memset (r0_data, 0, sizeof (eckd_count_t));
 			break;
-		case 0x00:
-                case 0x08:
-			define_extent (last_ccw, DE_data, trk, trk,
-				       DASD_ECKD_CCW_WRITE_CKD, device);
-			last_ccw->flags |= CCW_FLAG_CC;
-			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_CKD, device, device->sizes.bp_block);
-			LO_data->length = bs;
-			last_ccw->flags |= CCW_FLAG_CC;
-			last_ccw++;
-			break;
 		case 0x04:
-                case 0x0c:
-			define_extent (last_ccw, DE_data, trk, trk,
-				       DASD_ECKD_CCW_WRITE_CKD, device);
+                        fdata->blksize = 8;
+		case 0x00:
+			if (define_extent (last_ccw, DE_data, fdata->start_unit, fdata->start_unit,
+                                           DASD_ECKD_CCW_WRITE_CKD, device, fcp)) {
+                                dasd_free_request (fcp, device);
+                                return NULL;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
-			locate_record (last_ccw, LO_data, trk, 0, wrccws,
-				       DASD_ECKD_CCW_WRITE_CKD, device, 0);
-			LO_data->length = bs;
+			if (locate_record (last_ccw, LO_data, fdata->start_unit, 0, wrccws,
+                                           DASD_ECKD_CCW_WRITE_CKD, device, fdata->blksize, fcp)) {
+                                goto clear_fcp;
+                        }
 			last_ccw->flags |= CCW_FLAG_CC;
 			last_ccw++;
 			break;
 		default:
-			PRINT_WARN ("Unknown format flags...%d\n", flags);
+			PRINT_WARN ("Unknown format flags...%d\n", fdata->intensity);
 			return NULL;
 		}
-		if (flags & 0x02) {
-			PRINT_WARN ("Unsupported format flag...%d\n", flags);
+		if (fdata->intensity & 0x02) {
+			PRINT_WARN ("Unsupported format flag...%d\n", fdata->intensity);
 			return NULL;
 		}
-		if (flags & 0x01) {	/* write record zero */
+		if (fdata->intensity & 0x01) {	/* write record zero */
 			r0_data->cyl = cyl;
 			r0_data->head = head;
 			r0_data->record = 0;
@@ -874,49 +853,73 @@
 			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_RECORD_ZERO;
 			last_ccw->count = 8;
 			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
-			set_normalized_cda (last_ccw, __pa (r0_data));
+			if (dasd_set_normalized_cda (last_ccw, __pa (r0_data), fcp, device)) {
+                                goto clear_fcp;
+                        }
 			last_ccw++;
 		}
-		/* write remaining records */
-		for (i = 0; i < rpt; i++) {
-			memset (ct_data + i, 0, sizeof (eckd_count_t));
-			(ct_data + i)->cyl = cyl;
-			(ct_data + i)->head = head;
-			(ct_data + i)->record = i + 1;
-			(ct_data + i)->kl = 0;
-#ifdef DASD_CDL
-                        if (formatCDL) { 
-                            // special handling when formatting CDL
-                            switch (trk) {
-                            case 0:
-                                if (i<3) {
-                                    (ct_data + i)->kl = 4;
-                                    (ct_data + i)->dl = sizes_trk0[i]-4;
-                                } else 
-                                    (ct_data + i)->dl = bs;
-                                break;
-                            case 1:
-                                (ct_data + i)->kl = 44;
-                                (ct_data + i)->dl = LABEL_SIZE-44;
-                                break;
-                            default:
-                                (ct_data + i)->dl = bs;
-                                break;
-                            }
-                        }
-                        else
-#endif                            
-                        (ct_data + i)->dl = bs;
+		if ((fdata->intensity & ~0x08) & 0x04) {	/* erase track */
+			memset (ct_data, 0, sizeof (eckd_count_t));
+			ct_data->cyl = cyl;
+			ct_data->head = head;
+			ct_data->record = 1;
+			ct_data->kl = 0;
+			ct_data->dl = 0;
 			last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
-			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
 			last_ccw->count = 8;
-			set_normalized_cda (last_ccw, __pa (ct_data + i));
+			last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
+			if (dasd_set_normalized_cda (last_ccw, __pa (ct_data), fcp, device)) {
+                                goto clear_fcp;
+                        }
 			last_ccw++;
+		} else {	/* write remaining records */
+			for (i = 0; i < rpt; i++) {
+				memset (ct_data + i, 0, sizeof (eckd_count_t));
+				(ct_data + i)->cyl = cyl;
+				(ct_data + i)->head = head;
+				(ct_data + i)->record = i + 1;
+				(ct_data + i)->kl = 0;
+				if (fdata->intensity & 0x08) {
+					// special handling when formatting CDL
+					switch (fdata->start_unit) {
+					case 0:
+						if (i < 3) {
+							(ct_data + i)->kl = 4;
+							
+							    (ct_data + i)->dl =
+							    sizes_trk0[i] - 4;
+						} else
+							(ct_data + i)->dl = fdata->blksize;
+						break;
+					case 1:
+						(ct_data + i)->kl = 44;
+						(ct_data + i)->dl = LABEL_SIZE - 44;
+						break;
+					default:
+						(ct_data + i)->dl = fdata->blksize;
+						break;
+					}
+				} else
+					(ct_data + i)->dl = fdata->blksize;
+				last_ccw->cmd_code = DASD_ECKD_CCW_WRITE_CKD;
+				last_ccw->flags |= CCW_FLAG_CC | CCW_FLAG_SLI;
+				last_ccw->count = 8;
+				if (dasd_set_normalized_cda (last_ccw,
+                                                             __pa (ct_data + i), fcp, device)) {
+                                goto clear_fcp;
+                                }
+				last_ccw++;
+			}
 		}
 		(last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
 		fcp->device = device;
 		fcp->status = CQR_STATUS_FILLED;
 	}
+        goto out;
+ clear_fcp:
+        dasd_free_request (fcp, device);
+        fcp=NULL;
+ out:
 	return fcp;
 }
 
@@ -927,7 +930,7 @@
 
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
@@ -946,56 +949,56 @@
 dasd_eckd_erp_action (ccw_req_t * cqr)
 {
 	dasd_device_t *device = (dasd_device_t *) cqr->device;
-        
+
 	switch (device->devinfo.sid_data.cu_type) {
 	case 0x3990:
 	case 0x2105:
 		return dasd_3990_erp_action;
 	case 0x9343:
-                /* Return dasd_9343_erp_action; */
+		/* Return dasd_9343_erp_action; */
 	default:
-		return default_erp_action;
+		return dasd_default_erp_action;
 	}
 }
 
 static dasd_erp_postaction_fn_t
 dasd_eckd_erp_postaction (ccw_req_t * cqr)
 {
-	return default_erp_postaction;
+	return dasd_default_erp_postaction;
 }
 
 
-#ifdef DASD_CDL
 inline unsigned char
-dasd_eckd_cdl_cmd(dasd_device_t *device,int recid,int cmd) {
-    dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-    int byt_per_blk = device->sizes.bp_block;
-    int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
-    switch (cmd) {
-    case READ:
-        if (recid < 3) 
-            return DASD_ECKD_CCW_READ_KD_MT;
-        if (recid < blk_per_trk)
-            return DASD_ECKD_CCW_READ_MT;
-        if (recid < 2*blk_per_trk)
-            return DASD_ECKD_CCW_READ_KD_MT;
-        return DASD_ECKD_CCW_READ_MT;
-        break;
-    case WRITE:
-        if (recid < 3)
-            return DASD_ECKD_CCW_WRITE_KD_MT;
-        if (recid < blk_per_trk)
-            return DASD_ECKD_CCW_WRITE_MT;
-        if (recid < 2*blk_per_trk)
-            return DASD_ECKD_CCW_WRITE_KD_MT;
-        return DASD_ECKD_CCW_WRITE_MT;
-        break;
-    default:
-        BUG();
-    }
-    return 0; // never executed
+dasd_eckd_cdl_cmd (dasd_device_t * device, int recid, int cmd)
+{
+	dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
+	int byt_per_blk = device->sizes.bp_block;
+	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+	switch (cmd) {
+	case READ:
+		if (recid < 3)
+			return DASD_ECKD_CCW_READ_KD_MT;
+		if (recid < blk_per_trk)
+			return DASD_ECKD_CCW_READ_MT;
+		if (recid < 2 * blk_per_trk)
+			return DASD_ECKD_CCW_READ_KD_MT;
+		return DASD_ECKD_CCW_READ_MT;
+		break;
+	case WRITE:
+		if (recid < 3)
+			return DASD_ECKD_CCW_WRITE_KD_MT;
+		if (recid < blk_per_trk)
+			return DASD_ECKD_CCW_WRITE_MT;
+		if (recid < 2 * blk_per_trk)
+			return DASD_ECKD_CCW_WRITE_KD_MT;
+		return DASD_ECKD_CCW_WRITE_MT;
+		break;
+	default:
+		BUG ();
+	}
+	return 0;		// never executed
 }
-#endif
+
 
 static ccw_req_t *
 dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
@@ -1014,11 +1017,9 @@
 	int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
 	int btrk = (req->sector >> shift) / blk_per_trk;
 	int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
-#ifdef DASD_CDL
-        int recid = req->sector >> shift;
-        int locate4k_set=0;
-        int nlocs=0;
-#endif
+	int recid = req->sector >> shift;
+	int locate4k_set = 0;
+	int nlocs = 0;
 
 	if (req->cmd == READ) {
 		rw_cmd = DASD_ECKD_CCW_READ_MT;
@@ -1032,142 +1033,78 @@
 	/* count bhs to prevent errors, when bh smaller than block */
 	bhct = 0;
 	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
+		if (bh->b_size < byt_per_blk)
+                        BUG();
+                bhct+= bh->b_size >> (device->sizes.s2b_shift+9);
+	}
+	if (btrk < 2 && private->uses_cdl) {
+		if (etrk < 2)
+                        nlocs = bhct;
+                else
+                        nlocs = 2 * blk_per_trk - recid;
 	}
-#ifndef DASD_CDL
-	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
-				    2 + bhct + 1,
-				    sizeof (DE_eckd_data_t) +
-				    sizeof (LO_eckd_data_t));
-#else
-        if (btrk<2 && private->uses_cdl) {
-            nlocs+= 2*blk_per_trk-recid;
-            if (etrk<2)
-                nlocs-=2*blk_per_trk-((req->sector + req->nr_sectors - 1) >> shift);
-        }
-        rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
+	rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 
                                     2 + nlocs + bhct + 1,
-                                    sizeof (DE_eckd_data_t) +
-                                    (1+nlocs)*sizeof (LO_eckd_data_t));
-#endif
+                                    sizeof (DE_eckd_data_t) + (1 +
+                                                               nlocs) *
+                                    sizeof (LO_eckd_data_t),
+                                    device);
 	if (!rw_cp) {
 		return NULL;
 	}
 	DE_data = rw_cp->data;
 	LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
 	ccw = rw_cp->cpaddr;
-	define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device);
-	ccw->flags |= CCW_FLAG_CC;
-#ifndef DASD_CDL
-	ccw++;
-        locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
-                       req->nr_sectors >> shift, rw_cmd, device, device->sizes.bp_block);
+	if (define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device, rw_cp)) {
+                goto clear_rw_cp;
+        }
 	ccw->flags |= CCW_FLAG_CC;
-#endif
 	for (bh = req->bh; bh != NULL;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-#ifdef DASD_CDL
-                                if (!locate4k_set) {
-                                    // we need to chain a locate record before our rw-ccw
-                                    ccw++;
-                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        if (!locate4k_set) {
+                                // we need to chain a locate record before our rw-ccw
+                                ccw++;
+                                if ((recid / blk_per_trk) < 2
+                                    && private->uses_cdl) {
                                         /* Do a locate record for our special blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
-                                                       recid % blk_per_trk + 1, 1, 
-                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
-                                                       device, 
-                                                       dasd_eckd_cdl_reclen(device,recid));
-                                    } else {
-                                        // Do a locate record for standard blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
+                                        int cmd = dasd_eckd_cdl_cmd (device,recid, req->cmd);
+                                        if (locate_record (ccw, 
+                                                       LO_data++,
+                                                       recid / blk_per_trk, 
                                                        recid % blk_per_trk + 1, 
-                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
-                                                       rw_cmd,device, device->sizes.bp_block);
-                                        locate4k_set=1;
-                                    }                                        
-                                    ccw->flags |= CCW_FLAG_CC;
-                                }
-#endif
-				ccw++;
-#ifndef DASD_CDL
-				ccw->flags |= CCW_FLAG_CC;
-				ccw->cmd_code= rw_cmd;
-				ccw->count = bh->b_size;
-#else
-                                ccw->flags |= CCW_FLAG_CC;
-                                ccw->cmd_code=locate4k_set?rw_cmd:
-                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
-                                ccw->count =locate4k_set?bh->b_size:
-                                    dasd_eckd_cdl_reclen(device,recid);
-#endif
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-#ifdef DASD_CDL
-                                recid++;
-#endif
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-#ifdef DASD_CDL
-                                if (!locate4k_set) {
-                                    // we need to chain a locate record before our rw-ccw
-                                    ccw++;
-                                    if ((recid/blk_per_trk)<2 && private->uses_cdl) {
-                                        /* Do a locate record for our special blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk, 
-                                                       recid % blk_per_trk + 1, 1, 
-                                                       dasd_eckd_cdl_cmd(device,recid,req->cmd), 
-                                                       device, 
-                                                       dasd_eckd_cdl_reclen(device,recid));
-                                    } else {
+                                                       1, cmd, device,
+                                                           dasd_eckd_cdl_reclen(device, recid), rw_cp)) {
+                                                goto clear_rw_cp;
+                                        }
+                                } else {
                                         // Do a locate record for standard blocks */
-                                        locate_record (ccw, LO_data++, recid/blk_per_trk,
-                                                       recid % blk_per_trk + 1, 
-                                                       (((req->sector + req->nr_sectors) >> shift)-recid),
-                                                       rw_cmd,device, device->sizes.bp_block);
-                                        locate4k_set=1;
-                                    }                                        
-                                    ccw->flags |= CCW_FLAG_CC;
+                                        if (locate_record (ccw, 
+                                                       LO_data++,
+                                                       recid /blk_per_trk,
+                                                       recid %blk_per_trk + 1,
+                                                       (((req->sector +
+                                                          req->nr_sectors) >>
+                                                         shift) - recid), 
+                                                       rw_cmd, device,
+                                                           device->sizes.bp_block, rw_cp)) {
+                                                goto clear_rw_cp;
+                                        }
+                                        locate4k_set = 1;
                                 }
-#endif
-				ccw++;
-#ifndef DASD_CDL
-				ccw->flags |= CCW_FLAG_DC;
-				ccw->cmd_code= rw_cmd;
-				ccw->count = bh->b_size;
-#else
-                                ccw->flags |= locate4k_set?CCW_FLAG_DC:CCW_FLAG_CC;
-                                ccw->cmd_code=locate4k_set?rw_cmd:
-                                    dasd_eckd_cdl_cmd(device,recid,req->cmd);
-                                ccw->count =locate4k_set?bh->b_size:
-                                    dasd_eckd_cdl_reclen(device,recid);
-#endif
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-#ifdef DASD_CDL
-                                recid++;
-#endif
-			}
-			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill small request %ld vs. %d (%ld sects)\n",
-					    size,
-					    byt_per_blk,
-					    req->nr_sectors);
-
-				ccw_free_request (rw_cp);
-				return NULL;
-			}
-			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC;
-		}
+                                ccw->flags |= CCW_FLAG_CC;
+                        }
+                        ccw++;
+                        ccw->flags |= CCW_FLAG_CC;
+                        ccw->cmd_code = locate4k_set ? rw_cmd :
+                                dasd_eckd_cdl_cmd (device, recid, req->cmd);
+                        ccw->count = locate4k_set ? byt_per_blk :
+                                dasd_eckd_cdl_reclen (device, recid);
+                        if (dasd_set_normalized_cda (ccw, __pa (bh->b_data+size), rw_cp, device)) {
+                                goto clear_rw_cp;
+                        }
+                        recid++;
+                }
+                bh = bh->b_reqnext;
 	}
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
 	rw_cp->device = device;
@@ -1176,11 +1113,15 @@
 	rw_cp->lpm = LPM_ANYPATH;
 	rw_cp->retries = 2;
 	asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
-	check_then_set (&rw_cp->status,
-				       CQR_STATUS_EMPTY,
-				       CQR_STATUS_FILLED);
+	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+        goto out;
+ clear_rw_cp:
+        dasd_free_request (rw_cp, device);
+        rw_cp=NULL;
+ out:
 	return rw_cp;
 }
+
 #if 0
 int
 dasd_eckd_cleanup_request (ccw_req_t * cqr)
@@ -1197,7 +1138,8 @@
 				ccw->flags |= CCW_FLAG_CC;
 				ccw->cmd_code = rw_cmd;
 				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
+				set_normalized_cda (ccw,
+						    __pa (bh->b_data + size));
 			}
 			bh = bh->b_reqnext;
 		} else {	/* group N bhs to fit into byt_per_blk */
@@ -1218,7 +1160,8 @@
 ccw_req_t *
 dasd_eckd_reserve (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0);
+	ccw_req_t *cqr =
+	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
 	if (cqr == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No memory to allocate initialization request\n");
@@ -1234,7 +1177,8 @@
 ccw_req_t *
 dasd_eckd_release (struct dasd_device_t * device)
 {
-	ccw_req_t *cqr = ccw_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0);
+	ccw_req_t *cqr =
+	    dasd_alloc_request (dasd_eckd_discipline.name, 1 + 1, 0, device);
 	if (cqr == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
 			"No memory to allocate initialization request\n");
@@ -1254,67 +1198,91 @@
 	ccw1_t *cp;
 
 	cp = cqr->cpaddr;
-        do {
+	do {
 		if (cp->cmd_code == cmd)
 			return cp;
 		if (cp->cmd_code == CCW_CMD_TIC) {
-			cp = (ccw1_t *)cp->cda;
-                        continue;
-		} 
-                if ( cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC) ) {
-                        cp ++;
-                        continue;
-		}
-                break;
-	} while ( 1 );
-        return NULL;
+			cp = (ccw1_t *) (long) cp->cda;
+			continue;
+		}
+		if (cp->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) {
+			cp++;
+			continue;
+		}
+		break;
+	} while (1);
+	return NULL;
 }
 
-ccw_req_t *
-dasd_eckd_merge_cp ( dasd_device_t *device )
+static ccw_req_t *
+dasd_eckd_merge_cp (dasd_device_t * device)
 {
-        return NULL;
+	return NULL;
 }
 
-static char *
-dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
+static int
+dasd_eckd_fill_info (dasd_device_t * device, dasd_information_t * info)
 {
+	int rc = 0;
+	info->label_block = 2;
+	if (((dasd_eckd_private_t *) device->private)->uses_cdl)
+		info->FBA_layout = 0;
+	else
+		info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_eckd_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_eckd_private_t *) device->private)->rdc_data,
+		sizeof (dasd_eckd_characteristics_t));
+	info->confdata_size = sizeof (dasd_eckd_confdata_t);
+	memcpy (info->configuration_data,
+		&((dasd_eckd_private_t *) device->private)->conf_data,
+		sizeof (dasd_eckd_confdata_t));
+	return rc;
+}
+
+static char*
+dasd_eckd_dump_sense (struct dasd_device_t *device, 
+                      ccw_req_t            *req)
+{
+
 	char *page = (char *) get_free_page (GFP_ATOMIC);
 	devstat_t *stat = &device->dev_status;
 	char *sense = stat->ii.sense.data;
 	int len, sl, sct;
 
 	if (page == NULL) {
+                printk (KERN_ERR PRINTK_HEADER
+                        "No memory to dump sense data\n");
 		return NULL;
 	}
-	len = sprintf (page, KERN_WARNING PRINTK_HEADER
+
+	len = sprintf (page, KERN_ERR PRINTK_HEADER
 		       "device %04X on irq %d: I/O status report:\n",
 		       device->devinfo.devno, device->devinfo.irq);
-	len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
+	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
 			"in req: %p CS: 0x%02X DS: 0x%02X\n",
 			req, stat->cstat, stat->dstat);
-	len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-			"Failing CCW: %p\n", (void *) stat->cpa);
-        {
-            ccw1_t *act = req -> cpaddr;
-            int i = req -> cplength;
-            do {
-#ifdef ERP_DEBUB
-                printk ( KERN_INFO "CCW %p: %08X %08X\n", 
-                         act,((int*)act)[0],((int*)act)[1]);
-                printk ( KERN_INFO "DAT: %08X %08X %08X %08X\n", 
-                         ((int*)act->cda)[0],((int*)act->cda)[1],
-                         ((int*)act->cda)[2],((int*)act->cda)[3]);
-#endif /* ERP_DEBUG */
-                act ++;
-            } while ( --i );
-        }
+	len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+			"Failing CCW: %p\n", (void *) (long) stat->cpa);
+	{
+		ccw1_t *act = req->cpaddr;
+		int i = req->cplength;
+		do {
+#ifdef ERP_DEBUG
+			printk (KERN_ERR "CCW %p: %08X %08X\n",
+				act, ((int *) act)[0], ((int *) act)[1]);
+			printk (KERN_ERR "DAT: %08X %08X %08X %08X\n",
+				((int *) act->cda)[0], ((int *) act->cda)[1],
+				((int *) act->cda)[2], ((int *) act->cda)[3]);
+#endif				/* ERP_DEBUG */
+			act++;
+		} while (--i);
+	}
 	if (stat->flag & DEVSTAT_FLAG_SENSE_AVAIL) {
 		for (sl = 0; sl < 4; sl++) {
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
 					"Sense(hex) %2d-%2d:",
-					(8 * sl),
-					((8 * sl) + 7));
+					(8 * sl), ((8 * sl) + 7));
 
 			for (sct = 0; sct < 8; sct++) {
 				len += sprintf (page + len, " %02x",
@@ -1325,22 +1293,29 @@
 
 		if (sense[27] & DASD_SENSE_BIT_0) {
 			/* 24 Byte Sense Data */
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-				     "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+					"24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
 					sense[7] >> 4, sense[7] & 0x0f,
 					sense[1] & 0x10 ? "" : "no");
 		} else {
 			/* 32 Byte Sense Data */
-			len += sprintf (page + len, KERN_WARNING PRINTK_HEADER
-				   "32 Byte: Format: %x Exception class %x\n",
+			len += sprintf (page + len, KERN_ERR PRINTK_HEADER
+					"32 Byte: Format: %x Exception class %x\n",
 					sense[6] & 0x0f, sense[22] >> 4);
 		}
 	}
-	return page;
+
+        printk ("Sense data:\n%s", 
+                page);
+
+        free_page ((unsigned long) page);
+        
+	return NULL;
 }
 
-dasd_discipline_t dasd_eckd_discipline =
-{
+
+dasd_discipline_t dasd_eckd_discipline = {
+        owner: THIS_MODULE,
 	name:"ECKD",
 	ebcname:"ECKD",
 	max_blocks:255,
@@ -1350,6 +1325,7 @@
 	do_analysis:dasd_eckd_do_analysis,
 	fill_geometry:dasd_eckd_fill_geometry,
 	start_IO:dasd_start_IO,
+	term_IO:dasd_term_IO,
 	format_device:dasd_eckd_format_device,
 	examine_error:dasd_eckd_examine_error,
 	erp_action:dasd_eckd_erp_action,
@@ -1359,7 +1335,8 @@
 	int_handler:dasd_int_handler,
 	reserve:dasd_eckd_reserve,
 	release:dasd_eckd_release,
-	merge_cp:dasd_eckd_merge_cp
+	merge_cp:dasd_eckd_merge_cp,
+	fill_info:dasd_eckd_fill_info,
 };
 
 int
@@ -1369,40 +1346,62 @@
 	printk (KERN_INFO PRINTK_HEADER
 		"%s discipline initializing\n", dasd_eckd_discipline.name);
 	ASCEBC (dasd_eckd_discipline.ebcname, 4);
-	dasd_discipline_enq (&dasd_eckd_discipline);
+	dasd_discipline_add (&dasd_eckd_discipline);
 #ifdef CONFIG_DASD_DYNAMIC
-        {
-	int i;
-	for (i = 0; i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t); i++) {
-                printk (KERN_INFO PRINTK_HEADER
-                        "We are interested in: CU %04X/%02x\n",
-			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode);
-		s390_device_register (&dasd_eckd_known_devices[i]);
-        }
-        }
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We are interested in: CU %04X/%02x\n",
+				dasd_eckd_known_devices[i].ci.hc.ctype,
+				dasd_eckd_known_devices[i].ci.hc.cmode);
+			s390_device_register (&dasd_eckd_known_devices[i]);
+		}
+	}
 #endif				/* CONFIG_DASD_DYNAMIC */
 	return rc;
 }
 
 void
-dasd_eckd_cleanup( void ) {
-        printk ( KERN_INFO PRINTK_HEADER
-                 "%s discipline cleaning up\n", dasd_eckd_discipline.name);
+dasd_eckd_cleanup (void)
+{
+	printk (KERN_INFO PRINTK_HEADER
+		"%s discipline cleaning up\n", dasd_eckd_discipline.name);
 #ifdef CONFIG_DASD_DYNAMIC
-        {
-	int i;
-        for ( i=0; i<sizeof(dasd_eckd_known_devices)/sizeof(devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We were interested in: CU %04X/%02x\n",
-			dasd_eckd_known_devices[i].ci.hc.ctype,
-			dasd_eckd_known_devices[i].ci.hc.cmode);
-		s390_device_unregister(&dasd_eckd_known_devices[i]);
-	}
-        } 
-#endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_deq(&dasd_eckd_discipline);
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_eckd_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We were interested in: CU %04X/%02x\n",
+				dasd_eckd_known_devices[i].ci.hc.ctype,
+				dasd_eckd_known_devices[i].ci.hc.cmode);
+			s390_device_unregister (&dasd_eckd_known_devices[i]);
+		}
+	}
+#endif				/* CONFIG_DASD_DYNAMIC */
+	dasd_discipline_del (&dasd_eckd_discipline);
 }
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_eckd_init ();
+	return rc;
+}
+
+void
+cleanup_module (void)
+{
+	dasd_eckd_cleanup ();
+	return;
+}
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_eckd.h linux/drivers/s390/block/dasd_eckd.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_eckd.h	Wed Apr 11 19:02:28 2001
+++ linux/drivers/s390/block/dasd_eckd.h	Mon Dec  3 22:58:52 2001
@@ -10,6 +10,7 @@
 #define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
 #define DASD_ECKD_CCW_WRITE_KD 0x0d
 #define DASD_ECKD_CCW_READ_KD 0x0e
+#define DASD_ECKD_CCW_ERASE 0x11
 #define DASD_ECKD_CCW_READ_COUNT 0x12
 #define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
 #define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
@@ -26,52 +27,51 @@
 #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
 #define DASD_ECKD_CCW_RESERVE 0xB4
 
-
-typedef 
-struct eckd_count_t {
+typedef
+    struct eckd_count_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
 	__u8 kl;
 	__u16 dl;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-eckd_count_t;
+    eckd_count_t;
 
 typedef
-struct ch_t {
+    struct ch_t {
 	__u16 cyl;
 	__u16 head;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-ch_t;
+    ch_t;
 
 typedef
-struct chs_t {
+    struct chs_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-chs_t;
+    chs_t;
 
 typedef
-struct chr_t {
+    struct chr_t {
 	__u16 cyl;
 	__u16 head;
 	__u8 record;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-chr_t;
+    chr_t;
 
 typedef
-struct geom_t {
+    struct geom_t {
 	__u16 cyl;
 	__u16 head;
 	__u32 sector;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-geom_t;
+    geom_t;
 
 typedef struct eckd_home_t {
 	__u8 skip_control[14];
@@ -82,12 +82,12 @@
 	__u8 reserved;
 	__u8 key_length;
 	__u8 reserved2[2];
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-eckd_home_t;
+    eckd_home_t;
 
 typedef
-struct DE_eckd_data_t {
+    struct DE_eckd_data_t {
 	struct {
 		unsigned char perm:2;	/* Permissions on this extent */
 		unsigned char reserved:1;
@@ -108,12 +108,12 @@
 	__u8 reserved;
 	ch_t beg_ext;
 	ch_t end_ext;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-DE_eckd_data_t;
+    DE_eckd_data_t;
 
 typedef
-struct LO_eckd_data_t {
+    struct LO_eckd_data_t {
 	struct {
 		unsigned char orientation:2;
 		unsigned char operation:6;
@@ -129,12 +129,12 @@
 	chr_t search_arg;
 	__u8 sector;
 	__u16 length;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-LO_eckd_data_t;
+    LO_eckd_data_t;
 
 typedef
-struct dasd_eckd_characteristics_t {
+    struct dasd_eckd_characteristics_t {
 	__u16 cu_type;
 	struct {
 		unsigned char support:2;
@@ -204,9 +204,9 @@
 	__u8 factor8;
 	__u8 reserved2[3];
 	__u8 reserved3[10];
-} __attribute__             ((packed)) 
+} __attribute__ ((packed))
 
-dasd_eckd_characteristics_t;
+    dasd_eckd_characteristics_t;
 
 typedef struct dasd_eckd_confdata_t {
 	struct {
@@ -323,10 +323,10 @@
 		__u8 log_dev_address;
 		unsigned char reserved2[12];
 	} __attribute__ ((packed)) neq;
-} __attribute__      ((packed)) 
+} __attribute__ ((packed))
 
-dasd_eckd_confdata_t;
+    dasd_eckd_confdata_t;
 
 int dasd_eckd_init (void);
-void dasd_eckd_cleanup(void);
+void dasd_eckd_cleanup (void);
 #endif				/* DASD_ECKD_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_fba.c linux/drivers/s390/block/dasd_fba.c
--- linux-2.4.8-pre4/drivers/s390/block/dasd_fba.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/s390/block/dasd_fba.c	Mon Dec  3 22:58:52 2001
@@ -15,16 +15,18 @@
 #include <linux/slab.h>
 #include <linux/hdreg.h>	/* HDIO_GETGEO                      */
 #include <linux/blk.h>
+
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
-#include <asm/dasd.h>
-
 #include <asm/ebcdic.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/s390dyn.h>
 
+#include "dasd_int.h"
 #include "dasd_fba.h"
+#include "dasd_3370_erp.h"
+#include "dasd_9336_erp.h"
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
@@ -39,44 +41,38 @@
 dasd_discipline_t dasd_fba_discipline;
 
 typedef struct
-dasd_fba_private_t {
+    dasd_fba_private_t {
 	dasd_fba_characteristics_t rdc_data;
 } dasd_fba_private_t;
 
 #ifdef CONFIG_DASD_DYNAMIC
 static
-devreg_t dasd_fba_known_devices[] =
-{
+devreg_t dasd_fba_known_devices[] = {
 	{
-		ci:
-		{hc:
-		 {ctype:0x6310,
-                  dtype:0x9336}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	},
+	      ci: { hc: {ctype:0x6310, dtype:0x9336}},
+	      flag:(DEVREG_MATCH_CU_TYPE |
+                    DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+              oper_func:dasd_oper_handler
+        },
 	{
-		ci:
-		{hc:
-		 {ctype:0x3880,
-                  dtype:0x3370}},
-		flag:(DEVREG_MATCH_CU_TYPE |
-                      DEVREG_MATCH_DEV_TYPE| 
-                      DEVREG_TYPE_DEVCHARS),
-		oper_func:dasd_oper_handler
-	}
+                ci: { hc: {ctype:0x3880, dtype:0x3370}},
+                flag:(DEVREG_MATCH_CU_TYPE |
+                      DEVREG_MATCH_DEV_TYPE | DEVREG_TYPE_DEVCHARS),
+                oper_func:dasd_oper_handler
+        }
 };
 #endif
-static inline void
+static inline int
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
-	       int blksize, int beg, int nr)
+	       int blksize, int beg, int nr, ccw_req_t* cqr,
+               dasd_device_t* device)
 {
+        int rc=0;
 	memset (DE_data, 0, sizeof (DE_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
 	ccw->count = 16;
-	set_normalized_cda (ccw, __pa (DE_data));
+	if (rc=dasd_set_normalized_cda (ccw, __pa (DE_data), cqr, device))
+                return rc;
 	if (rw == WRITE)
 		(DE_data->mask).perm = 0x0;
 	else if (rw == READ)
@@ -86,16 +82,17 @@
 	DE_data->blk_size = blksize;
 	DE_data->ext_loc = beg;
 	DE_data->ext_end = nr - 1;
+        return rc;
 }
 
 static inline void
 locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
-	       int block_ct)
+	       int block_ct, ccw_req_t* cqr, dasd_device_t* device)
 {
 	memset (LO_data, 0, sizeof (LO_fba_data_t));
 	ccw->cmd_code = DASD_FBA_CCW_LOCATE;
 	ccw->count = 8;
-	set_normalized_cda (ccw, __pa (LO_data));
+	dasd_set_normalized_cda (ccw, __pa (LO_data), cqr, device);
 	if (rw == WRITE)
 		LO_data->operation.cmd = 0x5;
 	else if (rw == READ)
@@ -109,9 +106,9 @@
 static int
 dasd_fba_id_check (s390_dev_info_t * info)
 {
-        if (info->sid_data.cu_type == 0x3880)
-                if (info->sid_data.dev_type == 0x3370)
-                        return 0;
+	if (info->sid_data.cu_type == 0x3880)
+		if (info->sid_data.dev_type == 0x3370)
+			return 0;
 	if (info->sid_data.cu_type == 0x6310)
 		if (info->sid_data.dev_type == 0x9336)
 			return 0;
@@ -127,37 +124,43 @@
 
 	if (device == NULL) {
 		printk (KERN_WARNING PRINTK_HEADER
-		   "Null device pointer passed to characteristics checker\n");
-		return -ENODEV;
+			"Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
 	}
-        if ( device->private != NULL ) {
-                kfree(device->private);
-        }
-        device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL);
+	device->private = kmalloc (sizeof (dasd_fba_private_t), GFP_KERNEL);
 	if (device->private == NULL) {
-                printk (KERN_WARNING PRINTK_HEADER
-                        "memory allocation failed for private data\n");
-                return -ENOMEM;
+		printk (KERN_WARNING PRINTK_HEADER
+			"memory allocation failed for private data\n");
+                rc = -ENOMEM;
+                goto fail;
 	}
 	private = (dasd_fba_private_t *) device->private;
 	rdc_data = (void *) &(private->rdc_data);
 	rc = read_dev_chars (device->devinfo.irq, &rdc_data, 32);
 	if (rc) {
-            printk (KERN_WARNING PRINTK_HEADER
-                    "Read device characteristics returned error %d\n", rc);
-            kfree(private);
-            device->private=NULL;
-            return rc;
+		printk (KERN_WARNING PRINTK_HEADER
+			"Read device characteristics returned error %d\n", rc);
+                goto fail;
 	}
 	printk (KERN_INFO PRINTK_HEADER
 		"%04X on sch %d: %04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)\n",
 		device->devinfo.devno, device->devinfo.irq,
-                device->devinfo.sid_data.dev_type, device->devinfo.sid_data.dev_model,
-                device->devinfo.sid_data.cu_type, device->devinfo.sid_data.cu_model,
+		device->devinfo.sid_data.dev_type,
+		device->devinfo.sid_data.dev_model,
+		device->devinfo.sid_data.cu_type,
+		device->devinfo.sid_data.cu_model,
 		(private->rdc_data.blk_bdsa *
 		 (private->rdc_data.blk_size >> 9)) >> 11,
 		private->rdc_data.blk_size);
-	return 0;
+        goto out;
+ fail:
+        if ( rc ) {
+                kfree(device->private);
+                device->private = NULL;
+        }
+        
+ out:
+	return rc;
 }
 
 static int
@@ -187,7 +190,7 @@
 		device->sizes.s2b_shift++;
 
 	device->sizes.blocks = (private->rdc_data.blk_bdsa);
-        device->sizes.pt_block = 1;
+	device->sizes.pt_block = 1;
 
 	return rc;
 }
@@ -221,7 +224,7 @@
 	dasd_device_t *device = (dasd_device_t *) cqr->device;
 	if (stat->cstat == 0x00 &&
 	    stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-		return dasd_era_none;
+		    return dasd_era_none;
 
 	switch (device->devinfo.sid_data.dev_model) {
 	case 0x3370:
@@ -236,17 +239,16 @@
 static dasd_erp_action_fn_t
 dasd_fba_erp_action (ccw_req_t * cqr)
 {
-	return default_erp_action;
+	return dasd_default_erp_action;
 }
 
 static dasd_erp_postaction_fn_t
 dasd_fba_erp_postaction (ccw_req_t * cqr)
 {
-	if (cqr->function == default_erp_action)
-		return default_erp_postaction;
+	if (cqr->function == dasd_default_erp_action)
+		return dasd_default_erp_postaction;
 	printk (KERN_WARNING PRINTK_HEADER
-		"unknown ERP action %p\n",
-		cqr->function);
+		"unknown ERP action %p\n", cqr->function);
 	return NULL;
 }
 
@@ -255,7 +257,7 @@
 {
 	ccw_req_t *rw_cp = NULL;
 	int rw_cmd;
-	int bhct, i;
+	int bhct, i = 0;
 	long size;
 	ccw1_t *ccw;
 	DE_fba_data_t *DE_data;
@@ -263,7 +265,7 @@
 	struct buffer_head *bh;
 	dasd_fba_private_t *private = (dasd_fba_private_t *) device->private;
 	int byt_per_blk = device->sizes.bp_block;
-
+        
 	if (req->cmd == READ) {
 		rw_cmd = DASD_FBA_CCW_READ;
 	} else if (req->cmd == WRITE) {
@@ -273,20 +275,30 @@
 		return NULL;
 	}
 	/* Build the request */
-	/* count bhs to prevent errors, when bh smaller than block */
+	/* count hs to prevent errors, when bh smaller than block */
+        bh = req -> bh;
 	bhct = 0;
-	for (bh = req->bh; bh; bh = bh->b_reqnext) {
-		if (bh->b_size > byt_per_blk)
-			for (size = 0; size < bh->b_size; size += byt_per_blk)
-				bhct++;
-		else
-			bhct++;
-	}
-
-	rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
-				    1 + 2*bhct,
-				    sizeof (DE_fba_data_t) +
-				    bhct*sizeof (LO_fba_data_t));
+        while ( bh != NULL ) {
+                if (bh->b_size < byt_per_blk) {
+                        BUG();
+                }
+                bhct += bh->b_size >> (device->sizes.s2b_shift+9);
+                bh = bh->b_reqnext;
+        }
+        
+        if (private->rdc_data.mode.bits.data_chain) {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            2 + bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            sizeof (LO_fba_data_t),
+                                            device);
+        } else {
+                rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                            1 + 2 * bhct,
+                                            sizeof (DE_fba_data_t) +
+                                            bhct * sizeof (LO_fba_data_t),
+                                            device);
+        }
 	if (!rw_cp) {
 		return NULL;
 	}
@@ -294,64 +306,77 @@
 	LO_data = rw_cp->data + sizeof (DE_fba_data_t);
 	ccw = rw_cp->cpaddr;
 
-	define_extent (ccw, DE_data, req->cmd, byt_per_blk,
-		       req->sector, req->nr_sectors);
+	if (define_extent (ccw, DE_data, req->cmd, byt_per_blk,
+                           req->sector, req->nr_sectors, rw_cp, device)) {
+                goto clear_rw_cp;
+        }
 	ccw->flags |= CCW_FLAG_CC;
-
-	for (i = 0, bh = req->bh; bh;) {
-		if (bh->b_size > byt_per_blk) {
-			for (size = 0; size < bh->b_size; size += byt_per_blk) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
-                                ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-                                ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-				ccw->cmd_code = rw_cmd;
-				ccw->count = byt_per_blk;
-				set_normalized_cda (ccw, __pa (bh->b_data + size));
-                                i++;
-                                LO_data++;
-			}
-			bh = bh->b_reqnext;
-		} else {	/* group N bhs to fit into byt_per_blk */
-			for (size = 0; bh != NULL && size < byt_per_blk;) {
-                                ccw++;
-                                locate_record (ccw, LO_data, req->cmd, i, 1);
+        ccw ++;
+        locate_record (ccw, LO_data, req->cmd, 0, 
+                       private->rdc_data.mode.bits.data_chain ? bhct : 1, rw_cp, device);
+        if (ccw->cda == 0) {
+                goto clear_rw_cp;
+        }
+        ccw->flags |= CCW_FLAG_CC;
+        
+        bh = req -> bh;
+        i = 0;
+        while ( bh != NULL ) {
+                for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                        ccw ++;
+                        ccw->cmd_code = rw_cmd;
+                        ccw->count = byt_per_blk;
+                        if (dasd_set_normalized_cda (ccw,__pa (bh->b_data + size), rw_cp, device)) {
+                                goto clear_rw_cp;
+                        }
+                        if (private->rdc_data.mode.bits.data_chain) {
+                                ccw->flags |= CCW_FLAG_DC;
+                        } else {
                                 ccw->flags |= CCW_FLAG_CC;
-				ccw++;
-				if (private->rdc_data.mode.bits.data_chain) {
-					ccw->flags |= CCW_FLAG_DC|CCW_FLAG_SLI;
-				} else {
-					PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-					ccw_free_request (rw_cp);
-					return NULL;
-				}
-				ccw->cmd_code = rw_cmd;
-				ccw->count = bh->b_size;
-				set_normalized_cda (ccw, __pa (bh->b_data));
-				size += bh->b_size;
-				bh = bh->b_reqnext;
-                                i++;
-                                LO_data++;
-			}
-			ccw->flags &= ~CCW_FLAG_DC;
-			ccw->flags |= CCW_FLAG_CC|CCW_FLAG_SLI;
-			if (size != byt_per_blk) {
-				PRINT_WARN ("Cannot fulfill request smaller than block\n");
-				ccw_free_request (rw_cp);
-				return NULL;
-			}
-		}
-	}
+                        }
+                }
+                bh = bh->b_reqnext;
+                if ( bh != NULL &&
+                     !(private->rdc_data.mode.bits.data_chain)) {
+                        ccw++;
+                        i++;
+                        LO_data++;
+                        locate_record (ccw, LO_data, req->cmd, i, 1, rw_cp, device);
+                        if (ccw->cda == 0) {
+                                goto clear_rw_cp;
+                        }
+                        ccw->flags |= CCW_FLAG_CC;
+                }
+        }
 	ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
 
 	rw_cp->device = device;
 	rw_cp->expires = 5 * TOD_MIN;		/* 5 minutes */
 	rw_cp->req = req;
 	check_then_set (&rw_cp->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+        goto out;
+ clear_rw_cp:
+        dasd_free_request (rw_cp, device);
+        rw_cp = NULL;
+ out:
 	return rw_cp;
 }
 
+static int
+dasd_fba_fill_info (dasd_device_t * device, dasd_information_t * info)
+{
+	int rc = 0;
+	info->label_block = 1;
+	info->FBA_layout = 1;
+	info->characteristics_size = sizeof (dasd_fba_characteristics_t);
+	memcpy (info->characteristics,
+		&((dasd_fba_private_t *) device->private)->rdc_data,
+		sizeof (dasd_fba_characteristics_t));
+	info->confdata_size = 0;
+	return rc;
+}
+
+
 static char *
 dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 {
@@ -367,25 +392,26 @@
 	return page;
 }
 
-dasd_discipline_t dasd_fba_discipline =
-{
+dasd_discipline_t dasd_fba_discipline = {
+        owner: THIS_MODULE,
 	name:"FBA ",
 	ebcname:"FBA ",
-	max_blocks:((PAGE_SIZE >> 1)/sizeof(ccw1_t)-1),
+	max_blocks:((PAGE_SIZE >> 1) / sizeof (ccw1_t) - 1),
 	id_check:dasd_fba_id_check,
 	check_characteristics:dasd_fba_check_characteristics,
 	do_analysis:dasd_fba_do_analysis,
 	fill_geometry:dasd_fba_fill_geometry,
 	start_IO:dasd_start_IO,
+	term_IO:dasd_term_IO,
 	examine_error:dasd_fba_examine_error,
 	erp_action:dasd_fba_erp_action,
 	erp_postaction:dasd_fba_erp_postaction,
 	build_cp_from_req:dasd_fba_build_cp_from_req,
 	dump_sense:dasd_fba_dump_sense,
-	int_handler:dasd_int_handler
+	int_handler:dasd_int_handler,
+	fill_info:dasd_fba_fill_info,
 };
 
-
 int
 dasd_fba_init (void)
 {
@@ -393,18 +419,22 @@
 	printk (KERN_INFO PRINTK_HEADER
 		"%s discipline initializing\n", dasd_fba_discipline.name);
 	ASCEBC (dasd_fba_discipline.ebcname, 4);
-	dasd_discipline_enq (&dasd_fba_discipline);
-#ifdef CONFIG_DASD_DYNAMIC 
-        {
-            int i;
-            for (i = 0; i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t); i++) {
-		printk (KERN_INFO PRINTK_HEADER
-			"We are interested in: CU %04X/%02x\n",
-			dasd_fba_known_devices[i].ci.hc.ctype,
-			dasd_fba_known_devices[i].ci.hc.cmode);
-		s390_device_register (&dasd_fba_known_devices[i]);
-            }
-        }
+	dasd_discipline_add (&dasd_fba_discipline);
+#ifdef CONFIG_DASD_DYNAMIC
+	{
+		int i;
+		for (i = 0;
+		     i < sizeof (dasd_fba_known_devices) / sizeof (devreg_t);
+		     i++) {
+			printk (KERN_INFO PRINTK_HEADER
+				"We are interested in: Dev %04X/%02X @ CU %04X/%02x\n",
+				dasd_fba_known_devices[i].ci.hc.dtype,
+				dasd_fba_known_devices[i].ci.hc.dmode,
+				dasd_fba_known_devices[i].ci.hc.ctype,
+				dasd_fba_known_devices[i].ci.hc.cmode);
+			s390_device_register (&dasd_fba_known_devices[i]);
+		}
+	}
 #endif				/* CONFIG_DASD_DYNAMIC */
         return rc;
 }
@@ -417,16 +447,31 @@
         {
 	int i;
         for ( i=0; i<sizeof(dasd_fba_known_devices)/sizeof(devreg_t); i++) {
-                printk (KERN_INFO PRINTK_HEADER
-                        "We were interested in: CU %04X/%02x\n",
-                        dasd_fba_known_devices[i].ci.hc.ctype,
-                        dasd_fba_known_devices[i].ci.hc.cmode);
                 s390_device_unregister(&dasd_fba_known_devices[i]);
         }
         }
 #endif /* CONFIG_DASD_DYNAMIC */
-        dasd_discipline_deq(&dasd_fba_discipline);
+        dasd_discipline_del(&dasd_fba_discipline);
+}
+
+#ifdef MODULE
+int
+init_module (void)
+{
+	int rc = 0;
+	rc = dasd_fba_init ();
+	return rc;
 }
+
+void
+cleanup_module (void)
+{
+	dasd_fba_cleanup ();
+	return;
+}
+#endif
+
+
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_fba.h linux/drivers/s390/block/dasd_fba.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_fba.h	Tue Feb 13 14:13:44 2001
+++ linux/drivers/s390/block/dasd_fba.h	Mon Dec  3 22:58:52 2001
@@ -3,7 +3,7 @@
 #define DASD_FBA_H
 
 typedef
-struct DE_fba_data_t {
+    struct DE_fba_data_t {
 	struct {
 		unsigned char perm:2;	/* Permissions on this extent */
 		unsigned char zero:2;	/* Must be zero */
@@ -16,12 +16,12 @@
 	__u32 ext_loc;		/* Extent locator */
 	__u32 ext_beg;		/* logical number of block 0 in extent */
 	__u32 ext_end;		/* logocal number of last block in extent */
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-DE_fba_data_t;
+    DE_fba_data_t;
 
 typedef
-struct LO_fba_data_t {
+    struct LO_fba_data_t {
 	struct {
 		unsigned char zero:4;
 		unsigned char cmd:4;
@@ -29,12 +29,12 @@
 	__u8 auxiliary;
 	__u16 blk_ct;
 	__u32 blk_nr;
-} __attribute__ ((packed)) 
+} __attribute__ ((packed))
 
-LO_fba_data_t;
+    LO_fba_data_t;
 
 typedef
-struct dasd_fba_characteristics_t {
+    struct dasd_fba_characteristics_t {
 	union {
 		__u8 c;
 		struct {
@@ -67,10 +67,10 @@
 	__u16 blk_ce;
 	__u32 reserved2;
 	__u16 reserved3;
-} __attribute__            ((packed)) 
+} __attribute__ ((packed))
 
-dasd_fba_characteristics_t;
+    dasd_fba_characteristics_t;
 
 int dasd_fba_init (void);
-void dasd_fba_cleanup(void);
+void dasd_fba_cleanup (void);
 #endif				/* DASD_FBA_H */
diff -urN linux-2.4.8-pre4/drivers/s390/block/dasd_int.h linux/drivers/s390/block/dasd_int.h
--- linux-2.4.8-pre4/drivers/s390/block/dasd_int.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/s390/block/dasd_int.h	Mon Dec  3 22:58:52 2001
@@ -0,0 +1,390 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ *
+ * History of changes (starts July 2000)
+ * 02/01/01 added dynamic registration of ioctls
+ */
+
+#ifndef DASD_INT_H
+#define DASD_INT_H
+
+#define DASD_API_VERSION 0
+
+#include <asm/dasd.h>
+
+#define CONFIG_DASD_DYNAMIC
+
+typedef int(*dasd_ioctl_fn_t) (void *inp, int no, long args);
+int dasd_ioctl_no_register(struct module *, int no, dasd_ioctl_fn_t handler);
+int dasd_ioctl_no_unregister(struct module *, int no, dasd_ioctl_fn_t handler);
+
+#define DASD_NAME "dasd"
+#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+
+#define DASD_STATE_DEL   -1
+#define DASD_STATE_NEW    0
+#define DASD_STATE_KNOWN  1
+#define DASD_STATE_ACCEPT 2
+#define DASD_STATE_INIT   3
+#define DASD_STATE_READY  4
+#define DASD_STATE_ONLINE 5
+
+
+#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
+#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
+#define DASD_FORMAT_INTENS_INVALIDATE    0x04
+#define DASD_FORMAT_INTENS_CDL 0x08
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <linux/blk.h> 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/blkdev.h> 
+#include <linux/devfs_fs_kernel.h>
+#endif
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/compatmac.h>
+
+#include <asm/ccwcache.h>
+#include <asm/irq.h>
+#include <asm/s390dyn.h>
+#include <asm/todclk.h>
+#include <asm/debug.h>
+
+/* Kernel Version Compatibility section */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
+typedef struct request *request_queue_t;
+#define block_device_operations file_operations
+#define __setup(x,y) struct dasd_device_t
+#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops)
+#define register_disk(dd,dev,partn,ops,size) \
+do { \
+	dd->sizes[MINOR(dev)] = size >> 1; \
+	resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \
+} while(0)
+#define init_waitqueue_head(x) do { *x = NULL; } while(0)
+#define blk_cleanup_queue(x) do {} while(0)
+#define blk_init_queue(x...) do {} while(0)
+#define blk_queue_headactive(x...) do {} while(0)
+#define blk_queue_make_request(x) do {} while(0)
+#define list_empty(x) (0)
+#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
+do { \
+        blk_dev[d_major].request_fn = d_request_fn; \
+        blk_dev[d_major].queue = d_queue_fn; \
+        blk_dev[d_major].current_request = d_current; \
+} while(0)
+#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
+	major:D_MAJOR, \
+	major_name:D_NAME, \
+	minor_shift:D_PARTN_BITS, \
+	max_p:1 << D_PARTN_BITS, \
+	max_nr:D_PER_MAJOR, \
+	nr_real:D_PER_MAJOR,
+static inline struct request * 
+dasd_next_request( request_queue_t *queue ) 
+{
+    return *queue;
+}
+static inline void 
+dasd_dequeue_request( request_queue_t * q, struct request *req )
+{
+        *q = req->next;
+        req->next = NULL;
+}
+#else
+#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
+do { \
+        blk_dev[d_major].queue = d_queue_fn; \
+} while(0)
+#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
+	major:D_MAJOR, \
+	major_name:D_NAME, \
+	minor_shift:D_PARTN_BITS, \
+	max_p:1 << D_PARTN_BITS, \
+	nr_real:D_PER_MAJOR, \
+        fops:&dasd_device_operations, 
+static inline struct request * 
+dasd_next_request( request_queue_t *queue ) 
+{
+        return blkdev_entry_next_request(&queue->queue_head);
+}
+static inline void 
+dasd_dequeue_request( request_queue_t * q, struct request *req )
+{
+        blkdev_dequeue_request (req);
+}
+#endif
+
+/* dasd_range_t are used for dynamic device att-/detachment */
+typedef struct dasd_devreg_t {
+        devreg_t devreg; /* the devreg itself */
+        /* build a linked list of devregs, needed for cleanup */
+        struct list_head list;
+} dasd_devreg_t;
+
+typedef struct {
+	struct list_head list;
+	struct module *owner;
+	int no;
+	dasd_ioctl_fn_t handler;
+} dasd_ioctl_list_t;
+
+typedef enum {
+	dasd_era_fatal = -1,	/* no chance to recover              */
+	dasd_era_none = 0,	/* don't recover, everything alright */
+	dasd_era_msg = 1,	/* don't recover, just report...     */
+	dasd_era_recover = 2	/* recovery action recommended       */
+} dasd_era_t;
+
+/* BIT DEFINITIONS FOR SENSE DATA */
+#define DASD_SENSE_BIT_0 0x80
+#define DASD_SENSE_BIT_1 0x40
+#define DASD_SENSE_BIT_2 0x20
+#define DASD_SENSE_BIT_3 0x10
+
+#define check_then_set(where,from,to) \
+do { \
+        if ((*(where)) != (from) ) { \
+                printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
+                BUG(); \
+        } \
+        (*(where)) = (to); \
+} while (0)
+
+#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
+do { \
+        int d_devno = d_device->devinfo.devno; \
+        int d_irq = d_device->devinfo.irq; \
+        char *d_name = d_device->name; \
+        int d_major = MAJOR(d_device->kdev); \
+        int d_minor = MINOR(d_device->kdev); \
+        printk(d_loglevel PRINTK_HEADER \
+               "/dev/%s(%d:%d),%04x@0x%x:" \
+               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
+} while(0)
+
+/* 
+ * struct dasd_sizes_t
+ * represents all data needed to access dasd with properly set up sectors
+ */
+typedef
+struct dasd_sizes_t {
+	unsigned long blocks; /* size of volume in blocks */
+	unsigned int bp_block; /* bytes per block */
+	unsigned int s2b_shift; /* log2 (bp_block/512) */
+        unsigned int pt_block; /* from which block to read the partn table */
+} dasd_sizes_t;
+
+/* 
+ * struct dasd_chanq_t 
+ * represents a queue of channel programs related to a single device
+ */
+typedef
+struct dasd_chanq_t {
+	ccw_req_t *head;
+	ccw_req_t *tail;
+} dasd_chanq_t;
+
+#define DASD_DEVICE_FORMAT_STRING "Device: %p"
+#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_event(d_device->debug_area,d_level,\
+                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                    d_device, d_data);\
+} while(0);
+#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
+do {\
+        if ( d_device->debug_area != NULL )\
+        debug_sprintf_exception(d_device->debug_area,d_level,\
+                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
+                        d_device, d_data);\
+} while(0);
+
+#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
+#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_event(dasd_debug_area, d_level,\
+                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                    d_fn, d_data);\
+} while(0);
+#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
+do {\
+        if ( dasd_debug_area != NULL )\
+        debug_sprintf_exception(dasd_debug_area, d_level,\
+                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
+                        d_fn, d_data);\
+} while(0);
+
+struct dasd_device_t;
+struct request;
+
+/* 
+ * signatures for the functions of dasd_discipline_t 
+ * make typecasts much easier
+ */
+typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
+typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
+
+typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *);
+typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
+typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
+typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
+typedef int (*dasd_io_stopper_fn_t) (ccw_req_t *);
+typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
+typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
+typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
+typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
+typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
+typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
+typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *);
+typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *);
+typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *);
+typedef int (*dasd_info_fn_t) (struct dasd_device_t *, dasd_information_t *);
+typedef int (*dasd_use_count_fn_t) (int);
+
+
+/*
+ * the dasd_discipline_t is
+ * sth like a table of virtual functions, if you think of dasd_eckd
+ * inheriting dasd...
+ * no, currently we are not planning to reimplement the driver in C++
+ */
+typedef struct dasd_discipline_t {
+        struct module *owner;
+	char ebcname[8]; /* a name used for tagging and printks */
+        char name[8];		/* a name used for tagging and printks */
+	int max_blocks;	/* maximum number of blocks to be chained */
+	dasd_ck_id_fn_t id_check;	/* to check sense data */
+	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
+	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
+	dasd_do_analysis_fn_t do_analysis;	/* to complete the analysis of the volume */
+	dasd_fill_geometry_fn_t fill_geometry;	/* to set up hd_geometry */
+	dasd_io_starter_fn_t start_IO;
+	dasd_io_stopper_fn_t term_IO;
+        dasd_format_fn_t format_device;		/* to format the device */
+	dasd_error_examine_fn_t examine_error;
+	dasd_error_analyse_fn_t erp_action;
+	dasd_erp_analyse_fn_t erp_postaction;
+        dasd_cp_builder_fn_t build_cp_from_req;
+        dasd_dump_sense_fn_t dump_sense;
+        dasd_int_handler_fn_t int_handler;
+        dasd_reserve_fn_t reserve;
+        dasd_release_fn_t release;
+        dasd_merge_cp_fn_t merge_cp;
+        dasd_info_fn_t fill_info;
+	struct list_head list;	/* used for list of disciplines */
+} dasd_discipline_t;
+
+#define DASD_DEFAULT_FEATURES 0
+#define DASD_FEATURE_READONLY 1
+
+/* dasd_range_t are used for ordering the DASD devices */
+typedef struct dasd_range_t {
+	unsigned int from;	/* first DASD in range */
+	unsigned int to;	/* last DASD in range */
+	char discipline[4];	/* placeholder to force discipline */
+        int features;
+	struct list_head list;	/* next one in linked list */
+} dasd_range_t;
+
+
+
+#define DASD_MAJOR_INFO_REGISTERED 1
+#define DASD_MAJOR_INFO_IS_STATIC 2
+
+typedef struct major_info_t {
+	struct list_head list;
+	struct dasd_device_t **dasd_device;
+	int flags;
+	struct gendisk gendisk; /* actually contains the major number */
+} __attribute__ ((packed)) major_info_t;
+
+typedef struct dasd_device_t {
+	s390_dev_info_t devinfo;
+	dasd_discipline_t *discipline;
+	int level;
+        atomic_t open_count;
+        kdev_t kdev;
+        major_info_t *major_info;
+	struct dasd_chanq_t queue;
+        wait_queue_head_t wait_q;
+        request_queue_t *request_queue;
+        struct timer_list timer;      
+	devstat_t dev_status; /* needed ONLY!! for request_irq */
+        dasd_sizes_t sizes;
+        char name[16]; /* The name of the device in /dev */
+	char *private;	/* to be used by the discipline internally */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        devfs_handle_t devfs_entry;
+#endif /* LINUX_IS_24 */
+	struct tq_struct bh_tq;
+        atomic_t bh_scheduled;
+        debug_info_t *debug_area;
+        dasd_profile_info_t profile;
+        ccw_req_t *init_cqr;
+        atomic_t plugged;
+        void* lowmem_cqr;
+        void* lowmem_ccws;
+        void* lowmem_idals;
+        void* lowmem_idal_ptr;
+}  dasd_device_t;
+
+int dasd_init (void);
+void dasd_discipline_add(dasd_discipline_t *);
+void dasd_discipline_del(dasd_discipline_t *);
+int dasd_start_IO (ccw_req_t *);
+int dasd_term_IO (ccw_req_t *);
+void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t *dasd_default_erp_action (ccw_req_t *);
+ccw_req_t *dasd_default_erp_postaction (ccw_req_t *);
+inline void dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
+inline void dasd_chanq_enq (dasd_chanq_t *, ccw_req_t *);
+inline void dasd_chanq_enq_head (dasd_chanq_t *, ccw_req_t *);
+ccw_req_t *dasd_alloc_request (char *, int, int, dasd_device_t *);
+void dasd_free_request (ccw_req_t *, dasd_device_t *);
+int dasd_oper_handler (int irq, devreg_t * devreg);
+void dasd_schedule_bh (dasd_device_t *);
+int dasd_sleep_on_req(ccw_req_t*);
+int  dasd_set_normalized_cda ( ccw1_t * cp, unsigned long address, ccw_req_t* request, dasd_device_t* device );
+
+extern debug_info_t *dasd_debug_area;
+extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
+
+#endif /* __KERNEL__ */
+
+#endif				/* DASD_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff -urN linux-2.4.8-pre4/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- linux-2.4.8-pre4/drivers/scsi/aha152x.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/scsi/aha152x.c	Mon Dec  3 22:58:53 2001
@@ -624,7 +624,7 @@
 static void parerr_run(struct Scsi_Host *shpnt);
 static void rsti_run(struct Scsi_Host *shpnt);
 
-static void complete(struct Scsi_Host *shpnt);
+static void is_complete(struct Scsi_Host *shpnt);
 
 /*
  * driver states
@@ -1869,7 +1869,7 @@
 		struct Scsi_Host *shpnt = aha152x_host[i];
 		if (shpnt && HOSTDATA(shpnt)->service) {
 			HOSTDATA(shpnt)->service=0;
-			complete(shpnt);
+			is_complete(shpnt);
 		}
 	}
 }
@@ -2935,7 +2935,7 @@
  * bottom-half handler
  *
  */
-static void complete(struct Scsi_Host *shpnt)
+static void is_complete(struct Scsi_Host *shpnt)
 {
 	int dataphase;
 	unsigned long flags;
diff -urN linux-2.4.8-pre4/drivers/scsi/aic7xxx/aic7xxx.c linux/drivers/scsi/aic7xxx/aic7xxx.c
--- linux-2.4.8-pre4/drivers/scsi/aic7xxx/aic7xxx.c	Fri May  4 15:16:28 2001
+++ linux/drivers/scsi/aic7xxx/aic7xxx.c	Mon Dec  3 22:58:53 2001
@@ -1343,22 +1343,21 @@
 	       hscb->scsiid,
 	       hscb->lun,
 	       hscb->cdb_len);
-	i = 0;
 	printf("Shared Data: %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[0],
+	       hscb->shared_data.cdb[1],
+	       hscb->shared_data.cdb[2],
+	       hscb->shared_data.cdb[3]);
 	printf("             %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[4],
+	       hscb->shared_data.cdb[5],
+	       hscb->shared_data.cdb[6],
+	       hscb->shared_data.cdb[7]);
 	printf("             %#02x %#02x %#02x %#02x\n",
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++],
-	       hscb->shared_data.cdb[i++]);
+	       hscb->shared_data.cdb[8],
+	       hscb->shared_data.cdb[9],
+	       hscb->shared_data.cdb[10],
+	       hscb->shared_data.cdb[11]);
 	printf("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
 		ahc_le32toh(hscb->dataptr),
 		ahc_le32toh(hscb->datacnt),
diff -urN linux-2.4.8-pre4/drivers/scsi/atp870u.c linux/drivers/scsi/atp870u.c
--- linux-2.4.8-pre4/drivers/scsi/atp870u.c	Mon Dec  3 22:58:44 2001
+++ linux/drivers/scsi/atp870u.c	Mon Dec  3 22:58:53 2001
@@ -11,7 +11,7 @@
  *		   enable 32 bit fifo transfer
  *		   support cdrom & remove device run ultra speed
  *		   fix disconnect bug  2000/12/21
- *		   support atp880 chip lvd u160 2001/05/15
+ *		   support atp880 chip lvd u160 2001/05/15 (7.1)
  */
 
 #include <linux/module.h>
@@ -65,8 +65,10 @@
 	unsigned short wide_idu;
 	unsigned short active_idu;
 	unsigned short ultra_map;
+	unsigned short async;
 	unsigned short deviceid;
 	unsigned char ata_cdbu[16];
+	unsigned char sp[16];
 	Scsi_Cmnd *querequ[qcnt];
 	struct atp_id
 	{
@@ -1694,8 +1696,9 @@
 	static unsigned char satn[9] =	{0, 0, 0, 0, 0, 0, 0, 6, 6};
 	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
 	static unsigned char synn[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
-	static unsigned char synu[6] =	{0x80, 1, 3, 1, 0x0a, 0x0e};
-	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x0a, 0x0e};
+	unsigned char synu[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synuw[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
 	static unsigned char wide[6] =	{0x80, 1, 2, 3, 1, 0};
 	static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
 	struct atp_unit *dev = &atp_unit[host];
@@ -1834,17 +1837,18 @@
 		if ((mbuf[7] & 0x60) == 0) {
 			goto not_wide;
 		}
-		if ((dev->global_map & 0x20) == 0) {
+		if ((i < 8) && ((dev->global_map & 0x20) == 0)) {
 			goto not_wide;
 		}
 		if (lvdmode == 0)
 		{
 		   goto chg_wide;
 		}
-		if ((mbuf[2] & 0x07) < 0x03)	      // force u2
+		if (dev->sp[i] != 0x04) 	 // force u2
 		{
 		   goto chg_wide;
 		}
+
 		tmport = wkport + 0x5b;
 		outb(0x01, tmport);
 		tmport = wkport + 0x43;
@@ -2129,10 +2133,28 @@
 		if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) ||
 		    ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0)))
 		{
-			goto set_sync;
+			m = 1;
+			m = m << i;
+			if ((dev->async & m) != 0)
+			{
+			   goto set_sync;
+			}
 		}
 		continue;
 set_sync:
+		if (dev->sp[i] == 0x02)
+		{
+		   synu[4]=0x0c;
+		   synuw[4]=0x0c;
+		}
+		else
+		{
+		   if (dev->sp[i] >= 0x03)
+		   {
+		      synu[4]=0x0a;
+		      synuw[4]=0x0a;
+		   }
+		}
 		tmport = wkport + 0x5b;
 		j = 0;
 		if ((m & dev->wide_idu) != 0) {
@@ -2175,7 +2197,11 @@
 			if ((inb(tmport) & 0x01) != 0) {
 				tmport -= 0x06;
 				if ((m & dev->wide_idu) != 0) {
-					outb(synw[j++], tmport);
+					if ((m & dev->ultra_map) != 0) {
+						outb(synuw[j++], tmport);
+					} else {
+						outb(synw[j++], tmport);
+					}
 				} else {
 					if ((m & dev->ultra_map) != 0) {
 						outb(synu[j++], tmport);
@@ -2321,13 +2347,13 @@
 /* return non-zero on detection */
 int atp870u_detect(Scsi_Host_Template * tpnt)
 {
-	unsigned char irq, h, k;
+	unsigned char irq, h, k, m;
 	unsigned long flags;
 	unsigned int base_io, error, tmport;
 	unsigned short index = 0;
 	struct pci_dev *pdev[3];
 	unsigned char chip_ver[3], host_id;
-	unsigned short dev_id[3];
+	unsigned short dev_id[3], n;
 	struct Scsi_Host *shpnt = NULL;
 	int tmpcnt = 0;
 	int count = 0;
@@ -2368,6 +2394,7 @@
 		}
 		for (k = 0; k < 16; k++) {
 			dev->id[k].curr_req = 0;
+			dev->sp[k] = 0x04;
 		}
 	}
 	h = 0;
@@ -2500,7 +2527,7 @@
 		   host_id = inb(base_io + 0x39);
 		   host_id >>= 0x04;
 
-		   printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d    IO:%x, IRQ:%d.\n"
+		   printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra160 LVD/SE SCSI Adapter: %d    IO:%x, IRQ:%d.\n"
 			  ,h, base_io, irq);
 		   dev->ioport = base_io + 0x40;
 		   dev->pciport = base_io + 0x28;
@@ -2515,11 +2542,67 @@
 		   dev->global_map = inb(tmport);
 		   tmport += 0x07;
 		   dev->ultra_map = inw(tmport);
-		   if (dev->ultra_map == 0) {
-			   dev->scam_on = 0x00;
-			   dev->global_map = 0x20;
-			   dev->ultra_map = 0xffff;
+
+		   n=0x3f09;
+next_fblk:
+		   if (n >= 0x4000)
+		   {
+		      goto flash_ok;
 		   }
+		   m=0;
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   if (inb(base_io + 0x30) == 0xff)
+		   {
+		      goto flash_ok;
+		   }
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   outw(n,base_io + 0x34);
+		   n += 0x0002;
+		   dev->sp[m++]=inb(base_io + 0x30);
+		   dev->sp[m++]=inb(base_io + 0x31);
+		   dev->sp[m++]=inb(base_io + 0x32);
+		   dev->sp[m++]=inb(base_io + 0x33);
+		   n += 0x0018;
+		   goto next_fblk;
+flash_ok:
+		   outw(0,base_io + 0x34);
+		   dev->ultra_map=0;
+		   dev->async = 0;
+		   for (k=0; k < 16; k++)
+		   {
+		       n=1;
+		       n = n << k;
+		       if (dev->sp[k] > 1)
+		       {
+			  dev->ultra_map |= n;
+		       }
+		       else
+		       {
+			  if (dev->sp[k] == 0)
+			  {
+			     dev->async |= n;
+			  }
+		       }
+		   }
+		   dev->async = ~(dev->async);
+		   outb(dev->global_map,base_io + 0x35);
+
 		   shpnt = scsi_register(tpnt, 4);
 		   if(shpnt==NULL)
 			   return count;
@@ -2557,6 +2640,7 @@
 		   tmport = base_io + 0x51;
 		   outb(0x20, tmport);
 
+		   tscam(h);
 		   is880(h, base_io);
 		   tmport = base_io + 0x38;
 		   outb(0xb0, tmport);
@@ -2646,7 +2730,7 @@
 		{
 		    printk(" %2x ",workrequ->cmnd[k]);
 		}
-		printk(" last_lenu= %lx ",dev->id[j].last_lenu);
+		printk(" last_lenu= %x ",dev->id[j].last_lenu);
 	   }
 	}
 	return (SCSI_ABORT_SNOOZE);
@@ -2680,7 +2764,7 @@
 {
 	static char buffer[128];
 
-	strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.4+ac ");
+	strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.5+ac ");
 
 	return buffer;
 }
@@ -2725,7 +2809,7 @@
 	if (offset == 0) {
 		memset(buff, 0, sizeof(buff));
 	}
-	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.4+ac\n");
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.5+ac\n");
 	len += size;
 	pos = begin + len;
 	size = 0;
@@ -2791,4 +2875,3 @@
 
 static Scsi_Host_Template driver_template = ATP870U;
 #include "scsi_module.c"
-
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfc.Readme linux/drivers/scsi/cpqfc.Readme
--- linux-2.4.8-pre4/drivers/scsi/cpqfc.Readme	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfc.Readme	Mon Dec  3 22:58:53 2001
@@ -6,6 +6,23 @@
 33 and 66MHz.  Only supports FC-AL.
 SEST size 512 Exchanges (simultaneous I/Os) limited by module kmalloc() 
 	max of 128k bytes contiguous.
+
+Ver 2.0.2  July 23, 2001
+   Changed the semiphore changes so the driver would compile in 2.4.7. 
+   This version is for 2.4.7 and beyond. 
+ 
+Ver 2.0.1  May 	7, 2001
+   Merged version 1.3.6 fixes into version 2.0.0.   
+
+Ver 2.0.0  May   7, 2001
+  Fixed problem so spinlock is being initialized to UNLOCKED. 
+  Fixed updated driver so it compiles in the 2.4 tree. 
+ 
+ Ver 1.3.6  Feb  27, 2001
+   Added Target_Device_Reset function for SCSI error handling
+   Fixed problem with not reseting addressing mode after implicit logout
+ 
+
 Ver 1.3.4  Sep   7, 2000
   Added Modinfo information
   Fixed problem with statically linking the driver
@@ -212,5 +229,5 @@
 
 
 Send questions/comments to:
-donald.zimmerman@compaq.com
-dszimmerman@yahoo.com
+Amy Vanzant-Hodge (fibrechannel@compaq.com)
+
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfcTS.h linux/drivers/scsi/cpqfcTS.h
--- linux-2.4.8-pre4/drivers/scsi/cpqfcTS.h	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfcTS.h	Mon Dec  3 22:58:53 2001
@@ -5,11 +5,13 @@
 // These functions are required by the Linux SCSI layers
 extern int cpqfcTS_detect(Scsi_Host_Template *);
 extern int cpqfcTS_release(struct Scsi_Host *);
-const char * cpqfcTS_info(struct Scsi_Host *);
+extern const char * cpqfcTS_info(struct Scsi_Host *);
 extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int);
 extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 extern int cpqfcTS_abort(Scsi_Cmnd *);
 extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
 extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]);
 extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
 
@@ -24,8 +26,10 @@
  proc_info:              cpqfcTS_proc_info,      \
  ioctl:                  cpqfcTS_ioctl,          \
  queuecommand:           cpqfcTS_queuecommand,   \
- eh_abort_handler:       cpqfcTS_abort,          \
+ eh_device_reset_handler:   cpqfcTS_eh_device_reset,   \
+ eh_abort_handler:       cpqfcTS_eh_abort,       \
  reset:                  cpqfcTS_reset,          \
+ abort:                  cpqfcTS_abort,		 \
  bios_param:             cpqfcTS_biosparam,      \
  can_queue:              CPQFCTS_REQ_QUEUE_LEN,  \
  this_id:                -1,                     \
@@ -33,7 +37,8 @@
  cmd_per_lun:            CPQFCTS_CMD_PER_LUN,    \
  present:                0,                      \
  unchecked_isa_dma:      0,                      \
- use_clustering:         ENABLE_CLUSTERING       \
+ use_clustering:         ENABLE_CLUSTERING,      \
+ use_new_eh_code:        1			 \
 }
 
 #endif /* CPQFCTS_H */ 
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfcTScontrol.c linux/drivers/scsi/cpqfcTScontrol.c
--- linux-2.4.8-pre4/drivers/scsi/cpqfcTScontrol.c	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/cpqfcTScontrol.c	Mon Dec  3 22:58:53 2001
@@ -42,11 +42,7 @@
 #include <linux/unistd.h>
 #include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 
 #include "sd.h"
 #include "hosts.h"   // Scsi_Host definition for INT handler
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfcTSinit.c linux/drivers/scsi/cpqfcTSinit.c
--- linux-2.4.8-pre4/drivers/scsi/cpqfcTSinit.c	Thu Jul 19 21:09:34 2001
+++ linux/drivers/scsi/cpqfcTSinit.c	Mon Dec  3 22:58:53 2001
@@ -49,11 +49,7 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>   // ioctl related
 #include <asm/irq.h>
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,18)
-#include <asm/spinlock.h>
-#else
 #include <linux/spinlock.h>
-#endif
 #include "sd.h"
 #include <scsi/scsi_ioctl.h>
 #include "hosts.h"
@@ -62,10 +58,15 @@
 
 #include "cpqfcTS.h"
 
+#include <linux/config.h>  
 #include <linux/module.h>
+#include <linux/version.h> 
+
 /* Embedded module documentation macros - see module.h */
 MODULE_AUTHOR("Compaq Computer Corporation");
 MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA");
+  
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
 
 // This struct was originally defined in 
 // /usr/src/linux/include/linux/proc_fs.h
@@ -104,24 +105,24 @@
 
   // since x86 port space is 64k, we only need the lower 16 bits
   cpqfcHBAdata->fcChip.Registers.IOBaseL = 
-    PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
   
   cpqfcHBAdata->fcChip.Registers.IOBaseU = 
-    PciDev->base_address[2] & PCI_BASE_ADDRESS_IO_MASK;
+    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
   
   // 32-bit memory addresses
   cpqfcHBAdata->fcChip.Registers.MemBase = 
-    PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK;
+    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
 
   cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
-    ioremap( PciDev->base_address[3] & PCI_BASE_ADDRESS_MEM_MASK,
+    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
              0x200);
   
   cpqfcHBAdata->fcChip.Registers.RAMBase = 
-    PciDev->base_address[4];
+    PciDev->resource[4].start;
   
   cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
-    PciDev->base_address[5];
+    PciDev->resource[5].start;
   
   // now the Tachlite chip registers
   // the REGISTER struct holds both the physical address & last
@@ -296,10 +297,14 @@
       	continue;
       DEBUG_PCI( printk("  HBA found!\n"));
       DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[0]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[1]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[2]));
-      DEBUG_PCI(printk("  PciDev->baseaddress[]= %lx\n", PciDev->base_address[3]));
+      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
+				PciDev->resource[0].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
+				PciDev->resource[1].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
+				PciDev->resource[2].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
+				PciDev->resource[3].start));
 
       scsi_set_pci_device(HostAdapter, PciDev);      
       HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
@@ -308,7 +313,7 @@
       // for a total I/O port address space of 512 bytes.
       // mask out the I/O port address (lower) & record
       HostAdapter->io_port = (unsigned int)
-	     PciDev->base_address[1] & PCI_BASE_ADDRESS_IO_MASK;
+	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
       HostAdapter->n_io_port = 0xff;
       
       // i.e., expect 128 targets (arbitrary number), while the
@@ -316,7 +321,6 @@
       HostAdapter->max_id =  0;   // incremented as devices log in    
       HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
       HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
-      HostAdapter->hostt->use_new_eh_code = 1; // new error handling
       
       // get the pointer to our HBA specific data... (one for
       // each HBA on the PCI bus(ses)).
@@ -333,7 +337,7 @@
       Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
      
       cpqfcHBAdata->HBAnum = NumberOfAdapters;
-
+      cpqfcHBAdata->hba_spinlock = SPIN_LOCK_UNLOCKED;
 
       // request necessary resources and check for conflicts
       if( request_irq( HostAdapter->irq,
@@ -414,9 +418,12 @@
 	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
 	
 	int wait_time;
+	unsigned long flags=0;
+ 
+        spin_unlock_irqrestore(&io_request_lock, flags);
         for( wait_time = jiffies + 4*HZ; wait_time > jiffies; )
 	  schedule();  // (our worker task needs to run)
-
+	spin_lock_irqsave(&io_request_lock, flags);
       }
       
       NumberOfAdapters++; 
@@ -458,7 +465,7 @@
   Scsi_Cmnd *ScsiPassThruCmnd;
   unsigned long flags;
 
-  ENTER("cpqfcTS_ioctl");
+  ENTER("cpqfcTS_ioctl ");
   
   // can we find an FC device mapping to this SCSI target?
   DumCmnd.channel = ScsiDev->channel;		// For searching
@@ -476,6 +483,7 @@
  
   else  // we know what FC device to operate on...
   {
+	// printk("ioctl CMND %d", Cmnd);
     switch (Cmnd) 
     {
       // Passthrough provides a mechanism to bypass the RAID
@@ -496,8 +504,8 @@
 	  return -EPERM;
 
 	// copy the caller's struct to our space.
-        copy_from_user_ret( &ioc, arg, 
-			  sizeof( VENDOR_IOCTL_REQ), -EFAULT);
+        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
+		return( -EFAULT);
 
 	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
 
@@ -512,13 +520,14 @@
         // Now build a SCSI_CMND to pass down...
 	// This function allocates and sets Scsi_Cmnd ptrs such as
 	//  ->channel, ->target, ->host
-        ScsiPassThruCmnd = scsi_allocate_device(NULL, ScsiDev, 1);
+        ScsiPassThruCmnd = scsi_allocate_device(ScsiDev, 1, 1);
 
         // Need data from user?
 	// make sure caller's buffer is in kernel space.
 	if( (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) &&
 	    vendor_cmd->len)
-          copy_from_user_ret( buf, vendor_cmd->bufp, vendor_cmd->len, -EFAULT);
+        if(  copy_from_user( buf, vendor_cmd->bufp, vendor_cmd->len))
+		return( -EFAULT);
 	    
 	// copy the CDB (if/when MAX_COMMAND_SIZE is 16, remove copy below)
         memcpy( &ScsiPassThruCmnd->cmnd[0], 
@@ -590,16 +599,17 @@
         scsi_release_command(ScsiPassThruCmnd); // "de-allocate"
         ScsiPassThruCmnd = NULL;
 
-        if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-          (*SDpnt->scsi_request_fn)();
+        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+        //  (*SDpnt->scsi_request_fn)();
 
-        wake_up(&SDpnt->device_wait);
+        wake_up(&SDpnt->scpnt_wait);
         spin_unlock_irqrestore(&io_request_lock, flags);
 
 	// need to pass data back to user (space)?
 	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
 	     vendor_cmd->len )
-          copy_to_user_ret( vendor_cmd->bufp, buf, vendor_cmd->len, -EFAULT);
+        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
+		return( -EFAULT);
 
         if( buf) 
 	  kfree( buf);
@@ -621,8 +631,8 @@
 	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
 			  (cpqfcHBAdata->PciDev->vendor <<16); 
 	      
-        copy_to_user_ret( arg, &pciinfo, 
-			  sizeof(cpqfc_pci_info_struct), -EFAULT);
+        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+		return( -EFAULT);
         return 0;
       }
 
@@ -634,8 +644,8 @@
 	if( !arg)
 	  return -EINVAL;
 
-        copy_to_user_ret( arg, &DriverVer, 
-			  sizeof(DriverVer), -EFAULT);
+        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
+		return( -EFAULT);
         return 0;
       }
 
@@ -657,6 +667,17 @@
         put_user(pLoggedInPort->u.ucWWN[i], 
 		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
         break;
+
+
+      case SCSI_IOCTL_FC_TDR:
+          
+        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
+
+        break;
+
+
+
+
     default:
       result = -EINVAL;
       break;
@@ -1351,13 +1372,20 @@
 
 int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
 {
+//	printk(" cpqfcTS_abort called?? \n");
+ 	return 0;
+}
+ 
+int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+{
+
   struct Scsi_Host *HostAdapter = Cmnd->host;
   // get the pointer to our Scsi layer HBA buffer  
   CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
   PTACHYON fcChip = &cpqfcHBAdata->fcChip;
   FC_EXCHANGES *Exchanges = fcChip->Exchanges;
   int i;
-  ENTER("cpqfcTS_abort");
+  ENTER("cpqfcTS_eh_abort");
 
   Cmnd->result = DID_ABORT <<16;  // assume we'll find it
 
@@ -1443,28 +1471,117 @@
 Done:
   
 //    panic("_abort");
-  LEAVE("cpqfcTS_abort");
+  LEAVE("cpqfcTS_eh_abort");
   return 0;  // (see scsi.h)
 }    
 
 
+// FCP-SCSI Target Device Reset
+// See dpANS Fibre Channel Protocol for SCSI
+// X3.269-199X revision 12, pg 25
+
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
+                               unsigned int reset_flags)
+{
+  int timeout = 10*HZ;
+  int retries = 1;
+  char scsi_cdb[12];
+  unsigned long flags;
+  int result;
+  Scsi_Cmnd * SCpnt;
+  Scsi_Device * SDpnt;
 
 
-// To be done...	
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
-{
-  int return_status = SUCCESS;
+  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
 
-  ENTER("cpqfcTS_reset");
+  if (ScsiDev->host->eh_active) return FAILED;
 
+  memset( scsi_cdb, 0, sizeof( scsi_cdb));
 
-            
+  scsi_cdb[0] = RELEASE;
 
-  LEAVE("cpqfcTS_reset");
-  return return_status;
-}    
+  spin_lock_irqsave(&io_request_lock, flags);
 
+  // allocate with wait = true, interruptible = false 
+  SCpnt = scsi_allocate_device(ScsiDev, 1, 0);
+  {
+    DECLARE_COMPLETION(wait);
+        
+    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+	SCpnt->request.waiting = &wait;
+	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
+	spin_unlock_irqrestore(&io_request_lock, flags);
+	wait_for_completion(&wait);
+    spin_lock_irqsave(&io_request_lock, flags);
+    SCpnt->request.waiting = NULL;
+  }
+    
+/*
+      if(driver_byte(SCpnt->result) != 0)
+	  switch(SCpnt->sense_buffer[2] & 0xf) {
+	case ILLEGAL_REQUEST:
+	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
+	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
+	    break;
+	case NOT_READY: // This happens if there is no disc in drive 
+	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
+		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
+		break;
+	    }
+	case UNIT_ATTENTION:
+	    if (dev->removable){
+		dev->changed = 1;
+		SCpnt->result = 0; // This is no longer considered an error
+		// gag this error, VFS will log it anyway /axboe 
+		// printk(KERN_INFO "Disc change detected.\n"); 
+		break;
+	    };
+	default: // Fall through for non-removable media
+	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
+		   dev->host->host_no,
+		   dev->id,
+		   dev->lun,
+		   SCpnt->result);
+	    printk("\tSense class %x, sense error %x, extended sense %x\n",
+		   sense_class(SCpnt->sense_buffer[0]),
+		   sense_error(SCpnt->sense_buffer[0]),
+		   SCpnt->sense_buffer[2] & 0xf);
+	    
+      };
+*/    
+  result = SCpnt->result;
+
+  SDpnt = SCpnt->device;
+  scsi_release_command(SCpnt);
+  SCpnt = NULL;
+
+  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+  // 	(*SDpnt->scsi_request_fn)();
+
+  wake_up(&SDpnt->scpnt_wait);
+  spin_unlock_irqrestore(&io_request_lock, flags);
+  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+  return SUCCESS;
+}
+
+
+int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+{
+  Scsi_Device *SDpnt = Cmnd->device;
+  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+  return cpqfcTS_TargetDeviceReset( SDpnt, 0);
+}
+
+	
+int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+{
 
+  ENTER("cpqfcTS_reset");
+
+  LEAVE("cpqfcTS_reset");
+  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+}
 
 /* This function determines the bios parameters for a given
    harddisk. These tend to be numbers that are made up by the
@@ -1805,15 +1922,7 @@
 }
 
 
-
-
-#ifdef MODULE
-
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
-
-
-#endif
-
 
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfcTSstructs.h linux/drivers/scsi/cpqfcTSstructs.h
--- linux-2.4.8-pre4/drivers/scsi/cpqfcTSstructs.h	Tue Sep 19 08:01:34 2000
+++ linux/drivers/scsi/cpqfcTSstructs.h	Mon Dec  3 22:58:53 2001
@@ -29,9 +29,9 @@
                          for( wait_time=jiffies + (secs*HZ); \
 		         wait_time > jiffies ;) ; }
 #define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define VER_MAJOR 1
-#define VER_MINOR 3
-#define VER_SUBMINOR 4
+#define VER_MAJOR 2
+#define VER_MINOR 0
+#define VER_SUBMINOR 2
 
 // Macros for kernel (esp. SMP) tracing using a PCI analyzer
 // (e.g. x86).
@@ -225,6 +225,7 @@
 #define ELS_RJT 0x1000000
 #define SCSI_REPORT_LUNS 0x0A0
 #define REPORT_LUNS 0xA0 // SCSI-3 command op-code
+#define FCP_TARGET_RESET 0x200
 
 #define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
 
diff -urN linux-2.4.8-pre4/drivers/scsi/cpqfcTSworker.c linux/drivers/scsi/cpqfcTSworker.c
--- linux-2.4.8-pre4/drivers/scsi/cpqfcTSworker.c	Fri Mar  2 18:38:38 2001
+++ linux/drivers/scsi/cpqfcTSworker.c	Mon Dec  3 22:58:53 2001
@@ -149,7 +149,6 @@
               CPQFCHBA* cpqfcHBAdata, 
 	      TachFCHDR_GCMND* fchs);
 
-
 // (see scsi_error.c comments on kernel task creation)
 
 void cpqfcTSWorkerThread( void *host)
@@ -1069,6 +1068,7 @@
   pFcPort->flogi = FALSE;
   pFcPort->LOGO_timer = 0;
   pFcPort->device_blocked = TRUE; // block Scsi Requests
+  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
 }
 
   
@@ -2934,7 +2934,6 @@
   ULONG ulStatus;
   UCHAR *ucBuff;
 
-
   if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
   {
     printk("Discard Q'd ReportLun command\n");
@@ -2976,7 +2975,7 @@
 
     Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
     Cmnd->target = pLoggedInPort->ScsiNexus.target;
-    
+
 	    
     ulStatus = cpqfcTSBuildExchange(
       cpqfcHBAdata,
@@ -3404,7 +3403,7 @@
     if( port_id_valid ) // look for alpa first
     {
       if( pLoggedInPort->port_id == port_id )
-        break;  // found it!
+          break;  // found it!
     }
     if( wwn_valid ) // look for wwn second
     {
@@ -4326,7 +4325,6 @@
       break;
     
     
-    
     case BLS_ABTS:   // FC defined basic link service command ABTS 
                      // Abort Sequence
                      
@@ -4498,6 +4496,7 @@
 
                          // Fibre Channel SCSI 'originator' sequences...
                          // (originator means 'initiator' in FCP-SCSI)
+
     case SCSI_IWE: // TachLite Initiator Write Entry
     {
       PFC_LOGGEDIN_PORT pLoggedInPort = 
@@ -6171,7 +6170,18 @@
       // 4 bytes Control Field FCP_CNTL
       *payload++ = 0;    // byte 0: (MSB) reserved
       *payload++ = 0;    // byte 1: task codes
-      *payload++ = 0;    // byte 2: task management flags
+
+                         // byte 2: task management flags
+      // another "use" of the spare field to accomplish TDR
+      // note combination needed
+      if( (Cmnd->cmnd[0] == RELEASE) &&
+          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
+      {
+        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
+        *payload++ = 0x20;    // target device reset bit
+      }
+      else
+        *payload++ = 0;    // no TDR
 		      // byte 3: (LSB) execution management codes
 		      // bit 0 write, bit 1 read (don't set together)
       
diff -urN linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_cs.c linux/drivers/scsi/pcmcia/nsp_cs.c
--- linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_cs.c	Wed Jul  4 11:50:38 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.c	Mon Dec  3 22:58:53 2001
@@ -9,7 +9,7 @@
     Ver.0.1   Initial version
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 
 ======================================================================*/
 
@@ -23,7 +23,7 @@
 
 ***********************************************************************/
 
-/* $Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $ */
+/* $Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $ */
 
 #ifdef NSP_KERNEL_2_2
 #include <pcmcia/config.h>
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 #include <linux/tqueue.h>
 #include <linux/interrupt.h>
+#include <linux/module.h>
 #include <linux/major.h>
 #include <linux/blk.h>
 #include <linux/stat.h>
@@ -71,7 +72,7 @@
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 MODULE_PARM_DESC(pc_debug, "set debug level");
-static char *version = "$Id: nsp_cs.c,v 1.28 2001/02/15 02:56:32 elca Exp $";
+static char *version = "$Id: nsp_cs.c,v 1.35 2001/07/05 16:58:24 elca Exp $";
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #else
 #define DEBUG(n, args...) /* */
@@ -90,13 +91,14 @@
 	struct bus_operations *bus;
 } scsi_info_t;
 
-static void nsp_release(u_long arg);
-static int nsp_event(event_t event, int priority,
+static void nsp_cs_release(u_long arg);
+static int nsp_cs_event(event_t event, int priority,
 		     event_callback_args_t *args);
-static dev_link_t *nsp_attach(void);
-static void nsp_detach(dev_link_t *);
+static dev_link_t *nsp_cs_attach(void);
+static void nsp_cs_detach(dev_link_t *);
 static int nsp_detect(Scsi_Host_Template * );
-static const char * nsp_info(struct Scsi_Host *);
+static int nsp_release(struct Scsi_Host *shpnt);
+static const char * nsp_info(struct Scsi_Host *shpnt);
 static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
 static int nsp_abort(Scsi_Cmnd *);
 static int nsp_reset(Scsi_Cmnd *, unsigned int);
@@ -130,25 +132,29 @@
 /* /usr/src/linux/drivers/scsi/hosts.h */
 static Scsi_Host_Template driver_template = {
 /*	next:			NULL,*/
-/*	proc_dir:		NULL,*/
+#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
+	proc_dir:	       &proc_scsi_nsp, /* kernel 2.2 */
+#else
+	proc_name:	       "nsp_cs",       /* kernel 2.4 */
+#endif
 /*	proc_info:		NULL,*/
 	name:			"WorkBit NinjaSCSI-3/32Bi",
 	detect:			nsp_detect,
-/*	release:		NULL,*/
+	release:		nsp_release,
 	info:			nsp_info,
 /*	command:		NULL,*/
 	queuecommand:		nsp_queuecommand,
 /*	eh_strategy_handler:	nsp_eh_strategy,*/
-/*	eh_abort_handler:	nsp_eh_abort,*/
-/*	eh_device_reset_handler: nsp_eh_device_reset,*/
+	eh_abort_handler:	nsp_eh_abort,
+	eh_device_reset_handler: nsp_eh_device_reset,
 	eh_bus_reset_handler:	nsp_eh_bus_reset,
-/*	eh_host_reset_handler:	nsp_eh_host_reset,*/
+	eh_host_reset_handler:	nsp_eh_host_reset,
 	abort:			nsp_abort,
 	reset:			nsp_reset,
 /*	slave_attach:		NULL,*/
-/*	bios_param:		nsp_biosparam,*/
+/*	bios_param:		NULL,*/
 	can_queue:		1,
-	this_id:		-1,
+	this_id:		SCSI_INITIATOR_ID,
 	sg_tablesize:		SG_ALL,
 	cmd_per_lun:		1,
 /*	present:		0,*/
@@ -172,25 +178,24 @@
 	//unsigned int base    = SCpnt->host->io_port;
 	unsigned char target = SCpnt->target;
 #endif
+	nsp_hw_data *data = &nsp_data;
 
 	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
 	      SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
-	//DEBUG(0, " before CurrentSC=0x%p\n", nsp_data.CurrentSC);
+	//DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC);
 
-	if(nsp_data.CurrentSC != NULL) {
+	if(data->CurrentSC != NULL) {
 		printk(KERN_DEBUG " " __FUNCTION__ "() CurrentSC!=NULL this can't be happen\n");
-		nsp_data.CurrentSC = NULL;
-		SCpnt->result	   = DID_BAD_TARGET << 16;
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_BAD_TARGET << 16;
 		done(SCpnt);
-		return FAILED;
+		return FALSE;
 	}
 
-#ifdef PCMCIA_DEBUG
 	show_command(SCpnt);
-#endif
 
 	SCpnt->scsi_done	= done;
-	nsp_data.CurrentSC	= SCpnt;
+	data->CurrentSC		= SCpnt;
 	RESID		        = SCpnt->request_bufflen;
 
 	SCpnt->SCp.Status	= -1;
@@ -217,62 +222,63 @@
 		SCpnt->SCp.buffers_residual = 0;
 	}
 
-	if(nsphw_start_selection(SCpnt) == FALSE) {
+	if(nsphw_start_selection(SCpnt, data) == FALSE) {
 		DEBUG(0, " selection fail\n");
-		nsp_data.CurrentSC = NULL;
-		SCpnt->result	   = DID_NO_CONNECT << 16;
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
 		done(SCpnt);
-		return FAILED;
+		return FALSE;
 	}
 
 
 	//DEBUG(0, __FUNCTION__ "() out\n");
-	return SUCCESS;
+	return TRUE;
 }
 
 /*
  * setup PIO FIFO transfer mode and enable/disable to data out
  */
-static void nsp_setup_fifo(unsigned int base, int enabled)
+static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
 {
-	unsigned char transfer_mode;
+	unsigned int  base = data->BaseAddress;
+	unsigned char transfer_mode_reg;
 
 	//DEBUG(0, __FUNCTION__ "() enabled=%d\n", enabled);
 
 	if (enabled != FALSE) {
-		transfer_mode = TRANSFER_GO | BRAIND;
+		transfer_mode_reg = TRANSFER_GO | BRAIND;
 	} else {
-		transfer_mode = 0;
+		transfer_mode_reg = 0;
 	}
 
-	transfer_mode |= nsp_data.TransferMode;
+	transfer_mode_reg |= data->TransferMode;
 
-	nsp_index_write(base, TRANSFERMODE, transfer_mode);
+	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
 }
 
 /*
  * Initialize Ninja hardware
  */
-static int nsphw_init(void)
+static int nsphw_init(nsp_hw_data *data)
 {
-	unsigned int base     = nsp_data.BaseAddress;
+	unsigned int base     = data->BaseAddress;
 	int	     i, j;
 	sync_data    tmp_sync = { SyncNegotiation: SYNC_NOT_YET,
 				  SyncPeriod:	   0,
 				  SyncOffset:	   0
 	};
 
-	//DEBUG(0, __FUNCTION__ "() in\n");
+	DEBUG(0, __FUNCTION__ "() in base=0x%x\n", base);
 
-	nsp_data.ScsiClockDiv = CLOCK_40M;
-	nsp_data.CurrentSC    = NULL;
-	nsp_data.FifoCount    = 0;
-	nsp_data.TransferMode = MODE_IO8;
+	data->ScsiClockDiv = CLOCK_40M;
+	data->CurrentSC    = NULL;
+	data->FifoCount    = 0;
+	data->TransferMode = MODE_IO8;
 
 	/* setup sync data */
 	for ( i = 0; i < N_TARGET; i++ ) {
 		for ( j = 0; j < N_LUN; j++ ) {
-			nsp_data.Sync[i][j] = tmp_sync;
+			data->Sync[i][j] = tmp_sync;
 		}
 	}
 
@@ -285,7 +291,7 @@
 	nsp_index_write(base, SCSIIRQMODE,  0);
 
 	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
-	nsp_index_write(base, CLOCKDIV,	    nsp_data.ScsiClockDiv);
+	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);
 
 	nsp_index_write(base, PARITYCTRL,   0);
 	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
@@ -313,7 +319,7 @@
 					    SCSI_RESET_IRQ_EI	 );
 	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
 
-	nsp_setup_fifo(base, FALSE);
+	nsp_setup_fifo(data, FALSE);
 
 	return TRUE;
 }
@@ -321,7 +327,8 @@
 /*
  * Start selection phase
  */
-static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt)
+static unsigned int nsphw_start_selection(Scsi_Cmnd   *SCpnt,
+					  nsp_hw_data *data)
 {
 	unsigned int  host_id	 = SCpnt->host->this_id;
 	unsigned int  base	 = SCpnt->host->io_port;
@@ -331,7 +338,6 @@
 
 	//DEBUG(0, __FUNCTION__ "()in\n");
 
-
 	phase = nsp_index_read(base, SCSIBUSMON);
 	if(phase != BUSMON_BUS_FREE) {
 		//DEBUG(0, " bus busy\n");
@@ -371,8 +377,8 @@
 	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN);
 
 	/* check selection timeout */
-	nsp_start_timer(SCpnt, 1000/51);
-	nsp_data.SelectionTimeOut = 1;
+	nsp_start_timer(SCpnt, data, 1000/51);
+	data->SelectionTimeOut = 1;
 
 	return TRUE;
 }
@@ -402,11 +408,11 @@
 /*
  * setup synchronous data transfer mode
  */
-static int nsp_msg(Scsi_Cmnd *SCpnt)
+static int nsp_msg(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned char	       target = SCpnt->target;
 	unsigned char	       lun    = SCpnt->lun;
-	sync_data	      *sync   = &(nsp_data.Sync[target][lun]);
+	sync_data	      *sync   = &(data->Sync[target][lun]);
 	struct nsp_sync_table *sync_table;
 	unsigned int	       period, offset;
 	int		       i;
@@ -421,7 +427,7 @@
 
 	DEBUG(0, " period=0x%x, offset=0x%x\n", period, offset);
 
-	if (nsp_data.ScsiClockDiv == CLOCK_20M) {
+	if (data->ScsiClockDiv == CLOCK_20M) {
 		sync_table = &nsp_sync_table_20M[0];
 	} else {
 		sync_table = &nsp_sync_table_40M[0];
@@ -440,17 +446,19 @@
 		 */
 		DEBUG(0, " no proper period/offset\n");
 
-		sync->SyncPeriod   = 0;
-		sync->SyncOffset   = 0;
-		sync->SyncRegister = 0;
-		sync->AckWidth	   = 0;
+		sync->SyncPeriod      = 0;
+		sync->SyncOffset      = 0;
+		sync->SyncRegister    = 0;
+		sync->AckWidth	      = 0;
+		sync->SyncNegotiation = SYNC_OK;
 
 		return FALSE;
 	}
 
-	sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
-			     (offset & SYNCREG_OFFSET_MASK);
-	sync->AckWidth	   = sync_table->ack_width;
+	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
+		                (offset & SYNCREG_OFFSET_MASK);
+	sync->AckWidth	      = sync_table->ack_width;
+	sync->SyncNegotiation = SYNC_OK;
 
 	DEBUG(0, " sync_reg=0x%x, ack_width=0x%x\n", sync->SyncRegister, sync->AckWidth);
 
@@ -461,12 +469,12 @@
 /*
  * start ninja hardware timer
  */
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time)
 {
 	unsigned int base = SCpnt->host->io_port;
 
 	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);
-	nsp_data.TimerCount = time;
+	data->TimerCount = time;
 	nsp_index_write(base, TIMERCOUNT, time);
 }
 
@@ -535,16 +543,15 @@
 /*
  * transfer SCSI message
  */
-static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
+static int nsp_xfer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int phase)
 {
 	unsigned int  base = SCpnt->host->io_port;
-	char	     *buf  = nsp_data.MsgBuffer;
-	int	      len  = MIN(MSGBUF_SIZE, nsp_data.MsgLen);
+	char	     *buf  = data->MsgBuffer;
+	int	      len  = MIN(MSGBUF_SIZE, data->MsgLen);
 	int	      ptr;
 	int	      ret;
 
 	//DEBUG(0, __FUNCTION__ "()\n");
-/**!**/
 	for (ptr = 0; len > 0; len --, ptr ++) {
 
 		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
@@ -554,16 +561,16 @@
 		}
 
 		/* if last byte, negate ATN */
-		if (len == 1) {
+		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
 			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
 		}
 
 		/* read & write message */
 		if (phase & BUSMON_IO) {
-			//DEBUG(0, " read msg\n");
+			DEBUG(0, " read msg\n");
 			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
 		} else {
-			//DEBUG(0, " write msg\n");
+			DEBUG(0, " write msg\n");
 			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
 		}
 		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
@@ -575,9 +582,8 @@
 /*
  * get extra SCSI data from fifo
  */
-static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
+static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
-	unsigned int base = SCpnt->host->io_port;
 	unsigned int count;
 
 	//DEBUG(0, __FUNCTION__ "()\n");
@@ -587,7 +593,7 @@
 	}
 
 	count = nsp_fifo_count(SCpnt);
-	if (nsp_data.FifoCount == count) {
+	if (data->FifoCount == count) {
 		//DEBUG(0, " not use bypass quirk\n");
 		return 0;
 	}
@@ -597,8 +603,8 @@
 	 * data phase skip only occures in case of SCSI_LOW_READ
 	 */
 	SCpnt->SCp.phase = PH_DATA;
-	nsp_pio_read(SCpnt);
-	nsp_setup_fifo(base, FALSE);
+	nsp_pio_read(SCpnt, data);
+	nsp_setup_fifo(data, FALSE);
 
 	DEBUG(0, " use bypass quirk\n");
 	return 0;
@@ -607,7 +613,7 @@
 /*
  * accept reselection
  */
-static int nsp_reselected(Scsi_Cmnd *SCpnt)
+static int nsp_reselected(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base = SCpnt->host->io_port;
 	unsigned char reg;
@@ -616,7 +622,7 @@
 
 	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
 
-	nsp_nexus(SCpnt);
+	nsp_nexus(SCpnt, data);
 	reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
 	nsp_index_write(base, SCSIBUSCTRL, reg);
 	nsp_index_write(base, SCSIBUSCTRL, reg | AUTODIRECTION | ACKENB);
@@ -653,14 +659,14 @@
 /*
  * read data in DATA IN phase
  */
-static void nsp_pio_read(Scsi_Cmnd *SCpnt)
+static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base     = SCpnt->host->io_port;
 	int	      time_out, i;
 	int	      ocount, res;
 	unsigned char stat, fifo_stat;
 
-	ocount = nsp_data.FifoCount;
+	ocount = data->FifoCount;
 
 	DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
 
@@ -693,7 +699,7 @@
 
 		res = MIN(res, SCpnt->SCp.this_residual);
 
-		switch (nsp_data.TransferMode) {
+		switch (data->TransferMode) {
 		case MODE_IO32:
 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
 			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
@@ -725,7 +731,7 @@
 		time_out = jiffies + 10 * HZ;
 	}
 
-	nsp_data.FifoCount = ocount;
+	data->FifoCount = ocount;
 
 	if (!i) {
 		printk(KERN_DEBUG __FUNCTION__ "() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
@@ -736,16 +742,16 @@
 /*
  * write data in DATA OUT phase
  */
-static void nsp_pio_write(Scsi_Cmnd *SCpnt)
+static void nsp_pio_write(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
 	unsigned int  base     = SCpnt->host->io_port;
 	int	      time_out, i;
 	unsigned int  ocount, res;
 	unsigned char stat;
 
-	ocount	 = nsp_data.FifoCount;
+	ocount	 = data->FifoCount;
 
-	DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", nsp_data.FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+	DEBUG(0, __FUNCTION__ "() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID);
 
 	time_out = jiffies + 10 * HZ;
 
@@ -767,7 +773,7 @@
 		res = MIN(SCpnt->SCp.this_residual, WFIFO_CRIT);
 
 		//DEBUG(0, " ptr=0x%p this=0x%x res=0x%x\n", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
-		switch (nsp_data.TransferMode) {
+		switch (data->TransferMode) {
 		case MODE_IO32:
 			res &= ~(BIT(1)|BIT(0)); /* align 4 */
 			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
@@ -798,7 +804,7 @@
 		time_out = jiffies + 10 * HZ;
 	}
 
-	nsp_data.FifoCount = ocount;
+	data->FifoCount = ocount;
 
 	if (!i) {
 		printk(KERN_DEBUG __FUNCTION__ "() pio write timeout resid=%d\n", RESID);
@@ -812,12 +818,12 @@
 /*
  * setup synchronous/asynchronous data transfer mode
  */
-static int nsp_nexus(Scsi_Cmnd *SCpnt)
+static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
 {
-	unsigned int  base   = SCpnt->host->io_port;
-	unsigned char target = SCpnt->target;
-	unsigned char lun    = SCpnt->lun;
-	sync_data *sync = &(nsp_data.Sync[target][lun]);
+	unsigned int   base   = SCpnt->host->io_port;
+	unsigned char  target = SCpnt->target;
+	unsigned char  lun    = SCpnt->lun;
+	sync_data     *sync   = &(data->Sync[target][lun]);
 
 	//DEBUG(0, __FUNCTION__ "() in SCpnt=0x%p\n", SCpnt);
 
@@ -827,16 +833,16 @@
 
 	if (RESID % 4 != 0   ||
 	    RESID     <= 256 ) {
-		nsp_data.TransferMode = MODE_IO8;
+		data->TransferMode = MODE_IO8;
 	} else {
-		nsp_data.TransferMode = MODE_IO32;
+		data->TransferMode = MODE_IO32;
 	}
 
 	/* setup pdma fifo */
-	nsp_setup_fifo(base, TRUE);
+	nsp_setup_fifo(data, TRUE);
 
 	/* clear ack counter */
-	nsp_data.FifoCount = 0;
+	data->FifoCount = 0;
 	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
 					  ACK_COUNTER_CLEAR |
 					  REQ_COUNTER_CLEAR |
@@ -845,6 +851,7 @@
 	return 0;
 }
 
+#include "nsp_message.c"
 /*
  * interrupt handler
  */
@@ -853,13 +860,25 @@
 	unsigned int   base;
 	unsigned char  i_src, irq_phase, phase;
 	Scsi_Cmnd     *tmpSC;
-	int	       ret, len;
-	unsigned char  data_reg, control_reg;
-
-
-	//DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC);
+	int            len;
+	unsigned char  target, lun;
+	unsigned int  *sync_neg;
+	int            i, tmp;
+	nsp_hw_data   *data;
+
+	//printk("&nsp_data=0x%p, dev_id=0x%p\n", &nsp_data, dev_id);
+
+	/* sanity check */
+	if (&nsp_data != dev_id) {
+		DEBUG(0, " irq conflict? this can't happen\n");
+		return;
+	}
+	data = dev_id;
+	if (irq != data->IrqNumber) {
+		return;
+	}
 
-	base = nsp_data.BaseAddress;
+	base = data->BaseAddress;
 	//DEBUG(0, " base=0x%x\n", base);
 
 	/*
@@ -891,16 +910,16 @@
 	/*
 	 * timer interrupt handler (scsi vs timer interrupts)
 	 */
-	//DEBUG(0, " timercount=%d\n", nsp_data.TimerCount);
-	if (nsp_data.TimerCount != 0) {
+	//DEBUG(0, " timercount=%d\n", data->TimerCount);
+	if (data->TimerCount != 0) {
 		//DEBUG(0, " stop timer\n");
 		nsp_index_write(base, TIMERCOUNT, 0);
 		nsp_index_write(base, TIMERCOUNT, 0);
-		nsp_data.TimerCount = 0;
+		data->TimerCount = 0;
 	}
 
 	if ((i_src & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
-	    nsp_data.SelectionTimeOut == 0) {
+	    data->SelectionTimeOut == 0) {
 		//DEBUG(0, " timer start\n");
 		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
 		return;
@@ -908,11 +927,14 @@
 
 	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
 
-	if (nsp_data.CurrentSC == NULL) {
+	if (data->CurrentSC == NULL) {
 		printk(KERN_DEBUG __FUNCTION__ " CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", i_src, phase, irq_phase);
 		return;
 	} else {
-		tmpSC = nsp_data.CurrentSC;
+		tmpSC    = data->CurrentSC;
+		target   = tmpSC->target;
+		lun      = tmpSC->lun;
+		sync_neg = &(data->Sync[target][lun].SyncNegotiation);
 	}
 
 	/*
@@ -921,8 +943,8 @@
 	if ((i_src & IRQSTATUS_SCSI) != 0) {
 		if ((irq_phase & SCSI_RESET_IRQ) != 0) {
 			printk(KERN_DEBUG " " __FUNCTION__ "() bus reset (power off?)\n");
-
-			nsp_data.CurrentSC = NULL;
+			*sync_neg          = SYNC_NOT_YET;
+			data->CurrentSC    = NULL;
 			tmpSC->result	   = DID_RESET << 16;
 			tmpSC->scsi_done(tmpSC);
 			return;
@@ -931,7 +953,7 @@
 		if ((irq_phase & RESELECT_IRQ) != 0) {
 			DEBUG(0, " reselect\n");
 			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
-			if (nsp_reselected(tmpSC) != FALSE) {
+			if (nsp_reselected(tmpSC, data) != FALSE) {
 				return;
 			}
 		}
@@ -945,28 +967,29 @@
 
 	switch(tmpSC->SCp.phase) {
 	case PH_SELSTART:
+		*sync_neg = SYNC_NOT_YET;
 		if ((phase & BUSMON_BSY) == 0) {
-			//DEBUG(0, " selection count=%d\n", nsp_data.SelectionTimeOut);
-			if (nsp_data.SelectionTimeOut >= NSP_SELTIMEOUT) {
+			//DEBUG(0, " selection count=%d\n", data->SelectionTimeOut);
+			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
 				DEBUG(0, " selection time out\n");
-				nsp_data.SelectionTimeOut = 0;
+				data->SelectionTimeOut = 0;
 				nsp_index_write(base, SCSIBUSCTRL, 0);
 
-				nsp_data.CurrentSC = NULL;
-				tmpSC->result	   = DID_NO_CONNECT << 16;
+				data->CurrentSC = NULL;
+				tmpSC->result   = DID_NO_CONNECT << 16;
 				tmpSC->scsi_done(tmpSC);
 
 				return;
 			}
-			nsp_data.SelectionTimeOut += 1;
-			nsp_start_timer(tmpSC, 1000/51);
+			data->SelectionTimeOut += 1;
+			nsp_start_timer(tmpSC, data, 1000/51);
 			return;
 		}
 
 		/* attention assert */
 		//DEBUG(0, " attention assert\n");
-		nsp_data.SelectionTimeOut = 0;
-		tmpSC->SCp.phase	  = PH_SELECTED;
+		data->SelectionTimeOut = 0;
+		tmpSC->SCp.phase       = PH_SELECTED;
 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
 		udelay(1);
 		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
@@ -976,16 +999,17 @@
 
 	case PH_RESELECT:
 		//DEBUG(0, " phase reselect\n");
+		*sync_neg = SYNC_NOT_YET;
 		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
 
-			nsp_data.CurrentSC = NULL;
-			tmpSC->result	   = DID_ABORT << 16;
+			data->CurrentSC = NULL;
+			tmpSC->result	= DID_ABORT << 16;
 			tmpSC->scsi_done(tmpSC);
 			return;
 		}
 		/* fall thru */
 	default:
-		if (( i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
+		if ((i_src & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
 			return;
 		}
 		break;
@@ -999,8 +1023,9 @@
 	/* normal disconnect */
 	if ((irq_phase & LATCHED_BUS_FREE) != 0) {
 		//DEBUG(0, " normal disconnect i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
-		if ((tmpSC->SCp.Message == 0)) {     /* all command complete and return status */
-			nsp_data.CurrentSC = NULL;
+		if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) {     /* all command complete and return status */
+			*sync_neg       = SYNC_NOT_YET;
+			data->CurrentSC = NULL;
 			tmpSC->result = (DID_OK		    << 16) |
 					(tmpSC->SCp.Message <<	8) |
 					(tmpSC->SCp.Status  <<	0);
@@ -1017,8 +1042,9 @@
 	if (phase == 0) {
 		printk(KERN_DEBUG " " __FUNCTION__ " unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", i_src, phase, irq_phase);
 
-		nsp_data.CurrentSC = NULL;
-		tmpSC->result	   = DID_ERROR << 16;
+		*sync_neg       = SYNC_NOT_YET;
+		data->CurrentSC = NULL;
+		tmpSC->result   = DID_ERROR << 16;
 		tmpSC->scsi_done(tmpSC);
 		return;
 	}
@@ -1033,7 +1059,7 @@
 
 		tmpSC->SCp.phase = PH_COMMAND;
 
-		nsp_nexus(tmpSC);
+		nsp_nexus(tmpSC, data);
 
 		/* write scsi command */
 		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
@@ -1049,7 +1075,7 @@
 		tmpSC->SCp.phase = PH_DATA;
 		tmpSC->SCp.have_data_in = IO_OUT;
 
-		nsp_pio_write(tmpSC);
+		nsp_pio_write(tmpSC, data);
 
 		break;
 
@@ -1059,12 +1085,12 @@
 		tmpSC->SCp.phase = PH_DATA;
 		tmpSC->SCp.have_data_in = IO_IN;
 
-		nsp_pio_read(tmpSC);
+		nsp_pio_read(tmpSC, data);
 
 		break;
 
 	case BUSPHASE_STATUS:
-		nsp_dataphase_bypass(tmpSC);
+		nsp_dataphase_bypass(tmpSC, data);
 		DEBUG(0, " BUSPHASE_STATUS\n");
 
 		tmpSC->SCp.phase = PH_STATUS;
@@ -1082,78 +1108,64 @@
 
 		tmpSC->SCp.phase = PH_MSG_OUT;
 
-		/*
-		 * XXX: NSP QUIRK
-		 * NSP invoke interrupts only in the case of scsi phase changes,
-		 * therefore we should poll the scsi phase here to catch 
-		 * the next "msg out" if exists (no scsi phase changes).
-		 */
-		ret = 16;
-		len = 0;
-
-		nsp_msg(tmpSC);
-
-		nsp_data.MsgBuffer[len] = IDENTIFY(TRUE, tmpSC->lun); len++;
-		nsp_data.MsgLen		= len;
-
-		do {
-			DEBUG(0, " msgout loop\n");
-
-			if (nsp_xfer(tmpSC, BUSPHASE_MESSAGE_OUT)) {
-				printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n");
-			}
-
-			/* catch a next signal */
-			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
-		} while (ret > 0 && len-- > 0);
+		data->MsgLen = len = 0;
+		if (*sync_neg == SYNC_NOT_YET) {
+			data->Sync[target][lun].SyncPeriod = 0;
+			data->Sync[target][lun].SyncOffset = 0;
+			nsp_msg(tmpSC, data);
+
+			data->MsgBuffer[len] = IDENTIFY(TRUE, lun); len++;
+			/*
+			data->MsgBuffer[len] = MSG_EXTENDED;        len++;
+			data->MsgBuffer[len] = 3;                   len++;
+			data->MsgBuffer[len] = MSG_EXT_SDTR;        len++;
+			data->MsgBuffer[len] = 0x0c;                len++;
+			data->MsgBuffer[len] = 15;                  len++;
+			*/
+		}
+		if (len == 0) {
+			data->MsgBuffer[len] = MSG_NO_OPERATION; len++;
+		}
+		data->MsgLen = len;
 
+		show_message(data);
+		nsp_message_out(tmpSC, data);
 		break;
 
 	case BUSPHASE_MESSAGE_IN:
-		nsp_dataphase_bypass(tmpSC);
+		nsp_dataphase_bypass(tmpSC, data);
 		DEBUG(0, " BUSPHASE_MESSAGE_IN\n");
 		if ((phase & BUSMON_REQ) == 0) {
 			goto timer_out;
 		}
 
 		tmpSC->SCp.phase = PH_MSG_IN;
+		nsp_message_in(tmpSC, data);
 
 		/*
-		 * XXX: NSP QUIRK
-		 * NSP invoke interrupts only in the case of scsi phase changes,
-		 * therefore we should poll the scsi phase here to catch 
-		 * the next "msg in" if exists (no scsi phase changes).
-		 */
-		ret = 16;
-		len = 0;
-
-		do {
-			//DEBUG(0, " msgin loop\n");
-			/* read data */
-			data_reg = nsp_index_read(base, SCSIDATAIN);
-
-			/* assert ACK */
-			control_reg = nsp_index_read(base, SCSIBUSCTRL);
-			control_reg |= SCSI_ACK;
-			nsp_index_write(base, SCSIBUSCTRL, control_reg);
-			nsp_negate_signal(tmpSC, BUSMON_REQ, "msgin<REQ>");
-
-			nsp_data.MsgBuffer[len] = data_reg; len++;
-			DEBUG(0, " msg=0x%x\n", data_reg);
-
-			/* deassert ACK */
-			control_reg =  nsp_index_read(base, SCSIBUSCTRL);
-			control_reg &= ~SCSI_ACK;
-			nsp_index_write(base, SCSIBUSCTRL, control_reg);
-
-			/* catch a next signal */
-			ret = nsp_expect_signal(tmpSC, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
-		} while (ret > 0 && MSGBUF_SIZE > len);
+		if (data->MsgLen       >= 5            &&
+		    data->MsgBuffer[0] == MSG_EXTENDED &&
+		    data->MsgBuffer[1] == 3            &&
+		    data->MsgBuffer[2] == MSG_EXT_SDTR ) {
+			data->Sync[target][lun].SyncPeriod = data->MsgBuffer[3];
+			data->Sync[target][lun].SyncOffset = data->MsgBuffer[4];
+			nsp_msg(tmpSC, data);
+		}
+		*/
+
+		/* search last messeage byte */
+		tmp = -1;
+		for (i = 0; i < data->MsgLen; i++) {
+			tmp = data->MsgBuffer[i];
+			if (data->MsgBuffer[i] == MSG_EXTENDED) {
+				i += (1 + data->MsgBuffer[i+1]);
+			}
+		}
+		tmpSC->SCp.Message = tmp;
 
-		nsp_data.MsgLen	   = len;
-		tmpSC->SCp.Message = nsp_data.MsgBuffer[len-1];
+		DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, data->MsgLen);
+		show_message(data);
 
-		//DEBUG(0, " message=0x%x len=%d\n", tmpSC->SCp.Message, nsp_data.MsgLen);
 		break;
 
 	case BUSPHASE_SELECT:
@@ -1167,7 +1179,7 @@
 	return;	
 
 timer_out:
-	nsp_start_timer(tmpSC, 1000/102);
+	nsp_start_timer(tmpSC, data, 1000/102);
 	return;
 }
 
@@ -1175,6 +1187,136 @@
 #include "nsp_debug.c"
 #endif	/* DBG_SHOWCOMMAND */
 
+/*----------------------------------------------------------------*/
+/* look for ninja3 card and init if found			  */
+/*----------------------------------------------------------------*/
+static int nsp_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	nsp_hw_data *data = &nsp_data;
+
+	DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
+
+	request_region(data->BaseAddress, data->NumAddress, "nsp_cs");
+	host		  = scsi_register(sht, 0);
+	host->io_port	  = data->BaseAddress;
+	host->unique_id	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->irq	  = data->IrqNumber;
+	host->dma_channel = -1;
+
+	sprintf(nspinfo,
+/* Buffer size is 100 bytes */
+/*  0         1         2         3         4         5         6         7         8         9         0*/
+/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
+   "NinjaSCSI-3/32Bi Driver version 2.7, I/O 0x%04lx-0x%04lx IRQ %2d",
+		host->io_port, host->io_port + host->n_io_port,
+		host->irq);
+	sht->name	  = nspinfo;
+
+	DEBUG(0, __FUNCTION__ " end\n");
+
+	return 1; /* detect done. */
+}
+
+static int nsp_release(struct Scsi_Host *shpnt)
+{
+	nsp_hw_data *data = &nsp_data;
+
+        if (shpnt->irq) {
+                free_irq(shpnt->irq, data);
+	}
+        if (shpnt->io_port) {
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	}
+	return 0;
+}
+
+/*----------------------------------------------------------------*/
+/* return info string						  */
+/*----------------------------------------------------------------*/
+static const char *nsp_info(struct Scsi_Host *shpnt)
+{
+	return nspinfo;
+}
+
+/*---------------------------------------------------------------*/
+/* error handler                                                 */
+/*---------------------------------------------------------------*/
+static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p why=%d\n", SCpnt, why);
+
+	return nsp_eh_bus_reset(SCpnt);
+}
+
+static int nsp_abort(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	nsp_eh_bus_reset(SCpnt);
+
+	return SUCCESS;
+}
+
+/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
+{
+	return FAILED;
+}*/
+
+static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	nsp_eh_bus_reset(SCpnt);
+	return SUCCESS;
+}
+
+static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	DEBUG(0, __FUNCTION__ " SCpnt=0x%p\n", SCpnt);
+
+	return FAILED;
+}
+
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->host->io_port;
+	int	     i;
+
+	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p base=0x%x\n", SCpnt, base);
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+
+	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
+	mdelay(100); /* 100ms */
+	nsp_index_write(base, SCSIBUSCTRL, 0);
+	for(i = 0; i < 5; i++) {
+		nsp_index_read(base, IRQPHASESENCE); /* dummy read */
+	}
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+
+	return SUCCESS;
+}
+
+static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = &nsp_data;
+
+	DEBUG(0, __FUNCTION__ "\n");
+
+	nsphw_init(data);
+	nsp_eh_bus_reset(SCpnt);
+
+	return SUCCESS;
+}
+
+
+/**********************************************************************
+  PCMCIA functions
+  *********************************************************************/
+
 /*====================================================================*/
 static void cs_error(client_handle_t handle, int func, int ret)
 {
@@ -1183,7 +1325,7 @@
 }
 
 /*======================================================================
-    nsp_attach() creates an "instance" of the driver, allocating
+    nsp_cs_attach() creates an "instance" of the driver, allocating
     local data structures for one device.  The device is registered
     with Card Services.
 
@@ -1191,7 +1333,7 @@
     configure the card at this point -- we wait until we receive a
     card insertion event.
 ======================================================================*/
-static dev_link_t *nsp_attach(void)
+static dev_link_t *nsp_cs_attach(void)
 {
 	scsi_info_t  *info;
 	client_reg_t  client_reg;
@@ -1202,13 +1344,13 @@
 
 	/* Create new SCSI device */
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
-	if (!info) return NULL;
+	if (!info) { return NULL; }
 	memset(info, 0, sizeof(*info));
 	link = &info->link;
 	link->priv = info;
 
 	/* Initialize the dev_link_t structure */
-	link->release.function	 = &nsp_release;
+	link->release.function	 = &nsp_cs_release;
 	link->release.data	 = (u_long)link;
 
 	/* The io structure describes IO port mapping */
@@ -1227,6 +1369,7 @@
 		}
 	}
 	link->irq.Handler	 = &nspintr;
+	link->irq.Instance       = &nsp_data;
 
 	/* General socket configuration */
 	link->conf.Attributes	 = CONF_ENABLE_IRQ;
@@ -1244,18 +1387,18 @@
 		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
 		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET	|
 		CS_EVENT_PM_SUSPEND	| CS_EVENT_PM_RESUME	 ;
-	client_reg.event_handler = &nsp_event;
+	client_reg.event_handler = &nsp_cs_event;
 	client_reg.Version	 = 0x0210;
 	client_reg.event_callback_args.client_data = link;
 	ret = CardServices(RegisterClient, &link->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
 		cs_error(link->handle, RegisterClient, ret);
-		nsp_detach(link);
+		nsp_cs_detach(link);
 		return NULL;
 	}
 
 	return link;
-} /* nsp_attach */
+} /* nsp_cs_attach */
 
 
 /*======================================================================
@@ -1264,7 +1407,7 @@
     structures are freed.  Otherwise, the structures will be freed
     when the device is released.
 ======================================================================*/
-static void nsp_detach(dev_link_t *link)
+static void nsp_cs_detach(dev_link_t *link)
 {
 	dev_link_t **linkp;
 
@@ -1282,7 +1425,7 @@
 
 	del_timer(&link->release);
 	if (link->state & DEV_CONFIG) {
-		nsp_release((u_long)link);
+		nsp_cs_release((u_long)link);
 		if (link->state & DEV_STALE_CONFIG) {
 			link->state |= DEV_STALE_LINK;
 			return;
@@ -1298,11 +1441,11 @@
 	*linkp = link->next;
 	kfree(link->priv);
 
-} /* nsp_detach */
+} /* nsp_cs_detach */
 
 
 /*======================================================================
-    nsp_config() is scheduled to run after a CARD_INSERTION event
+    nsp_cs_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
 ======================================================================*/
@@ -1312,7 +1455,7 @@
 if (CardServices(fn, args) != 0) goto next_entry
 /*====================================================================*/
 
-static void nsp_config(dev_link_t *link)
+static void nsp_cs_config(dev_link_t *link)
 {
 	client_handle_t	  handle = link->handle;
 	scsi_info_t	 *info	 = link->priv;
@@ -1324,6 +1467,7 @@
 	Scsi_Device	 *dev;
 	dev_node_t	**tail, *node;
 	struct Scsi_Host *host;
+	nsp_hw_data      *data = &nsp_data;
 
 	DEBUG(0, __FUNCTION__ "() in\n");
 
@@ -1369,14 +1513,14 @@
 	release_region(link->io.BasePort1, link->io.NumPorts1);
 
 	/* Set port and IRQ */
-	nsp_data.BaseAddress = link->io.BasePort1;
-	nsp_data.NumAddress  = link->io.NumPorts1;
-	nsp_data.IrqNumber   = link->irq.AssignedIRQ;
+	data->BaseAddress = link->io.BasePort1;
+	data->NumAddress  = link->io.NumPorts1;
+	data->IrqNumber   = link->irq.AssignedIRQ;
 
 	DEBUG(0, __FUNCTION__ " I/O[0x%x+0x%x] IRQ %d\n",
-	      nsp_data.BaseAddress, nsp_data.NumAddress, nsp_data.IrqNumber);
+	      data->BaseAddress, data->NumAddress, data->IrqNumber);
 
-	if(nsphw_init() == FALSE) {
+	if(nsphw_init(data) == FALSE) {
 		goto cs_failed;
 	}
 
@@ -1446,19 +1590,19 @@
 
 cs_failed:
 	cs_error(link->handle, last_fn, last_ret);
-	nsp_release((u_long)link);
+	nsp_cs_release((u_long)link);
 	return;
 
-} /* nsp_config */
+} /* nsp_cs_config */
 #undef CS_CHECK
 #undef CFG_CHECK
 
 /*======================================================================
-    After a card is removed, nsp_release() will unregister the net
+    After a card is removed, nsp_cs_release() will unregister the net
     device, and release the PCMCIA configuration.  If the device is
     still open, this will be postponed until it is closed.
 ======================================================================*/
-static void nsp_release(u_long arg)
+static void nsp_cs_release(u_long arg)
 {
 	dev_link_t *link = (dev_link_t *)arg;
 
@@ -1492,9 +1636,9 @@
 	link->state &= ~DEV_CONFIG;
 
 	if (link->state & DEV_STALE_LINK) {
-		nsp_detach(link);
+		nsp_cs_detach(link);
 	}
-} /* nsp_release */
+} /* nsp_cs_release */
 
 /*======================================================================
 
@@ -1509,7 +1653,7 @@
     the card is still present.
     
 ======================================================================*/
-static int nsp_event(event_t		    event,
+static int nsp_cs_event(event_t		    event,
 		     int		    priority,
 		     event_callback_args_t *args)
 {
@@ -1532,7 +1676,7 @@
 		DEBUG(0, " event: insert\n");
 		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 		info->bus    =  args->bus;
-		nsp_config(link);
+		nsp_cs_config(link);
 		break;
 
 	case CS_EVENT_PM_SUSPEND:
@@ -1556,11 +1700,9 @@
 
 			CardServices(RequestConfiguration, link->handle, &link->conf);
 			tmp.host = info->host;
-			nsp_reset(&tmp, 0);
+			nsp_eh_host_reset(&tmp);
 		}
 		info->stop = 0;
-		/* restart IO */
-		nsphw_init();
 		break;
 
 	default:
@@ -1569,110 +1711,12 @@
 	}
 	DEBUG(0, __FUNCTION__ " end\n");
 	return 0;
-} /* nsp_event */
-
-/*----------------------------------------------------------------*/
-/* look for ninja3 card and init if found			  */
-/*----------------------------------------------------------------*/
-static int nsp_detect(Scsi_Host_Template *sht)
-{
-	struct Scsi_Host *host;	/* registered host structure */
-
-	DEBUG(0, __FUNCTION__ " this_id=%d\n", sht->this_id);
-
-#if (KERNEL_VERSION(2,3,99) > LINUX_VERSION_CODE)
-	sht->proc_dir	  = &proc_scsi_nsp; /* kernel 2.2 */
-#else
-	sht->proc_name	  = "nsp_cs";	    /* kernel 2.4 */
-#endif
-
-	sht->this_id	  = SCSI_INITIATOR_ID;
-
-	request_region(nsp_data.BaseAddress, nsp_data.NumAddress,"nsp_cs");
-	host		  = scsi_register(sht, 0);
-	host->io_port	  = nsp_data.BaseAddress;
-	host->unique_id	  = nsp_data.BaseAddress;
-	host->n_io_port	  = nsp_data.NumAddress;
-	host->irq	  = nsp_data.IrqNumber;
-	host->dma_channel = -1;
-
-	sprintf(nspinfo,
-/* Buffer size is 100 bytes */
-/*  0         1         2         3         4         5         6         7         8         9         0*/
-/*  01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890*/
-   "NinjaSCSI-3/32Bi Driver version 2.0, I/O 0x%04lx-0x%04lx IRQ %2d",
-		host->io_port, host->io_port + host->n_io_port,
-		host->irq);
-	sht->name	  = nspinfo;
-
-	DEBUG(0, __FUNCTION__ " end\n");
-
-	return 1; /* detect done. */
-}
-
-
-/*----------------------------------------------------------------*/
-/* return info string						  */
-/*----------------------------------------------------------------*/
-static const char *nsp_info(struct Scsi_Host *host)
-{
-	return nspinfo;
-}
-
-static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int why)
-{
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p why=%d\n", SCpnt, why);
-
-	return nsp_eh_bus_reset(SCpnt);
-}
-
-static int nsp_abort(Scsi_Cmnd *SCpnt)
-{
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
-	return FAILED;
-}
-
-/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
-{
-}
-static int nsp_eh_abort(Scsi_Cmnd * cmd)
-{
-	DEBUG(0, __FUNCTION__"() SCpnt\n");
-}
-
-static nsp_eh_device_reset(Scsi_Cmnd *)
-{
-}
-*/
-static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
-	unsigned int base = SCpnt->host->io_port;
-	int	     i;
-
-	DEBUG(0, __FUNCTION__ "() SCpnt=0x%p\n", SCpnt);
-
-	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
-
-	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
-	mdelay(100); /* 100ms */
-	nsp_index_write(base, SCSIBUSCTRL, 0);
-	for(i = 0; i < 5; i++) {
-		(void) nsp_index_read(base, IRQPHASESENCE); /* dummy read */
-	}
-
-	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
-
-	return 0;
-}
-/*
-static nsp_eh_host_reset(Scsi_Cmnd *)
-{
-}*/
+} /* nsp_cs_event */
 
 /*======================================================================*
  *	module entry point
  *====================================================================*/
-static int __init nsp_init(void)
+static int __init nsp_cs_init(void)
 {
 	servinfo_t serv;
 
@@ -1684,27 +1728,27 @@
 		       "does not match!\n");
 		return -1;
 	}
-	register_pcmcia_driver(&dev_info, &nsp_attach, &nsp_detach);
+	register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
 
 	DEBUG(0, __FUNCTION__ "() out\n");
 	return 0;
 }
 
 
-static void __exit nsp_cleanup(void)
+static void __exit nsp_cs_cleanup(void)
 {
-	DEBUG(0, "nsp_cs: unloading\n");
+	DEBUG(0, __FUNCTION__ "() unloading\n");
 	unregister_pcmcia_driver(&dev_info);
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG) {
-			nsp_release((u_long)dev_list);
+			nsp_cs_release((u_long)dev_list);
 		}
-		nsp_detach(dev_list);
+		nsp_cs_detach(dev_list);
 	}
 }
 
-module_init(nsp_init);
-module_exit(nsp_cleanup);
+module_init(nsp_cs_init);
+module_exit(nsp_cs_cleanup);
 
 /*
  *
diff -urN linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_cs.h linux/drivers/scsi/pcmcia/nsp_cs.h
--- linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_cs.h	Wed Jul  4 11:50:38 2001
+++ linux/drivers/scsi/pcmcia/nsp_cs.h	Mon Dec  3 22:58:53 2001
@@ -6,11 +6,11 @@
     Ver 0.1 : Initial version.
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 
 =========================================================*/
 
-/* $Id: nsp_cs.h,v 1.18 2001/02/09 04:42:19 elca Exp $ */
+/* $Id: nsp_cs.h,v 1.21 2001/07/04 14:45:31 elca Exp $ */
 
 #ifndef  __nsp_cs__
 #define  __nsp_cs__
@@ -38,6 +38,8 @@
 /* SCSI initiator must be 7 */
 #define SCSI_INITIATOR_ID  7
 
+#define NSP_SELTIMEOUT 200
+
 /* base register */
 #define	IRQCONTROL	0x00
 #  define IRQCONTROL_RESELECT_CLEAR     BIT(0)
@@ -239,9 +241,9 @@
 	Scsi_Cmnd    *CurrentSC;
 
 	int           FifoCount;
-#if (KERNEL_VERSION(2,4,0) > LINUX_VERSION_CODE)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0))
 	int           Residual;
-#define RESID nsp_data.Residual
+#define RESID data->Residual
 #else
 #define RESID SCpnt->resid
 #endif
@@ -256,21 +258,30 @@
 } nsp_hw_data;
 
 
-static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt);
-static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time);
+static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time);
 
+static int nsp_eh_abort(Scsi_Cmnd * SCpnt);
+static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);
 static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt);
+static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt);
 
 static int nsp_fifo_count(Scsi_Cmnd *SCpnt);
-static void nsp_pio_read(Scsi_Cmnd *SCpnt);
-static int nsp_nexus(Scsi_Cmnd *SCpnt);
+static void nsp_pio_read(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
+static int nsp_nexus(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
 
 #ifdef PCMCIA_DEBUG
 # ifdef DBG_SHOWCOMMAND
 static void show_command(Scsi_Cmnd *ptr);
 static void show_phase(Scsi_Cmnd *SCpnt);
 static void show_busphase(unsigned char stat);
+static void show_message(nsp_hw_data *data);
 # endif /* DBG_SHOWCOMMAND */
+#else
+# define show_command(ptr)   /* */
+# define show_phase(SCpnt)   /* */
+# define show_busphase(stat) /* */
+# define show_message(data)  /* */
 #endif
 
 /*
@@ -297,6 +308,11 @@
 };
 
 
-#define NSP_SELTIMEOUT 200
+/* SCSI messaage */
+#define MSG_COMMAND_COMPLETE 0x00
+#define MSG_EXTENDED         0x01
+#define MSG_NO_OPERATION     0x08
+
+#define MSG_EXT_SDTR         0x01
 
 #endif  /*__nsp_cs__*/
diff -urN linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_debug.c linux/drivers/scsi/pcmcia/nsp_debug.c
--- linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_debug.c	Wed Jul  4 11:50:38 2001
+++ linux/drivers/scsi/pcmcia/nsp_debug.c	Mon Dec  3 22:58:53 2001
@@ -3,10 +3,10 @@
       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
 
     This software may be used and distributed according to the terms of
-    the GNU General Public License.
+    the GNU Public License.
 =========================================================================*/
 
-/* $Id: nsp_debug.c,v 1.5 2001/02/08 08:08:58 elca Exp $ */
+/* $Id: nsp_debug.c,v 1.6 2001/07/04 14:43:53 elca Exp $ */
 
 /*
  * Show the command data of a command
@@ -193,3 +193,16 @@
 		break;
 	}
 }
+
+static void show_message(nsp_hw_data *data)
+{
+	int i;
+
+	printk(KERN_DEBUG "msg:");
+	for(i=0; i < data->MsgLen; i++) {
+		printk(" %02x", data->MsgBuffer[i]);
+	}
+	printk("\n");
+}
+
+/* end */
diff -urN linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_io.h linux/drivers/scsi/pcmcia/nsp_io.h
--- linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_io.h	Wed Jul  4 11:50:38 2001
+++ linux/drivers/scsi/pcmcia/nsp_io.h	Mon Dec  3 22:58:53 2001
@@ -3,7 +3,7 @@
       By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
  
   This software may be used and distributed according to the terms of
-  the GNU General Public License.
+  the GNU Public License.
 
   */
 
diff -urN linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_message.c linux/drivers/scsi/pcmcia/nsp_message.c
--- linux-2.4.8-pre4/drivers/scsi/pcmcia/nsp_message.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/scsi/pcmcia/nsp_message.c	Mon Dec  3 22:58:53 2001
@@ -0,0 +1,76 @@
+/*==========================================================================
+  NinjaSCSI-3 message handler
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+   This software may be used and distributed according to the terms of
+   the GNU Public License.
+ */
+
+/* $Id: nsp_message.c,v 1.6 2001/07/05 10:56:37 elca Exp $ */
+
+static void nsp_message_in(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+{
+	unsigned int  base = SCpnt->host->io_port;
+	unsigned char data_reg, control_reg;
+	int           ret, len;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg in" if exists (no scsi phase changes).
+	 */
+	ret = 16;
+	len = 0;
+
+	DEBUG(0, " msgin loop\n");
+	do {
+		/* read data */
+		data_reg = nsp_index_read(base, SCSIDATAIN);
+
+		/* assert ACK */
+		control_reg = nsp_index_read(base, SCSIBUSCTRL);
+		control_reg |= SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+		nsp_negate_signal(SCpnt, BUSMON_REQ, "msgin<REQ>");
+
+		data->MsgBuffer[len] = data_reg; len++;
+
+		/* deassert ACK */
+		control_reg =  nsp_index_read(base, SCSIBUSCTRL);
+		control_reg &= ~SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
+	} while (ret > 0 && MSGBUF_SIZE > len);
+
+	data->MsgLen = len;
+
+}
+
+static void nsp_message_out(Scsi_Cmnd *SCpnt, nsp_hw_data *data)
+{
+	int ret = 1;
+	int len = data->MsgLen;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg out" if exists (no scsi phase changes).
+	 */
+
+	DEBUG(0, " msgout loop\n");
+	do {
+		if (nsp_xfer(SCpnt, data, BUSPHASE_MESSAGE_OUT)) {
+			printk(KERN_DEBUG " " __FUNCTION__ " msgout: xfer short\n");
+		}
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
+	} while (ret > 0 && len-- > 0);
+
+}
+
+/* end */
diff -urN linux-2.4.8-pre4/drivers/scsi/qlogicfc.c linux/drivers/scsi/qlogicfc.c
--- linux-2.4.8-pre4/drivers/scsi/qlogicfc.c	Fri Apr 27 13:59:19 2001
+++ linux/drivers/scsi/qlogicfc.c	Mon Dec  3 22:58:53 2001
@@ -1337,21 +1337,10 @@
 		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
 	}
 
-	switch (Cmnd->cmnd[0]) {
-	case TEST_UNIT_READY:
-	case START_STOP:
-	        break;
-	case WRITE_10:
-	case WRITE_6:
-	case WRITE_BUFFER:
-	case MODE_SELECT:
+	if (Cmnd->sc_data_direction == SCSI_DATA_WRITE)
 		cmd->control_flags = cpu_to_le16(CFLAG_WRITE);
-		break;
-	default:
+	else 
 		cmd->control_flags = cpu_to_le16(CFLAG_READ);
-		break;
-	}
-
 
 	if (Cmnd->device->tagged_supported) {
 		if ((jiffies - hostdata->tag_ages[Cmnd->target]) > (2 * SCSI_TIMEOUT)) {
@@ -1870,6 +1859,11 @@
 
 	hostdata = (struct isp2x00_hostdata *) host->hostdata;
 
+	/*
+	 *	This cannot be right - PCI writes are posted
+	 *	(apparently this is hardware design flaw not software ?)
+	 */
+	 
 	outw(0x01, host->io_port + ISP_CTRL_STATUS);
 	udelay(100);
 	outw(HCCR_RESET, host->io_port + HOST_HCCR);
diff -urN linux-2.4.8-pre4/drivers/scsi/sd.c linux/drivers/scsi/sd.c
--- linux-2.4.8-pre4/drivers/scsi/sd.c	Thu Jul  5 11:28:17 2001
+++ linux/drivers/scsi/sd.c	Mon Dec  3 22:58:53 2001
@@ -762,8 +762,17 @@
 	 */
 
 	SRpnt = scsi_allocate_request(rscsi_disks[i].device);
+	if (!SRpnt) {
+		printk(KERN_WARNING "(sd_init_onedisk:) Request allocation failure.\n");
+		return i;
+	}
 
 	buffer = (unsigned char *) scsi_malloc(512);
+	if (!buffer) {
+		printk(KERN_WARNING "(sd_init_onedisk:) Memory allocation failure.\n");
+		scsi_release_request(SRpnt);
+		return i;
+	}
 
 	spintime = 0;
 
diff -urN linux-2.4.8-pre4/drivers/usb/usbkbd.c linux/drivers/usb/usbkbd.c
--- linux-2.4.8-pre4/drivers/usb/usbkbd.c	Tue Jun 12 15:53:37 2001
+++ linux/drivers/usb/usbkbd.c	Mon Dec  3 22:58:53 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: usbkbd.c,v 1.16 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: usbkbd.c,v 1.20 2001/04/26 08:34:49 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  USB HIDBP Keyboard support
  *
@@ -249,7 +249,7 @@
 			
 	input_register_device(&kbd->dev);
 
-	printk(KERN_INFO "input%d: %s on on usb%d:%d.%d\n",
+	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
 		 kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum);
 
 	return kbd;
diff -urN linux-2.4.8-pre4/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.8-pre4/fs/buffer.c	Mon Dec  3 22:58:44 2001
+++ linux/fs/buffer.c	Mon Dec  3 22:58:53 2001
@@ -194,16 +194,20 @@
 	} while (--count);
 }
 
+/*
+ * Write some buffers from the head of the dirty queue.
+ *
+ * This must be called with the LRU lock held, and will
+ * return without it!
+ */
 #define NRSYNC (32)
-static void write_unlocked_buffers(kdev_t dev)
+static int write_some_buffers(kdev_t dev)
 {
 	struct buffer_head *next;
 	struct buffer_head *array[NRSYNC];
 	unsigned int count;
 	int nr;
 
-repeat:
-	spin_lock(&lru_list_lock);
 	next = lru_list[BUF_DIRTY];
 	nr = nr_buffers_type[BUF_DIRTY] * 2;
 	count = 0;
@@ -224,7 +228,7 @@
 
 			spin_unlock(&lru_list_lock);
 			write_locked_buffers(array, count);
-			goto repeat;
+			return -EAGAIN;
 		}
 		unlock_buffer(bh);
 		put_bh(bh);
@@ -233,6 +237,18 @@
 
 	if (count)
 		write_locked_buffers(array, count);
+	return 0;
+}
+
+/*
+ * Write out all buffers on the dirty list.
+ */
+static void write_unlocked_buffers(kdev_t dev)
+{
+	do {
+		spin_lock(&lru_list_lock);
+	} while (write_some_buffers(dev));
+	run_task_queue(&tq_disk);
 }
 
 static int wait_for_locked_buffers(kdev_t dev, int index, int refile)
@@ -767,7 +783,7 @@
 	if (free_shortage())
 		page_launder(GFP_NOFS, 0);
 	if (!grow_buffers(size)) {
-		wakeup_bdflush(1);
+		wakeup_bdflush();
 		current->policy |= SCHED_YIELD;
 		__set_current_state(TASK_RUNNING);
 		schedule();
@@ -1078,7 +1094,19 @@
 
 	if (state < 0)
 		return;
-	wakeup_bdflush(state);
+	wakeup_bdflush();
+
+	/*
+	 * If we're getting a lot out of balance, start some IO ourselves.
+	 *
+	 * This only queues it, and does not actually start it - we'll let
+	 * bdflush do that, or let it happen as a result of a lot of calls
+	 * to balance_dirty() filling up the request queues.
+	 */
+	if (state > 0) {
+		spin_lock(&lru_list_lock);
+		write_some_buffers(dev);
+	}
 }
 
 static __inline__ void __mark_dirty(struct buffer_head *bh)
@@ -2400,7 +2428,7 @@
 			loop = 1;
 			goto cleaned_buffers_try_again;
 		}
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 	}
 	return 0;
 }
@@ -2524,69 +2552,11 @@
  * a limited number of buffers to the disks and then go back to sleep again.
  */
 
-/* This is the _only_ function that deals with flushing async writes
-   to disk.
-   NOTENOTENOTENOTE: we _only_ need to browse the DIRTY lru list
-   as all dirty buffers lives _only_ in the DIRTY lru list.
-   As we never browse the LOCKED and CLEAN lru lists they are infact
-   completly useless. */
-static int flush_dirty_buffers(int check_flushtime)
-{
-	struct buffer_head * bh, *next;
-	int flushed = 0, i;
-
- restart:
-	spin_lock(&lru_list_lock);
-	bh = lru_list[BUF_DIRTY];
-	if (!bh)
-		goto out_unlock;
-	for (i = nr_buffers_type[BUF_DIRTY]; i-- > 0; bh = next) {
-		next = bh->b_next_free;
-
-		if (!buffer_dirty(bh)) {
-			__refile_buffer(bh);
-			continue;
-		}
-		if (buffer_locked(bh))
-			continue;
-
-		if (check_flushtime) {
-			/* The dirty lru list is chronologically ordered so
-			   if the current bh is not yet timed out,
-			   then also all the following bhs
-			   will be too young. */
-			if (time_before(jiffies, bh->b_flushtime))
-				goto out_unlock;
-		} else {
-			if (++flushed > bdf_prm.b_un.ndirty)
-				goto out_unlock;
-		}
-
-		/* OK, now we are committed to write it out. */
-		get_bh(bh);
-		spin_unlock(&lru_list_lock);
-		ll_rw_block(WRITE, 1, &bh);
-		put_bh(bh);
-
-		if (current->need_resched)
-			schedule();
-		goto restart;
-	}
- out_unlock:
-	spin_unlock(&lru_list_lock);
-
-	return flushed;
-}
-
 DECLARE_WAIT_QUEUE_HEAD(bdflush_wait);
 
-void wakeup_bdflush(int block)
+void wakeup_bdflush(void)
 {
-	if (waitqueue_active(&bdflush_wait))
-		wake_up_interruptible(&bdflush_wait);
-
-	if (block)
-		flush_dirty_buffers(0);
+	wake_up_interruptible(&bdflush_wait);
 }
 
 /* 
@@ -2604,10 +2574,20 @@
 	sync_supers(0);
 	unlock_kernel();
 
-	flush_dirty_buffers(1);
-	/* must really sync all the active I/O request to disk here */
-	run_task_queue(&tq_disk);
-	return 0;
+	spin_lock(&lru_list_lock);
+	for (;;) {
+		if (write_some_buffers(NODEV)) {
+			struct buffer_head *bh;
+
+			spin_lock(&lru_list_lock);
+			bh = lru_list[BUF_DIRTY];
+			if (!time_before(jiffies, bh->b_flushtime))
+				continue;
+			spin_unlock(&lru_list_lock);
+		}
+		run_task_queue(&tq_disk);
+		return 0;
+	}
 }
 
 int block_sync_page(struct page *page)
@@ -2677,7 +2657,7 @@
 int bdflush(void *startup)
 {
 	struct task_struct *tsk = current;
-	int flushed;
+
 	/*
 	 *	We have a bare-bones task_struct, and really should fill
 	 *	in a few more things so "top" and /proc/2/{exe,root,cwd}
@@ -2700,14 +2680,8 @@
 	for (;;) {
 		CHECK_EMERGENCY_SYNC
 
-		flushed = flush_dirty_buffers(0);
-
-		/*
-		 * If there are still a lot of dirty buffers around,
-		 * skip the sleep and flush some more. Otherwise, we
-		 * go to sleep waiting a wakeup.
-		 */
-		if (!flushed || balance_dirty_state(NODEV) < 0) {
+		spin_lock(&lru_list_lock);
+		if (!write_some_buffers(NODEV) || balance_dirty_state(NODEV) < 0) {
 			run_task_queue(&tq_disk);
 			interruptible_sleep_on(&bdflush_wait);
 		}
diff -urN linux-2.4.8-pre4/fs/partitions/check.c linux/fs/partitions/check.c
--- linux-2.4.8-pre4/fs/partitions/check.c	Mon Dec  3 22:58:44 2001
+++ linux/fs/partitions/check.c	Mon Dec  3 22:58:53 2001
@@ -77,11 +77,23 @@
 };
 
 /*
+ *	This is ucking fugly but its probably the best thing for 2.4.x
+ *	Take it as a clear reminder than we should put the device name
+ *	generation in the object kdev_t points to in 2.5.
+ */
+ 
+#ifdef CONFIG_ARCH_S390
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
+EXPORT_SYMBOL(genhd_dasd_name);
+#endif
+
+/*
  * disk_name() is used by partition check code and the md driver.
  * It formats the devicename of the indicated disk into
  * the supplied buffer (of size at least 32), and returns
  * a pointer to that same buffer (for convenience).
  */
+
 char *disk_name (struct gendisk *hd, int minor, char *buf)
 {
 	unsigned int part;
@@ -96,6 +108,12 @@
 		if (pos >= 0)
 			return buf + pos;
 	}
+
+#ifdef CONFIG_ARCH_S390
+	if (genhd_dasd_name
+	    && genhd_dasd_name (buf, unit - 'a', part, hd) == 0)
+		return buf;
+#endif
 	/*
 	 * IDE devices use multiple major numbers, but the drives
 	 * are named as:  {hda,hdb}, {hdc,hdd}, {hde,hdf}, {hdg,hdh}..
diff -urN linux-2.4.8-pre4/fs/partitions/ibm.c linux/fs/partitions/ibm.c
--- linux-2.4.8-pre4/fs/partitions/ibm.c	Sun May 20 12:11:39 2001
+++ linux/fs/partitions/ibm.c	Mon Dec  3 22:58:53 2001
@@ -10,14 +10,14 @@
  * 02/13/00 VTOC partition support added
  */
 
-#include <linux/module.h>
+#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/genhd.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/blk.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>
 #include <linux/ioctl.h>
 #include <linux/version.h>
@@ -29,14 +29,6 @@
 #include "check.h"
 #include <asm/vtoc.h>
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-/* We hook in when DASD is a module... */
-int (*genhd_dasd_name)(char*,int,int,struct gendisk*) = NULL;
-int (*genhd_dasd_fillgeo)(int,struct hd_geometry *) = NULL;
-EXPORT_SYMBOL(genhd_dasd_fillgeo);
-EXPORT_SYMBOL(genhd_dasd_name);
-#endif /* LINUX_IS_24 */
-
 typedef enum {
   ibm_partition_lnx1 = 0,
   ibm_partition_vol1 = 1,
@@ -50,6 +42,73 @@
 			     [ibm_partition_none] = "(nonl)"
 };
 
+static int
+get_drive_geometry(int kdev,struct hd_geometry *geo) 
+{
+	int rc = 0;
+	mm_segment_t old_fs;
+	struct file *filp;
+	struct inode *inode;
+        /* find out offset of volume label (partn table) */
+        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+        if ( filp == NULL ) {
+                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
+r filp\n");
+                return -ENOMEM;
+        }
+        memset(filp,0,sizeof(struct file));
+        filp ->f_mode = 1; /* read only */
+        inode = get_empty_inode();
+	if ( inode == NULL )
+		return -ENOMEM;
+        inode -> i_rdev = kdev;
+	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
+	rc = blkdev_open(inode,filp);
+        if ( rc == 0 ) {
+		old_fs=get_fs();
+		set_fs(KERNEL_DS);
+		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, HDIO_GETGEO, 
+						     (unsigned long)(geo))
+			;
+		set_fs(old_fs);
+	}
+	blkdev_put(inode->i_bdev,BDEV_FILE);
+	return rc;
+}
+
+static int
+get_drive_info(int kdev,dasd_information_t *info) 
+{
+	int rc = 0;
+	mm_segment_t old_fs;
+	struct file *filp;
+	struct inode *inode;
+        /* find out offset of volume label (partn table) */
+        filp = (struct file *)kmalloc (sizeof(struct file),GFP_KERNEL);
+        if ( filp == NULL ) {
+                printk (KERN_WARNING __FILE__ " ibm_partition: kmalloc failed fo
+r filp\n");
+                return -ENOMEM;
+        }
+        memset(filp,0,sizeof(struct file));
+        filp ->f_mode = 1; /* read only */
+        inode = get_empty_inode();
+	if ( inode == NULL )
+		return -ENOMEM;
+        inode -> i_rdev = kdev;
+	inode -> i_bdev = bdget(kdev_t_to_nr(kdev));
+        rc = blkdev_open(inode,filp);
+        if ( rc == 0 ) {
+		old_fs=get_fs();
+		set_fs(KERNEL_DS);
+		rc = inode-> i_bdev -> bd_op->ioctl (inode, filp, BIODASDINFO, 
+						     (unsigned long)(info));
+		set_fs(old_fs);
+	}
+	blkdev_put(inode->i_bdev,BDEV_FILE);
+	return rc;
+}
+
 static ibm_partition_t
 get_partition_type ( char * type )
 {
@@ -110,38 +169,52 @@
 	ibm_partition_t partition_type;
 	char type[5] = {0,};
 	char name[7] = {0,};
-	struct hd_geometry geo;
+	struct hd_geometry *geo;
 	int blocksize;
 	int offset=0, size=0, psize=0, counter=0;
 	unsigned int blk;
 	format1_label_t f1;
 	volume_label_t vlabel;
+	dasd_information_t *info;
 
 	if ( first_sector != 0 ) {
 		BUG();
 	}
-	if ( !genhd_dasd_fillgeo ) {
+	info = (struct dasd_information_t *)kmalloc(sizeof(dasd_information_t),
+						    GFP_KERNEL);
+	if ( info == NULL )
+		return 0;
+	if (get_drive_info (dev,info)) 
+		return 0;
+	geo = (struct hd_geometry *)kmalloc(sizeof(struct hd_geometry),
+					    GFP_KERNEL);
+	if ( geo == NULL )
+		return 0;
+	if (get_drive_geometry (dev,geo)) 
 		return 0;
-	}
-	genhd_dasd_fillgeo(dev,&geo);
 	blocksize = hardsect_size[MAJOR(dev)][MINOR(dev)];
 	if ( blocksize <= 0 ) {
 		return 0;
 	}
-
+	
 	set_blocksize(dev, blocksize);  /* OUCH !! */
-	if ( ( bh = bread( dev, geo.start, blocksize) ) != NULL ) {
+	if ( ( bh = bread( dev, info->label_block, blocksize) ) != NULL ) {
 		strncpy ( type,bh -> b_data + 0, 4);
-		strncpy ( name,bh -> b_data + 4, 6);
+		if ((!info->FBA_layout) && (!strcmp(info->type,"ECKD"))) {
+		        
+		        strncpy ( name,bh -> b_data + 8, 6);
+		} else {
+		        strncpy ( name,bh -> b_data + 4, 6);		  
+		}
 		memcpy (&vlabel, bh->b_data, sizeof(volume_label_t));
         } else {
 		return 0;
 	}
 	EBCASC(type,4);
 	EBCASC(name,6);
-
+	
 	partition_type = get_partition_type(type);
-	printk ( "%6s/%6s:",part_names[partition_type],name);
+	printk ( "%4s/%8s:",part_names[partition_type],name);
 	switch ( partition_type ) {
 	case ibm_partition_cms1:
 		if (* (((long *)bh->b_data) + 13) != 0) {
@@ -152,38 +225,37 @@
 			size = (label[7]-1)*(blocksize>>9); 
 			printk ("(MDSK)");
 		} else {
-			offset = (geo.start + 1);
+			offset = (info->label_block + 1);
 			size = hd -> sizes[MINOR(dev)]<<1;
 		}
-		two_partitions( hd, MINOR(dev), blocksize, 
-				offset, size);
+		two_partitions( hd, MINOR(dev), blocksize, offset, size);
 		break;
 	case ibm_partition_lnx1: 
 	case ibm_partition_none:
-		offset = (geo.start + 1);
+		offset = (info->label_block + 1);
 		size = hd -> sizes[MINOR(dev)]<<1;
-		two_partitions( hd, MINOR(dev), blocksize, 
-				offset, size);
+		two_partitions( hd, MINOR(dev), blocksize, offset, size);
 		break;
-	case ibm_partition_vol1:
+	case ibm_partition_vol1: 
+		size = hd -> sizes[MINOR(dev)]<<1;
 		add_gd_partition(hd, MINOR(dev), 0, size);
-
+		
 		/* get block number and read then first format1 label */
-		blk = cchhb2blk(&vlabel.vtoc, &geo) + 1;
+		blk = cchhb2blk(&vlabel.vtoc, geo) + 1;
 		if ((buf = bread( dev, blk, blocksize)) != NULL) {
 		        memcpy (&f1, buf->b_data, sizeof(format1_label_t));
 			bforget(buf);
 		}
-
+		
 		while (f1.DS1FMTID == _ascebc['1']) {
-		        offset = cchh2blk(&f1.DS1EXT1.llimit, &geo);
-			psize  = cchh2blk(&f1.DS1EXT1.ulimit, &geo) - 
-				offset + 1;
+		        offset = cchh2blk(&f1.DS1EXT1.llimit, geo);
+			psize  = cchh2blk(&f1.DS1EXT1.ulimit, geo) - 
+				offset + geo->sectors;
 			
 			counter++;
 			add_gd_partition(hd, MINOR(dev) + counter, 
-					  offset * (blocksize >> 9),
-					  psize * (blocksize >> 9));
+					 offset * (blocksize >> 9),
+					 psize * (blocksize >> 9));
 			
 			blk++;
 			if ((buf = bread( dev, blk, blocksize)) != NULL) {
@@ -197,9 +269,8 @@
 		add_gd_partition( hd, MINOR(dev), 0, 0);
 		add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
 	}
-
+	
 	printk ( "\n" );
 	bforget(bh);
 	return 1;
 }
-
diff -urN linux-2.4.8-pre4/fs/read_write.c linux/fs/read_write.c
--- linux-2.4.8-pre4/fs/read_write.c	Tue Apr 17 14:36:44 2001
+++ linux/fs/read_write.c	Mon Dec  3 22:58:53 2001
@@ -15,6 +15,7 @@
 #include <asm/uaccess.h>
 
 struct file_operations generic_ro_fops = {
+	llseek:		generic_file_llseek,
 	read:		generic_file_read,
 	mmap:		generic_file_mmap,
 };
@@ -22,6 +23,34 @@
 ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
 {
 	return -EISDIR;
+}
+
+loff_t generic_file_llseek(struct file *file, loff_t offset, int origin)
+{
+	long long retval;
+
+	switch (origin) {
+		case 2:
+			offset += file->f_dentry->d_inode->i_size;
+			break;
+		case 1:
+			offset += file->f_pos;
+	}
+	retval = -EINVAL;
+	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
+		if (offset != file->f_pos) {
+			file->f_pos = offset;
+			file->f_reada = 0;
+			file->f_version = ++event;
+		}
+		retval = offset;
+	}
+	return retval;
+}
+
+loff_t no_llseek(struct file *file, loff_t offset, int origin)
+{
+	return -ESPIPE;
 }
 
 loff_t default_llseek(struct file *file, loff_t offset, int origin)
diff -urN linux-2.4.8-pre4/include/asm-i386/serial.h linux/include/asm-i386/serial.h
--- linux-2.4.8-pre4/include/asm-i386/serial.h	Fri Jul 20 12:53:55 2001
+++ linux/include/asm-i386/serial.h	Mon Dec  3 22:58:53 2001
@@ -31,7 +31,9 @@
 #else
 #define RS_TABLE_SIZE
 #endif
-	
+
+#define MCA_COM_FLAGS	(STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
+
 /*
  * The following define the access methods for the HUB6 card. All
  * access is through two ports for all 24 possible chips. The card is
@@ -113,12 +115,12 @@
 
 #ifdef CONFIG_MCA
 #define MCA_SERIAL_PORT_DFNS			\
-	{ 0, BASE_BAUD, 0x3220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x3228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x4228, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5220, 3, STD_COM_FLAGS },	\
-	{ 0, BASE_BAUD, 0x5228, 3, STD_COM_FLAGS },
+	{ 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS },	\
+	{ 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
 #else
 #define MCA_SERIAL_PORT_DFNS
 #endif
diff -urN linux-2.4.8-pre4/include/asm-s390/cache.h linux/include/asm-s390/cache.h
--- linux-2.4.8-pre4/include/asm-s390/cache.h	Mon Dec  3 22:58:44 2001
+++ linux/include/asm-s390/cache.h	Mon Dec  3 22:58:53 2001
@@ -12,6 +12,6 @@
 #define __ARCH_S390_CACHE_H
 
 #define L1_CACHE_BYTES     256
-#define L1_CACHE_SHIFT     16
+#define L1_CACHE_SHIFT     8
 
 #endif
diff -urN linux-2.4.8-pre4/include/asm-s390/dasd.h linux/include/asm-s390/dasd.h
--- linux-2.4.8-pre4/include/asm-s390/dasd.h	Mon Dec  3 22:58:44 2001
+++ linux/include/asm-s390/dasd.h	Mon Dec  3 22:58:53 2001
@@ -4,43 +4,39 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
+ * This file is the interface of the DASD device driver, which is exported to user space
+ * any future changes wrt the API will result in a change of the APIVERSION reported
+ * to userspace by the DASDAPIVER-ioctl
+ *
  * History of changes (starts July 2000)
- * 02/01/01 added dynamic registration of ioctls
+ * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
  */
 
 #ifndef DASD_H
 #define DASD_H
-
-#undef ERP_DEBUG               /* enable debug messages */
-#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
-#define CONFIG_DASD_DYNAMIC
-
 #include <linux/ioctl.h>
-#include <asm/irq.h>
 
-#define IOCTL_LETTER 'D'
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,0) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,1) 
-/* Issue a reserve/release command, rsp. */
-#define BIODASDRSRV    _IO(IOCTL_LETTER,2) /* reserve */
-#define BIODASDRLSE    _IO(IOCTL_LETTER,3) /* release */
-#define BIODASDSLCK    _IO(IOCTL_LETTER,4) /* steal lock */
-/* Read sense ID infpormation */
-#define BIODASDRSID    _IOR(IOCTL_LETTER,0,senseid_t)
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* translate blocknumber of partition to absolute */
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
+#define DASD_IOCTL_LETTER 'D'
 
-typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
-int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
-int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+#if (DASD_API_VERSION == 0)
 
-#define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
-#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct profile_info_t
+ * holds the profinling information 
+ */
+typedef struct dasd_profile_info_t {
+        unsigned int dasd_io_reqs;	 /* number of requests processed at all */
+        unsigned int dasd_io_sects;	 /* number of sectors processed at all */
+        unsigned int dasd_io_secs[32];	 /* histogram of request's sizes */
+        unsigned int dasd_io_times[32];	 /* histogram of requests's times */
+        unsigned int dasd_io_timps[32];	 /* histogram of requests's times per sector */
+        unsigned int dasd_io_time1[32];	 /* histogram of time from build to start */
+        unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
+        unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
+        unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+} dasd_profile_info_t;
 
 /* 
  * struct format_data_t
@@ -50,332 +46,65 @@
 	int start_unit; /* from track */
 	int stop_unit;  /* to track */
 	int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */
-} __attribute__ ((packed)) format_data_t;
-
-#define DASD_FORMAT_DEFAULT_START_UNIT 0
-#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
-#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
-#define DASD_FORMAT_DEFAULT_INTENSITY -1
-
-#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
-#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
-#define DASD_FORMAT_INTENS_INVALIDATE    0x04
-#define DASD_FORMAT_INTENS_CDL 0x08
-#ifdef __KERNEL__
-#include <linux/version.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-#include <asm/ccwcache.h>
-#include <linux/blk.h> 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#include <linux/blkdev.h> 
-#include <linux/devfs_fs_kernel.h>
-#endif
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/compatmac.h>
-
-#include <asm/s390dyn.h>
-#include <asm/todclk.h>
-#include <asm/debug.h>
-
-/* Kernel Version Compatibility section */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
-typedef struct request *request_queue_t;
-#define block_device_operations file_operations
-#define __setup(x,y) struct dasd_device_t
-#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops)
-#define register_disk(dd,dev,partn,ops,size) \
-do { \
-	dd->sizes[MINOR(dev)] = size >> 1; \
-	resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \
-} while(0)
-#define init_waitqueue_head(x) do { *x = NULL; } while(0)
-#define blk_cleanup_queue(x) do {} while(0)
-#define blk_init_queue(x...) do {} while(0)
-#define blk_queue_headactive(x...) do {} while(0)
-#define blk_queue_make_request(x) do {} while(0)
-#define list_empty(x) (0)
-#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
-do { \
-        blk_dev[d_major].request_fn = d_request_fn; \
-        blk_dev[d_major].queue = d_queue_fn; \
-        blk_dev[d_major].current_request = d_current; \
-} while(0)
-#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
-	major:D_MAJOR, \
-	major_name:D_NAME, \
-	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
-	max_nr:D_PER_MAJOR, \
-	nr_real:D_PER_MAJOR,
-static inline struct request * 
-dasd_next_request( request_queue_t *queue ) 
-{
-    return *queue;
-}
-static inline void 
-dasd_dequeue_request( request_queue_t * q, struct request *req )
-{
-        *q = req->next;
-        req->next = NULL;
-}
-#else
-#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
-do { \
-        blk_dev[d_major].queue = d_queue_fn; \
-} while(0)
-#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
-	major:D_MAJOR, \
-	major_name:D_NAME, \
-	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
-	nr_real:D_PER_MAJOR,
-static inline struct request * 
-dasd_next_request( request_queue_t *queue ) 
-{
-        return blkdev_entry_next_request(&queue->queue_head);
-}
-static inline void 
-dasd_dequeue_request( request_queue_t * q, struct request *req )
-{
-        blkdev_dequeue_request (req);
-}
-#endif
-
-/* dasd_range_t are used for dynamic device att-/detachment */
-typedef struct dasd_devreg_t {
-        devreg_t devreg; /* the devreg itself */
-        /* build a linked list of devregs, needed for cleanup */
-        struct list_head list;
-} dasd_devreg_t;
-
-typedef struct {
-	struct list_head list;
-	int no;
-	dasd_ioctl_fn_t handler;
-} dasd_ioctl_list_t;
-
-typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover              */
-	dasd_era_none = 0,	/* don't recover, everything alright */
-	dasd_era_msg = 1,	/* don't recover, just report...     */
-	dasd_era_recover = 2	/* recovery action recommended       */
-} dasd_era_t;
-
-/* BIT DEFINITIONS FOR SENSE DATA */
-#define DASD_SENSE_BIT_0 0x80
-#define DASD_SENSE_BIT_1 0x40
-#define DASD_SENSE_BIT_2 0x20
-#define DASD_SENSE_BIT_3 0x10
-
-#define check_then_set(where,from,to) \
-do { \
-        if ((*(where)) != (from) ) { \
-                printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
-                BUG(); \
-        } \
-        (*(where)) = (to); \
-} while (0)
-
-#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
-do { \
-        int d_devno = d_device->devinfo.devno; \
-        int d_irq = d_device->devinfo.irq; \
-        char *d_name = d_device->name; \
-        int d_major = MAJOR(d_device->kdev); \
-        int d_minor = MINOR(d_device->kdev); \
-        printk(d_loglevel PRINTK_HEADER \
-               "/dev/%s(%d:%d),%04X IRQ0x%x:" \
-               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
-} while(0)
-
-/* 
- * struct dasd_sizes_t
- * represents all data needed to access dasd with properly set up sectors
- */
-typedef
-struct dasd_sizes_t {
-	unsigned long blocks; /* size of volume in blocks */
-	unsigned int bp_block; /* bytes per block */
-	unsigned int s2b_shift; /* log2 (bp_block/512) */
-        unsigned int pt_block; /* from which block to read the partn table */
-} dasd_sizes_t;
+        int intensity;  
+} format_data_t;
 
-/* 
- * struct dasd_chanq_t 
- * represents a queue of channel programs related to a single device
- */
-typedef
-struct dasd_chanq_t {
-	ccw_req_t *head;
-	ccw_req_t *tail;
-} dasd_chanq_t;
-
-#define DASD_DEVICE_FORMAT_STRING "Device: %p"
-#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
-do {\
-        if ( d_device->debug_area != NULL )\
-        debug_sprintf_event(d_device->debug_area,d_level,\
-                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
-                    d_device, d_data);\
-} while(0);
-#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
-do {\
-        if ( d_device->debug_area != NULL )\
-        debug_sprintf_exception(d_device->debug_area,d_level,\
-                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
-                        d_device, d_data);\
-} while(0);
-
-#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
-#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
-do {\
-        if ( dasd_debug_area != NULL )\
-        debug_sprintf_event(dasd_debug_area, d_level,\
-                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
-                    d_fn, d_data);\
-} while(0);
-#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
-do {\
-        if ( dasd_debug_area != NULL )\
-        debug_sprintf_exception(dasd_debug_area, d_level,\
-                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
-                        d_fn, d_data);\
-} while(0);
-
-struct dasd_device_t;
-struct request;
+/*
+ * values to be used for format_data_t.intensity
+ * 0/8: normal format
+ * 1/9: also write record zero
+ * 3/11: also write home address
+ * 4/12: invalidate track
+ */
+#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
+#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
+#define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
+#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
 /* 
- * signatures for the functions of dasd_discipline_t 
- * make typecasts much easier
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
  */
-typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
-typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
-
-typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *);
-typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
-typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
-typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
-typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
-typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
-typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
-typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
-typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
-typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
-typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *);
-typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *);
-typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *);
-
-
-/*
- * the dasd_discipline_t is
- * sth like a table of virtual functions, if you think of dasd_eckd
- * inheriting dasd...
- * no, currently we are not planning to reimplement the driver in C++
- */
-typedef struct dasd_discipline_t {
-	char ebcname[8]; /* a name used for tagging and printks */
-        char name[8];		/* a name used for tagging and printks */
-	int max_blocks;	/* maximum number of blocks to be chained */
-	dasd_ck_id_fn_t id_check;	/* to check sense data */
-	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
-	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
-	dasd_do_analysis_fn_t do_analysis;	/* to complete the analysis of the volume */
-	dasd_fill_geometry_fn_t fill_geometry;	/* to set up hd_geometry */
-	dasd_io_starter_fn_t start_IO;
-        dasd_format_fn_t format_device;		/* to format the device */
-	dasd_error_examine_fn_t examine_error;
-	dasd_error_analyse_fn_t erp_action;
-	dasd_erp_analyse_fn_t erp_postaction;
-        dasd_cp_builder_fn_t build_cp_from_req;
-        dasd_dump_sense_fn_t dump_sense;
-        dasd_int_handler_fn_t int_handler;
-        dasd_reserve_fn_t reserve;
-        dasd_release_fn_t release;
-        dasd_merge_cp_fn_t merge_cp;
-	
-	struct dasd_discipline_t *next;	/* used for list of disciplines */
-} dasd_discipline_t;
-
-#define DASD_MAJOR_INFO_REGISTERED 1
-#define DASD_MAJOR_INFO_IS_STATIC 2
-
-typedef struct major_info_t {
-	struct list_head list;
-	struct dasd_device_t **dasd_device;
-	int flags;
-	struct gendisk gendisk; /* actually contains the major number */
-} __attribute__ ((packed)) major_info_t;
-
-typedef struct dasd_profile_info_t {
-        unsigned long dasd_io_reqs;	/* number of requests processed at all */
-        unsigned long dasd_io_secs[32];	/* histogram of request's sizes */
-        unsigned long dasd_io_times[32];	/* histogram of requests's times */
-        unsigned long dasd_io_timps[32];	/* histogram of requests's times per sector */
-        unsigned long dasd_io_time1[32];	/* histogram of time from build to start */
-       unsigned  long dasd_io_time2[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time2ps[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time3[32];	/* histogram of time from irq to end */
-} dasd_profile_info_t;
-
-typedef struct dasd_device_t {
-	s390_dev_info_t devinfo;
-	dasd_discipline_t *discipline;
-	int level;
-        int open_count;
-        kdev_t kdev;
-        major_info_t *major_info;
-	struct dasd_chanq_t queue;
-        wait_queue_head_t wait_q;
-        request_queue_t request_queue;
-        struct timer_list timer;      
-	devstat_t dev_status; /* needed ONLY!! for request_irq */
-        dasd_sizes_t sizes;
-        char name[16]; /* The name of the device in /dev */
-	char *private;	/* to be used by the discipline internally */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-        devfs_handle_t devfs_entry;
-#endif /* LINUX_IS_24 */
-	struct tq_struct bh_tq;
-        atomic_t bh_scheduled;
-        debug_info_t *debug_area;
-        dasd_profile_info_t profile;
-        struct proc_dir_entry *proc_dir; /* directory node */
-        struct proc_dir_entry *proc_info; /* information from dasd_device_t */
-        struct proc_dir_entry *proc_stats; /* statictics information */
-}  dasd_device_t;
-
-/* dasd_device_t.level can be: */
-#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
-#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
-#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
-#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
-#define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_ONLINE 0x10
-
-int dasd_init (void);
-void dasd_discipline_enq (dasd_discipline_t *);
-int dasd_discipline_deq(dasd_discipline_t *);
-int dasd_start_IO (ccw_req_t *);
-void dasd_int_handler (int , void *, struct pt_regs *);
-ccw_req_t *default_erp_action (ccw_req_t *);
-ccw_req_t *default_erp_postaction (ccw_req_t *);
-int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
-ccw_req_t *dasd_alloc_request (char *, int, int);
-void dasd_free_request (ccw_req_t *);
-extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
-extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
-int dasd_oper_handler (int irq, devreg_t * devreg);
-void dasd_schedule_bh (dasd_device_t *);
-
-#endif /* __KERNEL__ */
+typedef struct dasd_information_t {
+        unsigned int devno; /* S/390 devno */
+        unsigned int real_devno; /* for aliases */
+        unsigned int schid; /* S/390 subchannel identifier */
+        unsigned int cu_type  : 16; /* from SenseID */
+        unsigned int cu_model :  8; /* from SenseID */
+        unsigned int dev_type : 16; /* from SenseID */
+        unsigned int dev_model : 8; /* from SenseID */
+        unsigned int open_count; 
+        unsigned int req_queue_len; 
+        unsigned int chanq_len;
+        char type[4]; /* from discipline.name, 'none' for unknown */
+        unsigned int status; /* current device level */
+        unsigned int label_block; /* where to find the VOLSER */
+        unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
+        unsigned int characteristics_size;
+        unsigned int confdata_size;
+        char characteristics[64]; /* from read_device_characteristics */
+        char configuration_data[256]; /* from read_configuration_data */
+} dasd_information_t;
 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)  
+/* Issue a reserve/release command, rsp. */
+#define BIODASDRSRV    _IO(DASD_IOCTL_LETTER,2) /* reserve */
+#define BIODASDRLSE    _IO(DASD_IOCTL_LETTER,3) /* release */
+#define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
+/* reset profiling information of a device */
+#define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* retrieve API version number */
+#define DASDAPIVER     _IOR(DASD_IOCTL_LETTER,0,int)
+/* Get information on a dasd device */
+#define BIODASDINFO    _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+/* retrieve profiling information of a device */
+#define BIODASDPRRD    _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t)
+/* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
+#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
+#endif /* DASD_API_VERSION */
 #endif				/* DASD_H */
 
 /*
diff -urN linux-2.4.8-pre4/include/asm-s390/vtoc.h linux/include/asm-s390/vtoc.h
--- linux-2.4.8-pre4/include/asm-s390/vtoc.h	Wed Apr 11 19:02:28 2001
+++ linux/include/asm-s390/vtoc.h	Mon Dec  3 22:58:53 2001
@@ -15,41 +15,188 @@
 #include <linux/types.h>
 #include <linux/hdreg.h>
 #include <linux/version.h>
-#endif
 #include <asm/dasd.h>
+#endif
+
+#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
 #define VTOC_START_HH 0x1
+#define FIRST_USABLE_CYL 1
+#define FIRST_USABLE_TRK 2
+
+#define DASD_3380_TYPE 13148
+#define DASD_3390_TYPE 13200
+#define DASD_9345_TYPE 37701
+
+#define DASD_3380_VALUE 0xbb60
+#define DASD_3390_VALUE 0xe5a2
+#define DASD_9345_VALUE 0xbc98
+
+#define VOLSER_LENGTH 6
+#define BIG_DISK_SIZE 0x10000
+
+#define VTOC_ERROR "VTOC error:"
 
 enum failure {unable_to_open,
 	      unable_to_seek,
 	      unable_to_write,
 	      unable_to_read};
 
-typedef struct ttr {
+unsigned char ASCtoEBC[256] =
+{
+  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
+  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+  0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+  /*10  DL    D1    D2    D3    D4    NK    SN    EB */
+  0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+  /*18  CN    EM    SB    EC    FS    GS    RS    US */
+  0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
+  /*20  SP     !     "     #     $     %     &     ' */
+  0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+  /*28   (     )     *     +     ,     -    .      / */
+  0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+  /*30   0     1     2     3     4     5     6     7 */
+  0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+  /*38   8     9     :     ;     <     =     >     ? */
+  0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+  /*40   @     A     B     C     D     E     F     G */
+  0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+  /*48   H     I     J     K     L     M     N     O */
+  0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+  /*50   P     Q     R     S     T     U     V     W */
+  0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+  /*58   X     Y     Z     [     \     ]     ^     _ */
+  0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
+  /*60   `     a     b     c     d     e     f     g */
+  0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  /*68   h     i     j     k     l     m     n     o */
+  0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+  /*70   p     q     r     s     t     u     v     w */
+  0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+  /*78   x     y     z     {     |     }     ~    DL */
+  0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+
+unsigned char EBCtoASC[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     °     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     §  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+typedef struct ttr 
+{
         __u16 tt;
         __u8  r;
 } __attribute__ ((packed)) ttr_t;
 
-typedef struct cchhb {
+typedef struct cchhb 
+{
         __u16 cc;
         __u16 hh;
         __u8 b;
 } __attribute__ ((packed)) cchhb_t;
 
-typedef struct cchh {
+typedef struct cchh 
+{
         __u16 cc;
         __u16 hh;
 } __attribute__ ((packed)) cchh_t;
 
-typedef struct labeldate {
+typedef struct labeldate 
+{
         __u8  year;
         __u16 day;
 } __attribute__ ((packed)) labeldate_t;
 
 
-typedef struct volume_label {
+typedef struct volume_label 
+{
         char volkey[4];         /* volume key = volume label                 */
 	char vollbl[4];	        /* volume label                              */
 	char volid[6];	        /* volume identifier                         */
@@ -66,7 +213,8 @@
 } __attribute__ ((packed)) volume_label_t;
 
 
-typedef struct extent {
+typedef struct extent 
+{
         __u8  typeind;          /* extent type indicator                     */
         __u8  seqno;            /* extent sequence number                    */
         cchh_t llimit;          /* starting point of this extent             */
@@ -74,7 +222,8 @@
 } __attribute__ ((packed)) extent_t;
 
 
-typedef struct dev_const {
+typedef struct dev_const 
+{
         __u16 DS4DSCYL;           /* number of logical cyls                  */
         __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
         __u16 DS4DEVTK;           /* device track length                     */
@@ -88,7 +237,8 @@
 } __attribute__ ((packed)) dev_const_t;
 
 
-typedef struct format1_label {
+typedef struct format1_label 
+{
 	char  DS1DSNAM[44];       /* data set name                           */
 	__u8  DS1FMTID;           /* format identifier                       */
 	char  DS1DSSN[6];         /* data set serial number                  */
@@ -124,7 +274,8 @@
 } __attribute__ ((packed)) format1_label_t;
 
 
-typedef struct format4_label {
+typedef struct format4_label 
+{
 	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
         __u8  DS4IDFMT;           /* format identifier                       */
 	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
@@ -153,6 +304,43 @@
 } __attribute__ ((packed)) format4_label_t;
 
 
+typedef struct ds5ext 
+{
+	__u16 t;                  /* RTA of the first track of free extent   */
+	__u16 fc;                 /* number of whole cylinders in free ext.  */
+	__u8  ft;                 /* number of remaining free tracks         */
+} __attribute__ ((packed)) ds5ext_t;
+
+
+typedef struct format5_label 
+{
+	char DS5KEYID[4];         /* key identifier                          */
+	ds5ext_t DS5AVEXT;        /* first available (free-space) extent.    */
+	ds5ext_t DS5EXTAV[7];     /* seven available extents                 */
+	__u8 DS5FMTID;            /* format identifier                       */
+	ds5ext_t DS5MAVET[18];    /* eighteen available extents              */
+	cchhb_t DS5PTRDS[5];      /* pointer to next format5 DSCB            */
+} __attribute__ ((packed)) format5_label_t;
+
+
+typedef struct ds7ext 
+{
+	__u32 a;                  /* starting RTA value                      */
+	__u32 b;                  /* ending RTA value + 1                    */
+} __attribute__ ((packed)) ds7ext_t;
+
+
+typedef struct format7_label 
+{
+	char DS7KEYID[4];         /* key identifier                          */
+	ds7ext_t DS7EXTNT[5];     /* space for 5 extent descriptions         */
+	__u8 DS7FMTID;            /* format identifier                       */
+	ds7ext_t DS7ADEXT[11];    /* space for 11 extent descriptions        */
+	char res1[2];             /* reserved                                */
+	cchhb_t DS7PTRDS;         /* pointer to next FMT7 DSCB               */
+} __attribute__ ((packed)) format7_label_t;
+
+
 char * vtoc_ebcdic_enc (
         unsigned char source[LINE_LENGTH],
         unsigned char target[LINE_LENGTH],
@@ -181,45 +369,126 @@
         __u8 year,
         __u16 day);
 
+void vtoc_volume_label_init (
+	volume_label_t *vlabel);
 
 int vtoc_read_volume_label (
         char * device,
         unsigned long vlabel_start,
         volume_label_t * vlabel);
+
 int vtoc_write_volume_label (
-        char * device,
+        char *device,
         unsigned long vlabel_start,
-        volume_label_t * vlabel);
+        volume_label_t *vlabel);
+
+void vtoc_volume_label_set_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+char *vtoc_volume_label_get_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+void vtoc_volume_label_set_key (
+        volume_label_t *vlabel,
+        char *key);     
+
+void vtoc_volume_label_set_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
+char *vtoc_volume_label_get_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
 void vtoc_read_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
         format4_label_t *f4,
-        format1_label_t *f1);
+        format5_label_t *f5,
+        format7_label_t *f7);
+
 void vtoc_write_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
 	format4_label_t *f4,
-	format1_label_t *f1);
-void vtoc_init_format4_label (
-        struct hd_geometry *geo,
-        format4_label_t *f4lbl,
-	unsigned int usable_partitions,
-	unsigned int cylinders,
-	unsigned int tracks,
-	unsigned int blocks);
+	format5_label_t *f5,
+	format7_label_t *f7);
+
+
 void vtoc_init_format1_label (
         char *volid,
         unsigned int blksize,
         extent_t *part_extent,
         format1_label_t *f1);
+
+
+void vtoc_init_format4_label (
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks,
+	unsigned int blksize,
+	__u16 dev_type);
+
 void vtoc_update_format4_label (
 	format4_label_t *f4,
 	cchhb_t *highest_f1,
-	__u8 unused_update,
-	__u16 freespace_update);
+	__u16 unused_update);
+
 
+void vtoc_init_format5_label (
+	format5_label_t *f5);
 
+void vtoc_update_format5_label_add (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+ 
+void vtoc_update_format5_label_del (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+
+
+void vtoc_init_format7_label (
+	format7_label_t *f7);
+
+void vtoc_update_format7_label_add (
+	format7_label_t *f7,
+	int verbose,
+	__u32 a, 
+	__u32 b);
+
+void vtoc_update_format7_label_del (
+	format7_label_t *f7, 
+	int verbose,
+	__u32 a, 
+	__u32 b);
 
+
+void vtoc_set_freespace(
+	format4_label_t *f4,
+	format5_label_t *f5,
+	format7_label_t *f7,
+	char ch,
+	int verbose,
+	__u32 start,
+	__u32 stop,
+	int cyl,
+	int trk);
 
 
 
diff -urN linux-2.4.8-pre4/include/asm-s390x/cache.h linux/include/asm-s390x/cache.h
--- linux-2.4.8-pre4/include/asm-s390x/cache.h	Mon Dec  3 22:58:44 2001
+++ linux/include/asm-s390x/cache.h	Mon Dec  3 22:58:53 2001
@@ -12,6 +12,6 @@
 #define __ARCH_S390_CACHE_H
 
 #define L1_CACHE_BYTES     256
-#define L1_CACHE_SHIFT     16
+#define L1_CACHE_SHIFT     8
 
 #endif
diff -urN linux-2.4.8-pre4/include/asm-s390x/dasd.h linux/include/asm-s390x/dasd.h
--- linux-2.4.8-pre4/include/asm-s390x/dasd.h	Mon Dec  3 22:58:44 2001
+++ linux/include/asm-s390x/dasd.h	Mon Dec  3 22:58:53 2001
@@ -4,43 +4,39 @@
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
  *
+ * This file is the interface of the DASD device driver, which is exported to user space
+ * any future changes wrt the API will result in a change of the APIVERSION reported
+ * to userspace by the DASDAPIVER-ioctl
+ *
  * History of changes (starts July 2000)
- * 02/01/01 added dynamic registration of ioctls
+ * 05/04/01 created by moving the kernel interface to drivers/s390/block/dasd_int.h
  */
 
 #ifndef DASD_H
 #define DASD_H
-
-#undef ERP_DEBUG               /* enable debug messages */
-#undef ERP_FULL_ERP            /* enable full ERP - experimental code !!!! */
-#define CONFIG_DASD_DYNAMIC
-
 #include <linux/ioctl.h>
-#include <asm/irq.h>
 
-#define IOCTL_LETTER 'D'
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,0) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,1) 
-/* Issue a reserve/release command, rsp. */
-#define BIODASDRSRV    _IO(IOCTL_LETTER,2) /* reserve */
-#define BIODASDRLSE    _IO(IOCTL_LETTER,3) /* release */
-#define BIODASDSLCK    _IO(IOCTL_LETTER,4) /* steal lock */
-/* Read sense ID infpormation */
-#define BIODASDRSID    _IOR(IOCTL_LETTER,0,senseid_t)
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* translate blocknumber of partition to absolute */
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,0,int)
+#define DASD_IOCTL_LETTER 'D'
 
-typedef int(*dasd_ioctl_fn_t) (struct inode *inp, int no, long args);
-int dasd_ioctl_no_register(int no, dasd_ioctl_fn_t handler);
-int dasd_ioctl_no_unregister(int no, dasd_ioctl_fn_t handler);
+#if (DASD_API_VERSION == 0)
 
-#define DASD_NAME "dasd"
 #define DASD_PARTN_BITS 2
-#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct profile_info_t
+ * holds the profinling information 
+ */
+typedef struct dasd_profile_info_t {
+        unsigned int dasd_io_reqs;	 /* number of requests processed at all */
+        unsigned int dasd_io_sects;	 /* number of sectors processed at all */
+        unsigned int dasd_io_secs[32];	 /* histogram of request's sizes */
+        unsigned int dasd_io_times[32];	 /* histogram of requests's times */
+        unsigned int dasd_io_timps[32];	 /* histogram of requests's times per sector */
+        unsigned int dasd_io_time1[32];	 /* histogram of time from build to start */
+        unsigned int dasd_io_time2[32];	 /* histogram of time from start to irq */
+        unsigned int dasd_io_time2ps[32]; /* histogram of time from start to irq */
+        unsigned int dasd_io_time3[32];	 /* histogram of time from irq to end */
+} dasd_profile_info_t;
 
 /* 
  * struct format_data_t
@@ -50,332 +46,65 @@
 	int start_unit; /* from track */
 	int stop_unit;  /* to track */
 	int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */
-} __attribute__ ((packed)) format_data_t;
-
-#define DASD_FORMAT_DEFAULT_START_UNIT 0
-#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
-#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
-#define DASD_FORMAT_DEFAULT_INTENSITY -1
-
-#define DASD_FORMAT_INTENS_WRITE_RECZERO 0x01
-#define DASD_FORMAT_INTENS_WRITE_HOMEADR 0x02
-#define DASD_FORMAT_INTENS_INVALIDATE    0x04
-#define DASD_FORMAT_INTENS_CDL 0x08
-#ifdef __KERNEL__
-#include <linux/version.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-#include <asm/ccwcache.h>
-#include <linux/blk.h> 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-#include <linux/blkdev.h> 
-#include <linux/devfs_fs_kernel.h>
-#endif
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/compatmac.h>
-
-#include <asm/s390dyn.h>
-#include <asm/todclk.h>
-#include <asm/debug.h>
-
-/* Kernel Version Compatibility section */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
-typedef struct request *request_queue_t;
-#define block_device_operations file_operations
-#define __setup(x,y) struct dasd_device_t
-#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops)
-#define register_disk(dd,dev,partn,ops,size) \
-do { \
-	dd->sizes[MINOR(dev)] = size >> 1; \
-	resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \
-} while(0)
-#define init_waitqueue_head(x) do { *x = NULL; } while(0)
-#define blk_cleanup_queue(x) do {} while(0)
-#define blk_init_queue(x...) do {} while(0)
-#define blk_queue_headactive(x...) do {} while(0)
-#define blk_queue_make_request(x) do {} while(0)
-#define list_empty(x) (0)
-#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
-do { \
-        blk_dev[d_major].request_fn = d_request_fn; \
-        blk_dev[d_major].queue = d_queue_fn; \
-        blk_dev[d_major].current_request = d_current; \
-} while(0)
-#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
-	major:D_MAJOR, \
-	major_name:D_NAME, \
-	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
-	max_nr:D_PER_MAJOR, \
-	nr_real:D_PER_MAJOR,
-static inline struct request * 
-dasd_next_request( request_queue_t *queue ) 
-{
-    return *queue;
-}
-static inline void 
-dasd_dequeue_request( request_queue_t * q, struct request *req )
-{
-        *q = req->next;
-        req->next = NULL;
-}
-#else
-#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
-do { \
-        blk_dev[d_major].queue = d_queue_fn; \
-} while(0)
-#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \
-	major:D_MAJOR, \
-	major_name:D_NAME, \
-	minor_shift:D_PARTN_BITS, \
-	max_p:1 << D_PARTN_BITS, \
-	nr_real:D_PER_MAJOR,
-static inline struct request * 
-dasd_next_request( request_queue_t *queue ) 
-{
-        return blkdev_entry_next_request(&queue->queue_head);
-}
-static inline void 
-dasd_dequeue_request( request_queue_t * q, struct request *req )
-{
-        blkdev_dequeue_request (req);
-}
-#endif
-
-/* dasd_range_t are used for dynamic device att-/detachment */
-typedef struct dasd_devreg_t {
-        devreg_t devreg; /* the devreg itself */
-        /* build a linked list of devregs, needed for cleanup */
-        struct list_head list;
-} dasd_devreg_t;
-
-typedef struct {
-	struct list_head list;
-	int no;
-	dasd_ioctl_fn_t handler;
-} dasd_ioctl_list_t;
-
-typedef enum {
-	dasd_era_fatal = -1,	/* no chance to recover              */
-	dasd_era_none = 0,	/* don't recover, everything alright */
-	dasd_era_msg = 1,	/* don't recover, just report...     */
-	dasd_era_recover = 2	/* recovery action recommended       */
-} dasd_era_t;
-
-/* BIT DEFINITIONS FOR SENSE DATA */
-#define DASD_SENSE_BIT_0 0x80
-#define DASD_SENSE_BIT_1 0x40
-#define DASD_SENSE_BIT_2 0x20
-#define DASD_SENSE_BIT_3 0x10
-
-#define check_then_set(where,from,to) \
-do { \
-        if ((*(where)) != (from) ) { \
-                printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \
-                BUG(); \
-        } \
-        (*(where)) = (to); \
-} while (0)
-
-#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\
-do { \
-        int d_devno = d_device->devinfo.devno; \
-        int d_irq = d_device->devinfo.irq; \
-        char *d_name = d_device->name; \
-        int d_major = MAJOR(d_device->kdev); \
-        int d_minor = MINOR(d_device->kdev); \
-        printk(d_loglevel PRINTK_HEADER \
-               "/dev/%s(%d:%d),%04X IRQ0x%x:" \
-               d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \
-} while(0)
-
-/* 
- * struct dasd_sizes_t
- * represents all data needed to access dasd with properly set up sectors
- */
-typedef
-struct dasd_sizes_t {
-	unsigned long blocks; /* size of volume in blocks */
-	unsigned int bp_block; /* bytes per block */
-	unsigned int s2b_shift; /* log2 (bp_block/512) */
-        unsigned int pt_block; /* from which block to read the partn table */
-} dasd_sizes_t;
+        int intensity;  
+} format_data_t;
 
-/* 
- * struct dasd_chanq_t 
- * represents a queue of channel programs related to a single device
- */
-typedef
-struct dasd_chanq_t {
-	ccw_req_t *head;
-	ccw_req_t *tail;
-} dasd_chanq_t;
-
-#define DASD_DEVICE_FORMAT_STRING "Device: %p"
-#define DASD_DEVICE_DEBUG_EVENT(d_level, d_device, d_str, d_data...)\
-do {\
-        if ( d_device->debug_area != NULL )\
-        debug_sprintf_event(d_device->debug_area,d_level,\
-                    DASD_DEVICE_FORMAT_STRING d_str "\n",\
-                    d_device, d_data);\
-} while(0);
-#define DASD_DEVICE_DEBUG_EXCEPTION(d_level, d_device, d_str, d_data...)\
-do {\
-        if ( d_device->debug_area != NULL )\
-        debug_sprintf_exception(d_device->debug_area,d_level,\
-                        DASD_DEVICE_FORMAT_STRING d_str "\n",\
-                        d_device, d_data);\
-} while(0);
-
-#define DASD_DRIVER_FORMAT_STRING "Driver: <[%p]>"
-#define DASD_DRIVER_DEBUG_EVENT(d_level, d_fn, d_str, d_data...)\
-do {\
-        if ( dasd_debug_area != NULL )\
-        debug_sprintf_event(dasd_debug_area, d_level,\
-                    DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
-                    d_fn, d_data);\
-} while(0);
-#define DASD_DRIVER_DEBUG_EXCEPTION(d_level, d_fn, d_str, d_data...)\
-do {\
-        if ( dasd_debug_area != NULL )\
-        debug_sprintf_exception(dasd_debug_area, d_level,\
-                        DASD_DRIVER_FORMAT_STRING #d_fn ":" d_str "\n",\
-                        d_fn, d_data);\
-} while(0);
-
-struct dasd_device_t;
-struct request;
+/*
+ * values to be used for format_data_t.intensity
+ * 0/8: normal format
+ * 1/9: also write record zero
+ * 3/11: also write home address
+ * 4/12: invalidate track
+ */
+#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
+#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
+#define DASD_FMT_INT_INVAL  4 /* invalidate tracks */
+#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
 
 /* 
- * signatures for the functions of dasd_discipline_t 
- * make typecasts much easier
+ * struct dasd_information_t
+ * represents any data about the data, which is visible to userspace
  */
-typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
-typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr);
-
-typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *);
-typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
-typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
-typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
-typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
-typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
-typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
-typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
-typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
-typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
-typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
-typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *);
-typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *);
-typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *);
-
-
-/*
- * the dasd_discipline_t is
- * sth like a table of virtual functions, if you think of dasd_eckd
- * inheriting dasd...
- * no, currently we are not planning to reimplement the driver in C++
- */
-typedef struct dasd_discipline_t {
-	char ebcname[8]; /* a name used for tagging and printks */
-        char name[8];		/* a name used for tagging and printks */
-	int max_blocks;	/* maximum number of blocks to be chained */
-	dasd_ck_id_fn_t id_check;	/* to check sense data */
-	dasd_ck_characteristics_fn_t check_characteristics;	/* to check the characteristics */
-	dasd_init_analysis_fn_t init_analysis;	/* to start the analysis of the volume */
-	dasd_do_analysis_fn_t do_analysis;	/* to complete the analysis of the volume */
-	dasd_fill_geometry_fn_t fill_geometry;	/* to set up hd_geometry */
-	dasd_io_starter_fn_t start_IO;
-        dasd_format_fn_t format_device;		/* to format the device */
-	dasd_error_examine_fn_t examine_error;
-	dasd_error_analyse_fn_t erp_action;
-	dasd_erp_analyse_fn_t erp_postaction;
-        dasd_cp_builder_fn_t build_cp_from_req;
-        dasd_dump_sense_fn_t dump_sense;
-        dasd_int_handler_fn_t int_handler;
-        dasd_reserve_fn_t reserve;
-        dasd_release_fn_t release;
-        dasd_merge_cp_fn_t merge_cp;
-	
-	struct dasd_discipline_t *next;	/* used for list of disciplines */
-} dasd_discipline_t;
-
-#define DASD_MAJOR_INFO_REGISTERED 1
-#define DASD_MAJOR_INFO_IS_STATIC 2
-
-typedef struct major_info_t {
-	struct list_head list;
-	struct dasd_device_t **dasd_device;
-	int flags;
-	struct gendisk gendisk; /* actually contains the major number */
-} __attribute__ ((packed)) major_info_t;
-
-typedef struct dasd_profile_info_t {
-        unsigned long dasd_io_reqs;	/* number of requests processed at all */
-        unsigned long dasd_io_secs[32];	/* histogram of request's sizes */
-        unsigned long dasd_io_times[32];	/* histogram of requests's times */
-        unsigned long dasd_io_timps[32];	/* histogram of requests's times per sector */
-        unsigned long dasd_io_time1[32];	/* histogram of time from build to start */
-       unsigned  long dasd_io_time2[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time2ps[32];	/* histogram of time from start to irq */
-        unsigned long dasd_io_time3[32];	/* histogram of time from irq to end */
-} dasd_profile_info_t;
-
-typedef struct dasd_device_t {
-	s390_dev_info_t devinfo;
-	dasd_discipline_t *discipline;
-	int level;
-        int open_count;
-        kdev_t kdev;
-        major_info_t *major_info;
-	struct dasd_chanq_t queue;
-        wait_queue_head_t wait_q;
-        request_queue_t request_queue;
-        struct timer_list timer;      
-	devstat_t dev_status; /* needed ONLY!! for request_irq */
-        dasd_sizes_t sizes;
-        char name[16]; /* The name of the device in /dev */
-	char *private;	/* to be used by the discipline internally */
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-        devfs_handle_t devfs_entry;
-#endif /* LINUX_IS_24 */
-	struct tq_struct bh_tq;
-        atomic_t bh_scheduled;
-        debug_info_t *debug_area;
-        dasd_profile_info_t profile;
-        struct proc_dir_entry *proc_dir; /* directory node */
-        struct proc_dir_entry *proc_info; /* information from dasd_device_t */
-        struct proc_dir_entry *proc_stats; /* statictics information */
-}  dasd_device_t;
-
-/* dasd_device_t.level can be: */
-#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
-#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
-#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
-#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
-#define DASD_DEVICE_LEVEL_ANALYSED 0x08
-#define DASD_DEVICE_LEVEL_ONLINE 0x10
-
-int dasd_init (void);
-void dasd_discipline_enq (dasd_discipline_t *);
-int dasd_discipline_deq(dasd_discipline_t *);
-int dasd_start_IO (ccw_req_t *);
-void dasd_int_handler (int , void *, struct pt_regs *);
-ccw_req_t *default_erp_action (ccw_req_t *);
-ccw_req_t *default_erp_postaction (ccw_req_t *);
-int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *);
-ccw_req_t *dasd_alloc_request (char *, int, int);
-void dasd_free_request (ccw_req_t *);
-extern int (*genhd_dasd_name) (char *, int, int, struct gendisk *);
-extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
-int dasd_oper_handler (int irq, devreg_t * devreg);
-void dasd_schedule_bh (dasd_device_t *);
-
-#endif /* __KERNEL__ */
+typedef struct dasd_information_t {
+        unsigned int devno; /* S/390 devno */
+        unsigned int real_devno; /* for aliases */
+        unsigned int schid; /* S/390 subchannel identifier */
+        unsigned int cu_type  : 16; /* from SenseID */
+        unsigned int cu_model :  8; /* from SenseID */
+        unsigned int dev_type : 16; /* from SenseID */
+        unsigned int dev_model : 8; /* from SenseID */
+        unsigned int open_count; 
+        unsigned int req_queue_len; 
+        unsigned int chanq_len;
+        char type[4]; /* from discipline.name, 'none' for unknown */
+        unsigned int status; /* current device level */
+        unsigned int label_block; /* where to find the VOLSER */
+        unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
+        unsigned int characteristics_size;
+        unsigned int confdata_size;
+        char characteristics[64]; /* from read_device_characteristics */
+        char configuration_data[256]; /* from read_configuration_data */
+} dasd_information_t;
 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(DASD_IOCTL_LETTER,1)  
+/* Issue a reserve/release command, rsp. */
+#define BIODASDRSRV    _IO(DASD_IOCTL_LETTER,2) /* reserve */
+#define BIODASDRLSE    _IO(DASD_IOCTL_LETTER,3) /* release */
+#define BIODASDSLCK    _IO(DASD_IOCTL_LETTER,4) /* steal lock */
+/* reset profiling information of a device */
+#define BIODASDPRRST   _IO(DASD_IOCTL_LETTER,5)
+/* retrieve API version number */
+#define DASDAPIVER     _IOR(DASD_IOCTL_LETTER,0,int)
+/* Get information on a dasd device */
+#define BIODASDINFO    _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
+/* retrieve profiling information of a device */
+#define BIODASDPRRD    _IOR(DASD_IOCTL_LETTER,2,dasd_profile_info_t)
+/* #define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
+#define BIODASDFMT     _IOW(DASD_IOCTL_LETTER,1,format_data_t) 
+#endif /* DASD_API_VERSION */
 #endif				/* DASD_H */
 
 /*
diff -urN linux-2.4.8-pre4/include/asm-s390x/vtoc.h linux/include/asm-s390x/vtoc.h
--- linux-2.4.8-pre4/include/asm-s390x/vtoc.h	Wed Apr 11 19:02:29 2001
+++ linux/include/asm-s390x/vtoc.h	Mon Dec  3 22:58:53 2001
@@ -15,41 +15,188 @@
 #include <linux/types.h>
 #include <linux/hdreg.h>
 #include <linux/version.h>
-#endif
 #include <asm/dasd.h>
+#endif
+
+#define DASD_API_VERSION 0
 
 #define LINE_LENGTH 80
 #define VTOC_START_CC 0x0
 #define VTOC_START_HH 0x1
+#define FIRST_USABLE_CYL 1
+#define FIRST_USABLE_TRK 2
+
+#define DASD_3380_TYPE 13148
+#define DASD_3390_TYPE 13200
+#define DASD_9345_TYPE 37701
+
+#define DASD_3380_VALUE 0xbb60
+#define DASD_3390_VALUE 0xe5a2
+#define DASD_9345_VALUE 0xbc98
+
+#define VOLSER_LENGTH 6
+#define BIG_DISK_SIZE 0x10000
+
+#define VTOC_ERROR "VTOC error:"
 
 enum failure {unable_to_open,
 	      unable_to_seek,
 	      unable_to_write,
 	      unable_to_read};
 
-typedef struct ttr {
+unsigned char ASCtoEBC[256] =
+{
+  /*00  NL    SH    SX    EX    ET    NQ    AK    BL */
+  0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+  0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+  /*10  DL    D1    D2    D3    D4    NK    SN    EB */
+  0x10, 0x11, 0x12, 0x13, 0x3C, 0x15, 0x32, 0x26,
+  /*18  CN    EM    SB    EC    FS    GS    RS    US */
+  0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F,
+  /*20  SP     !     "     #     $     %     &     ' */
+  0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+  /*28   (     )     *     +     ,     -    .      / */
+  0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+  /*30   0     1     2     3     4     5     6     7 */
+  0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+  /*38   8     9     :     ;     <     =     >     ? */
+  0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+  /*40   @     A     B     C     D     E     F     G */
+  0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+  /*48   H     I     J     K     L     M     N     O */
+  0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+  /*50   P     Q     R     S     T     U     V     W */
+  0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+  /*58   X     Y     Z     [     \     ]     ^     _ */
+  0xE7, 0xE8, 0xE9, 0xAD, 0xE0, 0xBD, 0x5F, 0x6D,
+  /*60   `     a     b     c     d     e     f     g */
+  0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+  /*68   h     i     j     k     l     m     n     o */
+  0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+  /*70   p     q     r     s     t     u     v     w */
+  0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+  /*78   x     y     z     {     |     }     ~    DL */
+  0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+  0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0xFF
+};
+
+
+unsigned char EBCtoASC[256] =
+{
+ /* 0x00   NUL   SOH   STX   ETX  *SEL    HT  *RNL   DEL */
+          0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
+ /* 0x08   -GE  -SPS  -RPT    VT    FF    CR    SO    SI */
+          0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /* 0x10   DLE   DC1   DC2   DC3  -RES   -NL    BS  -POC
+                                  -ENP  ->LF             */
+          0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
+ /* 0x18   CAN    EM  -UBS  -CU1  -IFS  -IGS  -IRS  -ITB
+                                                    -IUS */
+          0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x20   -DS  -SOS    FS  -WUS  -BYP    LF   ETB   ESC
+                                  -INP                   */
+          0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
+ /* 0x28   -SA  -SFE   -SM  -CSP  -MFA   ENQ   ACK   BEL
+                       -SW                               */ 
+          0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
+ /* 0x30  ----  ----   SYN   -IR   -PP  -TRN  -NBS   EOT */
+          0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
+ /* 0x38  -SBS   -IT  -RFF  -CU3   DC4   NAK  ----   SUB */
+          0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
+ /* 0x40    SP   RSP           ä              ----       */
+          0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
+ /* 0x48                       .     <     (     +     | */
+          0x87, 0xA4, 0x9B, 0x2E, 0x3C, 0x28, 0x2B, 0x7C,
+ /* 0x50     &                                      ---- */
+          0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
+ /* 0x58           ß     !     $     *     )     ;       */
+          0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
+ /* 0x60     -     /  ----     Ä  ----  ----  ----       */
+          0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
+ /* 0x68              ----     ,     %     _     >     ? */ 
+          0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
+ /* 0x70  ----        ----  ----  ----  ----  ----  ---- */
+          0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ /* 0x78     *     `     :     #     @     '     =     " */
+          0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
+ /* 0x80     *     a     b     c     d     e     f     g */
+          0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ /* 0x88     h     i              ----  ----  ----       */
+          0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
+ /* 0x90     °     j     k     l     m     n     o     p */
+          0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
+ /* 0x98     q     r                    ----        ---- */
+          0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
+ /* 0xA0           ~     s     t     u     v     w     x */
+          0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ /* 0xA8     y     z              ----  ----  ----  ---- */
+          0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
+ /* 0xB0     ^                    ----     §  ----       */
+          0x5E, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
+ /* 0xB8        ----     [     ]  ----  ----  ----  ---- */
+          0xAB, 0x07, 0x5B, 0x5D, 0x07, 0x07, 0x07, 0x07,
+ /* 0xC0     {     A     B     C     D     E     F     G */
+          0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ /* 0xC8     H     I  ----           ö              ---- */
+          0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
+ /* 0xD0     }     J     K     L     M     N     O     P */
+          0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ /* 0xD8     Q     R  ----           ü                   */
+          0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
+ /* 0xE0     \           S     T     U     V     W     X */
+          0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ /* 0xE8     Y     Z        ----     Ö  ----  ----  ---- */
+          0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
+ /* 0xF0     0     1     2     3     4     5     6     7 */
+          0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ /* 0xF8     8     9  ----  ----     Ü  ----  ----  ---- */
+          0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
+};
+
+typedef struct ttr 
+{
         __u16 tt;
         __u8  r;
 } __attribute__ ((packed)) ttr_t;
 
-typedef struct cchhb {
+typedef struct cchhb 
+{
         __u16 cc;
         __u16 hh;
         __u8 b;
 } __attribute__ ((packed)) cchhb_t;
 
-typedef struct cchh {
+typedef struct cchh 
+{
         __u16 cc;
         __u16 hh;
 } __attribute__ ((packed)) cchh_t;
 
-typedef struct labeldate {
+typedef struct labeldate 
+{
         __u8  year;
         __u16 day;
 } __attribute__ ((packed)) labeldate_t;
 
 
-typedef struct volume_label {
+typedef struct volume_label 
+{
         char volkey[4];         /* volume key = volume label                 */
 	char vollbl[4];	        /* volume label                              */
 	char volid[6];	        /* volume identifier                         */
@@ -66,7 +213,8 @@
 } __attribute__ ((packed)) volume_label_t;
 
 
-typedef struct extent {
+typedef struct extent 
+{
         __u8  typeind;          /* extent type indicator                     */
         __u8  seqno;            /* extent sequence number                    */
         cchh_t llimit;          /* starting point of this extent             */
@@ -74,7 +222,8 @@
 } __attribute__ ((packed)) extent_t;
 
 
-typedef struct dev_const {
+typedef struct dev_const 
+{
         __u16 DS4DSCYL;           /* number of logical cyls                  */
         __u16 DS4DSTRK;           /* number of tracks in a logical cylinder  */
         __u16 DS4DEVTK;           /* device track length                     */
@@ -88,7 +237,8 @@
 } __attribute__ ((packed)) dev_const_t;
 
 
-typedef struct format1_label {
+typedef struct format1_label 
+{
 	char  DS1DSNAM[44];       /* data set name                           */
 	__u8  DS1FMTID;           /* format identifier                       */
 	char  DS1DSSN[6];         /* data set serial number                  */
@@ -124,7 +274,8 @@
 } __attribute__ ((packed)) format1_label_t;
 
 
-typedef struct format4_label {
+typedef struct format4_label 
+{
 	char  DS4KEYCD[44];       /* key code for VTOC labels: 44 times 0x04 */
         __u8  DS4IDFMT;           /* format identifier                       */
 	cchhb_t DS4HPCHR;         /* highest address of a format 1 DSCB      */
@@ -153,6 +304,43 @@
 } __attribute__ ((packed)) format4_label_t;
 
 
+typedef struct ds5ext 
+{
+	__u16 t;                  /* RTA of the first track of free extent   */
+	__u16 fc;                 /* number of whole cylinders in free ext.  */
+	__u8  ft;                 /* number of remaining free tracks         */
+} __attribute__ ((packed)) ds5ext_t;
+
+
+typedef struct format5_label 
+{
+	char DS5KEYID[4];         /* key identifier                          */
+	ds5ext_t DS5AVEXT;        /* first available (free-space) extent.    */
+	ds5ext_t DS5EXTAV[7];     /* seven available extents                 */
+	__u8 DS5FMTID;            /* format identifier                       */
+	ds5ext_t DS5MAVET[18];    /* eighteen available extents              */
+	cchhb_t DS5PTRDS[5];      /* pointer to next format5 DSCB            */
+} __attribute__ ((packed)) format5_label_t;
+
+
+typedef struct ds7ext 
+{
+	__u32 a;                  /* starting RTA value                      */
+	__u32 b;                  /* ending RTA value + 1                    */
+} __attribute__ ((packed)) ds7ext_t;
+
+
+typedef struct format7_label 
+{
+	char DS7KEYID[4];         /* key identifier                          */
+	ds7ext_t DS7EXTNT[5];     /* space for 5 extent descriptions         */
+	__u8 DS7FMTID;            /* format identifier                       */
+	ds7ext_t DS7ADEXT[11];    /* space for 11 extent descriptions        */
+	char res1[2];             /* reserved                                */
+	cchhb_t DS7PTRDS;         /* pointer to next FMT7 DSCB               */
+} __attribute__ ((packed)) format7_label_t;
+
+
 char * vtoc_ebcdic_enc (
         unsigned char source[LINE_LENGTH],
         unsigned char target[LINE_LENGTH],
@@ -181,45 +369,126 @@
         __u8 year,
         __u16 day);
 
+void vtoc_volume_label_init (
+	volume_label_t *vlabel);
 
 int vtoc_read_volume_label (
         char * device,
         unsigned long vlabel_start,
         volume_label_t * vlabel);
+
 int vtoc_write_volume_label (
-        char * device,
+        char *device,
         unsigned long vlabel_start,
-        volume_label_t * vlabel);
+        volume_label_t *vlabel);
+
+void vtoc_volume_label_set_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+char *vtoc_volume_label_get_volser (
+	volume_label_t *vlabel,
+	char *volser);
+
+void vtoc_volume_label_set_key (
+        volume_label_t *vlabel,
+        char *key);     
+
+void vtoc_volume_label_set_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
+char *vtoc_volume_label_get_label (
+	volume_label_t *vlabel,
+	char *lbl);
+
 void vtoc_read_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
         format4_label_t *f4,
-        format1_label_t *f1);
+        format5_label_t *f5,
+        format7_label_t *f7);
+
 void vtoc_write_label (
         char *device,
         unsigned long position,
+        format1_label_t *f1,
 	format4_label_t *f4,
-	format1_label_t *f1);
-void vtoc_init_format4_label (
-        struct hd_geometry *geo,
-        format4_label_t *f4lbl,
-	unsigned int usable_partitions,
-	unsigned int cylinders,
-	unsigned int tracks,
-	unsigned int blocks);
+	format5_label_t *f5,
+	format7_label_t *f7);
+
+
 void vtoc_init_format1_label (
         char *volid,
         unsigned int blksize,
         extent_t *part_extent,
         format1_label_t *f1);
+
+
+void vtoc_init_format4_label (
+        format4_label_t *f4lbl,
+	unsigned int usable_partitions,
+	unsigned int cylinders,
+	unsigned int tracks,
+	unsigned int blocks,
+	unsigned int blksize,
+	__u16 dev_type);
+
 void vtoc_update_format4_label (
 	format4_label_t *f4,
 	cchhb_t *highest_f1,
-	__u8 unused_update,
-	__u16 freespace_update);
+	__u16 unused_update);
+
 
+void vtoc_init_format5_label (
+	format5_label_t *f5);
 
+void vtoc_update_format5_label_add (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+ 
+void vtoc_update_format5_label_del (
+	format5_label_t *f5,
+	int verbose,
+	int cyl,
+	int trk,
+	__u16 a, 
+	__u16 b, 
+	__u8 c);
+
+
+void vtoc_init_format7_label (
+	format7_label_t *f7);
+
+void vtoc_update_format7_label_add (
+	format7_label_t *f7,
+	int verbose,
+	__u32 a, 
+	__u32 b);
+
+void vtoc_update_format7_label_del (
+	format7_label_t *f7, 
+	int verbose,
+	__u32 a, 
+	__u32 b);
 
+
+void vtoc_set_freespace(
+	format4_label_t *f4,
+	format5_label_t *f5,
+	format7_label_t *f7,
+	char ch,
+	int verbose,
+	__u32 start,
+	__u32 stop,
+	int cyl,
+	int trk);
 
 
 
diff -urN linux-2.4.8-pre4/include/linux/blkdev.h linux/include/linux/blkdev.h
--- linux-2.4.8-pre4/include/linux/blkdev.h	Mon Dec  3 22:58:44 2001
+++ linux/include/linux/blkdev.h	Mon Dec  3 22:58:53 2001
@@ -180,7 +180,7 @@
 #define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK)
 
 /* read-ahead in pages.. */
-#define MAX_READAHEAD	127
+#define MAX_READAHEAD	31
 #define MIN_READAHEAD	3
 
 #define blkdev_entry_to_request(entry) list_entry((entry), struct request, queue)
diff -urN linux-2.4.8-pre4/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.8-pre4/include/linux/fs.h	Mon Dec  3 22:58:44 2001
+++ linux/include/linux/fs.h	Mon Dec  3 22:58:53 2001
@@ -1316,7 +1316,7 @@
 }
 extern void set_blocksize(kdev_t, int);
 extern struct buffer_head * bread(kdev_t, int, int);
-extern void wakeup_bdflush(int wait);
+extern void wakeup_bdflush(void);
 
 extern int brw_page(int, struct page *, kdev_t, int [], int);
 
@@ -1342,7 +1342,7 @@
 extern ssize_t generic_file_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t generic_file_write(struct file *, const char *, size_t, loff_t *);
 extern void do_generic_file_read(struct file *, loff_t *, read_descriptor_t *, read_actor_t);
-
+extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
 extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
 
 extern struct file_operations generic_ro_fops;
diff -urN linux-2.4.8-pre4/include/linux/ibmtr.h linux/include/linux/ibmtr.h
--- linux-2.4.8-pre4/include/linux/ibmtr.h	Wed Jul  4 11:50:39 2001
+++ linux/include/linux/ibmtr.h	Mon Dec  3 22:58:53 2001
@@ -169,7 +169,7 @@
 
 struct tok_info {
 	unsigned char irq;
-	__u32 mmio;
+	void *mmio;
 	unsigned char hw_address[32];
 	unsigned char adapter_type;
 	unsigned char data_rate;
diff -urN linux-2.4.8-pre4/include/linux/pci_ids.h linux/include/linux/pci_ids.h
--- linux-2.4.8-pre4/include/linux/pci_ids.h	Tue Jul  3 07:55:20 2001
+++ linux/include/linux/pci_ids.h	Mon Dec  3 22:58:53 2001
@@ -437,7 +437,15 @@
 #define PCI_DEVICE_ID_SI_601		0x0601
 #define PCI_DEVICE_ID_SI_620		0x0620
 #define PCI_DEVICE_ID_SI_630		0x0630
+#define PCI_DEVICE_ID_SI_635		0x0635
+#define PCI_DEVICE_ID_SI_640		0x0640
+#define PCI_DEVICE_ID_SI_645		0x0645
+#define PCI_DEVICE_ID_SI_650		0x0650
 #define PCI_DEVICE_ID_SI_730		0x0730
+#define PCI_DEVICE_ID_SI_735		0x0735
+#define PCI_DEVICE_ID_SI_740		0x0740
+#define PCI_DEVICE_ID_SI_745		0x0745
+#define PCI_DEVICE_ID_SI_750		0x0750
 #define PCI_DEVICE_ID_SI_630_VGA	0x6300
 #define PCI_DEVICE_ID_SI_730_VGA	0x7300
 #define PCI_DEVICE_ID_SI_900		0x0900
diff -urN linux-2.4.8-pre4/include/linux/serial.h linux/include/linux/serial.h
--- linux-2.4.8-pre4/include/linux/serial.h	Fri Jul 20 12:52:18 2001
+++ linux/include/linux/serial.h	Mon Dec  3 22:58:53 2001
@@ -141,7 +141,8 @@
 					     --- no longer used */
 #define ASYNC_CONS_FLOW		0x00800000 /* flow control for console  */
 
-#define ASYNC_INTERNAL_FLAGS	0xFF800000 /* Internal flags */
+#define ASYNC_BOOT_ONLYMCA	0x00400000 /* Probe only if MCA bus */
+#define ASYNC_INTERNAL_FLAGS	0xFFC00000 /* Internal flags */
 
 /*
  * Multiport serial configuration structure --- external structure
diff -urN linux-2.4.8-pre4/lib/vsprintf.c linux/lib/vsprintf.c
--- linux-2.4.8-pre4/lib/vsprintf.c	Fri Apr 13 20:26:07 2001
+++ linux/lib/vsprintf.c	Mon Dec  3 22:58:53 2001
@@ -9,6 +9,11 @@
  * Wirzenius wrote this portably, Torvalds fucked it up :-)
  */
 
+/* 
+ * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
+ * - changed to provide snprintf and vsnprintf functions
+ */
+
 #include <stdarg.h>
 #include <linux/types.h>
 #include <linux/string.h>
@@ -121,14 +126,15 @@
 #define SPECIAL	32		/* 0x */
 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
 
-static char * number(char * str, long long num, int base, int size, int precision, int type)
+static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
 {
 	char c,sign,tmp[66];
-	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
+	const char *digits;
+	const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+	const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
 	int i;
 
-	if (type & LARGE)
-		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+	digits = (type & LARGE) ? large_digits : small_digits;
 	if (type & LEFT)
 		type &= ~ZEROPAD;
 	if (base < 2 || base > 36)
@@ -162,46 +168,73 @@
 	if (i > precision)
 		precision = i;
 	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
-	if (sign)
-		*str++ = sign;
+	if (!(type&(ZEROPAD+LEFT))) {
+		while(size-->0) {
+			if (buf <= end)
+				*buf = ' ';
+			++buf;
+		}
+	}
+	if (sign) {
+		if (buf <= end)
+			*buf = sign;
+		++buf;
+	}
 	if (type & SPECIAL) {
-		if (base==8)
-			*str++ = '0';
-		else if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
-		}
-	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
+		if (base==8) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+		} else if (base==16) {
+			if (buf <= end)
+				*buf = '0';
+			++buf;
+			if (buf <= end)
+				*buf = digits[33];
+			++buf;
+		}
+	}
+	if (!(type & LEFT)) {
+		while (size-- > 0) {
+			if (buf <= end)
+				*buf = c;
+			++buf;
+		}
+	}
+	while (i < precision--) {
+		if (buf <= end)
+			*buf = '0';
+		++buf;
+	}
+	while (i-- > 0) {
+		if (buf <= end)
+			*buf = tmp[i];
+		++buf;
+	}
+	while (size-- > 0) {
+		if (buf <= end)
+			*buf = ' ';
+		++buf;
+	}
+	return buf;
 }
 
 /**
- * vsprintf - Format a string and place it in a buffer
- * @buf: The buffer to place the result into
- * @fmt: The format string to use
- * @args: Arguments for the format string
- *
- * Call this function if you are already dealing with a va_list.
- * You probably want sprintf instead.
+* vsnprintf - Format a string and place it in a buffer
+* @buf: The buffer to place the result into
+* @size: The size of the buffer, including the trailing null space
+* @fmt: The format string to use
+* @args: Arguments for the format string
+*
+* Call this function if you are already dealing with a va_list.
+* You probably want snprintf instead.
  */
-int vsprintf(char *buf, const char *fmt, va_list args)
+int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
 {
 	int len;
 	unsigned long long num;
 	int i, base;
-	char * str;
+	char *str, *end, c;
 	const char *s;
 
 	int flags;		/* flags to number() */
@@ -210,16 +243,25 @@
 	int precision;		/* min. # of digits for integers; max
 				   number of chars for from string */
 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
-	                        /* 'z' support added 23/7/1999 S.H.    */
+				/* 'z' support added 23/7/1999 S.H.    */
 				/* 'z' changed to 'Z' --davidm 1/25/99 */
 
-	
-	for (str=buf ; *fmt ; ++fmt) {
+	str = buf;
+	end = buf + size - 1;
+
+	if (end < buf - 1) {
+		end = ((void *) -1);
+		size = end - buf + 1;
+	}
+
+	for (; *fmt ; ++fmt) {
 		if (*fmt != '%') {
-			*str++ = *fmt;
+			if (str <= end)
+				*str = *fmt;
+			++str;
 			continue;
 		}
-			
+
 		/* process flags */
 		flags = 0;
 		repeat:
@@ -230,8 +272,8 @@
 				case ' ': flags |= SPACE; goto repeat;
 				case '#': flags |= SPECIAL; goto repeat;
 				case '0': flags |= ZEROPAD; goto repeat;
-				}
-		
+			}
+
 		/* get field width */
 		field_width = -1;
 		if (isdigit(*fmt))
@@ -272,83 +314,112 @@
 		base = 10;
 
 		switch (*fmt) {
-		case 'c':
-			if (!(flags & LEFT))
-				while (--field_width > 0)
-					*str++ = ' ';
-			*str++ = (unsigned char) va_arg(args, int);
-			while (--field_width > 0)
-				*str++ = ' ';
-			continue;
-
-		case 's':
-			s = va_arg(args, char *);
-			if (!s)
-				s = "<NULL>";
-
-			len = strnlen(s, precision);
-
-			if (!(flags & LEFT))
-				while (len < field_width--)
-					*str++ = ' ';
-			for (i = 0; i < len; ++i)
-				*str++ = *s++;
-			while (len < field_width--)
-				*str++ = ' ';
-			continue;
-
-		case 'p':
-			if (field_width == -1) {
-				field_width = 2*sizeof(void *);
-				flags |= ZEROPAD;
-			}
-			str = number(str,
-				(unsigned long) va_arg(args, void *), 16,
-				field_width, precision, flags);
-			continue;
-
+			case 'c':
+				if (!(flags & LEFT)) {
+					while (--field_width > 0) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				c = (unsigned char) va_arg(args, int);
+				if (str <= end)
+					*str = c;
+				++str;
+				while (--field_width > 0) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
 
-		case 'n':
-			if (qualifier == 'l') {
-				long * ip = va_arg(args, long *);
-				*ip = (str - buf);
-			} else if (qualifier == 'Z') {
-				size_t * ip = va_arg(args, size_t *);
-				*ip = (str - buf);
-			} else {
-				int * ip = va_arg(args, int *);
-				*ip = (str - buf);
-			}
-			continue;
+			case 's':
+				s = va_arg(args, char *);
+				if (!s)
+					s = "<NULL>";
+
+				len = strnlen(s, precision);
+
+				if (!(flags & LEFT)) {
+					while (len < field_width--) {
+						if (str <= end)
+							*str = ' ';
+						++str;
+					}
+				}
+				for (i = 0; i < len; ++i) {
+					if (str <= end)
+						*str = *s;
+					++str; ++s;
+				}
+				while (len < field_width--) {
+					if (str <= end)
+						*str = ' ';
+					++str;
+				}
+				continue;
 
-		case '%':
-			*str++ = '%';
-			continue;
+			case 'p':
+				if (field_width == -1) {
+					field_width = 2*sizeof(void *);
+					flags |= ZEROPAD;
+				}
+				str = number(str, end,
+						(unsigned long) va_arg(args, void *),
+						16, field_width, precision, flags);
+				continue;
+
+
+			case 'n':
+				/* FIXME:
+				* What does C99 say about the overflow case here? */
+				if (qualifier == 'l') {
+					long * ip = va_arg(args, long *);
+					*ip = (str - buf);
+				} else if (qualifier == 'Z') {
+					size_t * ip = va_arg(args, size_t *);
+					*ip = (str - buf);
+				} else {
+					int * ip = va_arg(args, int *);
+					*ip = (str - buf);
+				}
+				continue;
 
-		/* integer number formats - set up the flags and "break" */
-		case 'o':
-			base = 8;
-			break;
+			case '%':
+				if (str <= end)
+					*str = '%';
+				++str;
+				continue;
+
+				/* integer number formats - set up the flags and "break" */
+			case 'o':
+				base = 8;
+				break;
+
+			case 'X':
+				flags |= LARGE;
+			case 'x':
+				base = 16;
+				break;
 
-		case 'X':
-			flags |= LARGE;
-		case 'x':
-			base = 16;
-			break;
-
-		case 'd':
-		case 'i':
-			flags |= SIGN;
-		case 'u':
-			break;
-
-		default:
-			*str++ = '%';
-			if (*fmt)
-				*str++ = *fmt;
-			else
-				--fmt;
-			continue;
+			case 'd':
+			case 'i':
+				flags |= SIGN;
+			case 'u':
+				break;
+
+			default:
+				if (str <= end)
+					*str = '%';
+				++str;
+				if (*fmt) {
+					if (str <= end)
+						*str = *fmt;
+					++str;
+				} else {
+					--fmt;
+				}
+				continue;
 		}
 		if (qualifier == 'L')
 			num = va_arg(args, long long);
@@ -367,13 +438,54 @@
 			if (flags & SIGN)
 				num = (signed int) num;
 		}
-		str = number(str, num, base, field_width, precision, flags);
+		str = number(str, end, num, base,
+				field_width, precision, flags);
 	}
-	*str = '\0';
+	if (str <= end)
+		*str = '\0';
+	else if (size > 0)
+		/* don't write out a null byte if the buf size is zero */
+		*end = '\0';
+	/* the trailing null byte doesn't count towards the total
+	* ++str;
+	*/
 	return str-buf;
 }
 
 /**
+ * snprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @size: The size of the buffer, including the trailing null space
+ * @fmt: The format string to use
+ * @...: Arguments for the format string
+ */
+int snprintf(char * buf, size_t size, const char *fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args, fmt);
+	i=vsnprintf(buf,size,fmt,args);
+	va_end(args);
+	return i;
+}
+
+/**
+ * vsprintf - Format a string and place it in a buffer
+ * @buf: The buffer to place the result into
+ * @fmt: The format string to use
+ * @args: Arguments for the format string
+ *
+ * Call this function if you are already dealing with a va_list.
+ * You probably want sprintf instead.
+ */
+int vsprintf(char *buf, const char *fmt, va_list args)
+{
+	return vsnprintf(buf, 0xFFFFFFFFUL, fmt, args);
+}
+
+
+/**
  * sprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
  * @fmt: The format string to use
@@ -389,3 +501,4 @@
 	va_end(args);
 	return i;
 }
+
diff -urN linux-2.4.8-pre4/mm/highmem.c linux/mm/highmem.c
--- linux-2.4.8-pre4/mm/highmem.c	Fri Jun 29 16:17:34 2001
+++ linux/mm/highmem.c	Mon Dec  3 22:58:53 2001
@@ -309,7 +309,7 @@
 	 * No luck. First, kick the VM so it doesnt idle around while
 	 * we are using up our emergency rations.
 	 */
-	wakeup_bdflush(0);
+	wakeup_bdflush();
 
 	/*
 	 * Try to allocate from the emergency pool.
@@ -347,7 +347,7 @@
 	 * No luck. First, kick the VM so it doesnt idle around while
 	 * we are using up our emergency rations.
 	 */
-	wakeup_bdflush(0);
+	wakeup_bdflush();
 
 	/*
 	 * Try to allocate from the emergency pool.
diff -urN linux-2.4.8-pre4/mm/shmem.c linux/mm/shmem.c
--- linux-2.4.8-pre4/mm/shmem.c	Wed Jul 11 14:52:58 2001
+++ linux/mm/shmem.c	Mon Dec  3 22:58:53 2001
@@ -754,18 +754,8 @@
 	buf->f_type = TMPFS_MAGIC;
 	buf->f_bsize = PAGE_CACHE_SIZE;
 	spin_lock (&sb->u.shmem_sb.stat_lock);
-	if (sb->u.shmem_sb.max_blocks == ULONG_MAX) {
-		/*
-		 * This is only a guestimate and not honoured.
-		 * We need it to make some programs happy which like to
-		 * test the free space of a file system.
-		 */
-		buf->f_bavail = buf->f_bfree = nr_free_pages() + nr_swap_pages + atomic_read(&buffermem_pages);
-		buf->f_blocks = buf->f_bfree + ULONG_MAX - sb->u.shmem_sb.free_blocks;
-	} else {
-		buf->f_blocks = sb->u.shmem_sb.max_blocks;
-		buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
-	}
+	buf->f_blocks = sb->u.shmem_sb.max_blocks;
+	buf->f_bavail = buf->f_bfree = sb->u.shmem_sb.free_blocks;
 	buf->f_files = sb->u.shmem_sb.max_inodes;
 	buf->f_ffree = sb->u.shmem_sb.free_inodes;
 	spin_unlock (&sb->u.shmem_sb.stat_lock);
@@ -1013,17 +1003,11 @@
 	return 0;
 }
 
-static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+static int shmem_set_size(struct shmem_sb_info *info,
+			  unsigned long max_blocks, unsigned long max_inodes)
 {
 	int error;
-	unsigned long max_blocks, blocks;
-	unsigned long max_inodes, inodes;
-	struct shmem_sb_info *info = &sb->u.shmem_sb;
-
-	max_blocks = info->max_blocks;
-	max_inodes = info->max_inodes;
-	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
-		return -EINVAL;
+	unsigned long blocks, inodes;
 
 	spin_lock(&info->stat_lock);
 	blocks = info->max_blocks - info->free_blocks;
@@ -1043,6 +1027,17 @@
 	return error;
 }
 
+static int shmem_remount_fs (struct super_block *sb, int *flags, char *data)
+{
+	struct shmem_sb_info *info = &sb->u.shmem_sb;
+	unsigned long max_blocks = info->max_blocks;
+	unsigned long max_inodes = info->max_inodes;
+
+	if (shmem_parse_options (data, NULL, &max_blocks, &max_inodes))
+		return -EINVAL;
+	return shmem_set_size(info, max_blocks, max_inodes);
+}
+
 int shmem_sync_file(struct file * file, struct dentry *dentry, int datasync)
 {
 	return 0;
@@ -1053,9 +1048,16 @@
 {
 	struct inode * inode;
 	struct dentry * root;
-	unsigned long blocks = ULONG_MAX;	/* unlimited */
-	unsigned long inodes = ULONG_MAX;	/* unlimited */
+	unsigned long blocks, inodes;
 	int mode   = S_IRWXUGO | S_ISVTX;
+	struct sysinfo si;
+
+	/*
+	 * Per default we only allow half of the physical ram per
+	 * tmpfs instance
+	 */
+	si_meminfo(&si);
+	blocks = inodes = si.totalram / 2;
 
 #ifdef CONFIG_TMPFS
 	if (shmem_parse_options (data, &mode, &blocks, &inodes)) {
@@ -1179,6 +1181,10 @@
 		unregister_filesystem(&tmpfs_fs_type);
 		return PTR_ERR(res);
 	}
+
+	/* The internal instance should not do size checking */
+	if ((error = shmem_set_size(&res->mnt_sb->u.shmem_sb, ULONG_MAX, ULONG_MAX)))
+		printk (KERN_ERR "could not set limits on internal tmpfs\n");
 
 	return 0;
 }
diff -urN linux-2.4.8-pre4/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.4.8-pre4/mm/vmscan.c	Mon Dec  3 22:58:44 2001
+++ linux/mm/vmscan.c	Mon Dec  3 22:58:53 2001
@@ -641,7 +641,7 @@
 		/* We only do a few "out of order" flushes. */
 		maxlaunder = MAX_LAUNDER;
 		/* Kflushd takes care of the rest. */
-		wakeup_bdflush(0);
+		wakeup_bdflush();
 		goto dirty_page_rescan;
 	}
 
diff -urN linux-2.4.8-pre4/net/atm/common.c linux/net/atm/common.c
--- linux-2.4.8-pre4/net/atm/common.c	Wed Jun 27 17:10:55 2001
+++ linux/net/atm/common.c	Mon Dec  3 22:58:53 2001
@@ -210,7 +210,7 @@
 
 	if ((vpi != ATM_VPI_UNSPEC && vpi != ATM_VPI_ANY &&
 	    vpi >> dev->ci_range.vpi_bits) || (vci != ATM_VCI_UNSPEC &&
-	    vci != ATM_VCI_ANY && vci >> dev->ci_range.vci_bits))
+	    vci != ATM_VCI_ANY && vci > dev->ci_range.vci_bits))
 		return -EINVAL;
 	if (vci > 0 && vci < ATM_NOT_RSV_VCI && !capable(CAP_NET_BIND_SERVICE))
 		return -EPERM;
diff -urN linux-2.4.8-pre4/net/core/rtnetlink.c linux/net/core/rtnetlink.c
--- linux-2.4.8-pre4/net/core/rtnetlink.c	Sun Feb 27 18:45:10 2000
+++ linux/net/core/rtnetlink.c	Mon Dec  3 22:58:53 2001
@@ -274,7 +274,7 @@
 
 /* Process one rtnetlink message. */
 
-extern __inline__ int
+static __inline__ int
 rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
 {
 	struct rtnetlink_link *link;
diff -urN linux-2.4.8-pre4/scripts/Menuconfig linux/scripts/Menuconfig
--- linux-2.4.8-pre4/scripts/Menuconfig	Mon Jul  2 13:56:40 2001
+++ linux/scripts/Menuconfig	Mon Dec  3 22:58:53 2001
@@ -1335,7 +1335,7 @@
 	then
 		echo -e "\n\007Your display is too small to run Menuconfig!"
 		echo "It must be at least 19 lines by 80 columns."
-		exit 0
+		exit 1
 	fi 
 
 	ROWS=$((ROWS-4))  COLS=$((COLS-5))
