]> git.hungrycats.org Git - linux/commitdiff
v2.4.7.4 -> v2.4.7.5
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:03:48 +0000 (20:03 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 04:03:48 +0000 (20:03 -0800)
  - Alan Cox: more merging
  - L.C. Chang: new SiS IDE PCI id's.
  - Maciej Rozycki: make MP table parsing more anal. Should fix broken P4 MP tables.
  - Leonard Zubkoff: merge DAC960 completion changes
  - Christoph Rohland: saner tmpfs mount-time limit behaviour (and remount)
  - me: buffer.c logic update - faster and hopefully livelock-free

109 files changed:
Documentation/pci.txt
Documentation/sound/btaudio [new file with mode: 0644]
Documentation/video4linux/bttv/CARDLIST
Documentation/video4linux/bttv/Insmod-options
Documentation/video4linux/bttv/README
Documentation/video4linux/bttv/Sound-FAQ
MAINTAINERS
Makefile
arch/i386/boot/Makefile
arch/i386/boot/setup.S
arch/i386/kernel/mpparse.c
drivers/block/DAC960.c
drivers/block/DAC960.h
drivers/block/floppy.c
drivers/char/drm/agpsupport.c
drivers/char/mxser.c
drivers/char/nvram.c
drivers/char/riscom8.c
drivers/char/sbc60xxwdt.c
drivers/char/serial.c
drivers/char/sysrq.c
drivers/ide/sis5513.c
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_core.h
drivers/media/radio/Config.in
drivers/media/radio/Makefile
drivers/media/radio/radio-gemtek-pci.c [new file with mode: 0644]
drivers/media/video/adv7175.c
drivers/media/video/bt819.c
drivers/media/video/bt848.h
drivers/media/video/bt856.c
drivers/media/video/bttv-cards.c
drivers/media/video/bttv-driver.c
drivers/media/video/bttv.h
drivers/media/video/bttvp.h
drivers/media/video/msp3400.c
drivers/media/video/msp3400.h [new file with mode: 0644]
drivers/media/video/tda7432.c
drivers/media/video/tuner.c
drivers/media/video/tuner.h
drivers/media/video/tvaudio.c
drivers/net/arlan.c
drivers/net/hamradio/scc.c
drivers/net/irda/ali-ircc.c
drivers/net/irda/irda-usb.c
drivers/net/ne2.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/ibmtr_cs.c
drivers/net/tokenring/ibmtr.c
drivers/pci/quirks.c
drivers/s390/Config.in
drivers/s390/block/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3370_erp.c
drivers/s390/block/dasd_3370_erp.h [new file with mode: 0644]
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_3990_erp.h
drivers/s390/block/dasd_9336_erp.c
drivers/s390/block/dasd_9336_erp.h [new file with mode: 0644]
drivers/s390/block/dasd_9343_erp.c
drivers/s390/block/dasd_9343_erp.h
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_diag.h
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h
drivers/s390/block/dasd_int.h [new file with mode: 0644]
drivers/scsi/aha152x.c
drivers/scsi/aic7xxx/aic7xxx.c
drivers/scsi/atp870u.c
drivers/scsi/cpqfc.Readme
drivers/scsi/cpqfcTS.h
drivers/scsi/cpqfcTScontrol.c
drivers/scsi/cpqfcTSinit.c
drivers/scsi/cpqfcTSstructs.h
drivers/scsi/cpqfcTSworker.c
drivers/scsi/pcmcia/nsp_cs.c
drivers/scsi/pcmcia/nsp_cs.h
drivers/scsi/pcmcia/nsp_debug.c
drivers/scsi/pcmcia/nsp_io.h
drivers/scsi/pcmcia/nsp_message.c [new file with mode: 0644]
drivers/scsi/qlogicfc.c
drivers/scsi/sd.c
drivers/usb/usbkbd.c
fs/buffer.c
fs/partitions/check.c
fs/partitions/ibm.c
fs/read_write.c
include/asm-i386/serial.h
include/asm-s390/cache.h
include/asm-s390/dasd.h
include/asm-s390/vtoc.h
include/asm-s390x/cache.h
include/asm-s390x/dasd.h
include/asm-s390x/vtoc.h
include/linux/blkdev.h
include/linux/fs.h
include/linux/ibmtr.h
include/linux/pci_ids.h
include/linux/serial.h
lib/vsprintf.c
mm/highmem.c
mm/shmem.c
mm/vmscan.c
net/atm/common.c
net/core/rtnetlink.c
scripts/Menuconfig

index fecbfaf041ac55c2f047cfc7a7c5b63a53f583ba..0fcf90a7aa89ac28000ea8e74b72aaf79c20d3cb 100644 (file)
@@ -80,7 +80,7 @@ Each entry consists of:
        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 --git a/Documentation/sound/btaudio b/Documentation/sound/btaudio
new file mode 100644 (file)
index 0000000..97f0401
--- /dev/null
@@ -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>
index ee51e9fe37e37e91b82cc981a9669bde9f320b13..8b7f0369e51297804473a6d85f920037155971e0 100644 (file)
@@ -53,11 +53,19 @@ bttv.o
   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 @@ tuner.o
   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)
index a941406e87085014e46e21bad52f09c56cc61565..6ea97c4c3ea3798904b3cae55fae0c9978b2638f 100644 (file)
@@ -13,6 +13,9 @@ bttv.o
                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
index 3070af143226fb1b266b0edfe7180b950ad86bf4..ad41af7bbdc8bf5771c5d59e2c7defaeb6f405ae 100644 (file)
@@ -21,8 +21,7 @@ CONFIG_I2C=m
 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.
index 8a185e18471c5725c960ed689b57778df113f5c2..1fbcd42a79c73a1ac0722ba2d2c96d8217c01d0e 100644 (file)
@@ -109,6 +109,29 @@ out =      _out_put bits of the data register (BT848_GPIO_DATA),
 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 @@ Good luck,
 PS: If you have a new working entry, mail it to me.
 
 -- 
-Gerd Knorr <kraxel@goldbach.in-berlin.de>
+Gerd Knorr <kraxel@bytesex.org>
index e95b5b73972b89a9b6528c689ad7b0beb4a841fa..81fb87ca9e8a3b0650da580d4b9f35c08f361a88 100644 (file)
@@ -106,6 +106,13 @@ M: p_gortmaker@yahoo.com
 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
index 341803da98cddad0ac407e5e9d63d203d71001a0..5745ed7c1cb84326b93d7eb2c8c2daad3f58c4de 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 8
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index f238d05c5b1944a6c94993bbb128429abf938ea1..e04c85516416417001e924116de8f497c94e3728 100644 (file)
@@ -67,7 +67,7 @@ setup.o: setup.s
        $(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 @@ bsetup.o: bsetup.s
        $(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:
 
index 69f60775abad10613e5d135c95d465ecfb226327..6a14c8c5cd3572be9704ee857a34b505a44f5c3b 100644 (file)
@@ -44,7 +44,6 @@
  *
  */
 
-#define __ASSEMBLY__
 #include <linux/config.h>
 #include <asm/segment.h>
 #include <linux/version.h>
index ebd620a71b4320176bacdeb734d26e2f2dc644ae..25220e75cad3c096fd389619894b5ce5113bc48f 100644 (file)
@@ -273,24 +273,26 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
        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 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
                        }
                }
        }
+       if (!num_processors)
+               printk(KERN_ERR "SMP mptable: no processors registered!\n");
        return num_processors;
 }
 
@@ -508,8 +512,12 @@ void __init get_smp_config (void)
                 * 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
index 5f06d3aca3cb64d5710c6748ccc5e4547f49a415..fb39eb06a4540d508cab50eb5825faa5ceb86cf2 100644 (file)
@@ -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_PD_QueueCommand(DAC960_Command_T *Command)
 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 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
                                                 *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 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
          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 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
          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 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
          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 @@ static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
   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 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
              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 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
              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 @@ static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
     }
   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 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
              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 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
              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 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
     }
   if (CommandType == DAC960_ImmediateCommand)
     {
-      complete(Command->Waiting);
-      Command->Waiting = NULL;
+      complete(Command->Completion);
+      Command->Completion = NULL;
       return;
     }
   if (CommandType == DAC960_QueuedCommand)
index 44339b7c2b23a8cd296c432b6305d952dc6c0c0f..fa1361541e688008882c71bddbe8a7bd02a2cf73 100644 (file)
@@ -2139,6 +2139,7 @@ static char
 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 unsigned long ProcessorFlags_T;
 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 @@ typedef struct DAC960_Command
   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;
index 4e569fa9f90be3c2caf0013c4a59f512437c0ff1..b0327f71aa66a33d3bf9965c627c2a4d0b4173ff 100644 (file)
@@ -1034,7 +1034,7 @@ static void main_command_interrupt(void)
 }
 
 /* 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 @@ static int fdc_dtr(void)
         * 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 @@ static void setup_rw_floppy(void)
                        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 @@ static int start_motor(void (*function)(void) )
        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));
 }
 
index 5c61982d5c9b01ba4bf717ed323e99ad8a53c274..9c761dd814335d3477b25c2fec2014539d99147d 100644 (file)
@@ -292,8 +292,8 @@ drm_agp_head_t *drm_agp_init(void)
                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;
                }
index 7c10b0ce17587fe51b9c1c3b9d27d0eac7b52498..f9c5a3ff5819fae1649b1ebbb2901902c0ee45f4 100644 (file)
@@ -884,8 +884,6 @@ static int mxser_write(struct tty_struct *tty, int from_user,
        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);
index 05a69587eead3a820f0245fbac9617c77fb0e786..7c4d55ae992e8291495f9db3c4713d9cd5fc0151 100644 (file)
@@ -113,7 +113,7 @@ static int nvram_open_mode;         /* special open modes */
 #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 );
index 515bf9dc253571d8cc353aa32a2fe4b6c123b5cb..60b049aa44b580c2a338e02e11107970ad02ee22 100644 (file)
@@ -1866,10 +1866,10 @@ static int __init riscom8_setup(char *str)
 __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";
 
 /* 
index e511a15e42514efed4a5a6f509102cb2d766f9e8..b314bf6818db2d4e7402297660601ad68b215ba3 100644 (file)
@@ -178,7 +178,7 @@ static ssize_t fop_write(struct file * file, const char * buf, size_t count, lof
                        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 */
index 47cffac538ff431133f40077396beddd4cfb37f9..5ec65dd297a03ad3f8200a2450b9254e2b58b078 100644 (file)
@@ -5432,6 +5432,10 @@ static int __init rs_init(void)
                        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);
        }
index ad9b94da2a760444d24ad7d82ccfb93a09c8ecd0..9a31126aa0270db5da13d75068645db5c2a54479 100644 (file)
@@ -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 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
        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");
index 41afe4a503c11f1b1b38d4c192affba637a7d94d..e8f8379254e3f3cd34c3e56177139bc48803472a 100644 (file)
@@ -48,7 +48,15 @@ static const struct {
        { "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 @@ static int sis5513_tune_chipset (ide_drive_t *drive, byte speed)
                        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 @@ static int config_chipset_for_dma (ide_drive_t *drive, byte ultra)
 
        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 @@ unsigned int __init ata66_sis5513 (ide_hwif_t *hwif)
                        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 @@ void __init ide_init_sis5513 (ide_hwif_t *hwif)
                        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:
index 26baf1d8f43802df126d3aafb421dfaf86b95ba3..edfdf276b06266aac940a6527064ad0606d317e2 100644 (file)
@@ -353,7 +353,7 @@ void hpsb_packet_sent(struct hpsb_host *host, struct hpsb_packet *packet,
         }
 
         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 @@ void handle_packet_response(struct hpsb_host *host, int tcode, quadlet_t *data,
                 break;
         }
 
-        packet->state = complete;
+        packet->state = completed;
         up(&packet->state_change);
         run_task_queue(&packet->complete_tq);
 }
@@ -726,7 +726,7 @@ void abort_requests(struct hpsb_host *host)
         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 @@ void abort_timedouts(struct hpsb_host *host)
         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);
index d1130307b91d51fd0b2a4b445bb9d50df6c3f847..87762aee898a1cb1ba7ef1478e3076596efac7cd 100644 (file)
@@ -24,11 +24,11 @@ struct hpsb_packet {
         /* 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. */
index b5fb0c2c53a0bcff9d5c146688cc67f5e8420019..864eec2b4a1df69c4f0dcc6564933540ddcf6e26 100644 (file)
@@ -21,6 +21,7 @@ dep_tristate '  GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
 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
index fef1dbfb0d13bb75a974db0a4f399e343f623e30..ed1b138de796426d7bd0d4462b9fb555f6435c4b 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 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 --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
new file mode 100644 (file)
index 0000000..895ad4a
--- /dev/null
@@ -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 );
+
index c3a51d3e261dff8c5c2125478698a58a49423bea..f65dfe0d79f6ccc08b4e01499c82ceab125fbb8a 100644 (file)
@@ -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>
index 5a4f380d97bafd2cd545ec90fcdb80e390b17043..ecb3cc56f0e9cd78e0c803a76fa3cf57bdba8750 100644 (file)
@@ -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>
index 340accf31a8b117f3716fa51e714271070fb6ffb..b51f5b9f7b0d2c733f3f38e741ef1eef0e2a48e9 100644 (file)
 
 #define BT878_DEVCTRL 0x40
 #define BT878_EN_TBFX 0x02
+#define BT878_EN_VSFX 0x04
 
 #endif
index bd27d9f8e74a8a08fd5d1e157c5257d3b234a0ec..cd38c6215c92a90edb7b50080793ec405ba18f21 100644 (file)
@@ -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>
index 9b37527f47a2d9ff31c4b8ab954d7525e19b6f68..6a41c644f9f7e48b8bb37aa73242d4a5a2253171 100644 (file)
@@ -46,13 +46,16 @@ static void init_tea5757(struct bttv *btv);
 #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 @@ static struct CARD {
        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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
                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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
        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 @@ struct tvcard bttv_tvcards[] = {
         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 @@ void __devinit bttv_init_card(struct bttv *btv)
                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 @@ hauppauge_tuner[] __devinitdata =
         { 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 @@ void winview_audio(struct bttv *btv, struct video_audio *v, int set)
        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 @@ avermedia_tvphone_audio(struct bttv *btv, struct video_audio *v, int set)
        }
 }
 
+/* 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 @@ terratv_audio(struct bttv *btv, struct video_audio *v, int set)
        }
 }
 
+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 @@ void __devinit bttv_check_chipset(void)
 
        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 @@ int __devinit bttv_handle_chipset(struct bttv *btv)
 {
        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;
 }
index 01555bfe718b1b495a7a5c6f3eec94c190c4b52c..0d78394d5825637840893d2d665b0a851613bd5f 100644 (file)
@@ -69,6 +69,7 @@ static unsigned int irq_debug = 0;
 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_DESC(gbuffers,"number of capture buffers, default is 2 (64 max)");
 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 @@ static int  make_prisctab(struct bttv *btv, unsigned int *ro,
                 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 @@ static int vgrab(struct bttv *btv, struct video_mmap *mp)
        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 @@ static void bttv_close(struct video_device *dev)
 {
        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 @@ static void bttv_close(struct video_device *dev)
 
        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 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                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 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
        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 @@ static int vbi_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
        }
        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 @@ static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                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 @@ static void bt848_set_risc_jmps(struct bttv *btv, int flags)
                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 @@ static int __devinit init_bt848(struct bttv *btv)
        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 @@ static int __devinit init_bt848(struct bttv *btv)
 
        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 @@ static int __devinit init_bt848(struct bttv *btv)
        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 @@ static int __devinit init_bt848(struct bttv *btv)
                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 @@ static void bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
                                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;
index 88f26849e944c95fed02f2e9e4332b76c0061c6b..513c855a45b9cee0278ebb0004d893004a378187 100644 (file)
 #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 @@ extern wait_queue_head_t* bttv_get_gpio_queue(unsigned int card);
 
 /* 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_ */
index c4af43b32ea7282158208bca8828887bfff4839d..5dd21de8a642b5ae36513d3dce1d1f3afbcb1231 100644 (file)
@@ -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 @@ struct bttv {
 };
 #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)
index 50aa1a48c5cfbc0b46c1319da02e608016969693..b3d9887b16936a0b5e7a83e1cfc8d80317b206cc 100644 (file)
@@ -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 amsound = 0;    /* hard-wire AM sound at 6.5 Hz (france),
 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 @@ struct msp3400c {
        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 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode)
                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 @@ static void msp3400c_setstereo(struct i2c_client *client, int mode)
                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 @@ msp3400c_print_mode(struct msp3400c *msp)
        }
 }
 
+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 @@ static int msp3400c_thread(void *data)
                        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 @@ static int msp3410d_thread(void *data)
                        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 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
        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 @@ static int msp_attach(struct i2c_adapter *adap, int addr,
        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 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
        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 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
                }
                if (msp->active)
                        msp->restart = 1;
-#endif
                break;
 
        case AUDC_SET_RADIO:
@@ -1373,6 +1410,33 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
                        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 @@ static int msp_command(struct i2c_client *client,unsigned int cmd, void *arg)
                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 --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
new file mode 100644 (file)
index 0000000..9673133
--- /dev/null
@@ -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 */
index f40e58121c1c23a8725d0752c49194109049cf79..97e2be2b04094e723a165ee9e2b77e386ad1b275 100644 (file)
@@ -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)
  *
  * 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 @@ struct tda7432 {
        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 @@ static struct i2c_client client_template;
 /* 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 @@ static struct i2c_client client_template;
  
 #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 @@ static struct i2c_client client_template;
 #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 @@ static struct i2c_client client_template;
  */
 
 #define TDA7432_ATTEN_0DB      0x00
+#define TDA7432_MUTE        0x1 << 5
 
 
 /* Subaddress 0x07 - Loudness Control */
@@ -257,18 +262,19 @@ static int tda7432_set(struct i2c_client *client)
        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 @@ static void do_tda7432_init(struct i2c_client *client)
        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 @@ static int tda7432_command(struct i2c_client *client,
 {
        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 @@ static int tda7432_command(struct i2c_client *client,
                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 @@ static int tda7432_command(struct i2c_client *client,
                 * 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 @@ static int tda7432_command(struct i2c_client *client,
                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 @@ static struct i2c_client client_template =
         &driver
 };
 
-#ifdef MODULE
-int init_module(void)
-#else
 int tda7432_init(void)
-#endif
 {
 
        if ( (loudness < 0) || (loudness > 15) )
@@ -482,17 +526,17 @@ int tda7432_init(void)
                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:
index 308b3f1dc22dbfef1d98a2a9d54e38237bb8c8d0..c26dd99fd84843951527a21d4dab03b4d7f59f45 100644 (file)
@@ -36,12 +36,16 @@ static int type  = -1; /* insmod parameter */
 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 @@ static struct tunertype tuners[] = {
          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 @@ static void set_tv_freq(struct i2c_client *c, int freq)
         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 @@ static void set_radio_freq(struct i2c_client *c, int freq)
         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 @@ static int tuner_attach(struct i2c_adapter *adap, int addr,
         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;
index e85a3741c09d6bcc4f56bac08cc0decb517a3666..591ae3e7bc20e0f78a5bf551aeac75b981b1e7d2 100644 (file)
 #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 */
index a3856186fc9665779f6ac1e27029fef6734bedde..5cd813d0bff61e2d0621ac5c1845d9711b1de05f 100644 (file)
@@ -98,6 +98,7 @@ struct CHIPDESC {
        int  inputreg;
        int  inputmap[8];
        int  inputmute;
+       int  inputmask;
 };
 static struct CHIPDESC chiplist[];
 
@@ -113,7 +114,7 @@ struct CHIPSTATE {
 
        /* current settings */
        __u16 left,right,treble,bass,mode;
-
+       int prevmode;
        /* thread */
        struct task_struct  *thread;
        struct semaphore    *notify;
@@ -124,7 +125,7 @@ struct CHIPSTATE {
 
 
 /* ---------------------------------------------------------------------- */
-/* i2c addresses                                                           */
+/* i2c addresses                                                          */
 
 static unsigned short normal_i2c[] = {
        I2C_TDA8425   >> 1,
@@ -182,6 +183,18 @@ static int chip_write(struct CHIPSTATE *chip, int subaddr, int val)
        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 @@ static int chip_thread(void *data)
                        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 @@ void generic_checkmode(struct CHIPSTATE *chip)
        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 @@ void generic_checkmode(struct CHIPSTATE *chip)
 #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 @@ void tda985x_setmode(struct CHIPSTATE *chip, int mode)
  *  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 @@ void tda985x_setmode(struct CHIPSTATE *chip, int mode)
  *  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 @@ int tda9873_getmode(struct CHIPSTATE *chip)
 
 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 @@ void tda9873_setmode(struct CHIPSTATE *chip, int mode)
        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 @@ static struct CHIPDESC chiplist[] = {
                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 @@ static struct CHIPDESC chiplist[] = {
 
                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 @@ static int chip_attach(struct i2c_adapter *adap, int addr,
        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 @@ static int chip_attach(struct i2c_adapter *adap, int addr,
        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 @@ static int chip_detach(struct i2c_client *client)
 {
        struct CHIPSTATE *chip = client->data;
 
+       del_timer(&chip->wt);
        if (NULL != chip->thread) {
                /* shutdown async thread */
                DECLARE_MUTEX_LOCKED(sem);
@@ -1034,9 +1064,9 @@ static int chip_command(struct i2c_client *client,
        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 @@ static int chip_command(struct i2c_client *client,
        }
        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 */
                }
index 5d942a499ac3b09a9e2239f37ba9028a536b7f94..beef2128909c6713bc3a0d088fdf6203949eb0bb 100644 (file)
@@ -1435,7 +1435,7 @@ extern inline void arlan_queue_retransmit(struct net_device *dev)
        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);
 
index 8114827e5350a69b497234abcb297e40af5eca15..dd3088721ad41357557d0c1f000bf91a08f76085 100644 (file)
@@ -1775,8 +1775,8 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                                        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;
index ff796d26242f573e542c40fa482013dc9d0dd09a..0c29576ea3c59b4733d0b8cc43b2ebcea3b1e42c 100644 (file)
@@ -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 @@ static int ali_ircc_open(int i, chipio_t *info)
        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);
index b54f156dd577e055ea85f17254aca3c2aa46faca..257389d33b363091b393d2b587c5ad9a3b46c61e 100644 (file)
@@ -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>
 
index fb72b89bb091f8d0c82e454737b8abbb7404874d..29d4450e211ff94529c88bed6b3fece9eb400528 100644 (file)
@@ -118,9 +118,9 @@ static unsigned int addresses[7] __initdata =
 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 ne_block_output(struct net_device *dev, const int count,
  *
  */
 
-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_put_eeprom(unsigned char value, unsigned int addr)
        }
 }
 
-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 @@ static void dlink_send_eeprom_bit(unsigned int bit, unsigned int addr)
        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 void dlink_send_eeprom_word(unsigned int value, unsigned int len, unsigne
        }
 }
 
-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;
index a48bea863038e035c74584929b886c2250a2639f..da91816e379fcd052c5eb5c66eff9679ca96c6f4 100644 (file)
@@ -233,7 +233,7 @@ static void mdio_sync(ioaddr_t ioaddr, int bits);
 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 @@ static void tc574_config(dev_link_t *link)
                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 @@ static void dump_status(struct net_device *dev)
 /*
   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 @@ static void tc574_reset(struct net_device *dev)
        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 @@ static void tc574_reset(struct net_device *dev)
        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 @@ static void el3_tx_timeout(struct net_device *dev)
        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 @@ static void pop_tx_status(struct net_device *dev)
                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 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                                           " 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 @@ static int el3_rx(struct net_device *dev, int worklimit)
                                lp->stats.rx_dropped++;
                        }
                }
-               wait_for_completion(dev, RxDiscard);
+               tc574_wait_for_completion(dev, RxDiscard);
        }
 
        return worklimit;
index 1c894b7c518ffb966a750d4ac79b83557f4c60c9..a35f51d2dc0be41f6b585ffb197de57df56812b2 100644 (file)
@@ -528,7 +528,7 @@ static int tc589_event(event_t event, int priority,
 /*
   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 @@ static void el3_tx_timeout(struct net_device *dev)
     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 @@ static void pop_tx_status(struct net_device *dev)
        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 @@ static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
                       " 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 @@ static int el3_rx(struct net_device *dev)
            }
        }
        /* 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);
index 84da0179d942d9625dc1899e9be4efb5f51eeacb..fb4bf2e13aa91156726e5bc3f9524a614f712c5b 100644 (file)
@@ -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 @@ static void ibmtr_config(dev_link_t *link)
     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;
index 78280eae113a46cd4cbe305c472e51086c736e73..938021dede5b6267d7e05d4ca3baecb4408ae523 100644 (file)
@@ -228,7 +228,7 @@ static void __devinit PrtChanID(char *pcid, short stride)
        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 @@ int __devinit ibmtr_probe(struct net_device *dev)
        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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
 {
 
        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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
 #ifndef MODULE
 #ifndef PCMCIA
        dev = init_trdev(dev, 0);
+       if (!dev)
+               return -ENOMEM;
 #endif
 #endif
 
@@ -377,14 +378,14 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
         *    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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
         *    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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
        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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
           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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
                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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
                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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
                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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
                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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
                        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 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr)
        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",
index 795bb5e7598ded6bf3ba65dce18dc3ac3d3ba46a..d42545d625a58cc3e5509ca9ad52f72976ade8e9 100644 (file)
@@ -92,42 +92,58 @@ static void __init quirk_triton(struct pci_dev *dev)
  *     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 @@ static struct pci_fixup pci_fixups[] __initdata = {
        { 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 },
index 1619a064d153f27c0a0fa2b520f4a8145172778b..f3b8963cb591d5970ed31554ea12ff38067a4771 100644 (file)
@@ -14,12 +14,21 @@ comment 'S/390 block device drivers'
 
 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
index 0ddbc31b52d9b07ed8fb8bde8261996373cb6126..bd352622f45876c322fb2cc74110d9ccc165c340 100644 (file)
@@ -4,15 +4,18 @@
 
 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
@@ -20,3 +23,12 @@ 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)
+
index 58e3de6c43fc1b393337711f0a97992656e44ace..94108a2011838b67481b13616685891e193f044e 100644 (file)
@@ -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
  *          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 @@ MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
                    " Copyright 2000 IBM Corporation");
 MODULE_SUPPORTED_DEVICE ("dasd");
 MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");
-EXPORT_SYMBOL (dasd_discipline_enq);
-EXPORT_SYMBOL (dasd_discipline_deq);
+MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");
+EXPORT_SYMBOL (dasd_chanq_enq_head);
+EXPORT_SYMBOL (dasd_debug_area);
+EXPORT_SYMBOL (dasd_chanq_enq);
+EXPORT_SYMBOL (dasd_chanq_deq);
+EXPORT_SYMBOL (dasd_discipline_add);
+EXPORT_SYMBOL (dasd_discipline_del);
 EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_term_IO);
+EXPORT_SYMBOL (dasd_schedule_bh);
 EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_oper_handler);
 EXPORT_SYMBOL (dasd_alloc_request);
 EXPORT_SYMBOL (dasd_free_request);
-EXPORT_SYMBOL(dasd_ioctl_no_register);  
-EXPORT_SYMBOL(dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_ioctl_no_register);
+EXPORT_SYMBOL (dasd_ioctl_no_unregister);
+EXPORT_SYMBOL (dasd_default_erp_action);
+EXPORT_SYMBOL (dasd_default_erp_postaction);
+EXPORT_SYMBOL (dasd_sleep_on_req);
+EXPORT_SYMBOL (dasd_set_normalized_cda);
 
 /* SECTION: Constant definitions to be used within this file */
 
-#define PRINTK_HEADER DASD_NAME": "
+#define PRINTK_HEADER DASD_NAME":"
 
-#define DASD_EMERGENCY_REQUESTS 16
 #define DASD_MIN_SIZE_FOR_QUEUE 32
 #undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE
 #define DASD_CHANQ_MAX_SIZE 6
@@ -98,27 +125,36 @@ EXPORT_SYMBOL(dasd_ioctl_no_unregister);
 /* 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 @@ dasd_create_devreg (int devno)
        return r;
 }
 
-/* 
+/*
  * function: dasd_destroy_devreg
  * destroys the dasd_devreg_t given as argument
  */
@@ -153,44 +189,44 @@ dasd_destroy_devreg (dasd_devreg_t * devreg)
 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 @@ dasd_destroy_range (dasd_range_t * range)
        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 @@ dasd_add_range (int from, int to)
                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 @@ dasd_remove_range (dasd_range_t * range)
        {
                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_devindex_from_devno (int devno)
        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 @@ dasd_devindex_from_devno (int devno)
        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 @@ dasd_split_parm_string (char *str)
 {
        char *tmp = str;
        int count = 0;
-       do {
+       while (tmp != NULL && *tmp != '\0') {
                char *end;
                int len;
                end = strchr (tmp, ',');
@@ -370,27 +414,28 @@ dasd_split_parm_string (char *str)
                        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 @@ dasd_setup (char *str, int *ints)
        }
        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 @@ dasd_parse (char **str)
 {
        char *temp;
        int from, to;
+        int features = 0;
 
        if (*str) {
                /* turn off probeonly mode, if any dasd parameter is present */
@@ -472,12 +564,13 @@ dasd_parse (char **str)
                } 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 @@ dasd_parse (char **str)
 
 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 @@ get_new_major_info (void)
 
        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 @@ dasd_register_major (major_info_t * major_info)
        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 @@ dasd_register_major (major_info_t * major_info)
                                            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 @@ dasd_unregister_major (major_info_t * major_info)
                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 @@ dasd_unregister_major (major_info_t * major_info)
        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 @@ dasd_device_from_kdev (kdev_t kdev)
        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 @@ dasd_device_from_kdev (kdev_t kdev)
        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 @@ dasd_device_from_devno (int devno)
        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 @@ dasd_device_from_devno (int devno)
        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 @@ static dasd_profile_info_t dasd_global_profile;
 }
 
 /*
- * 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 @@ dasd_profile_add (ccw_req_t * cqr)
                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 (ccw_req_t * cqr)
        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;
+       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 @@ dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
                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 @@ dasd_start_IO (ccw_req_t * cqr)
        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 @@ dasd_start_IO (ccw_req_t * cqr)
                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 @@ sleep_on_req (ccw_req_t * req)
 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 @@ dasd_end_request (struct request *req, int uptodate)
        return;
 }
 
-/* 
+/*
  * function dasd_get_queue
  * returns the queue corresponding to a device behind a kdev
  */
@@ -1162,10 +1418,10 @@ static request_queue_t *
 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 @@ dasd_check_expire_time (ccw_req_t * cqr)
        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 @@ dasd_check_expire_time (ccw_req_t * cqr)
 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 @@ dasd_schedule_bh (dasd_device_t *device)
        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 @@ do_dasd_request (void)
  *  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 @@ void
 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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
         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(sense,0,32);
 
-/*
-                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);
+                        /* 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 @@ dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
  *   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 == NULL)
-               return NULL;
+       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;
+       }
 
        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 @@ default_erp_action (ccw_req_t * cqr)
  *   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 @@ default_erp_action (ccw_req_t * cqr)
  *   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,195 +2046,113 @@ static int
 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;
+       int openct = atomic_read (&device->open_count);
+
+       if (openct > 1) {
+               DASD_MESSAGE (KERN_WARNING, device, "%s",
+                             "dasd_format: device is open! expect errors.");
        }
-        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;
+       DASD_MESSAGE (KERN_INFO, device,
+                     "formatting units %d to %d (%d B blocks) flags %d",
+                     fdata->start_unit, fdata->stop_unit,
+                     fdata->blksize, fdata->intensity);
+       while ((!rc) && (fdata->start_unit <= fdata->stop_unit)) {
+                ccw_req_t *req;
+                dasd_format_fn_t ffn = device->discipline->format_device;
+               ffn = device->discipline->format_device;
+               if (ffn == NULL)
+                       break;
+               req = ffn (device, fdata);
+               if (req == NULL) {
+                       rc = -ENOMEM;
+                       break;
                }
-               if (rc) {
-                        DASD_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) {
-
-
+               if ((rc = dasd_sleep_on_req (req)) != 0) {
                        DASD_MESSAGE (KERN_WARNING, device,
-                                     " Formatting failed with rc = %d\n",
-                                     rc);
+                                     " Formatting of unit %d failed with rc = %d\n",
+                                     fdata->start_unit, rc);
                        break;
-               }
-                
-               dasd_free_request (req);        /* request is no longer used */
-               temp.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);
+               } 
+               dasd_free_request (req, device);        /* request is no longer used */
+               if ( signal_pending(current) )
+                       break;          
+               fdata->start_unit++;
+       }
        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)
 {
@@ -2013,31 +2182,37 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
                _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 @@ do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
                                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;
+       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;
         }
-        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 BIODASDENABLE:{
+                        dasd_range_t range = { 
+                                from: device->devinfo.devno,
+                                to: device->devinfo.devno 
+                        };
+                       if (!capable (CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
+                               break;
+                       }
+                        dasd_enable_ranges (&range, device->discipline, 0);
+                        break;
         }
-#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 BIODASDFMT:{
+                       /* fdata == NULL is no longer a valid arg to dasd_format ! */
+                       int partn = MINOR (inp->i_rdev) &
+                           ((1 << major_info->gendisk.minor_shift) - 1);
+                       format_data_t fdata;
+
+                       if (!capable (CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
                                break;
-                       offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
-                           device->sizes.s2b_shift;
-                       xlt += offset;
-                       rc = copy_to_user ((void *) data, &xlt,
-                                          sizeof (int)) ? -EFAULT : 0;
-                       break;
-               }
-       case BIODASDFORMAT:{
-                       /* fdata == NULL is a valid arg to dasd_format ! */
-                       int partn;
-                       format_data_t fdata =
-                       {
-                               DASD_FORMAT_DEFAULT_START_UNIT,
-                               DASD_FORMAT_DEFAULT_STOP_UNIT,
-                               DASD_FORMAT_DEFAULT_BLOCKSIZE,
-                               DASD_FORMAT_DEFAULT_INTENSITY};
-
-                        if (!capable(CAP_SYS_ADMIN)) {
-                            rc = -EACCES;
-                            break;
+                       }
+                        if (dasd_features_from_devno(device->devinfo.devno)&DASD_FEATURE_READONLY) {
+                                rc = -EROFS;
+                                break;
                         }
-                       if (data) {
-                               rc = copy_from_user (&fdata, (void *) data,
-                                                    sizeof (format_data_t));
-                               if (rc) {
-                                       rc = -EFAULT;
-                                       break;
-                               }
+                       if (!data) {
+                               rc = -EINVAL;
+                               break;
+                       }
+                       rc = copy_from_user (&fdata, (void *) data,
+                                            sizeof (format_data_t));
+                       if (rc) {
+                               rc = -EFAULT;
+                               break;
                        }
-                       partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
                        if (partn != 0) {
-                               printk (KERN_WARNING PRINTK_HEADER
-                                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
-                                    " Cannot low-level format a partition\n",
-                                       device->devinfo.devno, device->devinfo.irq, device->name,
-                                   MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+                               DASD_MESSAGE (KERN_WARNING, device, "%s",
+                                             "Cannot low-level format a partition");
                                return -EINVAL;
                        }
                        rc = dasd_format (device, &fdata);
                        break;
                }
+       case BIODASDPRRST:{
+                       if (!capable (CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
+                               break;
+                       }
+                       memset (&device->profile, 0,
+                               sizeof (dasd_profile_info_t));
+                       break;
+               }
+       case BIODASDPRRD:{
+                       rc = copy_to_user((long *)data,
+                                         (long *)&device->profile,
+                                         sizeof(dasd_profile_info_t));
+                       if (rc)
+                               rc = -EFAULT;
+                       break;
+               }
        case BIODASDRSRV:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->reserve (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+                       ccw_req_t *req;
+                       if (!capable (CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
+                               break;
+                       }
+                       req = device->discipline->reserve (device);
+                       rc = dasd_sleep_on_req (req);
+                       dasd_free_request (req, device);
+                       break;
+               }
        case BIODASDRLSE:{
-            ccw_req_t *req;
-            if (!capable(CAP_SYS_ADMIN)) {
-                rc = -EACCES;
-                break;
-            }
-            req = device->discipline->release (device);
-            rc = sleep_on_req (req);
-            dasd_free_request (req);
-            break;
-        }
+                       ccw_req_t *req;
+                       if (!capable (CAP_SYS_ADMIN)) {
+                               rc = -EACCES;
+                               break;
+                       }
+                       req = device->discipline->release (device);
+                       rc = dasd_sleep_on_req (req);
+                       dasd_free_request (req, device);
+                       break;
+               }
        case BIODASDSLCK:{
                        printk (KERN_WARNING PRINTK_HEADER
                                "Unsupported ioctl BIODASDSLCK\n");
                        break;
                }
-       default:{
-
-                       dasd_ioctl_list_t *old = dasd_find_ioctl(no);
-                       if ( old ) {
-                               rc = old->handler(inp,no,data);
+       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 {
-                               DASD_MESSAGE (KERN_INFO, device,
-                                           "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
-                                             no,
-                                             _IOC_DIR (no) == _IOC_NONE ? "0" :
-                                             _IOC_DIR (no) == _IOC_READ ? "r" :
-                                             _IOC_DIR (no) == _IOC_WRITE ? "w" :
-                                          _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ?
-                                             "rw" : "u",
-                                        _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
-                                             data);
-                               rc = -EINVAL;
-                       }       
+                               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) {
+                               if ( old->owner )
+                                       __MOD_INC_USE_COUNT(old->owner);
+                               rc = old->handler (inp, no, data);
+                               if ( old->owner )
+                                       __MOD_DEC_USE_COUNT(old->owner);
+                       } else {
+                               DASD_MESSAGE (KERN_INFO, device,
+                                             "ioctl 0x%08x=%s'0x%x'%d(%d) data %8lx\n",
+                                             no,
+                                             _IOC_DIR (no) == _IOC_NONE ? "0" :
+                                             _IOC_DIR (no) == _IOC_READ ? "r" :
+                                             _IOC_DIR (no) ==
+                                             _IOC_WRITE ? "w" : _IOC_DIR (no)
+                                             == (_IOC_READ | _IOC_WRITE) ? "rw"
+                                             : "u", _IOC_TYPE (no),
+                                             _IOC_NR (no), _IOC_SIZE (no),
+                                             data);
+                               rc = -ENOTTY;
+                       }
                        break;
                }
        }
@@ -2213,37 +2448,46 @@ static int
 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 @@ static int
 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 @@ block_device_operations dasd_device_operations =
        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 @@ dasd_fillgeo(int kdev,struct hd_geometry *geo)
                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 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
        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 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
                }
        }
        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,19 +2601,214 @@ dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
        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)
 {
-        device->request_queue.plugged = 1; /* inhibit further calls of request_fn */
+       atomic_set(&device->plugged,0); 
+        dasd_schedule_bh(device);
 }
 
 static void
-dasd_unplug_device (dasd_device_t *device)
+dasd_flush_chanq ( dasd_device_t * device, int destroy ) 
 {
-        generic_unplug_device(&device->request_queue);
+        ccw_req_t *cqr;
+        unsigned long flags;
+        if ( destroy ) {
+                s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                cqr = device->queue.head;
+                while ( cqr != NULL ) {
+                        if ( cqr -> status == CQR_STATUS_IN_IO )
+                                device->discipline->term_IO (cqr);
+                        if ( cqr->status != CQR_STATUS_DONE ||
+                             cqr->status != CQR_STATUS_FAILED ) {
+                                cqr->status = CQR_STATUS_FAILED;
+                        }
+                        dasd_schedule_bh(device);
+                        cqr = cqr->next;
+                }
+                s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
+        }
+        wait_event( device->wait_q, device->queue.head == NULL );
 }
 
+static void
+dasd_flush_request_queues ( dasd_device_t * device, int destroy )
+{
+        int i;
+        int major = MAJOR(device->kdev);
+        int minor = MINOR(device->kdev);
+        for ( i = 0; i < (1 << DASD_PARTN_BITS); i ++) {
+                if ( destroy )
+                        destroy_buffers(MKDEV(major,minor+i)); 
+                else
+                        invalidate_buffers(MKDEV(major,minor+i)); 
+        } 
+}
+
+static int
+dasd_disable_volume ( dasd_device_t * device, int force ) 
+{
+        int rc = 0;
+        int target  = DASD_STATE_KNOWN;
+        int count = atomic_read (&device->open_count);
+        int part;
+        
+       if ( count ) {
+               DASD_MESSAGE (KERN_EMERG, device, "%s",
+                             "device has vanished although it was open!");
+        }
+        if ( force ) {
+                dasd_flush_chanq(device,force);
+                dasd_flush_request_queues(device,force);
+                dasd_disable_blkdev(device);
+                target = DASD_STATE_DEL;
+        }
+
+#if 0
+        /* unregister devfs entries */
+        for (part = 0; part < (1 << DASD_PARTN_BITS); part++) {
+                devfs_unregister(device->major_info->gendisk.part[MINOR(device->kdev)+part].de);
+                device->major_info->gendisk.part[MINOR(device->kdev)+part].de = NULL;
+        }                        
+#endif
+        
+        DASD_MESSAGE (KERN_WARNING, device, 
+                      "disabling device, target state:%d",target);
+        dasd_set_device_level (device->devinfo.devno, 
+                               device->discipline, 
+                               target);
+        return rc;
+}
+
+static void
+dasd_disable_ranges (dasd_range_t *range, 
+                     dasd_discipline_t *d,
+                     int all, int force ) 
+{
+        dasd_range_t *rrange;
+        int j;
+
+        if (range == &dasd_range_head) {
+                rrange = list_entry (range->list.next, 
+                                     dasd_range_t, list);
+        } else {
+                rrange = range;
+        }
+        do {
+                for (j = rrange->from; j <= rrange->to; j++) {
+                        dasd_device_t **dptr;
+                        dasd_device_t *device;
+                        dptr = dasd_device_from_devno(j);
+                        if ( dptr == NULL ) {
+                            continue;
+                        }
+                        device = *dptr;
+                        if (device == NULL ||
+                            (d != NULL &&
+                             device -> discipline != d))
+                                continue;
+                        
+                        dasd_disable_volume(device, force);
+                }
+                rrange = list_entry (rrange->list.next, dasd_range_t, list);
+        } while ( all && rrange && rrange != range );
+}
+
+static void 
+dasd_enable_single_device ( unsigned long arg ) {
+        dasd_device_t * device =(dasd_device_t *) arg;
+        int devno = device->devinfo.devno;
+        dasd_range_t range = { from: devno, to:devno };
+        dasd_enable_ranges (&range,NULL,0);
+}
+
+static void
+dasd_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)
 {
@@ -2377,13 +2817,12 @@ dasd_not_oper_handler (int irq, int status)
        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 @@ dasd_not_oper_handler (int irq, int status)
                        "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 */
 
-int
-dasd_oper_handler (int irq, devreg_t * devreg)
+static inline dasd_device_t **
+dasd_find_device_addr ( int devno ) 
 {
-       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;
+        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;
         }
-       if (dasd_autodetect) {
-               dasd_add_range (devno, 0);
+#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;
        }
-       rc = dasd_enable_single_volume (irq);
-       return rc;
+        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));
+}
+
+static inline void
+dasd_destroy_partitions ( 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++) {
+                device->major_info->gendisk.part[minor+i].start_sect = 0;
+                device->major_info->gendisk.part[minor+i].nr_sects   = 0;
+        }
+        devfs_register_partitions(&device->major_info->gendisk,
+                                  MINOR(device->kdev),1);
+}
+
+static inline void
+dasd_resetup_partitions ( dasd_device_t * device ) 
+{
+    BUG();
+    dasd_destroy_partitions ( device ) ;
+    dasd_setup_partitions ( device ) ;
 }
-#endif /* CONFIG_DASD_DYNAMIC */
 
-/* 
- * function dasd_set_device_level 
+/*
+ * 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 @@ typedef struct {
        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 @@ dasd_devices_open (struct inode *inode, struct file *file)
        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);
-                                       break;
-                               case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
-                                       len += sprintf (info->data + len, "busy   \n");
+                               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_PREPARED:
-                                       len += sprintf (info->data + len, "n/f    \n");
+                               case DASD_STATE_ACCEPT:
+                                        len += sprintf (info->data + len,"accepted");
                                        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);
+                               case DASD_STATE_INIT:
+                                       len +=
+                                           sprintf (info->data + len,
+                                                    "busy   ");
                                        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 @@ dasd_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t *
 }
 
 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 @@ dasd_devices_close (struct inode *inode, struct file *file)
                        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 @@ dasd_statistics_open (struct inode *inode, struct file *file)
        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 @@ dasd_statistics_open (struct inode *inode, struct file *file)
                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_init (void)
                                                   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;
+               DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+                                        "ECKD discipline %s", "failed");
+               goto failed;
        }
-#endif                         /* CONFIG_DASD_ECKD */
+#endif /* CONFIG_DASD_ECKD */
+#if defined(CONFIG_DASD_ECKD_MODULE) && defined(CONFIG_DASD_AUTO_ECKD)
+        kernel_thread(dasd_request_module,"dasd_eckd_mod",SIGCHLD);
+#endif /* CONFIG_DASD_AUTO_ECKD */
 #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;
-               }
+               DASD_DRIVER_DEBUG_EVENT (1, dasd_init,
+                                        "FBA 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);
-                        }
+#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 @@ dasd_init (void)
 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 @@ int
 init_module (void)
 {
        int rc = 0;
-       return dasd_init ();
+       rc = dasd_init ();
        return rc;
 }
 
@@ -3453,7 +4111,7 @@ cleanup_module (void)
  * 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
index 55581f607d4530a4eb8b1d26f087e5a753616b2a..a81fa2f8abfb3ce294f6bd01cd78520a23952e0b 100644 (file)
@@ -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 @@ dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
        /* check for successful execution first */
        if (stat->cstat == 0x00 &&
            stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
+                   return dasd_era_none;
        if (sense[0] & 0x80) {  /* CMD reject */
                return dasd_era_fatal;
        }
diff --git a/drivers/s390/block/dasd_3370_erp.h b/drivers/s390/block/dasd_3370_erp.h
new file mode 100644 (file)
index 0000000..3b56392
--- /dev/null
@@ -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 */
index e4db50d3f354e1a3a1a4c3932c7ab77171dcd4d3..c589c022c56f71c5267a1b7708d1497a43d9162c 100644 (file)
@@ -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 @@ log_erp_chain (ccw_req_t *cqr,
         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_erp_chain (ccw_req_t *cqr,
                 /* 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 @@ log_erp_chain (ccw_req_t *cqr,
  *   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_3990_erp_examine_24 (char *sense)
  *   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_3990_erp_examine (ccw_req_t *cqr,
         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;
 
@@ -333,6 +349,37 @@ dasd_3990_erp_examine (ccw_req_t *cqr,
  ***************************************************************************** 
  */
 
+/*
+ * 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 
  *
@@ -365,8 +412,9 @@ dasd_3990_erp_block_queue (ccw_req_t     *erp,
 
         /* 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 @@ dasd_3990_erp_block_queue (ccw_req_t     *erp,
 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 @@ dasd_3990_erp_restart_queue (unsigned long erp)
                                    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 @@ dasd_3990_erp_restart_queue (unsigned long erp)
         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 @@ dasd_3990_erp_restart_queue (unsigned long erp)
 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_3990_erp_alternate_path (ccw_req_t *erp)
        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 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp)
                 
        } 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 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp)
         
 } /* end dasd_3990_erp_alternate_path */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_DCTL
  *
@@ -527,7 +573,7 @@ dasd_3990_erp_alternate_path (ccw_req_t *erp)
  *   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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_DCTL (ccw_req_t *erp,
        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 @@ dasd_3990_erp_DCTL (ccw_req_t *erp,
        return dctl_cqr;
 
 } /* end dasd_3990_erp_DCTL */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_ACTION_1 
@@ -595,6 +660,7 @@ dasd_3990_erp_DCTL (ccw_req_t *erp,
 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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_action_4 (ccw_req_t *erp,
                                                    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 @@ dasd_3990_erp_action_4 (ccw_req_t *erp,
  ***************************************************************************** 
  */
 
-#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 @@ dasd_3990_erp_action_4 (ccw_req_t *erp,
 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 @@ dasd_3990_erp_action_5 (ccw_req_t *erp)
  *   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 @@ dasd_3990_handle_env_data (char *sense)
                        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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_com_rej (ccw_req_t *erp,
 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 @@ ccw_req_t *
 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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_data_check (ccw_req_t *erp,
 
        } 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 @@ dasd_3990_erp_data_check (ccw_req_t *erp,
 
        } 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 @@ ccw_req_t *
 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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_inv_format (ccw_req_t *erp,
  *   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_MESSAGE (KERN_WARNING, device,
-                      "%s",
-                      "End-of-Cylinder - must never happen\n");
+       dasd_device_t *device = default_erp->device;
 
-        /* implement action 7 */
-        BUG();
+        DASD_MESSAGE (KERN_ERR, device, "%s",
+                      "End-of-Cylinder - must never happen");
 
-       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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_env_data (ccw_req_t *erp,
 
 } /* end dasd_3990_erp_env_data */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERP_NO_REC
  *
@@ -1708,28 +1738,24 @@ dasd_3990_erp_env_data (ccw_req_t *erp,
  *   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 @@ dasd_3990_erp_no_rec (ccw_req_t *erp,
 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 @@ dasd_3990_erp_file_prot (ccw_req_t *erp)
  *   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 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
            (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 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
                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 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
            (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 @@ dasd_3990_erp_inspect_24 ( ccw_req_t *erp,
  ***************************************************************************** 
  */
 
-#ifdef ERP_FULL_ERP
 /*
  * DASD_3990_ERPACTION_10_32 
  *
@@ -1898,19 +1904,18 @@ ccw_req_t *
 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 @@ dasd_3990_erp_action_10_32 (ccw_req_t *erp,
  *   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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
        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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
         /* 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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
         
         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 ) {
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "%s",
+       if (!erp) {
+
+                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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
         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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
         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 @@ dasd_3990_erp_action_1B_32 (ccw_req_t *default_erp,
        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 @@ ccw_req_t *
 dasd_3990_update_1B (ccw_req_t *previous_erp,
                      char      *sense)
 {
+
        dasd_device_t  *device = previous_erp->device;
         __u32          cpa     = 0;
         ccw_req_t      *cqr;
@@ -2103,13 +2121,13 @@ dasd_3990_update_1B (ccw_req_t *previous_erp,
        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 @@ dasd_3990_update_1B (ccw_req_t *previous_erp,
         /* 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;
         } 
@@ -2132,17 +2149,9 @@ dasd_3990_update_1B (ccw_req_t *previous_erp,
         /* Imprecise ending is not set -> addr from IRB-SCSW */
         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 @@ dasd_3990_update_1B (ccw_req_t *previous_erp,
         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 @@ dasd_3990_update_1B (ccw_req_t *previous_erp,
         
 } /* 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 @@ void
 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 @@ void
 dasd_3990_erp_compound_path (ccw_req_t *erp,
                              char      *sense)
 {
-
+        
         if (sense[25] & DASD_SENSE_BIT_3) {
                 dasd_3990_erp_alternate_path (erp);
                 
                 if (erp->status == CQR_STATUS_FAILED) {
                         /* reset the lpm and the status to be able to 
                          * try further actions. */
-        
+                        
                         erp->lpm = LPM_ANYPATH;
                         
                         check_then_set (&erp->status,
@@ -2316,7 +2320,6 @@ ccw_req_t *
 dasd_3990_erp_compound_code (ccw_req_t *erp,
                              char      *sense)
 {
-
         
         if (sense[25] & DASD_SENSE_BIT_2) {
 
@@ -2337,7 +2340,8 @@ dasd_3990_erp_compound_code (ccw_req_t *erp,
                         break;
                         
                 default:
-                        BUG();
+                        /* should not happen - continue */
+
                 }
         }
 
@@ -2367,16 +2371,17 @@ void
 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_config (ccw_req_t *erp,
  * 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 @@ ccw_req_t *
 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 @@ dasd_3990_erp_compound (ccw_req_t *erp,
         return erp;
         
 } /* end dasd_3990_erp_compound */
-#endif /* ERP_FULL_ERP */  
 
 /*
  * DASD_3990_ERP_INSPECT_32 
@@ -2468,6 +2462,7 @@ ccw_req_t *
 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 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
        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 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                         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");
-
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "update write command error - should not "
+                                      "happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
+
+                        erp = dasd_3990_erp_cleanup (erp,
+                                                     CQR_STATUS_FAILED);
                         break;
 
                case 0x10:      /* logging required for other channel program */
@@ -2534,17 +2521,16 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                         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");
-
-                        check_then_set (&erp->status,
-                                        CQR_STATUS_ERROR,
-                                        CQR_STATUS_FAILED);
+                        DASD_MESSAGE (KERN_ERR, device, "%s",
+                                      "next track outside defined extend - "
+                                      "should not happen;\n"
+                                      "Please send this message together with "
+                                      "the above sense data to linux390@de."
+                                      "ibm.com");
+
+                        erp= dasd_3990_erp_cleanup (erp,
+                                                    CQR_STATUS_FAILED);
                         break;
-#endif /* ERP_FULL_ERP */  
 
                case 0x1B:      /* unexpected condition during write */
 
@@ -2552,22 +2538,18 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                                                           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 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
                                                       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 @@ dasd_3990_erp_inspect_32 ( ccw_req_t *erp,
 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 @@ dasd_3990_erp_inspect (ccw_req_t *erp)
 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 @@ dasd_3990_erp_additional_erp (ccw_req_t *cqr)
        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 @@ int
 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 @@ dasd_3990_erp_error_match (ccw_req_t *cqr1,
 
                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 @@ dasd_3990_erp_error_match (ccw_req_t *cqr1,
  *   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 @@ dasd_3990_erp_in_erp (ccw_req_t *cqr)
 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 @@ dasd_3990_erp_further_erp (ccw_req_t *erp)
        } 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 @@ dasd_3990_erp_further_erp (ccw_req_t *erp)
                                 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 @@ dasd_3990_erp_further_erp (ccw_req_t *erp)
  * 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)) {
+       while (erp_done != erp) {
 
-#ifdef ERP_DEBUG
-                DASD_MESSAGE (KERN_WARNING, device,
-                              "successful ERP - dequeue and free request %p",
-                              (void *) erp_done);
-#endif /* ERP_DEBUG */
-
-               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);
 
-       }
-
-       if (erp_done == NULL)   /* erp_done should never be NULL! */
-               panic (PRINTK_HEADER "Programming error in ERP! The original "
-                       "request was lost\n");
+       } /* end while */
 
-#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);
+                if (erp->function == dasd_3990_erp_action_4) {
                         
-                } 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 */  
+                        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 @@ dasd_3990_erp_handle_match_erp (ccw_req_t *erp_head,
  *   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 @@ dasd_3990_erp_action (ccw_req_t *cqr)
                      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 @@ dasd_3990_erp_action (ccw_req_t *cqr)
        }
        /* 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,39 +3057,179 @@ dasd_3990_erp_action (ccw_req_t *cqr)
                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.
  * Emacs will notice this stuff at the end of the file and automatically
index 57d675eabafdc18194e24a54fc448fa4be666c0d..c2a5e0b8317b50142e3455fa3be6b4334d756260 100644 (file)
@@ -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 @@ ccw_req_t *dasd_2105_erp_action (ccw_req_t *);
 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 */
index 9ece67cc9b000b76edbc98cb2ec56d3b5298cb07..e8293701f6d3515aafe9ea55b7368e81fc3e5b40 100644 (file)
@@ -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
  *   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 --git a/drivers/s390/block/dasd_9336_erp.h b/drivers/s390/block/dasd_9336_erp.h
new file mode 100644 (file)
index 0000000..ec36138
--- /dev/null
@@ -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 */
index 5faaebe1f9a88c762ab6fa5d20506a25b3b84b72..77fee48964734ebb2a9c14b81d0c38e2d14dc11e 100644 (file)
@@ -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;
 }
index b3cf273cf85a38c633f14c9c8909f141ee2bcd01..560dac5008884938b9d4af10b78d9c8f9e69494a 100644 (file)
@@ -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 */
index 945d21938c2eadfe31b1ccd46a4a41cb952c0a32..be5ac9e8be84eba7636de7f74714305781f302f6 100644 (file)
@@ -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 @@ dia210 (void *devchar)
                              ".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 @@ dia210 (void *devchar)
 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 @@ dia250 (void *iob, int cmd)
                              ".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 @@ mdsk_init_io (dasd_device_t * device, int blocksize, int offset, int size)
 
        rc = dia250 (iib, INIT_BIO);
 
-       return rc&3;
+       return rc & 3;
 }
 
 static __inline__ int
@@ -128,7 +126,7 @@ mdsk_term_io (dasd_device_t * device)
        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 @@ dasd_start_diag (ccw_req_t * cqr)
        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 @@ dasd_start_diag (ccw_req_t * cqr)
 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 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code)
                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 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code)
                        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 @@ dasd_ext_handler (struct pt_regs *regs, __u16 code)
        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 @@ dasd_diag_check_characteristics (struct dasd_device_t *device)
 
        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 @@ dasd_diag_check_characteristics (struct dasd_device_t *device)
        for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
                diag_bio_t *bio;
                diag_rw_io_t *iob = &private->iob;
-                
+
                rc = mdsk_init_io (device, bsize, 0, 64);
                if (rc > 4) {
                        continue;
                }
-               cqr = ccw_alloc_request (dasd_diag_discipline.name, 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 @@ dasd_diag_examine_error (ccw_req_t * cqr, devstat_t * stat)
        return dasd_era_fatal;
 }
 
-static dasd_erp_action_fn_t
-dasd_diag_erp_action (ccw_req_t * cqr)
-{
-       return default_erp_action;
-}
-
-static dasd_erp_postaction_fn_t
-dasd_diag_erp_postaction (ccw_req_t * cqr)
-{
-       if (cqr->function == default_erp_action)
-               return default_erp_postaction;
-       printk (KERN_WARNING PRINTK_HEADER
-               "unknown ERP action %p\n",
-               cqr->function);
-       return NULL;
-}
-
 static ccw_req_t *
 dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
 {
@@ -459,14 +421,12 @@ dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
        }
        bhct = 0;
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
-               if (bh->b_size > byt_per_blk)
-                       for (size = 0; size < bh->b_size; size += byt_per_blk)
-                               bhct++;
-               else
-                       bhct++;
+               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 @@ dasd_diag_build_cp_from_req (dasd_device_t * device, struct request *req)
 
        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 @@ dasd_diag_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
        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 @@ dasd_diag_init (void)
        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
index dfc532650147f894a29117e0bccb02bbfed9b260..5e94215ce93e4d9f6d3971a4f308247088a86d08 100644 (file)
@@ -29,9 +29,9 @@ typedef struct dasd_diag_characteristics_t {
        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 @@ typedef struct diag_bio_t {
        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 @@ typedef struct diag_init_io_t {
        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 @@ typedef struct diag_rw_io_t {
        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);
index ed2b888cd8b56d253055bc70fe32a6b1e328bceb..844e8b9698069ea492ec42e59d300713222f754d 100644 (file)
@@ -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
 
 #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 @@ typedef struct
 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 @@ ceil_quot (unsigned int d1, unsigned int d2)
 }
 
 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 @@ recs_per_track (dasd_eckd_characteristics_t * rdc,
                                       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 @@ recs_per_track (dasd_eckd_characteristics_t * rdc,
                                       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 @@ define_extent (ccw1_t * de_ccw,
        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 @@ define_extent (ccw1_t * de_ccw,
        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 @@ define_extent (ccw1_t * de_ccw,
                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 @@ locate_record (ccw1_t * lo_ccw,
        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 @@ dasd_eckd_id_check (s390_dev_info_t * info)
 {
        if (info->sid_data.cu_type == 0x3990 ||
            info->sid_data.cu_type == 0x2105)
-               if (info->sid_data.dev_type == 0x3390)
-                       return 0;
+                   if (info->sid_data.dev_type == 0x3390) return 0;
        if (info->sid_data.cu_type == 0x3990 ||
            info->sid_data.cu_type == 0x2105)
-               if (info->sid_data.dev_type == 0x3380)
-                       return 0;
+                   if (info->sid_data.dev_type == 0x3380) return 0;
        if (info->sid_data.cu_type == 0x9343)
                if (info->sid_data.dev_type == 0x9345)
                        return 0;
@@ -408,7 +391,7 @@ dasd_eckd_id_check (s390_dev_info_t * info)
 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 @@ dasd_eckd_check_characteristics (struct dasd_device_t *device)
 
        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 @@ dasd_eckd_init_analysis (struct dasd_device_t *device)
        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 @@ dasd_eckd_do_analysis (struct dasd_device_t *device)
 {
        int sb, rpt;
        dasd_eckd_private_t *private = (dasd_eckd_private_t *) device->private;
-        eckd_count_t *count_area = NULL;
-        char *cdl_msg;
-#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 @@ dasd_eckd_fill_geometry (struct dasd_device_t *device, struct hd_geometry *geo)
        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 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
        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 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
 
                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 @@ dasd_eckd_format_device (dasd_device_t * device, format_data_t * fdata)
                        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 @@ dasd_eckd_examine_error (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;
 
        switch (device->devinfo.sid_data.cu_type) {
        case 0x3990:
@@ -946,56 +949,56 @@ static dasd_erp_action_fn_t
 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 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
        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 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
        /* 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);
        }
-#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,
+       if (btrk < 2 && private->uses_cdl) {
+               if (etrk < 2)
+                        nlocs = bhct;
+                else
+                        nlocs = 2 * blk_per_trk - recid;
+       }
+       rw_cp = dasd_alloc_request (dasd_eckd_discipline.name, 
                                     2 + nlocs + bhct + 1,
-                                    sizeof (DE_eckd_data_t) +
-                                    (1+nlocs)*sizeof (LO_eckd_data_t));
-#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 @@ dasd_eckd_build_cp_from_req (dasd_device_t * device, struct request *req)
        rw_cp->lpm = LPM_ANYPATH;
        rw_cp->retries = 2;
        asm volatile ("STCK %0":"=m" (rw_cp->buildclk));
-       check_then_set (&rw_cp->status,
-                                      CQR_STATUS_EMPTY,
-                                      CQR_STATUS_FILLED);
+       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 @@ dasd_eckd_cleanup_request (ccw_req_t * cqr)
                                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 @@ dasd_eckd_cleanup_request (ccw_req_t * cqr)
 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 @@ dasd_eckd_reserve (struct dasd_device_t * device)
 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 @@ dasd_eckd_find_cmd (ccw_req_t * cqr, int cmd)
        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;
+                       cp = (ccw1_t *) (long) cp->cda;
+                       continue;
                }
-                break;
-       } while ( 1 );
-        return NULL;
+               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 @@ dasd_eckd_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
 
                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 @@ dasd_discipline_t dasd_eckd_discipline =
        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 @@ dasd_discipline_t dasd_eckd_discipline =
        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,41 +1346,63 @@ dasd_eckd_init (void)
        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]);
+       {
+               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);
+#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.
  * Emacs will notice this stuff at the end of the file and automatically
index cc06fc974d1e313b2d17990432a699de8f410ce8..b2b564104d4e1e6129ead13d2803d348fa9e67e7 100644 (file)
@@ -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
 #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 @@ typedef struct eckd_home_t {
        __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 @@ struct DE_eckd_data_t {
        __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 @@ struct LO_eckd_data_t {
        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 @@ struct dasd_eckd_characteristics_t {
        __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 @@ typedef struct dasd_eckd_confdata_t {
                __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 */
index a94017a289a554b5bb2277d6155d2ebb576f90d9..d55de1aad2a97254d4a1b46f884f73840dfb573a 100644 (file)
 #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
 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 @@ define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
        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 @@ locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
 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 @@ dasd_fba_check_characteristics (struct dasd_device_t *device)
 
        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 @@ dasd_fba_do_analysis (struct dasd_device_t *device)
                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_fba_examine_error (ccw_req_t * cqr, devstat_t * stat)
        dasd_device_t *device = (dasd_device_t *) cqr->device;
        if (stat->cstat == 0x00 &&
            stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
+                   return dasd_era_none;
 
        switch (device->devinfo.sid_data.dev_model) {
        case 0x3370:
@@ -236,17 +239,16 @@ dasd_fba_examine_error (ccw_req_t * cqr, devstat_t * stat)
 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 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req)
 {
        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 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req)
        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 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req)
                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 @@ dasd_fba_build_cp_from_req (dasd_device_t * device, struct request *req)
        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 @@ dasd_fba_dump_sense (struct dasd_device_t *device, ccw_req_t * req)
        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 @@ dasd_fba_init (void)
        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 @@ dasd_fba_cleanup( void ) {
         {
        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
index f78403d85d64679390639dfdf631a8ccdc7841c6..8ddad39f4a2032b8e27e3e85c15a4eec7a03b94a 100644 (file)
@@ -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 @@ struct DE_fba_data_t {
        __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 @@ struct LO_fba_data_t {
        __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 @@ struct dasd_fba_characteristics_t {
        __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 --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
new file mode 100644 (file)
index 0000000..df0d3f8
--- /dev/null
@@ -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:
+ */
index 4109e29abaf1a0fca2ad7b76c3b407487347c732..37114177869806a9561a99b4e548e8f3e49831da 100644 (file)
@@ -624,7 +624,7 @@ static void msgi_end(struct Scsi_Host *shpnt);
 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 @@ static void run(void)
                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 @@ static void rsti_run(struct Scsi_Host *shpnt)
  * bottom-half handler
  *
  */
-static void complete(struct Scsi_Host *shpnt)
+static void is_complete(struct Scsi_Host *shpnt)
 {
        int dataphase;
        unsigned long flags;
index be44ba5b274617bbb21a3da3687609cfab4e0d4e..ed3ffbccac15a4a9bede1f5a4a922b8bc33eda79 100644 (file)
@@ -1343,22 +1343,21 @@ ahc_print_scb(struct scb *scb)
               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),
index 8776f56d3c323074356010dd40c274b88422daa8..86b98dbc9fca07939f1349bc1affd509caa414d1 100644 (file)
@@ -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 @@ struct atp_unit
        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 @@ void is880(unsigned long host, unsigned int wkport)
        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 @@ inq_ok:
                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 @@ not_wide:
                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 @@ try_sync:
                        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 @@ tar_dcons:
 /* 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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                }
                for (k = 0; k < 16; k++) {
                        dev->id[k].curr_req = 0;
+                       dev->sp[k] = 0x04;
                }
        }
        h = 0;
@@ -2500,7 +2527,7 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                   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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                   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 @@ int atp870u_detect(Scsi_Host_Template * tpnt)
                   tmport = base_io + 0x51;
                   outb(0x20, tmport);
 
+                  tscam(h);
                   is880(h, base_io);
                   tmport = base_io + 0x38;
                   outb(0xb0, tmport);
@@ -2646,7 +2730,7 @@ find_adp:
                {
                    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 @@ const char *atp870u_info(struct Scsi_Host *notused)
 {
        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 @@ int atp870u_proc_info(char *buffer, char **start, off_t offset, int length,
        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 @@ int atp870u_release (struct Scsi_Host *pshost)
 
 static Scsi_Host_Template driver_template = ATP870U;
 #include "scsi_module.c"
-
index 1d795a447a4d89dfc86b52b3ad10e684f5e3e122..769a7f5122cc575e8dd252535e482f5ada4cd43d 100644 (file)
@@ -6,6 +6,23 @@ Tested in single and dual HBA configuration, 32 and 64bit busses,
 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 @@ is used), logical volumes on the RA4x00 will no longer be visible.
 
 
 Send questions/comments to:
-donald.zimmerman@compaq.com
-dszimmerman@yahoo.com
+Amy Vanzant-Hodge (fibrechannel@compaq.com)
+
index 966c63b8c3d59f2eeaef9cc0dceab4d8b928ec78..b65eca0ceb4f4a2cedca3ed16f2e9f39b6f8b76b 100644 (file)
@@ -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 @@ extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
  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 @@ extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
  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 */ 
index 31f4750a9cffd620483807ab677dd9678523d2f1..b0e51829b214757ffbf06da1fdf5811df030aebd 100644 (file)
 #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
index 96894bf13ba4458aa93d53727246d0e3d93987ca..03ecac44281759fc35c4ea2c2bc730eb947942a9 100644 (file)
 #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"
 
 #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 @@ static void Cpqfc_initHBAdata( CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
 
   // 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 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
        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 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
       // 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 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
       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 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
       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 @@ int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
        // 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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
   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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
  
   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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
          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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
         // 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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
         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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
        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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
        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 @@ int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg)
         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_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
 
 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 @@ int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
 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
 
-
-// To be done...       
-int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
+                               unsigned int reset_flags)
 {
-  int return_status = SUCCESS;
+  int timeout = 10*HZ;
+  int retries = 1;
+  char scsi_cdb[12];
+  unsigned long flags;
+  int result;
+  Scsi_Cmnd * SCpnt;
+  Scsi_Device * SDpnt;
 
-  ENTER("cpqfcTS_reset");
 
+  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
 
-            
+  if (ScsiDev->host->eh_active) return FAILED;
 
-  LEAVE("cpqfcTS_reset");
-  return return_status;
-}    
+  memset( scsi_cdb, 0, sizeof( scsi_cdb));
 
+  scsi_cdb[0] = RELEASE;
 
+  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 @@ void* fcMemManager( ALIGNED_MEM *dynamic_mem, ULONG n_alloc, ULONG ab,
 }
 
 
-
-
-#ifdef MODULE
-
 static Scsi_Host_Template driver_template = CPQFCTS;
 
 #include "scsi_module.c"
 
-
-#endif
-
-
index 2680228a411e396c769c3904f3208dbf1205ffaa..c573d32b9f60879fc82174bb8963dc3109cdc884 100644 (file)
@@ -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 @@ typedef __u8 BOOLEAN;
 #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
 
index 5e54d0455887741d14066f43c114589d036a0099..d7bd4d9963bb5b166e4aa4f40c3ffc78ad17411b 100644 (file)
@@ -149,7 +149,6 @@ static void IssueReportLunsCommand(
               CPQFCHBA* cpqfcHBAdata, 
              TachFCHDR_GCMND* fchs);
 
-
 // (see scsi_error.c comments on kernel task creation)
 
 void cpqfcTSWorkerThread( void *host)
@@ -1069,6 +1068,7 @@ void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
   pFcPort->flogi = FALSE;
   pFcPort->LOGO_timer = 0;
   pFcPort->device_blocked = TRUE; // block Scsi Requests
+  pFcPort->ScsiNexus.VolumeSetAddressing=0;    
 }
 
   
@@ -2934,7 +2934,6 @@ static void IssueReportLunsCommand(
   ULONG ulStatus;
   UCHAR *ucBuff;
 
-
   if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
   {
     printk("Discard Q'd ReportLun command\n");
@@ -2976,7 +2975,7 @@ static void IssueReportLunsCommand(
 
     Cmnd->channel = pLoggedInPort->ScsiNexus.channel;
     Cmnd->target = pLoggedInPort->ScsiNexus.target;
-    
+
            
     ulStatus = cpqfcTSBuildExchange(
       cpqfcHBAdata,
@@ -3404,7 +3403,7 @@ PFC_LOGGEDIN_PORT  fcFindLoggedInPort(
     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 @@ ULONG cpqfcTSBuildExchange(
       break;
     
     
-    
     case BLS_ABTS:   // FC defined basic link service command ABTS 
                      // Abort Sequence
                      
@@ -4498,6 +4496,7 @@ ULONG cpqfcTSBuildExchange(
 
                          // 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 @@ static int build_FCP_payload( Scsi_Cmnd *Cmnd,
       // 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)
       
index cb96ac3ba5e12805a1020c8a5d3204f1fd404ad8..0815d1954be39542dd70c725b733978568830a72 100644 (file)
@@ -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 @@ MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
 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 @@ typedef struct scsi_info_t {
        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 @@ static char nspinfo[100];     /* description */
 /* /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 @@ static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
        //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 @@ static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                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 @@ static int nsphw_init(void)
        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 @@ static int nsphw_init(void)
                                            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 @@ static int nsphw_init(void)
 /*
  * 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 @@ static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt)
 
        //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 @@ static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt)
        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 @@ static struct nsp_sync_table nsp_sync_table_20M[] = {
 /*
  * 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 @@ static int nsp_msg(Scsi_Cmnd *SCpnt)
 
        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 @@ static int nsp_msg(Scsi_Cmnd *SCpnt)
                 */
                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 @@ static int nsp_msg(Scsi_Cmnd *SCpnt)
 /*
  * 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 @@ static int nsp_expect_signal(Scsi_Cmnd       *SCpnt,
 /*
  * 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 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
                }
 
                /* 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 @@ static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
 /*
  * 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 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
        }
 
        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 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
         * 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 @@ static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
 /*
  * 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 @@ static int nsp_reselected(Scsi_Cmnd *SCpnt)
 
        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 @@ static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
 /*
  * 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 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt)
 
                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 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt)
                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 @@ static void nsp_pio_read(Scsi_Cmnd *SCpnt)
 /*
  * 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 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt)
                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 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt)
                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 @@ static void nsp_pio_write(Scsi_Cmnd *SCpnt)
 /*
  * 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 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt)
 
        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 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt)
        return 0;
 }
 
+#include "nsp_message.c"
 /*
  * interrupt handler
  */
@@ -853,13 +860,25 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        unsigned int   base;
        unsigned char  i_src, irq_phase, phase;
        Scsi_Cmnd     *tmpSC;
-       int            ret, len;
-       unsigned char  data_reg, control_reg;
+       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);
 
-       //DEBUG(0, __FUNCTION__ "(%d) CurrentSC=0x%p\n", irq, nsp_data.CurrentSC);
+       /* 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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        /*
         * 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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
 
        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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
                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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
 
        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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
 
        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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        /* 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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
 
                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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
                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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
                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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
 
                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 @@ static void nspintr(int irq, void *dev_id, struct pt_regs *regs)
        return; 
 
 timer_out:
-       nsp_start_timer(tmpSC, 1000/102);
+       nsp_start_timer(tmpSC, data, 1000/102);
        return;
 }
 
@@ -1175,6 +1187,136 @@ timer_out:
 #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 @@ static void cs_error(client_handle_t handle, int func, int ret)
 }
 
 /*======================================================================
-    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 @@ static void cs_error(client_handle_t handle, int func, int ret)
     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 @@ static dev_link_t *nsp_attach(void)
 
        /* 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 @@ static dev_link_t *nsp_attach(void)
                }
        }
        link->irq.Handler        = &nspintr;
+       link->irq.Instance       = &nsp_data;
 
        /* General socket configuration */
        link->conf.Attributes    = CONF_ENABLE_IRQ;
@@ -1244,18 +1387,18 @@ static dev_link_t *nsp_attach(void)
                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 @@ static dev_link_t *nsp_attach(void)
     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 @@ static void nsp_detach(dev_link_t *link)
 
        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 @@ static void nsp_detach(dev_link_t *link)
        *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 @@ while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
 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 @@ static void nsp_config(dev_link_t *link)
        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 @@ static void nsp_config(dev_link_t *link)
        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 @@ static void nsp_config(dev_link_t *link)
 
 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 @@ static void nsp_release(u_long arg)
        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 @@ static void nsp_release(u_long arg)
     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 @@ static int nsp_event(event_t                  event,
                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 @@ static int nsp_event(event_t                 event,
 
                        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 @@ static int nsp_event(event_t               event,
        }
        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 @@ static int __init nsp_init(void)
                       "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);
 
 /*
  *
index b6309f935fac1847010375b80de763a80335b629..610ccfdecac80baece8eae5cce46c43340c24ac9 100644 (file)
@@ -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 @@ typedef struct _nsp_data {
        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 @@ typedef struct _nsp_data {
 } 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 @@ enum _data_in_out {
 };
 
 
-#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__*/
index 328f545894d8d3517569db1a59198584c911f1d3..4c72343c04d739361d54bc0e3f6d4cc4f7cad7b7 100644 (file)
@@ -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 @@ static void show_busphase(unsigned char stat)
                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 */
index 21156e516db95af4691c4fda100b49ad65ab6ce6..a26358dd56b2f54b0d319c654adf5a020d902399 100644 (file)
@@ -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 --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c
new file mode 100644 (file)
index 0000000..6385bfb
--- /dev/null
@@ -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 */
index 3bf203c8dada3518f695da50ff62c56dcbcfe4a9..56774a5b90499b4eb0e4b817a6c258b3b26e145a 100644 (file)
@@ -1337,21 +1337,10 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                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 @@ static int isp2x00_reset_hardware(struct Scsi_Host *host)
 
        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);
index 749f6f445c4aec87ed0148da6ac93b8e1be14fb1..57f1817c1443ac0002e93a42064d2af3667222c7 100644 (file)
@@ -762,8 +762,17 @@ static int sd_init_onedisk(int i)
         */
 
        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;
 
index 0985f01df3e89e31dea561f5b641bb57807cc887..9a6d8395b6af06b4429ef47f11c2570b81d67d73 100644 (file)
@@ -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 @@ static void *usb_kbd_probe(struct usb_device *dev, unsigned int ifnum,
                        
        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;
index 6b2702b00b7514e4c632c2937f8e1e1a1cd6f4f3..e2ccafa93f79b686d6f75c6d147f8afc55ec1c18 100644 (file)
@@ -194,16 +194,20 @@ static void write_locked_buffers(struct buffer_head **array, unsigned int count)
        } 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 @@ repeat:
 
                        spin_unlock(&lru_list_lock);
                        write_locked_buffers(array, count);
-                       goto repeat;
+                       return -EAGAIN;
                }
                unlock_buffer(bh);
                put_bh(bh);
@@ -233,6 +237,18 @@ repeat:
 
        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 @@ static void refill_freelist(int size)
        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 @@ void balance_dirty(kdev_t dev)
 
        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 @@ busy_buffer_page:
                        loop = 1;
                        goto cleaned_buffers_try_again;
                }
-               wakeup_bdflush(0);
+               wakeup_bdflush();
        }
        return 0;
 }
@@ -2524,69 +2552,11 @@ void __init buffer_init(unsigned long mempages)
  * 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 @@ static int sync_old_buffers(void)
        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 @@ asmlinkage long sys_bdflush(int func, long data)
 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 @@ int bdflush(void *startup)
        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);
                }
index 40a05ce1ad107c07d56eba0aaae3eaae9b7e3b04..89ef2495affc93b8fe904434ec0f8832ba092f7e 100644 (file)
@@ -76,12 +76,24 @@ static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_s
        NULL
 };
 
+/*
+ *     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 @@ char *disk_name (struct gendisk *hd, int minor, char *buf)
                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}..
index f5b3d7430ab9fc54a432b7d45bc7d6b02ad61b45..dac6bfa3fe825cac18385e444c6188adc9e58472 100644 (file)
  * 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>
 #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 @@ static char* part_names[] = {   [ibm_partition_lnx1] = "LNX1",
                             [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 @@ first_part_minor)
        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 @@ first_part_minor)
                        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 @@ first_part_minor)
                add_gd_partition( hd, MINOR(dev), 0, 0);
                add_gd_partition( hd, MINOR(dev) + 1, 0, 0);
        }
-
+       
        printk ( "\n" );
        bforget(bh);
        return 1;
 }
-
index 2d264640c901edcb4e58dbdc2db180fc67dd9eba..ff3a86cc85963d30d94528273e4f1bfad645f037 100644 (file)
@@ -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,
 };
@@ -24,6 +25,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)
 {
        long long retval;
index 33cd30fc9a6d5e74b43c8a7e34a020691b4fa1da..ecc8278676ed3c939ae570d4441abcfee9b40d0a 100644 (file)
@@ -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
 
 #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
index 93565f5e01914f3df2126ff3069685e62a758b1d..ae5338ec5064a14f9005adb6010c317f59a975e7 100644 (file)
@@ -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
index 3bde842ce28838d54d25096dba0afcc106dafccd..f9ee1d530e482734c1692f5144d5478ce9938729 100644 (file)
@@ -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 @@ typedef struct format_data_t {
        int start_unit; /* from track */
        int stop_unit;  /* to track */
        int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 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
+/*
+ * 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
  */
-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;
+#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 */
 
 /*
index 2f53faaa672843e6fc1291d5dfc3f3929fb416a9..4a7927896ed566cb77e3a02ab0a6543b7498d12f 100644 (file)
 #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 @@ typedef struct volume_label {
 } __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 @@ typedef struct extent {
 } __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 @@ typedef struct dev_const {
 } __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 @@ typedef struct format1_label {
 } __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 @@ typedef struct format4_label {
 } __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 @@ void vtoc_set_date (
         __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_update_format4_label (
-       format4_label_t *f4,
-       cchhb_t *highest_f1,
-       __u8 unused_update,
-       __u16 freespace_update);
 
 
+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,
+       __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);
 
 
 
index 93565f5e01914f3df2126ff3069685e62a758b1d..ae5338ec5064a14f9005adb6010c317f59a975e7 100644 (file)
@@ -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
index 3bde842ce28838d54d25096dba0afcc106dafccd..f9ee1d530e482734c1692f5144d5478ce9938729 100644 (file)
@@ -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 @@ typedef struct format_data_t {
        int start_unit; /* from track */
        int stop_unit;  /* to track */
        int blksize;    /* sectorsize */
-        int intensity;  /* 0: normal, 1:record zero, 3:home address, 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
+/*
+ * 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
  */
-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;
+#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 */
 
 /*
index 2f53faaa672843e6fc1291d5dfc3f3929fb416a9..4a7927896ed566cb77e3a02ab0a6543b7498d12f 100644 (file)
 #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 @@ typedef struct volume_label {
 } __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 @@ typedef struct extent {
 } __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 @@ typedef struct dev_const {
 } __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 @@ typedef struct format1_label {
 } __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 @@ typedef struct format4_label {
 } __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 @@ void vtoc_set_date (
         __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_update_format4_label (
-       format4_label_t *f4,
-       cchhb_t *highest_f1,
-       __u8 unused_update,
-       __u16 freespace_update);
 
 
+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,
+       __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);
 
 
 
index 2b2c0bb1e7cb0c969cbf53d1da3212955aa194f2..4ac152dcf660aa29086e5ba995df5c7375ad620d 100644 (file)
@@ -180,7 +180,7 @@ extern int * max_segments[MAX_BLKDEV];
 #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)
index a716192ba71630ab193e826e8091de78df487199..a2d4abe3daf695d3f08e9505d03a4d2f75e6b5de 100644 (file)
@@ -1316,7 +1316,7 @@ static inline void bforget(struct buffer_head *buf)
 }
 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 int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned
 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;
index 094d40af864d3adf9ba6a756dc223452a78b4eaf..dd8cbdc9f1a80b49d971c957659dc400979580ea 100644 (file)
@@ -169,7 +169,7 @@ typedef enum {      CLOSED, OPEN } open_state;
 
 struct tok_info {
        unsigned char irq;
-       __u32 mmio;
+       void *mmio;
        unsigned char hw_address[32];
        unsigned char adapter_type;
        unsigned char data_rate;
index b209d49792f6da549f21692c632e5c2b00bf4805..fcd93ba5e88ba22894db22d896117f81dfd60052 100644 (file)
 #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
index d03c78ba43fced693a5245b64729a2a7381531df..28da97697470035986021fefabc0da066bb6c88e 100644 (file)
@@ -141,7 +141,8 @@ struct serial_uart_config {
                                             --- 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
index 0537365a817f24b8a89fd08bf821007a0bbd6c55..421635abc06935878b1fbad95aa24a5b4cfd6a5a 100644 (file)
@@ -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 @@ static int skip_atoi(const char **s)
 #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 @@ static char * number(char * str, long long num, int base, int size, int precisio
        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 (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)
-                       *str++ = c;
-       while (i < precision--)
-               *str++ = '0';
-       while (i-- > 0)
-               *str++ = tmp[i];
-       while (size-- > 0)
-               *str++ = ' ';
-       return str;
+       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 vsprintf(char *buf, const char *fmt, va_list args)
        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 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                                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 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                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 's':
+                               s = va_arg(args, char *);
+                               if (!s)
+                                       s = "<NULL>";
 
-               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;
+                               len = strnlen(s, precision);
 
-               case '%':
-                       *str++ = '%';
-                       continue;
+                               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;
 
-               /* integer number formats - set up the flags and "break" */
-               case 'o':
-                       base = 8;
-                       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 '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;
+
+                       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 '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,12 +438,53 @@ int vsprintf(char *buf, const char *fmt, va_list args)
                        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
@@ -389,3 +501,4 @@ int sprintf(char * buf, const char *fmt, ...)
        va_end(args);
        return i;
 }
+
index 70bc76731aeba089ad3e738d45d23af2a6d1c860..5f3cef59c05f1b5fe7a8cd6c37671f0bb52834ea 100644 (file)
@@ -309,7 +309,7 @@ repeat_alloc:
         * 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 @@ repeat_alloc:
         * 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.
index 3bfe6e6b70458a6880562d4e0b2ac45218ba23fc..5eb87a6d5df737614c40481a4314ec2f05c520cd 100644 (file)
@@ -754,18 +754,8 @@ static int shmem_statfs(struct super_block *sb, struct statfs *buf)
        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 @@ static int shmem_parse_options(char *options, int *mode, unsigned long * blocks,
        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 @@ out:
        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 @@ static struct super_block *shmem_read_super(struct super_block * sb, void * data
 {
        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)) {
@@ -1180,6 +1182,10 @@ static int __init init_shmem_fs(void)
                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;
 }
 
index 22f8effef852c42b038a2143f2b87778b445d64b..6bb196e1dc022b906952a7df6721fa4f4acc0866 100644 (file)
@@ -641,7 +641,7 @@ page_active:
                /* 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;
        }
 
index 37386ca2690f967d5c5421e4365a6eaea95c7e7b..4e19203beadf25184d04427de76d18fb1e717cdf 100644 (file)
@@ -210,7 +210,7 @@ static int atm_do_connect_dev(struct atm_vcc *vcc,struct atm_dev *dev,int vpi,
 
        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;
index 8749dfb0d76bb168892c55ae640b83beabfb2ca4..569344e9258e7d0750cd706b4861e25733f268b7 100644 (file)
@@ -274,7 +274,7 @@ static int rtnetlink_done(struct netlink_callback *cb)
 
 /* 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;
index b48d36bcb9747a9d0f47673f4c5d7105ad23d992..8fb747899740e11b42254773a0c86edfab5d4e95 100644 (file)
@@ -1335,7 +1335,7 @@ set_geometry () {
        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))