]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.17pre13 2.2.17pre13
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:51 +0000 (15:21 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:21:51 +0000 (15:21 -0500)
o Fix compile errors on userhelper (Several people)
o Small Alpha update/fixes (Jay Estabrook)
o Add bootup documentation (H Peter Anvin)
o S/390 partial merge of updates (Martin Schwidefsky)
o Bonding driver fixes (Andreas Steinmetz)
o Geert changed address (Geert Uytterhoeven)

100 files changed:
CREDITS
Documentation/Changes
Documentation/Debugging390.txt
Documentation/fb/00-INDEX
Documentation/fb/framebuffer.txt
Documentation/fb/internals.txt
Documentation/i386/boot.txt [new file with mode: 0644]
Documentation/serial-console.txt
Makefile
Rules.make
arch/alpha/config.in
arch/alpha/kernel/sys_mikasa.c
arch/alpha/kernel/sys_noritake.c
arch/m68k/amiga/chipram.c
arch/m68k/tools/amiga/dmesg.c
arch/s390/Makefile
arch/s390/boot/Makefile
arch/s390/defconfig
arch/s390/kernel/debug.c
arch/s390/kernel/debug.h [deleted file]
arch/s390/kernel/entry.S
arch/s390/kernel/head.S
arch/s390/kernel/irq.c
arch/s390/kernel/mathemu.c
arch/s390/kernel/process.c
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/s390io.c
arch/s390/kernel/s390mach.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/lib/delay.c
arch/s390/mm/fault.c
arch/s390/tools/dasdfmt/Makefile
arch/s390/tools/dasdfmt/dasdfmt.8
arch/s390/tools/dasdfmt/dasdfmt.c
arch/s390/tools/hwc_cntl_key/hwc_cntl_key.c
arch/s390/tools/silo/silo.c
drivers/char/console.c
drivers/net/Space.c
drivers/net/a2065.c
drivers/net/a2065.h
drivers/net/ariadne.c
drivers/net/ariadne.h
drivers/net/bonding.c
drivers/net/de4x5.c
drivers/net/hydra.c
drivers/s390/Config.in
drivers/s390/Makefile
drivers/s390/block/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd.h [new file with mode: 0644]
drivers/s390/block/dasd_3370_erp.c [new file with mode: 0644]
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_9336_erp.c [new file with mode: 0644]
drivers/s390/block/dasd_9343_erp.c
drivers/s390/block/dasd_ccwstuff.c [deleted file]
drivers/s390/block/dasd_ccwstuff.h [deleted file]
drivers/s390/block/dasd_diag.c [new file with mode: 0644]
drivers/s390/block/dasd_diag.h [new file with mode: 0644]
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eckd.h [new file with mode: 0644]
drivers/s390/block/dasd_eckd_erp.c
drivers/s390/block/dasd_erp.c [deleted file]
drivers/s390/block/dasd_erp.h [deleted file]
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_fba.h [new file with mode: 0644]
drivers/s390/block/dasd_mdsk.c [deleted file]
drivers/s390/block/dasd_mdsk.h [deleted file]
drivers/s390/block/dasd_proc.c [deleted file]
drivers/s390/block/dasd_profile.c [deleted file]
drivers/s390/block/dasd_setup.c [deleted file]
drivers/s390/block/dasd_types.h [deleted file]
drivers/s390/ccwcache.c [new file with mode: 0644]
drivers/s390/char/con3215.c
drivers/s390/char/hwc_tty.c
drivers/s390/net/ctc.c
drivers/s390/net/iucv.c
include/asm-s390/atomic.h
include/asm-s390/bitops.h
include/asm-s390/ccwcache.h [new file with mode: 0644]
include/asm-s390/dasd.h [new file with mode: 0644]
include/asm-s390/debug.h [new file with mode: 0644]
include/asm-s390/delay.h
include/asm-s390/irq.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/queue.h
include/asm-s390/s390io.h
include/asm-s390/setup.h
include/asm-s390/spinlock.h
include/asm-s390/string.h
include/asm-s390/uaccess.h
include/asm-s390/ucontext.h
include/linux/dasd.h [deleted file]
include/linux/kmod.h
init/main.c
net/core/dev.c
scripts/makelst [new file with mode: 0644]

diff --git a/CREDITS b/CREDITS
index 1be684dbcb5855c660dbcb775cba4d12ce94a030..44b8e4fe5be441fff6eccb420b7d57983721c7d9 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2124,7 +2124,7 @@ S: Germany
 
 N: Geert Uytterhoeven
 E: geert@linux-m68k.org
-W: http://www.cs.kuleuven.ac.be/~geert/
+W: http://home.tvd.be/cr26864/
 P: 1024/EC4A1EE1 8B 88 38 35 88 1E 95 A1  CD 9E AE DC 4B 4A 2F 41
 D: m68k/Amiga and PPC/CHRP Longtrail coordinator
 D: Frame buffer device and XF68_FBDev maintainer
index a22e2da9b909e4516120e0dc0fde444bfb5f1d31..405b900ac5b853d5848b4eeb57a1f5f511f93196 100644 (file)
@@ -753,7 +753,7 @@ Fbset
 =====
 
 The 2.1 release:
-http://www.cs.kuleuven.ac.be/~geert/bin/fbset-2.1.tar.gz
+http://home.tvd.be/cr26864/Linux/fbdev/
 
 PCI utils
 =========
index 7c67c06d0220872643017f1472e8878202574de7..6123b097dcf5cc03f082dd7c9cd827a9c263a65a 100644 (file)
@@ -520,9 +520,46 @@ main(int argc,char *argv[])
 }
 
 
+New compiler changes
+====================
+
+main(int argc,char *argv[])
+{
+  4004fc:      90 7f f0 1c             stm     %r7,%r15,28(%r15)
+  400500:      a7 d5 00 04             bras    %r13,400508 <main+0xc>
+  400504:      00 40 04 f4             .long   0x004004f4 
+  # compiler now puts constant pool in code to so it saves an instruction 
+  400508:      18 0f                   lr      %r0,%r15
+  40050a:      a7 fa ff a0             ahi     %r15,-96
+  40050e:      50 00 f0 00             st      %r0,0(%r15)
+       return(test(5));
+  400512:      58 10 d0 00             l       %r1,0(%r13)
+  400516:      a7 28 00 05             lhi     %r2,5
+  40051a:      0d e1                   basr    %r14,%r1
+  # compiler adds 1 extra instruction to epilogue this is done to
+  # avoid processor pipeline stalls owing to data dependencies on g5 &
+  # above as register 14 in the old code was needed directly after being loaded 
+  # by the lm  %r11,%r15,140(%r15) for the br %14.
+  40051c:      58 40 f0 98             l       %r4,152(%r15)
+  400520:      98 7f f0 7c             lm      %r7,%r15,124(%r15)
+  400524:      07 f4                   br      %r4
+}
+
+Hartmut ( our compiler developer ) also has been threatening to take out the
+stack backchain in optimised code as this also causes pipeline stalls, you
+have been warned.
+
+
+
 Compiling programs for debugging on Linux for S390
 ==================================================
-Make sure that the gcc is compiling & linking with the -g flag on.
+Make sure that the gcc is compiling & linking with the -g flag on
+this generates plain old gnu stabs, don't use
+-ggdb, -gxcoff+ or any other silly option these other options more than
+likely don't work ( we haven't tested them ), -gstabs is supposed to add
+extra extensions to the debugging info for debugging c++ we haven't got
+round to testing this yet.
+
 This is typically done adding/appending the flags -g to the 
 CFLAGS & LDFLAGS variables Makefile of the program concerned.
 
@@ -695,6 +732,39 @@ extern inline void spin_lock(spinlock_t *lp)
 6) If debugging under VM go down to that section in the document for more info.
 
 
+I now have a tool which takes the pain out of --adjust-vma
+& you are able to do something like
+make /arch/s390/kernel/traps.lst
+& it automatically generates the correctly relocated entries for
+the text segment in traps.lst.
+
+Add the following lines to you Rules.make
+%.lst: %.c
+       $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+       $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
+
+Copy the code snippet below into the scripts directory in a file called makelst
+it is'nt very pretty but it works & dont forget to chmod 755 makelst
+to make it an executable.
+#      $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+#      $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
+#
+#    Copyright (C) 2000 IBM Corporation
+#    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+#
+
+t1=`$3 --syms $2/$1.o | grep .text | grep " F " | head -n 1`
+t2=`echo $t1 | gawk '{ print $6 }'`
+t3=`grep $t2 $2/System.map`
+t4=`echo $t3 | gawk '{ print $1 }'`
+t5=`echo $t1 | gawk '{ print $1 }'`
+t6=`echo $t4 - $t5 | sed s/a/A/ | sed s/b/B/ | sed s/c/C/ | sed s/d/D/ | sed s/e/E/ | sed s/f/F/`
+t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst
+
+
+
+
 strace:
 -------
 Q. What is it ?
@@ -941,6 +1011,9 @@ TR BR <INTO OR FROM> will trace branches into or out of an address.
 e.g.
 TR BR INTO 0 is often quite useful if a program is getting awkward & deciding
 to branch to 0 & crashing as this will stop at the address before in jumps to 0.
+TR I R <address range> RUN cmd d g
+single steps a range of addresses but stays running &
+displays the gprs on each step.
 
 
 
@@ -992,6 +1065,9 @@ script with breakpoints on every kernel procedure, this isn't a good idea
 because there are thousands of these routines & VM can only set 255 breakpoints
 at a time so you nearly had to spend as long pruning the file down as you would 
 entering the msg's by hand ),however, the trick might be useful for a single object file.
+On linux'es 3270 emulator x3270 there is a very useful option under the file ment
+Save Screens In File this is very good of keeping a copy of traces. 
+
 
 
 Tracing Program Exceptions
@@ -1436,9 +1512,9 @@ Ingo's favourite trick is tracing all the IO's & CCWS & spooling them into the r
 VM guest so he can ftp the logfile back to his own machine.I'll do a small bit of this & give you
  a look at the output.
 
-1) Spool stdout to VM guest linux4's reader
-SP PRT TO 
-2) Fill linux4's reader with the trace
+1) Spool stdout to VM reader
+SP PRT TO (another vm guest ) or * for the local vm guest
+2) Fill the reader with the trace
 TR IO 7c08-7c09 INST INT CCW PRT RUN
 3) Start up linux 
 i 00c  
@@ -1775,7 +1851,9 @@ Breakpoint 2 at 0x4d87a4: file top.c, line 2609.
 
 LDD
 ===
-This is a program which lists the shared libraries which a library needs.
+This is a program which lists the shared libraries which a library needs,
+Note you also get the relocations of the shared library text segments which
+help when using objdump --source.
 e.g.
  ldd ./gdb
 outputs
@@ -1784,6 +1862,21 @@ libm.so.6 => /lib/libm.so.6 (0x4005e000)
 libc.so.6 => /lib/libc.so.6 (0x40084000)
 /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
 
+
+Debugging shared libraries
+==========================
+Most programs use shared libraries, however it can be very painful
+when you single step instruction into a function like printf for the 
+first time & you end up in functions like _dl_runtime_resolve this is
+the ld.so doing lazy binding, lazy binding is a concept in ELF where 
+shared library functions are not loaded into memory unless they are 
+actually used, great for saving memory but a pain to debug.
+To get around this either relink the program -static or exit gdb type 
+export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing 
+the program in question.
+
+
 Debugging modules
 =================
 As modules are dynamically loaded into the kernel their address can be
index 4140afb88c268e26e046c5b8b0682b922f9d2fc3..4bdd38e1484d0dee61cb59b0b368ce22ca94baee 100644 (file)
@@ -1,8 +1,7 @@
 Index of files in Documentation/fb.  If you think something about frame
 buffer devices needs an entry here, needs correction or you've written one
 please mail me.
-                                   Geert Uytterhoeven
-                                   <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+                               Geert Uytterhoeven <geert@linux-m68k.org>
 
 00-INDEX
        - this file
index 644a007a57e79d2bcec2d154005d8a9981f62fcf..c268d025a40b18ae5c838076e1879b3100d80654 100644 (file)
@@ -1,7 +1,7 @@
                        The Frame Buffer Device
                        -----------------------
 
-Maintained by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+Maintained by Geert Uytterhoeven <geert@linux-m68k.org>
 Last revised: November 7, 1998
 
 
index 7a6b9e99c0d14092f40f9277fbcb52ef9a2926d2..a73d721d7bbaddac31f223c6d45807aa380612d3 100644 (file)
@@ -2,7 +2,7 @@
 This is a first start for some documentation about frame buffer device
 internals.
 
-Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>, 21 July 1998
+Geert Uytterhoeven <geert@linux-m68k.org>, 21 July 1998
 
 --------------------------------------------------------------------------------
 
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
new file mode 100644 (file)
index 0000000..5b60016
--- /dev/null
@@ -0,0 +1,381 @@
+                    THE LINUX/I386 BOOT PROTOCOL
+                    ----------------------------
+
+                   H. Peter Anvin <hpa@zytor.com>
+                Updated as of protocol version 2.02
+
+On the i386 platform, the Linux kernel uses a rather complicated boot
+convention.  This has evolved partially due to historical aspects, as
+well as the desire in the early days to have the kernel itself be a
+bootable image, the complicated PC memory model and due to changed
+expectations in the PC industry caused by the effective demise of
+real-mode DOS as a mainstream operating system.
+
+Currently, four versions of the Linux/i386 boot protocol exist.
+
+Old kernels:   zImage/Image support only.  Some very early kernels
+               may not even support a command line.
+
+Protocol 2.00: Added bzImage and initrd support, as well as a
+               formalized way to communicate between the boot loader
+               and the kernel.
+
+Protocol 2.01: Added a heap overrun warning.
+
+Protocol 2.02: New command line protocol.  Lower the
+               conventional-memory ceiling.  zImage deprecated but
+               still supported.
+
+
+**** MEMORY LAYOUT
+
+The traditional memory map for the kernel loader, used for Image or
+zImage kernels, typically looks like:
+
+       |                        |
+0A0000 +------------------------+
+       |  Reserved for BIOS     |      Do not use.  Reserved for BIOS EBDA.
+09A000 +------------------------+
+       |  Stack/heap/cmdline    |      For use by the kernel real-mode code.
+098000 +------------------------+      
+       |  Kernel setup          |      The kernel real-mode code.
+090200 +------------------------+
+       |  Kernel boot sector    |      The kernel legacy boot sector.
+090000 +------------------------+
+       |  Protected-mode kernel |      The bulk of the kernel image.
+010000 +------------------------+
+       |  Boot loader           |      <- Boot sector entry point 0000:7C00
+001000 +------------------------+
+       |  Reserved for MBR/BIOS |
+000800 +------------------------+
+       |  Typically used by MBR |
+000600 +------------------------+ 
+       |  BIOS use only         |
+000000 +------------------------+
+
+
+When using bzImage, the protected-mode kernel was relocated to
+0x100000 ("high memory"), and the kernel real-mode block (boot sector,
+setup, and stack/heap) was made relocatable to any address between
+0x10000 and end of low memory.  Unfortunately, in protocols 2.00 and
+2.01 the command line is still required to live in the 0x9XXXX memory
+range, and that memory range is still overwritten by the early kernel.
+The 2.02 protocol fixes that.
+
+It is desirable to keep the "memory ceiling" -- the highest point in
+low memory touched by the boot loader -- as low as possible, since
+some newer BIOSes have begun to allocate some rather large amounts of
+memory, called the Extended BIOS Data Area, near the top of low
+memory.  The boot loader should use the "INT 12h" BIOS call to verify
+how much low memory is available.
+
+Unfortunately, if INT 12h reports that the amount of memory is too
+low, there is usually nothing the boot loader can do but to report an
+error to the user.  The boot loader should therefore be designed to
+take up as little space in low memory as it reasonably can.  For
+zImage or old bzImage kernels, which need data written into the
+0x90000 segment, the boot loader should make sure not to use memory
+above the 0x9A000 point; too many BIOSes will break above that point.
+
+
+**** THE REAL-MODE KERNEL HEADER
+
+In the following text, and anywhere in the kernel boot sequence, "a
+sector" refers to 512 bytes.  It is independent of the actual sector
+size of the underlying medium.
+
+The first step in loading a Linux kernel should be to load the
+real-mode code (boot sector and setup code) and then examine the
+following header at offset 0x01f1.  The real-mode code can total up to
+32K, although the boot loader may choose to load only the first two
+sectors (1K) and then examine the bootup sector size.
+
+The header looks like:
+
+Offset Proto   Name            Meaning
+Size
+
+01F1/1 ALL     setup_sects     The size of the setup in sectors
+01F2/2 ALL     root_flags      If set, the root is mounted readonly
+01F4/2 ALL     syssize         DO NOT USE - for bootsect.S use only
+01F6/2 ALL     swap_dev        DO NOT USE - obsolete
+01F8/2 ALL     ram_size        DO NOT USE - for bootsect.S use only
+01FA/2 ALL     vid_mode        Video mode control
+01FC/2 ALL     root_dev        Default root device number
+01FE/2 ALL     boot_flag       0xAA55 magic number
+0200/2 2.00+   jump            Jump instruction
+0202/4 2.00+   header          Magic signature "HdrS"
+0206/2 2.00+   version         Boot protocol version supported
+0208/4 2.00+   realmode_swtch  Boot loader hook (see below)
+020C/4 2.00+   start_sys       Points to kernel version string
+0210/1 2.00+   type_of_loader  Boot loader identifier
+0211/1 2.00+   loadflags       Boot protocol option flags
+0212/2 2.00+   setup_move_size Move to high memory size (used with hooks)
+0214/4 2.00+   code32_start    Boot loader hook (see below)
+0218/4 2.00+   ramdisk_image   initrd load address (set by boot loader)
+021C/4 2.00+   ramdisk_size    initrd size (set by boot loader)
+0220/4 2.00+   bootsect_kludge DO NOT USE - for bootsect.S use only
+0224/4 2.01+   heap_end_ptr    Free memory after setup end
+0226/2 N/A     pad1            Unused
+0228/4 2.02+   cmd_line_ptr    32-bit pointer to the kernel command line
+
+For backwards compatibility, if the setup_sects field contains 0, the
+real value is 4.
+
+If the "HdrS" (0x53726448) magic number is not found at offset 0x202,
+the boot protocol version is "old".  Loading an old kernel, the
+following parameters should be assumed:
+
+       Image type = zImage
+       initrd not supported
+       Real-mode kernel must be located at 0x90000.
+
+Otherwise, the "version" field contains the protocol version,
+e.g. protocol version 2.01 will contain 0x0201 in this field.  When
+setting fields in the header, you must make sure only to set fields
+supported by the protocol version in use.
+
+Most boot loaders will simply load the kernel at its target address
+directly.  Such a boot loader do not need to worry about filling in
+most of the fields in the header.  The following fields should be
+filled out, however:
+
+  type_of_loader:
+       If your boot loader has an identifier assigned in
+       arch/i386/boot/setup.S, enter that value.  Otherwise, enter
+       0xFF here.
+
+  loadflags, heap_end_ptr:
+       If the protocol version is 2.01 or higher, enter the
+       offset limit of the setup heap into heap_end_ptr and set the
+       0x80 bit (CAN_USE_HEAP) of loadflags.  heap_end_ptr appears to
+       be relative to the start of setup (offset 0x0200).
+
+  setup_move_size: 
+       When using protocol 2.00 or 2.01, if the real mode
+       kernel is not loaded at 0x90000, it gets moved there later in
+       the loading sequence.  Fill in this field if you want
+       additional data (such as the kernel command line) moved in
+       addition to the real-mode kernel itself.
+
+  ramdisk_image, ramdisk_size:
+       If your boot loader has loaded an initial ramdisk (initrd),
+       set ramdisk_image to the 32-bit pointer to the ramdisk data
+       and the ramdisk_size to the size of the ramdisk data.
+
+       The initrd should typically be located as high in memory as
+       possible, as it may otherwise get overwritten by the early
+       kernel initialization sequence.  However, it must never be
+       located above address 0x3C000000 if you want all kernels to
+       read it.
+
+  cmd_line_ptr:
+       If the protocol version is 2.02 or higher, this is a 32-bit
+       pointer to the kernel command line.  The kernel command line
+       can be located anywhere between the end of setup and 0xA0000.
+       Fill in this field even if your boot loader does not support a
+       command line, in which case you can point this to an empty
+       string (or better yet, to the string "auto".)  If this field
+       is left at zero, the kernel will assume that your boot loader
+       does not support the 2.02 protocol.
+
+
+**** THE KERNEL COMMAND LINE
+
+The kernel command line has become an important way for the boot
+loader to communicate with the kernel.  Some of its options are also
+relevant to the boot loader itself, see "special command line options"
+below.
+
+The kernel command line is a null-terminated string up to 255
+characters long, plus the final null.
+
+If the boot protocol version is 2.02 or later, the address of the
+kernel command line is given by the header field cmd_line_ptr (see
+above.)
+
+If the protocol version is *not* 2.02 or higher, the kernel
+command line is entered using the following protocol:
+
+       At offset 0x0020 (word), "cmd_line_magic", enter the magic
+       number 0xA33F.
+
+       At offset 0x0022 (word), "cmd_line_offset", enter the offset
+       of the kernel command line (relative to the start of the
+       real-mode kernel).
+       
+       The kernel command line *must* be within the memory region
+       covered by setup_move_size, so you may need to adjust this
+       field.
+
+
+**** SAMPLE BOOT CONFIGURATION
+
+As a sample configuration, assume the following layout of the real
+mode segment:
+
+       0x0000-0x7FFF   Real mode kernel
+       0x8000-0x8FFF   Stack and heap
+       0x9000-0x90FF   Kernel command line
+
+Such a boot loader should enter the following fields in the header:
+
+       unsigned long base_ptr; /* base address for real-mode segment */
+
+       if ( setup_sects == 0 ) {
+               setup_sects = 4;
+       }
+
+       if ( protocol >= 0x0200 ) {
+               type_of_loader = <type code>;
+               if ( loading_initrd ) {
+                       ramdisk_image = <initrd_address>;
+                       ramdisk_size = <initrd_size>;
+               }
+               if ( protocol >= 0x0201 ) {
+                       heap_end_ptr = 0x9000 - 0x200;
+                       loadflags |= 0x80; /* CAN_USE_HEAP */
+               }
+               if ( protocol >= 0x0202 ) {
+                       cmd_line_ptr = base_ptr + 0x9000;
+               } else {
+                       cmd_line_magic  = 0xA33F;
+                       cmd_line_offset = 0x9000;
+                       setup_move_size = 0x9100;
+               }
+       } else {
+               /* Very old kernel */
+
+               cmd_line_magic  = 0xA33F;
+               cmd_line_offset = 0x9000;
+
+               /* A very old kernel MUST have its real-mode code
+                  loaded at 0x90000 */
+
+               if ( base_ptr != 0x90000 ) {
+                       /* Copy the real-mode kernel */
+                       memcpy(0x90000, base_ptr, (setup_sects+1)*512);
+                       /* Copy the command line */
+                       memcpy(0x99000, base_ptr+0x9000, 256);
+               }
+
+               /* It is recommended to clear memory up to the 32K mark */
+               memset(0x90000 + (setup_sects-1)*512, 0,
+                      (64-setup_sects-1)*512);
+       }
+
+
+**** LOADING THE REST OF THE KERNEL
+
+The non-real-mode kernel starts at offset (setup_sects+1)*512 in the
+kernel file (again, if setup_sects == 0 the real value is 4.)  It
+should be loaded at address 0x10000 for Image/zImage kernels and
+0x100000 for bzImage kernels.
+
+The kernel is a bzImage kernel if the protocol >= 2.00 and the 0x01
+bit (LOAD_HIGH) in the loadflags field is set:
+
+       is_bzImage = (protocol >= 0x0200) && (loadflags & 0x01);
+       load_address = is_bzImage ? 0x100000 : 0x10000;
+
+Note that Image/zImage kernels can be up to 512K in size, and thus use
+the entire 0x10000-0x90000 range of memory.  This means it is pretty
+much a requirement for these kernels to load the real-mode part at
+0x90000.  bzImage kernels allow much more flexibility.
+
+
+**** SPECIAL COMMAND LINE OPTIONS
+
+If the command line provided by the boot loader is entered by the
+user, the user may expect the following command line options to work.
+They should normally not be deleted from the kernel command line even
+though not all of them are actually meaningful to the kernel.
+
+  vga=<mode>
+       <mode> here is either an integer (in C notation, either
+       decimal, octal, or hexadecimal) or one of the strings
+       "normal" (meaning 0xFFFF), "ext" (meaning 0xFFFE) or "ask"
+       (meaning 0xFFFD).  This value should be entered into the
+       vid_mode field, as it is used by the kernel before the command
+       line is parsed.
+
+  mem=<size>
+       <size> is an integer in C notation optionally followed by K, M
+       or G (meaning << 10, << 20 or << 30).  This specifies to the
+       kernel the memory size.  This affects the possible placement
+       of an initrd, since an initrd should be placed near end of
+       memory.
+
+  initrd=<file>
+       An initrd should be loaded.  The meaning of <file> is
+       obviously bootloader-dependent.
+
+In addition, some boot loaders add the following options to the
+user-specified command line:
+
+  BOOT_IMAGE=<file>
+       The boot image which was loaded.  Again, the meaning of <file>
+       is obviously bootloader-dependent.
+
+  auto
+       The kernel was booted without explicit user intervention.
+
+If these options are added by the boot loader, it is highly
+recommended that they are located *first*, before the user-specified
+or configuration-specified command line.  Otherwise, "init=/bin/sh"
+gets confused by the "auto" option.
+
+
+**** RUNNING THE KERNEL
+
+The kernel is started by jumping to the kernel entry point, which is
+located at *segment* offset 0x20 from the start of the real mode
+kernel.  This means that if you loaded your real-mode kernel code at
+0x90000, the kernel entry point is 9020:0000.
+
+At entry, ds = es = ss = fs = gs should point to the start of the
+real-mode kernel code (0x9000 if the code is loaded at 0x90000), and
+sp should be set up properly, normally pointing to the top of the
+heap.  In our example from above, we would do:
+
+       seg = base_ptr >> 4;
+
+       cli();  /* Enter with interrupts disabled! */
+
+       _SS = seg;
+       _SP = 0x9000;   /* Load SP right after loading SS! */
+       _DS = _ES = _FS = _GS = seg;
+       jmp_far(seg+0x20, 0);   /* Run the kernel */
+
+If your boot sector accesses a floppy drive, it is recommended to
+switch off the floppy motor before running the kernel, since the
+kernel boot leaves interrupts off and thus the motor will not be
+switched off.
+
+
+**** ADVANCED BOOT TIME HOOKS
+
+If the boot loader runs in a particularly hostile environment (such as
+LOADLIN, which runs under DOS) it may be impossible to follow the
+standard memory location requirements.  Such a boot loader may use the
+following hooks that, if set, are invoked by the kernel at the
+appropriate time.  The use of these hooks should probably be
+considered an absolutely last resort!
+
+IMPORTANT: All the hooks are required to preserve %ebp, %esi and %edi
+across invocation.
+
+  realmode_swtch:
+       A 16-bit real mode far subroutine invoked immediately before
+       entering protected mode.  The default routine disables NMI, so
+       your routine should probably do so, too.
+
+  code32_start:
+       A 32-bit flat-mode routine *jumped* to immediately after the
+       transition to protected mode, but before the kernel is
+       uncompressed.  No segments, except CS, are set up; you should
+       set them up to KERNEL_DS (0x18) yourself.
+
+       After completing your hook, you should jump to the address
+       that was in this field before your boot loader overwrote it.
+
index 2894b8008110f039d71a746abd1af6a75b86fb8e..50ac8058cfd1bc5f36dfc88d1d295d4551afad2b 100644 (file)
@@ -87,8 +87,8 @@ Replace the sample values as needed.
 
 6. Thanks
 
-   Thanks to Geert Uytterhoeven <Geert.Uytterhoeven@cs.kuleuven.ac.be>
-   for porting the patches from 2.1.4x to 2.1.6x for taking care of
-   the integration of these patches into m68k, ppc and alpha.
+   Thanks to Geert Uytterhoeven <geert@linux-m68k.org> for porting
+   the patches from 2.1.4x to 2.1.6x and for taking care of the
+   integration of these patches into m68k, ppc and alpha.
 
 Miquel van Smoorenburg <miquels@cistron.nl>, 21-Mar-1998
index 5fe6d2d0b791fd2a51f31ecc36ec05eaaf5cef0f..a5da9d79ada965a4f4b0a65c196cbb445b1ab92f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 17
-EXTRAVERSION = pre12
+EXTRAVERSION = pre13
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 9d0311f8f44d6dfa3063acd8f30de115ac36486a..88d70750d044596c8144785fa54a50bf06e7629f 100644 (file)
@@ -61,6 +61,9 @@ first_rule: sub_dirs
 %.o: %.s
        $(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
 
+%.lst: %.c
+       $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+       $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
 #
 #
 #
index 72f8eb345c2f2a80fcfd6a4ad22e5db629d21126..d26f0bff07c7f9c87f2d3d57bf21c7c3e21ce3ba 100644 (file)
@@ -149,22 +149,26 @@ then
        define_bool CONFIG_ALPHA_IRONGATE y
 fi
 
+if [ "$CONFIG_ALPHA_JENSEN" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
+        -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
+        -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
+        -o "$CONFIG_ALPHA_EIGER" = "y" ]
+then
+        define_bool CONFIG_ALPHA_SRM y
+fi
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
-       -o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" \
-       -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \
-       -o "$CONFIG_ALPHA_MIKASA" = "y" -o "$CONFIG_ALPHA_ALCOR" = "y" \
-       -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_MIATA" = "y" \
-       -o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
-       -o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \
-       -o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
-       -o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_NAUTILUS" = "y" ]
+        -o "$CONFIG_ALPHA_EB64P" = "y"  -o "$CONFIG_ALPHA_PC164" = "y" \
+        -o "$CONFIG_ALPHA_TAKARA" = "y" -o "$CONFIG_ALPHA_EB164" = "y" \
+        -o "$CONFIG_ALPHA_ALCOR" = "y"  -o "$CONFIG_ALPHA_MIATA" = "y" \
+        -o "$CONFIG_ALPHA_LX164" = "y"  -o "$CONFIG_ALPHA_SX164" = "y" \
+       -o "$CONFIG_ALPHA_NAUTILUS" = "y" ]
 then
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
-  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
-      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
-    fi
-  fi
+#  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#    if [ "$CONFIG_ALPHA_SRM" = "y" ]; then
+#      bool '  Use SRM PCI setup' CONFIG_ALPHA_SRM_SETUP
+#    fi
+#  fi
 fi
 if [ "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_MIKASA" = "y" \
        -o "$CONFIG_ALPHA_SABLE" = "y" -o "$CONFIG_ALPHA_NORITAKE" = "y" \
index fa438dfb9a030ee496d00b4569758a11b95cbd56..8e14593dda313402436565ff1df051ff7bdd78df 100644 (file)
@@ -151,8 +151,9 @@ mikasa_primo_pci_fixup(void)
        common_pci_fixup(mikasa_map_irq, common_swizzle);
 }
 
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
 static void
-mikasa_machine_check(unsigned long vector, unsigned long la_ptr,
+mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
                     struct pt_regs * regs)
 {
 #define MCHK_NO_DEVSEL 0x205U
@@ -175,14 +176,14 @@ mikasa_machine_check(unsigned long vector, unsigned long la_ptr,
                (la_ptr + mchk_header->sys_offset);
 
 #ifdef DEBUG
-       printk("mikasa_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+       printk("mikasa_apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n",
               vector, la_ptr);
        printk("        pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
               regs->pc, mchk_header->size, mchk_header->proc_offset,
               mchk_header->sys_offset);
-       printk("mikasa_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
-              apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
-              mchk_sysdata->epic_pear);
+       printk("mikasa_apecs_machine_check: expected %d DCSR 0x%lx"
+              " PEAR 0x%lx\n", apecs_mcheck_expected,
+              mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear);
        ptr = (unsigned long *)la_ptr;
        for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
                printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
@@ -213,7 +214,7 @@ mikasa_machine_check(unsigned long vector, unsigned long la_ptr,
                wrmces(0x1f);
                mb();
                draina();
-               printk("mikasa_machine_check: HW correctable (0x%lx)\n",
+               printk("mikasa_apecs_machine_check: HW correctable (0x%lx)\n",
                       vector);
        }
        else {
@@ -239,6 +240,7 @@ mikasa_machine_check(unsigned long vector, unsigned long la_ptr,
 #endif
        }
 }
+#endif
 
 
 /*
@@ -252,7 +254,7 @@ struct alpha_machine_vector mikasa_mv __initmv = {
        DO_DEFAULT_RTC,
        DO_APECS_IO,
        DO_APECS_BUS,
-       machine_check:          mikasa_machine_check,
+       machine_check:          mikasa_apecs_machine_check,
        max_dma_address:        ALPHA_MAX_DMA_ADDRESS,
 
        nr_irqs:                32,
index 2ade29654e7037745d8e86a35015590878379ed7..1bbefee1227ee6b7f3c0e8d63b5e7554c03b77c4 100644 (file)
@@ -238,6 +238,97 @@ noritake_primo_pci_fixup(void)
        common_pci_fixup(noritake_map_irq, noritake_swizzle);
 }
 
+#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
+static void
+noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
+                    struct pt_regs * regs)
+{
+#define MCHK_NO_DEVSEL 0x205U
+#define MCHK_NO_TABT 0x204U
+
+       struct el_common *mchk_header;
+       struct el_apecs_procdata *mchk_procdata;
+       struct el_apecs_mikasa_sysdata_mcheck *mchk_sysdata;
+       unsigned long *ptr;
+       unsigned int code; /* workaround EGCS problem */
+       int i;
+
+       mchk_header = (struct el_common *)la_ptr;
+
+       mchk_procdata = (struct el_apecs_procdata *)
+               (la_ptr + mchk_header->proc_offset
+                - sizeof(mchk_procdata->paltemp));
+
+       mchk_sysdata = (struct el_apecs_mikasa_sysdata_mcheck *)
+               (la_ptr + mchk_header->sys_offset);
+
+#ifdef DEBUG
+       printk("noritake_apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n",
+              vector, la_ptr);
+       printk("        pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+              regs->pc, mchk_header->size, mchk_header->proc_offset,
+              mchk_header->sys_offset);
+       printk("noritake_apecs_machine_check: expected %d DCSR 0x%lx"
+              " PEAR 0x%lx\n", apecs_mcheck_expected,
+              mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear);
+       ptr = (unsigned long *)la_ptr;
+       for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+               printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
+       }
+#endif
+
+       /*
+        * Check if machine check is due to a badaddr() and if so,
+        * ignore the machine check.
+        */
+
+       code = mchk_header->code; /* workaround EGCS problem */
+
+       if (apecs_mcheck_expected &&
+           (code == MCHK_NO_DEVSEL || code == MCHK_NO_TABT))
+       {
+               apecs_mcheck_expected = 0;
+               apecs_mcheck_taken = 1;
+               mb();
+               mb(); /* magic */
+               apecs_pci_clr_err();
+               wrmces(0x7);
+               mb();
+               draina();
+       }
+       else if (vector == 0x620 || vector == 0x630) {
+               /* Disable correctable from now on.  */
+               wrmces(0x1f);
+               mb();
+               draina();
+               printk("noritake_apecs_machine_check: HW correctable (0x%lx)\n",
+                      vector);
+       }
+       else {
+               printk(KERN_CRIT "NORITAKE APECS machine check:\n");
+               printk(KERN_CRIT "  vector=0x%lx la_ptr=0x%lx code=0x%x\n",
+                      vector, la_ptr, code);
+               printk(KERN_CRIT
+                      "  pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
+                      regs->pc, mchk_header->size, mchk_header->proc_offset,
+                      mchk_header->sys_offset);
+               printk(KERN_CRIT "  expected %d DCSR 0x%lx PEAR 0x%lx\n",
+                      apecs_mcheck_expected, mchk_sysdata->epic_dcsr,
+                      mchk_sysdata->epic_pear);
+
+               ptr = (unsigned long *)la_ptr;
+               for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
+                       printk(KERN_CRIT " +%lx %lx %lx\n",
+                              i*sizeof(long), ptr[i], ptr[i+1]);
+               }
+#if 0
+               /* doesn't work with MILO */
+               show_regs(regs);
+#endif
+       }
+}
+#endif
+
 
 /*
  * The System Vectors
@@ -250,7 +341,7 @@ struct alpha_machine_vector noritake_mv __initmv = {
        DO_DEFAULT_RTC,
        DO_APECS_IO,
        DO_APECS_BUS,
-       machine_check:          apecs_machine_check,
+       machine_check:          noritake_apecs_machine_check,
        max_dma_address:        ALPHA_MAX_DMA_ADDRESS,
 
        nr_irqs:                48,
index 50d5a0de0be08eefd64b9e964813585b29c153b0..9211f85997a210e27b8679cb0a42cd3bc340007f 100644 (file)
@@ -1,8 +1,7 @@
 /*
 **  linux/amiga/chipram.c
 **
-**      Modified 03-May-94 by Geert Uytterhoeven
-**                           (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+**      Modified 03-May-94 by Geert Uytterhoeven <geert@linux-m68k.org>
 **          - 64-bit aligned allocations for full AGA compatibility
 */
 
index 9affff5659ccaf214690164a91a236e619e06b81..e892748e73865e633a3e2a6d4f3349647eb17424 100644 (file)
@@ -3,8 +3,7 @@
  *                                        in Chip RAM with the kernel command
  *                                        line option `debug=mem'.
  *
- *  Â© Copyright 1996 by Geert Uytterhoeven
- *                    (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  Â© Copyright 1996 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  *
  *  Usage:
index d78d10d1e25fa8bc1936c2656826acc137759f68..22b04fe6dec6a0872fc5d10049c17d5e98cbf5ff 100644 (file)
@@ -1,5 +1,5 @@
 
-# i386/Makefile
+# s390/Makefile
 #
 # This file is included by the global makefile so that you can add your own
 # architecture-specific flags and dependencies. Remember to do have actions
index 9d3a7911ffca959e48679c234868d755cf9d0497..693522a6c22eaaf7ad52a8cb812ae53de37ed88a 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the linux s390-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
index c2fda8dd5febdef0a21b57576f493fc9951a8036..cb4a8d726246d7626798b8ba57fc7ef0feccd166 100644 (file)
@@ -26,8 +26,8 @@ CONFIG_KMOD=y
 #
 CONFIG_FAST_IRQ=y
 CONFIG_IPL=y
-# CONFIG_IPL_TAPE is not set
-CONFIG_IPL_VM=y
+CONFIG_IPL_TAPE=y
+# CONFIG_IPL_VM is not set
 CONFIG_NET=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
@@ -41,9 +41,9 @@ CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
 CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_BLK_DEV_XPRAM=y
-CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_XPRAM=m
 # CONFIG_MDISK is not set
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
@@ -140,7 +140,8 @@ CONFIG_EXT2_FS=y
 #
 # CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_SMB_FS is not set
index 6a69d8902a01ad980cf7aa27fe400f67ff012fcd..d03d566110c6ddac8a86da6244543768c58ddf00 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/errno.h>
 #include <linux/malloc.h>
 #include <asm/ebcdic.h>
+#include <asm/debug.h>
 
 #ifdef MODULE
 #include <linux/module.h>
@@ -10,9 +11,7 @@
 
 #include <asm/ebcdic.h>
 
-#include "debug.h"
-
-debug_info_t debug_areas[MAX_DEBUG_AREAS];
+debug_info_t debug_areas[MAX_DEBUG_AREAS] = { {NULL, },};
 debug_info_t *free_area = 0;
 static int initialized = 0;
 
@@ -38,6 +37,7 @@ debug_register (char *name, int page_order, int nr_areas)
   rc = free_area;
   free_area = *((debug_info_t **) rc);
 
+  memset(rc, 0, nr_areas * sizeof(debug_info_t));
   rc->areas = (debug_entry_t **) kmalloc (nr_areas *
                                          sizeof (debug_entry_t *),
                                          GFP_ATOMIC);
@@ -59,14 +59,16 @@ debug_register (char *name, int page_order, int nr_areas)
          goto nopages;
        }
     }
-
   rc->page_order = page_order;
   rc->nr_areas = nr_areas;
   rc->name = kmalloc (strlen (name) + 1, GFP_ATOMIC);
   strncpy (rc->name, name, strlen (name));
+  ASCEBC(rc->name, strlen (name));
   rc->name[strlen (name)] = 0;
+
   rc->active_entry = kmalloc (nr_areas, GFP_ATOMIC);
   memset(rc->active_entry, 0, nr_areas * sizeof(int));
+  rc->level=3;
   printk (KERN_INFO "reserved %d areas of %d pages for debugging %s\n",
          nr_areas, 1 << page_order, name);
   goto exit;
diff --git a/arch/s390/kernel/debug.h b/arch/s390/kernel/debug.h
deleted file mode 100644 (file)
index 836204f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-
-#ifndef DEBUG_H
-#define DEBUG_H
-
-#include <asm/spinlock.h>
-
-#define MAX_DEBUG_AREAS 16
-
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
-
-typedef struct
-{
-  union
-  {
-    struct
-    {
-      unsigned long long cpuid:4;
-      unsigned long long clock:60;
-    }
-    fields;
-    unsigned long long stck;
-  }
-  id;
-  void *caller;
-  union
-  {
-    unsigned long tag;
-    char text[4];
-  }
-  tag;
-}
-debug_entry_t;
-
-typedef struct
-{
-  char *name;
-  int level;
-  int nr_areas;
-  int page_order;
-  debug_entry_t **areas;
-  int active_area;
-  int *active_entry;
-  spinlock_t lock;
-}
-debug_info_t;
-
-int debug_init (void);
-debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
-void debug_unregister (debug_info_t * id, char *name);
-void debug_event (debug_info_t * id, int level, unsigned int tag);
-void debug_text_event (debug_info_t * id, int level, char tag[4]);
-void debug_exception (debug_info_t * id, int level, unsigned int tag);
-void debug_text_exception (debug_info_t * id, int level, char tag[4]);
-
-#endif
index 89048b793647ce44c16907857a7aeca4b313f00a..6affe76f9828f77f1ac89d99d0a85b152ac81454 100644 (file)
@@ -300,7 +300,7 @@ ret_from_fork:
         stosm   24(%r15),0x03     # reenable interrupts
         sr      %r0,%r0           # child returns 0
         st      %r0,SP_R2(%r15)   # store return value (change R2 on stack)
-#ifdef __SMP__
+#ifdef CONFIG_SMP
         l       %r1,BASED(.Lschedtail)
        la      %r14,BASED(sysc_return)
         br      %r1               # call schedule_tail, return to sysc_return
@@ -787,7 +787,7 @@ mcck_int_handler:
 mcck_return:
         RESTORE_ALL
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 /*
  * Restart interruption handler, kick starter for additional CPUs
  */
@@ -862,6 +862,6 @@ restart_go:
 .Ltrace:       .long  syscall_trace
 .Lvfork:       .long  sys_vfork
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 .Lschedtail:   .long  schedule_tail
 #endif
index dd63400322c29eef9b5c6e7ca18f067f51c08f8a..ff047820cf2e06b47f734313bbfb072392b6f694 100644 (file)
@@ -5,8 +5,9 @@
  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *               Rob van der Heij
  *
- * There are 4 different IPL methods
+ * There are 5 different IPL methods
  *  1) load the image directly into ram at address 0 and do an PSW restart
  *  2) linload will load the image from address 0x10000 to memory 0x10000
  *     and start the code thru LPSW 0x0008000080010000 (VM only, deprecated)
@@ -14,6 +15,7 @@
  *     and ipl from it
  *  4) generate the vm reader ipl header, move the generated image to the
  *     VM reader (use option NOH!) and do a ipl from reader (VM only)
+ *  5) direct call of start by the SALIPL loader
  *  We use the cpuid to distinguish between VM and native ipl
  *  params for kernel are pushed to 0x10400 (see setup.h)
  */
 
 #ifndef CONFIG_IPL
         .org   0
-        .long  0x00080000,0x80000000+iplstart  # Just a restart PSW
-
-iplstart:
-        l     %r12,.Lparm                      # pointer to parameter area
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0          # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        slr   %r2,%r2
-        st    %r2,INITRD_SIZE-PARMAREA(%r12)  # null ramdisk
-        st    %r2,INITRD_START-PARMAREA(%r12)
-        j     start
-
-.Lparm: .long  PARMAREA
-.L4malign0:.long 0xffc00000
-        .align 8
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
-
+        .long  0x00080000,0x80000000+startup   # Just a restart PSW
 #else
 #ifdef CONFIG_IPL_TAPE
 #define IPL_BS 1024
@@ -74,92 +49,6 @@ iplstart:
         .long  0x00080000,0x80000000+.Lioint   # io new psw
 
         .org   0x100
-iplstart:
-       l     %r1,0xb8                         # load ipl subchannel number
-        lhi   %r2,IPL_BS                       # load start address
-        bras  %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-        l     %r12,.Lparm                      # pointer to parameter area
-
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0          # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        c     %r2,.Lbigmem               # more than 64 MB of memory ?
-        jl    .Lmemok                    # if yes load ramdisk to 32 MB
-        mvc   INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from tape
-#
-       l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
-        bras  %r14,.Lloader                    # load parameter file
-        ltr   %r2,%r2                          # got anything ?
-        jz    .Lnopf
-       chi   %r2,895
-       jnh   .Lnotrunc
-       lhi   %r2,895
-.Lnotrunc:
-       l     %r4,INITRD_START-PARMAREA(%r12)
-        la    %r5,0(%r4,%r2)
-        lr    %r3,%r2
-.Lidebc:
-        tm    0(%r5),0x80                      # high order bit set ?
-        jo    .Ldocv                           #  yes -> convert from EBCDIC
-        ahi   %r5,-1
-        brct  %r3,.Lidebc
-        j     .Lnocv
-.Ldocv:
-        l     %r3,.Lcvtab
-        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
-        tr    256(256,%r4),0(%r3)
-        tr    512(256,%r4),0(%r3)
-        tr    768(122,%r4),0(%r3)
-.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
-       mvc   0(256,%r3),0(%r4)
-       mvc   256(256,%r3),256(%r4)
-       mvc   512(256,%r3),512(%r4)
-       mvc   768(122,%r3),768(%r4)
-        slr   %r0,%r0
-        j     .Lcntlp
-.Ldelspc:
-        ic    %r0,0(%r2,%r3)
-        chi   %r0,0x20                         # is it a space ?
-        je    .Lcntlp
-        ahi   %r2,1
-        j     .Leolp
-.Lcntlp:
-        brct  %r2,.Ldelspc
-.Leolp:
-        slr   %r0,%r0
-        stc   %r0,0(%r2,%r3)                   # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from tape
-#      
-       l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
-        bras  %r14,.Lloader                    # load ramdisk
-       st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
-        ltr   %r2,%r2
-        jnz   .Lrdcont
-        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
-.Lrdcont:
-#
-# everything loaded, go for it
-#
-        j     start
 #
 # subroutine for loading from tape
 # Paramters:   
@@ -173,32 +62,32 @@ iplstart:
         lctl  %c6,%c6,.Lcr6               
         slr   %r2,%r2
 .Lldlp:
-        lhi   %r6,3                            # 3 retries
+        l   %r6,3                            # 3 retries
 .Lssch:
         ssch  0(%r3)                           # load chunk of IPL_BS bytes
-        jnz   .Llderr
+        bnz   .Llderr
 .Lw4end:
-        bras  %r14,.Lwait4io
+        bas   %r14,.Lwait4io
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Lrecov
+        bnz   .Lrecov
         slr   %r7,%r7
         icm   %r7,3,10(%r5)                    # get residual count
         lcr   %r7,%r7
-        ahi   %r7,IPL_BS                       # IPL_BS-residual=#bytes read
+        la    %r7,IPL_BS(%r7)                  # IPL_BS-residual=#bytes read
         ar    %r2,%r7                          # add to total size
         tm    8(%r5),0x01                      # found a tape mark ?
-        jnz   .Ldone
+        bnz   .Ldone
         l     %r0,.Lccwread+4                  # update CCW data addresses
         ar    %r0,%r7
         st    %r0,.Lccwread+4                
-        j     .Lldlp
+        b     .Lldlp
 .Ldone:
         l     %r14,.Lldret
         br    %r14                             # r2 contains the total size
 .Lrecov:
-        bras  %r14,.Lsense                     # do the sensing
-        brct  %r6,.Lssch                       # dec. retry count & branch
-        j     .Llderr
+        bas   %r14,.Lsense                     # do the sensing
+        bct   %r6,.Lssch                       # dec. retry count & branch
+        b     .Llderr
 #
 # Sense subroutine
 #
@@ -206,11 +95,11 @@ iplstart:
         st    %r14,.Lsnsret
         la    %r7,.Lorbsense              
         ssch  0(%r7)                           # start sense command
-        jnz   .Llderr
-        bras  %r14,.Lwait4io
+        bnz   .Llderr
+        bas   %r14,.Lwait4io
         l     %r14,.Lsnsret
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Llderr
+        bnz   .Llderr
         br    %r14
 #
 # Wait for interrupt subroutine
@@ -219,13 +108,13 @@ iplstart:
         lpsw  .Lwaitpsw                 
 .Lioint:
         c     %r1,0xb8                         # compare subchannel number
-        jne   .Lwait4io
+        bne   .Lwait4io
         tsch  0(%r5)
         slr   %r0,%r0
         tm    8(%r5),0x82                      # do we have a problem ?
-        jnz   .Lwtexit
+        bnz   .Lwtexit
         tm    8(%r5),0x04                      # got device end ?
-        jz    .Lwait4io
+        bz    .Lwait4io
 .Lwtexit:
         br    %r14
 .Llderr:
@@ -249,18 +138,12 @@ iplstart:
 .Lcr6:  .long  0xff000000
         .align 8
 .Lcrash:.long  0x000a0000,0x00000000
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
-.Lparm: .long  PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
 .Lldret:.long  0
 .Lsnsret: .long 0
-.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
-
-#endif  /* CONFIG_IPL_TAPE */
+#endif  /* CONFIG_IPL_NONE */
 
 #ifdef CONFIG_IPL_VM
+#define IPL_BS 0x730
         .org   0
         .long  0x00080000,0x80000000+iplstart  # The first 24 bytes are loaded
         .long  0x02000018,0x60000050           # by ipl to addresses 0-23.
@@ -287,103 +170,7 @@ iplstart:
         .long  0x02000690,0x60000050
         .long  0x020006e0,0x20000050
 
-
         .org   0xf0
-iplstart:
-       l     %r1,0xb8                         # load ipl subchannel number
-        lhi   %r2,0x730                        # load start address
-        bras  %r14,.Lloader                    # load rest of ipl image
-        st    %r1,__LC_IPLDEV                  # store ipl device number
-       l     %r12,.Lparm                      # pointer to parameter area
-
-#
-# find out memory size
-#
-        mvc   104(8,0),.Lpcmem0           # setup program check handler
-        slr   %r2,%r2
-        lhi   %r3,1
-        sll   %r3,20
-.Lloop0:
-        l     %r0,0(%r2)                 # test page
-        ar    %r2,%r3                    # add 1M
-        jnm   .Lloop0                    # r1 < 0x80000000 -> loop
-.Lchkmem0:
-        n     %r2,.L4malign0             # align to multiples of 4M
-        st    %r2,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
-        c     %r2,.Lbigmem               # more than 64 MB of memory ?
-        jl    .Lmemok                    # if yes load ramdisk to 32 MB
-        mvc   INITRD_START-PARMAREA(4,%r12),.Lrdstart
-.Lmemok:
-
-#
-# load parameter file from reader
-#
-        l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
-        bras  %r14,.Lloader                    # load parameter file
-        ltr   %r2,%r2                          # got anything ?
-        jz    .Lnopf
-        chi   %r2,895
-        jnh   .Lnotrunc
-        lhi   %r2,895
-.Lnotrunc:
-        l     %r4,INITRD_START-PARMAREA(%r12)
-        la    %r5,0(%r4,%r2)
-        lr    %r3,%r2
-.Lidebc:
-        tm    0(%r5),0x80                      # high order bit set ?
-        jo    .Ldocv                           #  yes -> convert from EBCDIC
-        ahi   %r5,-1
-        brct  %r3,.Lidebc
-        j     .Lnocv
-.Ldocv:
-        l     %r3,.Lcvtab
-        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
-        tr    256(256,%r4),0(%r3)
-        tr    512(256,%r4),0(%r3)
-        tr    768(122,%r4),0(%r3)
-.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
-        mvc   0(256,%r3),0(%r4)
-        mvc   256(256,%r3),256(%r4)
-        mvc   512(256,%r3),512(%r4)
-        mvc   768(122,%r3),768(%r4)
-        slr   %r0,%r0
-        j     .Lcntlp
-.Ldelspc:
-        ic    %r0,0(%r2,%r3)
-        chi   %r0,0x20                         # is it a space ?
-        je    .Lcntlp
-        ahi   %r2,1
-        j     .Leolp
-.Lcntlp:
-        brct  %r2,.Ldelspc
-.Leolp:
-        slr   %r0,%r0
-        stc   %r0,0(%r2,%r3)                   # terminate buffer
-.Lnopf:
-
-#
-# load ramdisk from reader
-#      
-       l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
-        bras  %r14,.Lloader                    # load ramdisk
-       st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
-        ltr   %r2,%r2
-        jnz   .Lrdcont
-        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
-.Lrdcont:
-
-#
-# everything loaded, reset files in reader, then go for it
-#
-        stidp __LC_CPUID                       # store cpuid
-        lh    %r0,__LC_CPUID+4                 # get cpu version
-        chi   %r0,0x7490                       # running on P/390 ?
-        je   start                             #   no -> skip reset
-        la    %r2,.Lreset              
-        lhi   %r3,26
-        .long 0x83230008
-       j     start
-
 #
 # subroutine for loading cards from the reader
 #
@@ -394,29 +181,29 @@ iplstart:
         la    %r7,20
 .Linit:
         st    %r2,4(%r6)                       # initialize CCW data addresses
-        ahi   %r2,0x50
-        ahi   %r6,8
-        brct  7,.Linit
+        la    %r2,0x50(%r2)
+        la    %r6,8(%r6)
+        bct   7,.Linit
 
         lctl  %c6,%c6,.Lcr6                    # set IO subclass mask
        slr   %r2,%r2
 .Lldlp:
         ssch  0(%r3)                           # load chunk of 1600 bytes
-        jnz   .Llderr
+        bnz   .Llderr
 .Lwait4irq:
         mvc   __LC_IO_NEW_PSW(8),.Lnewpsw      # set up IO interrupt psw
         lpsw  .Lwaitpsw              
 .Lioint:
         c     %r1,0xb8                         # compare subchannel number
-       jne   .Lwait4irq
+       bne   .Lwait4irq
        tsch  0(%r5)
 
        slr   %r0,%r0
        ic    %r0,8(%r5)                       # get device status
        chi   %r0,8                            # channel end ?
-       je    .Lcont
+       be    .Lcont
        chi   %r0,12                           # channel end + device end ?
-       je    .Lcont
+       be    .Lcont
 
         l     %r0,4(%r5)
         s     %r0,8(%r3)                       # r0/8 = number of ccws executed
@@ -436,9 +223,9 @@ iplstart:
         ahi   %r0,0x640
         st    %r0,4(%r6)
         ahi   %r6,8
-        brct  7,.Lincr
+        bct   7,.Lincr
 
-        j     .Lldlp
+        b     .Lldlp
 .Llderr:
         lpsw  .Lcrash              
 
@@ -447,16 +234,7 @@ iplstart:
 .Lirb: .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
 .Lcr6:  .long  0xff000000
 .Lloadp:.long  0,0
-.Lparm:        .long  PARMAREA
-.L4malign0:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
-.Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
-        .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
-        .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
         .align 8
-.Lpcmem0:.long  0x00080000,0x80000000 + .Lchkmem0
 .Lcrash:.long  0x000a0000,0x00000000
 .Lnewpsw:
         .long  0x00080000,0x80000000+.Lioint
@@ -468,28 +246,203 @@ iplstart:
         .long  0x02600050,0x00000000
         .endr
         .long  0x02200050,0x00000000
-       
-        .org   0x730     # end of the area loaded by the ipl channel program
 #endif  /* CONFIG_IPL_VM */
 
+iplstart:
+        lh    %r1,0xb8                         # test if subchannel number
+        bct   %r1,.Lnoload                     #  is valid
+       l     %r1,0xb8                         # load ipl subchannel number
+        la    %r2,IPL_BS                       # load start address
+        bas   %r14,.Lloader                    # load rest of ipl image
+        st    %r1,__LC_IPLDEV                  # store ipl device number
+        l     %r12,.Lparm                      # pointer to parameter area
+
+#
+# load parameter file from ipl device
+#
+       l     %r2,INITRD_START-PARMAREA(%r12)  # use ramdisk location as temp
+        bas   %r14,.Lloader                    # load parameter file
+        ltr   %r2,%r2                          # got anything ?
+        bz    .Lnopf
+       chi   %r2,895
+       bnh   .Lnotrunc
+       la    %r2,895
+.Lnotrunc:
+       l     %r4,INITRD_START-PARMAREA(%r12)
+        la    %r5,0(%r4,%r2)
+        lr    %r3,%r2
+.Lidebc:
+        tm    0(%r5),0x80                      # high order bit set ?
+        bo    .Ldocv                           #  yes -> convert from EBCDIC
+        ahi   %r5,-1
+        bct   %r3,.Lidebc
+        b     .Lnocv
+.Ldocv:
+        l     %r3,.Lcvtab
+        tr    0(256,%r4),0(%r3)                # convert parameters to ascii
+        tr    256(256,%r4),0(%r3)
+        tr    512(256,%r4),0(%r3)
+        tr    768(122,%r4),0(%r3)
+.Lnocv: la    %r3,COMMAND_LINE-PARMAREA(%r12)  # load adr. of command line
+       mvc   0(256,%r3),0(%r4)
+       mvc   256(256,%r3),256(%r4)
+       mvc   512(256,%r3),512(%r4)
+       mvc   768(122,%r3),768(%r4)
+        slr   %r0,%r0
+        b     .Lcntlp
+.Ldelspc:
+        ic    %r0,0(%r2,%r3)
+        chi   %r0,0x20                         # is it a space ?
+        be    .Lcntlp
+        ahi   %r2,1
+        b     .Leolp
+.Lcntlp:
+        brct  %r2,.Ldelspc
+.Leolp:
+        slr   %r0,%r0
+        stc   %r0,0(%r2,%r3)                   # terminate buffer
+.Lnopf:
+
+#
+# load ramdisk from ipl device
+#      
+       l     %r2,INITRD_START-PARMAREA(%r12)  # load adr. of ramdisk
+        bas   %r14,.Lloader                    # load ramdisk
+       st    %r2,INITRD_SIZE-PARMAREA(%r12)   # store size of ramdisk
+        ltr   %r2,%r2
+        bnz   .Lrdcont
+        st    %r2,INITRD_START-PARMAREA(%r12)  # no ramdisk found, null it
+.Lrdcont:
+
+#ifdef CONFIG_IPL_VM
+#
+# reset files in VM reader
+#
+        stidp __LC_CPUID                       # store cpuid
+        lh    %r0,__LC_CPUID+4                 # get cpu version
+        chi   %r0,0x7490                       # running on P/390 ?
+        be    start                            #   no -> skip reset
+        la    %r2,.Lreset              
+        lhi   %r3,26
+        .long 0x83230008
+#endif
+       
+#
+# everything loaded, go for it
+#
+.Lnoload:
+        l     %r1,.Lstartup
+        br    %r1
+
+.Lparm:        .long  PARMAREA
+.Lstartup: .long startup
+.Lcvtab:.long  _ebcasc                         # ebcdic to ascii table
+.Lreset:.byte  0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+        .byte  0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+        .byte  0xc8,0xd6,0xd3,0xc4             # "change rdr all keep nohold"
+
 #endif  /* CONFIG_IPL */
 
+#
+# SALIPL loader support. Based on a patch by Rob van der Heij.
+# This entry point is called directly from the SALIPL loader and
+# doesn't need a builtin ipl record.
+#
+        .org  0x800
+       .globl start
+start:
+       stm   %r0,%r15,0x07b0           # store registers
+       basr  %r12,%r0
+.base:
+       l     %r11,.parm
+       l     %r8,.cmd                  # pointer to command buffer
+
+       ltr   %r9,%r9                   # do we have SALIPL parameters?
+       bp    .sk8x8
+
+       mvc   0(64,%r8),0x00b0          # copy saved registers
+       xc    64(240-64,%r8),0(%r8)     # remainder of buffer
+       tr    0(64,%r8),.lowcase        
+       b     .gotr
+.sk8x8:
+       mvc   0(240,%r8),0(%r9)         # copy iplparms into buffer
+.gotr:
+       l     %r10,.tbl                 # EBCDIC to ASCII table
+       tr    0(240,%r8),0(%r10)
+       stidp __LC_CPUID                # Are we running on VM maybe
+       cli   __LC_CPUID,0xff
+       bnz   .test
+       .long 0x83300060                # diag 3,0,x'0060' - storage size
+       b     .done
+.test:
+       mvc   0x68(8,0),.pgmnw          # set up pgm check handler
+       l     %r2,.fourmeg
+       lr    %r3,%r2
+       bctr  %r3,%r0                   # 4M-1
+.loop:  iske  %r0,%r3
+       ar    %r3,%r2
+.pgmx:
+       sr    %r3,%r2
+       la    %r3,1(%r3)
+.done:
+       st    %r3,MEMORY_SIZE-PARMAREA(%r11)    
+       slr   %r0,%r0
+       st    %r0,INITRD_SIZE-PARMAREA(%r11)
+       st    %r0,INITRD_START-PARMAREA(%r11)
+       j     startup                   # continue with startup
+.tbl:  .long _ebcasc                   # translate table
+.cmd:  .long COMMAND_LINE              # address of command line buffer
+.parm: .long PARMAREA
+.fourmeg: .long 0x00400000             # 4M
+.pgmnw:        .long 0x00080000,.pgmx
+.lowcase:
+       .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 
+       .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
+       .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 
+       .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
+       .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 
+       .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+       .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 
+       .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
+       .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 
+       .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
+       .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 
+       .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+       .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 
+       .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
+       .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 
+       .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
+
+       .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 
+       .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+       .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 
+       .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
+       .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 
+       .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
+       .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 
+       .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
+       .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87   # .abcdefg 
+       .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf   # hi
+       .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97   # .jklmnop
+       .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf   # qr
+       .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7   # ..stuvwx
+       .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef   # yz
+       .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 
+       .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
+
 #
 # startup-code at 0x10000, running in real mode
-# this is called either by the ipl loader or directly by PSW restart or linload
+# this is called either by the ipl loader or directly by PSW restart
+# or linload or SALIPL
 #
         .org  0x10000
-        .globl start
-start:  basr  %r13,0                     # get base
+startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load all control registers
        l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
 
 #
-# find out memory size. That is done in the ipl loader too but for
-# ipl from dasd the size of the memory has to be detected too...
+# find out memory size.
 #
-        icm   %r0,15,MEMORY_SIZE-PARMAREA(%r12)
-        jnz   .Lsizeok
        mvc   104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler
         slr   %r1,%r1
         lhi   %r2,1
@@ -497,23 +450,57 @@ start:  basr  %r13,0                     # get base
 .Lloop:        
        l     %r0,0(%r1)                 # test page
        ar    %r1,%r2                    # add 1M
-       jnm   .Lloop                     # r1 < 0x80000000 -> loop
+       bnm   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
 .Lchkmem:
        n     %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
        st    %r1,MEMORY_SIZE-PARMAREA(%r12)  # store memory size
 .Lsizeok:
 
+#
+# Now we have to move the ramdisk to a location approriate for the
+# memory size. If we have more than 64 MB of memory we move it to 32MB
+# to make room for the page tables set up by paging_init.
+#
+        l     %r1,MEMORY_SIZE-PARMAREA(%r12)
+        cl    %r1,.Lbigmem-.LPG1(%r13)   # memory < 64mb ?
+        bl    .Lnomove-.LPG1(%r13)       # if yes ramdisk @8MB is ok
+        icm   %r4,15,INITRD_START-PARMAREA(%r12)
+        bz    .Lnomove-.LPG1(%r13)
+       l     %r2,.Lrdstart-.LPG1(%r13)  # new address of ramdisk
+       st    %r2,INITRD_START-PARMAREA(%r12)
+        l     %r1,INITRD_SIZE-PARMAREA(%r12)
+       ar    %r2,%r1                    # we start moving at the end
+       ar    %r4,%r1                    #  because new location > old location
+.Lmove:        lr    %r0,%r2                    # new - old is the maximum we can move
+       sr    %r0,%r4                    #  because of overlapping
+       cr    %r0,%r1                    # we shouldn't move more than there is
+       bnh   .Lnoend-.LPG1(%r13)
+       lr    %r0,%r1
+.Lnoend:cl    %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go
+       bnh   .Lchunk-.LPG1(%r13)
+       l     %r0,.Lmaxchunk-.LPG1(%r13)
+.Lchunk:sr    %r2,%r0                    # make source & destination pointer
+       sr    %r4,%r0
+       lr    %r3,%r0                    # set source & destination length
+       lr    %r5,%r0
+       mvcl  %r2,%r4
+       sr    %r2,%r0                    # substract length again, since
+       sr    %r4,%r0                    #  mvcl added it to the pointers
+       sr    %r1,%r0                    # substract chunk size from length
+       bnz   .Lmove-.LPG1(%r13)
+.Lnomove:
+
 #
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
        tm     __LC_CPUID,0xff          # running under VM ?
-       jno    .Lnovm
+       bno    .Lnovm-.LPG1(%r13)
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),1    # set VM flag
 .Lnovm:
         lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
-        jne    .Lnop390
+        bne    .Lnop390-.LPG1(%r13)
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),4    # set P/390 flag
 .Lnop390:
 
@@ -526,6 +513,7 @@ start:  basr  %r13,0                     # get base
         adbr   %f0,%f2                  # test IEEE add instruction
         oi     MACHINE_FLAGS+3-PARMAREA(%r12),2    # set IEEE fpu flag
 .Lchkfpu:
+
 #
 # find out if we have the CSP instruction
 #
@@ -563,6 +551,9 @@ start:  basr  %r13,0                     # get base
 .Lflt0: .double 0
 .Lparm1:.long  PARMAREA
 .L4malign:.long 0xffc00000
+.Lbigmem:.long 0x04000000
+.Lrdstart:.long 0x02000000
+.Lmaxchunk:.long  0x00ffffff
 
 #
 # params at 10400 (setup.h)
@@ -573,21 +564,12 @@ start:  basr  %r13,0                     # get base
        .long  0                        # MEMORY_SIZE
        .long  0                        # MACHINE_FLAGS (bit 0:VM, bit 1:IEEE)
         .long  RAMDISK_ORIGIN           # INITRD_START
-        .long  0x800000                 # INITRD_SIZE
+        .long  RAMDISK_SIZE             # INITRD_SIZE
        .word  0                        # RAMDISK_FLAGS
 
         .org   COMMAND_LINE
-#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-#       .byte  "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off"
-#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot "
-#       .byte  "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-#       .byte  "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot "
-#       .byte  "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
-#       .byte  "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro"
-#       .byte  "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot "
-#       .byte  "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off"
        .byte  "root=/dev/ram0 ro"
-#       .byte  0
+        .byte  0
 
 #
 # startup-code, running in virtual mode
index f90f91632eeb23e7a18342feb03c0cb59edab831..d110f9afdcf3f1f941ab66ccc966e99dcdc137ca 100644 (file)
@@ -86,7 +86,7 @@ int get_irq_list(char *buf)
                        continue;
 
                p += sprintf(p, "%3d: ",i);
-#ifndef __SMP__
+#ifndef CONFIG_SMP
                p += sprintf(p, "%10u ", kstat_irqs(i));
 #else
                for (j=0; j<smp_num_cpus; j++)
@@ -107,7 +107,7 @@ int get_irq_list(char *buf)
        } /* endfor */
 
        p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
-#ifdef __SMP__
+#ifdef CONFIG_SMP
        p += sprintf(p, "IPI: %10u\n", atomic_read(&ipi_count));
 #endif
 
@@ -119,7 +119,7 @@ int get_irq_list(char *buf)
  * Global interrupt locks for SMP. Allow interrupts to come in on any
  * CPU, yet make cli/sti act globally to protect critical regions..
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
 atomic_t global_irq_lock;
 atomic_t global_irq_count = ATOMIC_INIT(0);
index 1abf0f59498b4e9c31a8740b26256d351d840b0d..f99d721376d1b27931ac14ed54d0a10f5cf14462 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/mathemu.h>
 
+static void display_emulation_not_implemented(char *instr)
+{
+       struct pt_regs *regs=current->tss.regs;
+       printk("%s not implemented\n",instr);
+       printk("Process with %s instruction %s (pid: %d, stackpage=%08X)\n",
+              instr,
+                current->comm, current->pid, 4096+(addr_t)current);
+       printk("%s's PSW:    %08lx %08lx\n",instr,
+                (unsigned long) regs->psw.mask,
+                (unsigned long) regs->psw.addr);
+}
+
 static void set_CC_df(__u64 val1,__u64 val2) {
         int rc;
         rc = __cmpdf2(val1,val2);
@@ -69,7 +81,7 @@ static void emu_aebr (int rx, int ry) {
 }
 
 static void emu_axbr (int rx, int ry) {
-        printk("axbr emulation not implemented!\n");
+        display_emulation_not_implemented("axbr");
 }
 
 static void emu_cdb (int rx, __u64 val) {
@@ -109,15 +121,15 @@ static void emu_cfebr (int rx, int ry, int mask) {
 }
 
 static void emu_cfxbr (int rx, int ry, int mask) {
-        printk("cfxbr emulation not implemented!\n");
+        display_emulation_not_implemented("cfxbr");
 }
 
 static void emu_cxbr (int rx, int ry) {
-        printk("cxbr emulation not implemented!\n");
+        display_emulation_not_implemented("cxbr");
 }
 
 static void emu_cxfbr (int rx, int ry) {
-        printk("cxfbr emulation not implemented!\n");
+        display_emulation_not_implemented("cxfbr");
 }
 
 static void emu_ddb (int rx, __u64 val) {
@@ -143,51 +155,51 @@ static void emu_debr (int rx, int ry) {
 }
 
 static void emu_didbr (int rx, int ry, int mask) {
-        printk("didbr emulation not implemented!\n");
+        display_emulation_not_implemented("didbr");
 }
 
 static void emu_diebr (int rx, int ry, int mask) {
-        printk("diebr emulation not implemented!\n");
+        display_emulation_not_implemented("diebr");
 }
 
 static void emu_dxbr (int rx, int ry) {
-        printk("dxbr emulation not implemented!\n");
+        display_emulation_not_implemented("dxbr");
 }
 
 static void emu_efpc (int rx, int ry) {
-        printk("efpc emulation not implemented!\n");
+        display_emulation_not_implemented("efpc");
 }
 
 static void emu_fidbr (int rx, int ry, int mask) {
-        printk("fidbr emulation not implemented!\n");
+        display_emulation_not_implemented("fidbr");
 }
 
 static void emu_fiebr (int rx, int ry, int mask) {
-        printk("fiebr emulation not implemented!\n");
+        display_emulation_not_implemented("fiebr");
 }
 
 static void emu_fixbr (int rx, int ry, int mask) {
-        printk("fixbr emulation not implemented!\n");
+        display_emulation_not_implemented("fixbr");
 }
 
 static void emu_kdb (int rx, __u64 val) {
-        printk("kdb emulation not implemented!\n");
+        display_emulation_not_implemented("kdb");
 }
 
 static void emu_kdbr (int rx, int ry) {
-        printk("kdbr emulation not implemented!\n");
+        display_emulation_not_implemented("kdbr");
 }
 
 static void emu_keb (int rx, __u32 val) {
-        printk("keb emulation not implemented!\n");
+        display_emulation_not_implemented("keb");
 }
 
 static void emu_kebr (int rx, int ry) {
-        printk("kebr emulation not implemented!\n");
+        display_emulation_not_implemented("kebr");
 }
 
 static void emu_kxbr (int rx, int ry) {
-        printk("kxbr emulation not implemented!\n");
+        display_emulation_not_implemented("kxbr");
 }
 
 static void emu_lcdbr (int rx, int ry) {
@@ -203,7 +215,7 @@ static void emu_lcebr (int rx, int ry) {
 }
 
 static void emu_lcxbr (int rx, int ry) {
-        printk("lcxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lcxbr");
 }
 
 static void emu_ldeb (int rx, __u32 val) {
@@ -216,7 +228,7 @@ static void emu_ldebr (int rx, int ry) {
 }
 
 static void emu_ldxbr (int rx, int ry) {
-        printk("ldxbr emulation not implemented!\n");
+        display_emulation_not_implemented("ldxbr");
 }
 
 static void emu_ledbr (int rx, int ry) {
@@ -225,19 +237,19 @@ static void emu_ledbr (int rx, int ry) {
 }
 
 static void emu_lexbr (int rx, int ry) {
-        printk("lexbr emulation not implemented!\n");
+        display_emulation_not_implemented("lexbr");
 }
 
 static void emu_lndbr (int rx, int ry) {
-        printk("lndbr emulation not implemented!\n");
+        display_emulation_not_implemented("lndbr");
 }
 
 static void emu_lnebr (int rx, int ry) {
-        printk("lnebr emulation not implemented!\n");
+        display_emulation_not_implemented("lnebr");
 }
 
 static void emu_lnxbr (int rx, int ry) {
-        printk("lnxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lnxbr");
 }
 
 static void emu_lpdbr (int rx, int ry) {
@@ -251,7 +263,7 @@ static void emu_lpebr (int rx, int ry) {
 }
 
 static void emu_lpxbr (int rx, int ry) {
-        printk("lpxbr emulation not implemented!\n");
+        display_emulation_not_implemented("lpxbr");
 }
 
 static void emu_ltdbr (int rx, int ry) {
@@ -265,39 +277,39 @@ static void emu_ltebr (int rx, int ry) {
 }
 
 static void emu_ltxbr (int rx, int ry) {
-        printk("ltxbr emulation not implemented!\n");
+        display_emulation_not_implemented("ltxbr");
 }
 
 static void emu_lxdb (int rx, __u64 val) {
-        printk("lxdb emulation not implemented!\n");
+        display_emulation_not_implemented("lxdb");
 }
 
 static void emu_lxdbr (int rx, int ry) {
-        printk("lxdbr emulation not implemented!\n");
+        display_emulation_not_implemented("lxdbr");
 }
 
 static void emu_lxeb (int rx, __u32 val) {
-        printk("lxeb emulation not implemented!\n");
+        display_emulation_not_implemented("lxeb");
 }
 
 static void emu_lxebr (int rx, int ry) {
-        printk("lxebr emulation not implemented!\n");
+        display_emulation_not_implemented("lxebr");
 }
 
 static void emu_madb (int rx, __u64 val, int mask) {
-        printk("madb emulation not implemented!\n");
+        display_emulation_not_implemented("madb");
 }
 
 static void emu_madbr (int rx, int ry, int mask) {
-        printk(" emulation not implemented!\n");
+        display_emulation_not_implemented("madbr");
 }
 
 static void emu_maeb (int rx, __u32 val, int mask) {
-        printk("maeb emulation not implemented!\n");
+        display_emulation_not_implemented("maeb");
 }
 
 static void emu_maebr (int rx, int ry, int mask) {
-        printk("maebr emulation not implemented!\n");
+        display_emulation_not_implemented("maebr");
 }
 
 static void emu_mdb (int rx, __u64 val) {
@@ -312,11 +324,11 @@ static void emu_mdbr (int rx, int ry) {
 }
 
 static void emu_mdeb (int rx, __u32 val) {
-        printk("mdeb emulation not implemented!\n");
+        display_emulation_not_implemented("mdeb");
 }
 
 static void emu_mdebr (int rx, int ry) {
-        printk("mdebr emulation not implemented!\n");
+        display_emulation_not_implemented("mdebr");
 }
 
 static void emu_meeb (int rx, __u32 val) {
@@ -332,31 +344,31 @@ static void emu_meebr (int rx, int ry) {
 }
 
 static void emu_msdb (int rx, __u64 val, int mask) {
-        printk("msdb emulation not implemented!\n");
+        display_emulation_not_implemented("msdb");
 }
 
 static void emu_msdbr (int rx, int ry, int mask) {
-        printk("msdbr emulation not implemented!\n");
+        display_emulation_not_implemented("msdbr");
 }
 
 static void emu_mseb (int rx, __u32 val, int mask) {
-        printk("mseb emulation not implemented!\n");
+        display_emulation_not_implemented("mseb");
 }
 
 static void emu_msebr (int rx, int ry, int mask) {
-        printk("msebr emulation not implemented!\n");
+        display_emulation_not_implemented("msebr");
 }
 
 static void emu_mxbr (int rx, int ry) {
-        printk("mxbr emulation not implemented!\n");
+        display_emulation_not_implemented("mxbr");
 }
 
 static void emu_mxdb (int rx, __u64 val) {
-        printk("mxdb emulation not implemented!\n");
+        display_emulation_not_implemented("mxdb");
 }
 
 static void emu_mxdbr (int rx, int ry) {
-        printk("mxdbr emulation not implemented!\n");
+        display_emulation_not_implemented("mxdbr");
 }
 
 static void emu_sdb (int rx, __u64 val) {
@@ -384,43 +396,43 @@ static void emu_sebr (int rx, int ry) {
 }
 
 static void emu_sfpc (int rx, int ry) {
-        printk("sfpc emulation not implemented!\n");
+        display_emulation_not_implemented("sfpc");
 }
 
 static void emu_sqdb (int rx, __u64 val) {
-        printk("sqdb emulation not implemented!\n");
+        display_emulation_not_implemented("sqdb");
 }
 
 static void emu_sqdbr (int rx, int ry) {
-        printk("sqdbr emulation not implemented!\n");
+        display_emulation_not_implemented("sqdbr");
 }
 
 static void emu_sqeb (int rx, __u32 val) {
-        printk("sqeb emulation not implemented!\n");
+        display_emulation_not_implemented("sqeb");
 }
 
 static void emu_sqebr (int rx, int ry) {
-        printk("sqebr emulation not implemented!\n");
+        display_emulation_not_implemented("sqebr");
 }
 
 static void emu_sqxbr (int rx, int ry) {
-        printk("sqxbr emulation not implemented!\n");
+        display_emulation_not_implemented("sqxbr");
 }
 
 static void emu_sxbr (int rx, int ry) {
-        printk("sxbr emulation not implemented!\n");
+        display_emulation_not_implemented("sxbr");
 }
 
 static void emu_tcdb (int rx, __u64 val) {
-        printk("tcdb emulation not implemented!\n");
+        display_emulation_not_implemented("tcdb");
 }
 
 static void emu_tceb (int rx, __u32 val) {
-        printk("tceb emulation not implemented!\n");
+        display_emulation_not_implemented("tceb");
 }
 
 static void emu_tcxb (int rx, __u64 val) {
-        printk("tcxb emulation not implemented!\n");
+        display_emulation_not_implemented("tcxb");
 }
 
 
index f5d13c3c22f7301f7190b6e867ea79c63e1c481a..f71b5fc31e1cf68d733e9493a71ab8125b3bfc9d 100644 (file)
@@ -57,7 +57,7 @@ asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 static psw_t wait_psw;
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 static
 #endif
 int cpu_idle(void *unused)
@@ -69,7 +69,12 @@ int cpu_idle(void *unused)
        wait_psw.mask = _WAIT_PSW_MASK;
        wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
        while(1) {
+#ifdef CONFIG_SMP
+                if (atomic_read(&global_bh_lock) == 0 &&
+                    (bh_mask & bh_active)) {
+#else
                 if (bh_mask & bh_active) {
+#endif
                         do_bottom_half();
                         continue;
                 }
index 71a693960632314ffa6a0219194688958567412b..58a2568cab7054aac8ebe94f36fa386d8b8b0e5a 100644 (file)
@@ -5,10 +5,17 @@
  */
 #include <linux/config.h>
 #include <linux/module.h>
+#include <asm/debug.h>
+#include <linux/genhd.h>
+#include <asm/ccwcache.h>
 #include <asm/irq.h>
 #include <asm/string.h>
 #include <asm/checksum.h>\r
 #include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
+#include <asm/ebcdic.h>
+#include <asm/timex.h>
+#include <asm/delay.h>
 #if CONFIG_CHANDEV
 #include <asm/chandev.h>
 #endif
@@ -16,7 +23,6 @@
 #include <net/arp.h>
 #endif
 
-
 /*
  * I/O subsystem
  */
@@ -30,13 +36,28 @@ EXPORT_SYMBOL(get_irq_by_devno);
 EXPORT_SYMBOL(get_devno_by_irq);
 EXPORT_SYMBOL(get_irq_first);
 EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
 
-/*
- * External interrupts
- */
 EXPORT_SYMBOL(register_external_interrupt);
 EXPORT_SYMBOL(unregister_external_interrupt);
 
+/*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister); 
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_text_exception);
+
 /*
  * memory management
  */
@@ -61,10 +82,18 @@ EXPORT_SYMBOL_NOVERS(strrchr);
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
+EXPORT_SYMBOL_NOVERS(_ascebc_500);
+EXPORT_SYMBOL_NOVERS(_ebcasc_500);
+EXPORT_SYMBOL_NOVERS(_ascebc);
+EXPORT_SYMBOL_NOVERS(_ebcasc);
+EXPORT_SYMBOL_NOVERS(_ebc_tolower);
+EXPORT_SYMBOL_NOVERS(_ebc_toupper);
+
 /*
  * misc.
  */
-#ifdef __SMP__
+EXPORT_SYMBOL(__udelay);
+#ifdef CONFIG_SMP
 #include <asm/smplock.h>
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
@@ -73,17 +102,14 @@ EXPORT_SYMBOL(__global_restore_flags);
 EXPORT_SYMBOL(global_bh_lock);
 EXPORT_SYMBOL(synchronize_bh);
 EXPORT_SYMBOL(kernel_flag);
+EXPORT_SYMBOL(smp_ctl_set_bit);
+EXPORT_SYMBOL(smp_ctl_clear_bit);
 #endif
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
-#if CONFIG_CHANDEV
-EXPORT_SYMBOL(chandev_register_and_probe);
-EXPORT_SYMBOL(chandev_unregister);
-EXPORT_SYMBOL(chandev_initdevice);
-EXPORT_SYMBOL(chandev_initnetdevice);
-#endif
+EXPORT_SYMBOL(genhd_dasd_name);
+
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
 EXPORT_SYMBOL(arp_mc_map);
 #endif
-
index e80b1d05465da6b71ed2bfddfc9a29329fc785d6..c63e62852d89308d654101a0d3c3370957c9c122 100644 (file)
@@ -49,7 +49,6 @@ ioinfo_t         *ioinfo[__MAX_SUBCHANNELS] = {
 static spinlock_t sync_isc = SPIN_LOCK_UNLOCKED;
                                           // synchronous irq processing lock
 static psw_t      io_sync_wait;           // wait PSW for sync IO, prot. by sync_isc
-static psw_t      io_new_psw;             // save I/O new PSW, prot. by sync_isc
 static int        cons_dev          = -1; // identify console device
 static int        init_IRQ_complete = 0;
 static schib_t    init_schib;
@@ -340,7 +339,8 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                {
                        s390irq_spin_unlock_irqrestore( irq, flags);
 
-                       printk("free_irq() : error, dev_id does not match !");
+                       printk( "free_irq(%04X) : error, "
+                               "dev_id does not match !", irq);
 
                } /* endif */
 
@@ -349,7 +349,8 @@ void s390_free_irq(unsigned int irq, void *dev_id)
        {
                s390irq_spin_unlock_irqrestore( irq, flags);
 
-               printk("free_irq() : error, no action block ... !");
+               printk( "free_irq(%04X) : error, "
+                       "no action block ... !\n", irq);
 
        } /* endif */
 
@@ -906,7 +907,6 @@ int s390_start_IO( int            irq,      /* IRQ */
                if ( flag & DOIO_WAIT_FOR_INTERRUPT )
                {
                        int              io_sub = -1;
-                       __u32            io_parm;
          psw_t            io_new_psw;
          int              ccode;
                        uint64_t         time_start;            
@@ -2504,15 +2504,7 @@ int s390_process_IRQ( unsigned int irq )
                                ioinfo[irq]->devstat.flag             |= DEVSTAT_FINAL_STATUS;
                                ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS;
 
-                               if ( ioinfo[irq]->ui.flags.newreq )
-                               {
-                                       action->handler( irq, ioinfo[irq]->u_intparm );
-                               }
-                               else
-                               {
-                                       ((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-                               } /* endif */
+                               action->handler( irq, action->dev_id, &regs );
 
                                //
                                // reset intparm after final status or we will badly present unsolicited
@@ -2544,15 +2536,7 @@ int s390_process_IRQ( unsigned int irq )
                                         */
                                        if ( ret )
                                        {
-                                               if ( ioinfo[irq]->ui.flags.newreq )
-                                               {
-                                                       action->handler( irq, ioinfo[irq]->u_intparm );
-                                               }
-                                               else
-                                               {
-                                                       ((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-                                               } /* endif */
+                                               action->handler( irq, action->dev_id, &regs );
 
                                        } /* endif */
 
@@ -2573,23 +2557,14 @@ int s390_process_IRQ( unsigned int irq )
                                        ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_PCI;
                                        ioinfo[irq]->devstat.cstat &= ~SCHN_STAT_PCI;
                                }
-                               else if ( actl & SCSW_ACTL_SUSPENDED )
+
+                               if ( actl & SCSW_ACTL_SUSPENDED )
                                {
                                        ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_SUSPENDED;
 
                                } /* endif */
 
-                               if ( ioinfo[irq]->ui.flags.newreq )
-                               {
-                                       action->handler( irq, ioinfo[irq]->u_intparm );
-                               }
-                               else
-                               {
-                                       ((io_handler_func1_t)action->handler)( irq,
-                                                                              action->dev_id,
-                                                                              &regs );
-
-                               } /* endif */
+                               action->handler( irq, action->dev_id, &regs );
 
                        } /* endif */
 
@@ -2672,15 +2647,7 @@ int s390_process_IRQ( unsigned int irq )
 
                if ( !ioinfo[irq]->ui.flags.s_pend )
                {
-                       if ( ioinfo[irq]->ui.flags.newreq )
-                       {
-                               action->handler( irq, ioinfo[irq]->u_intparm );
-                       }
-                       else
-                       {
-                               ((io_handler_func1_t)action->handler)( irq, action->dev_id, &regs );
-
-                       } /* endif */
+                       action->handler( irq, action->dev_id, &regs );
 
                } /* endif */
 
@@ -3794,17 +3761,27 @@ int get_dev_info_by_irq( int irq, dev_info_t *pdi)
                pdi->devno = ioinfo[irq]->schib.pmcw.dev;
                pdi->irq   = irq;
 
-               if ( ioinfo[irq]->ui.flags.oper )
+               if (     ioinfo[irq]->ui.flags.oper
+           && !ioinfo[irq]->ui.flags.unknown )
                {
                        pdi->status = 0;
                        memcpy( &(pdi->sid_data),
                                &ioinfo[irq]->senseid,
                                sizeof( senseid_t));
                }
+               else if ( ioinfo[irq]->ui.flags.unknown )
+               {
+                       pdi->status = DEVSTAT_UNKNOWN_DEV;
+                       memset( &(pdi->sid_data),
+                               '\0',
+                               sizeof( senseid_t));
+                       pdi->sid_data.cu_type = 0xFFFF;
+
+               }
                else
                {
                        pdi->status = DEVSTAT_NOT_OPER;
-                       memcpy( &(pdi->sid_data),
+                       memset( &(pdi->sid_data),
                                '\0',
                                sizeof( senseid_t));
                        pdi->sid_data.cu_type = 0xFFFF;
@@ -3814,10 +3791,9 @@ int get_dev_info_by_irq( int irq, dev_info_t *pdi)
                if ( ioinfo[irq]->ui.flags.ready )
                        pdi->status |= DEVSTAT_DEVICE_OWNED;
 
-               return 0;
-
        } /* endif */
 
+       return 0;
 }
 
 
@@ -3843,23 +3819,37 @@ int get_dev_info_by_devno( unsigned int devno, dev_info_t *pdi)
                        if (    ioinfo[i] != INVALID_STORAGE_AREA
                             && ioinfo[i]->schib.pmcw.dev == devno )
                        {
-                               if ( ioinfo[i]->ui.flags.oper )
-                               {
-                                       pdi->status = 0;
+
                                        pdi->irq    = i;
                                        pdi->devno  = devno;
 
+                               if (    ioinfo[i]->ui.flags.oper
+                 && !ioinfo[i]->ui.flags.unknown )
+                               {
+                                       pdi->status = 0;
+
                                        memcpy( &(pdi->sid_data),
                                                &ioinfo[i]->senseid,
                                                sizeof( senseid_t));
                                }
+                               else if ( ioinfo[i]->ui.flags.unknown )
+                               {
+                                       pdi->status = DEVSTAT_UNKNOWN_DEV;
+
+                                       memset( &(pdi->sid_data),
+                       '\0',
+                       sizeof( senseid_t));
+
+                                       pdi->sid_data.cu_type = 0xFFFF;
+                               }
                                else
                                {
                                        pdi->status = DEVSTAT_NOT_OPER;
-                                       pdi->irq    = i;
-                                       pdi->devno  = devno;
 
-                                       memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
+                                       memset( &(pdi->sid_data),
+                       '\0',
+                       sizeof( senseid_t));
+
                                        pdi->sid_data.cu_type = 0xFFFF;
 
                                } /* endif */
@@ -3975,6 +3965,7 @@ void s390_device_recognition_irq( int irq )
                        else
                        {
                                ioinfo[irq]->ui.flags.syncio = 1; // global
+                               ioinfo[irq]->ui.flags.unknown = 0;
 
                                memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
 
@@ -4735,14 +4726,14 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                ioinfo[irq]->schib.pmcw.dev,
                                irq);
 #endif
-                       ioinfo[irq]->ui.flags.oper = 0;
+                       ioinfo[irq]->ui.flags.unknown = 1;
 
                } /* endif */
 
                /*
                 * Issue device info message if unit was operational .
                 */
-               if ( ioinfo[irq]->ui.flags.oper )
+               if ( ioinfo[irq]->ui.flags.unknown )
        {
                        if ( sid->dev_type != 0 )
       {
@@ -4766,7 +4757,7 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
        } /* endif */
 
-               if ( ioinfo[irq]->ui.flags.oper )
+               if ( ioinfo[irq]->ui.flags.unknown )
                        irq_ret = 0;
                else
                        irq_ret = -ENODEV;
@@ -5524,6 +5515,7 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 
 
 /* added by Holger Smolinski for reipl support in reipl.S */
+extern void do_reipl (int);
 void 
 reipl ( int sch )
 {
index 0ac379cf624be12e4a69d893f0e91ce55e57b95a..898f0307e4625eefe04bca76dde7cdf350510248 100644 (file)
@@ -119,9 +119,9 @@ void s390_init_machine_check( void )
 
        down( &s_sem[0]);
 
-       smp_ctl_clear_bit( 14, 25 );  // disable damage MCH     
+       ctl_clear_bit( 14, 25 );  // disable damage MCH         
 #if 1
-       smp_ctl_set_bit( 14, 28 );              // enable channel report MCH
+       ctl_set_bit( 14, 28 );          // enable channel report MCH
 #endif
 
 #ifdef S390_MACHCHK_DEBUG
index 2fecb21e1308b711201d66afae15b44bdb2987e4..c7fdaa6825541b88c3814146bc3e01dca2d47b4c 100644 (file)
@@ -43,6 +43,7 @@
 __u16 boot_cpu_addr;
 int cpus_initialized = 0;
 unsigned long cpu_initialized = 0;
+volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 
 /*
  * Setup options
@@ -75,6 +76,7 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, };
 void cpu_init (void)
 {
         int nr = smp_processor_id();
+        int addr = hard_smp_processor_id();
 
         if (test_and_set_bit(nr,&cpu_initialized)) {
                 printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr);
@@ -86,7 +88,7 @@ void cpu_init (void)
          * Store processor id in lowcore (used e.g. in timer_interrupt)
          */
         asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
-        S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id();
+        S390_lowcore.cpu_data.cpu_addr = addr;
         S390_lowcore.cpu_data.cpu_nr = nr;
 
         /*
@@ -132,7 +134,7 @@ __initfunc(void vmpoff_setup(char *str, char *ints))
  * Reboot, halt and power_off routines for non SMP.
  */
 
-#ifndef __SMP__
+#ifndef CONFIG_SMP
 void machine_restart(char * __unused)
 {
   reipl(S390_lowcore.ipl_device); 
@@ -142,14 +144,14 @@ void machine_halt(void)
 {
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_power_off(void)
 {
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 #endif
 
@@ -190,6 +192,7 @@ __initfunc(void setup_arch(char **cmdline_p,
          */
         cpu_init();
         boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
+        __cpu_logical_map[0] = boot_cpu_addr;
 
         /*
          * print what head.S has found out about the machine 
@@ -259,11 +262,14 @@ __initfunc(void setup_arch(char **cmdline_p,
                                delay = delay*60*1000000;
                                from++;
                        }
-                       tod_wait(delay);
+                       /* now wait for the requested amount of time */
+                       udelay(delay);
                 }
                 cn = *(from++);
                 if (!cn)
                         break;
+                if (cn == '\n')
+                        cn = ' ';  /* replace newlines with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
@@ -271,6 +277,7 @@ __initfunc(void setup_arch(char **cmdline_p,
                         break;
                 *(to++) = c;
         }
+        if (c == ' ' && to > command_line) to--;
         *to = '\0';
         *cmdline_p = command_line;
         memory_end += PAGE_OFFSET;
@@ -298,12 +305,12 @@ __initfunc(void setup_arch(char **cmdline_p,
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
 {
    printk("cpu %d "
-#ifdef __SMP__
+#ifdef CONFIG_SMP
            "phys_idx=%d "
 #endif
            "vers=%02X ident=%06X machine=%04X unused=%04X\n",
            cpuinfo->cpu_nr,
-#ifdef __SMP__
+#ifdef CONFIG_SMP
            cpuinfo->cpu_addr,
 #endif
            cpuinfo->cpu_id.version,
index 6fd939aaecc8bfd914adbd2a799464399bf13a74..cdd09d293d18e7d240be6f0f9be74bf456197b15 100644 (file)
@@ -231,15 +231,12 @@ badframe:
 asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
 {
        rt_sigframe *frame = (rt_sigframe *)regs->gprs[15];
-       stack_t st;
 
        if (sigreturn_common(regs,sizeof(rt_sigframe)))
                        goto badframe;
-       if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
-               goto badframe;
        /* It is more difficult to avoid calling this function than to
           call it and ignore errors.  */
-       do_sigaltstack(&st, NULL, regs->gprs[15]);
+       do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]);
        return regs->gprs[2];
 
 badframe:
@@ -359,6 +356,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        err |= __put_user(sas_ss_flags(orig_sp),
                          &frame->uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+       err |= __put_user(&frame->sc,&frame->uc.sc);
        regs->gprs[3] = (addr_t)&frame->info;
        regs->gprs[4] = (addr_t)&frame->uc;
 
index b16c827f63f18f29929103bc5bf0e8599ecae1e6..80b4acc2764654a846046f50f27fac84decf2a87 100644 (file)
@@ -43,6 +43,7 @@ extern void update_one_process( struct task_struct *p,
 extern int cpu_idle(void * unused);
 
 extern __u16 boot_cpu_addr;
+extern volatile int __cpu_logical_map[];
 
 /*
  * An array with a pointer the lowcore of every CPU.
@@ -53,7 +54,6 @@ struct _lowcore *lowcore_ptr[NR_CPUS];
 unsigned int     prof_multiplier[NR_CPUS];
 unsigned int     prof_counter[NR_CPUS];
 volatile int     cpu_number_map[NR_CPUS];
-volatile int     __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
 cycles_t         cacheflush_time=0;
 int              smp_threads_ready=0;      /* Set when the idlers are all forked. */
 unsigned long    ipi_count=0;              /* Number of IPIs delivered. */
@@ -107,7 +107,7 @@ void do_machine_halt(void)
         smp_send_stop();
         if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) 
                 cpcmd(vmhalt_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_halt(void)
@@ -124,7 +124,7 @@ void do_machine_power_off(void)
         smp_send_stop();
         if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
                 cpcmd(vmpoff_cmd, NULL, 0);
-                disabled_wait(0);
+        signal_processor(smp_processor_id(), sigp_stop_and_store_status);
         }
 
 void machine_power_off(void)
@@ -417,7 +417,7 @@ int smp_signal_others(sigp_order_code order_code, u32 parameter,
 
 void smp_send_stop(void)
 {
-        smp_signal_others(sigp_stop, 0, TRUE, NULL);
+        smp_signal_others(sigp_stop_and_store_status, 0, TRUE, NULL);
 }
 
 /*
@@ -472,7 +472,6 @@ void smp_count_cpus(void)
 {
         int curr_cpu;
 
-        __cpu_logical_map[0] = boot_cpu_addr;
         current->processor = 0;
         smp_num_cpus = 1;
         for (curr_cpu = 0;
@@ -498,11 +497,16 @@ extern void cpu_init (void);
 
 int __init start_secondary(void *cpuvoid)
 {
+        /* Setup the cpu */
         cpu_init();
+        /* Print info about this processor */
         print_cpu_info(&safe_get_cpu_lowcore(smp_processor_id()).cpu_data);
+        /* Wait for completion of smp startup */
         while (!atomic_read(&smp_commenced))
                 /* nothing */ ;
+        /* init per CPU 100 hz timer */
         init_100hz_timer();
+        /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
 
index 53c4c2e68a975743b6f0ed0e359f616ff2ad5a03..cc650354f9aadcd00ade3ce1cbeeee327b129fbc 100644 (file)
@@ -145,7 +145,7 @@ void do_settimeofday(struct timeval *tv)
  * as well as call the "do_timer()" routine every clocktick
  */
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
 extern __u16 boot_cpu_addr;
 #endif
 
@@ -160,7 +160,7 @@ void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
  
         save_flags(flags);
         cli();
-#ifdef __SMP__
+#ifdef CONFIG_SMP
        if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr) {
                write_lock(&xtime_lock);
                last_timer_cc = S390_lowcore.jiffy_timer_cc;
@@ -177,7 +177,7 @@ void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
  * profiling, except when we simulate SMP mode on a uniprocessor
  * system, in that case we have to call the local interrupt handler.
  */
-#ifdef __SMP__
+#ifdef CONFIG_SMP
         /* when SMP, do smp_local_timer_interrupt for *all* CPUs,
            but only do the rest for the boot CPU */
         smp_local_timer_interrupt(regs);
@@ -186,12 +186,12 @@ void do_timer_interrupt(struct pt_regs *regs, __u16 error_code)
                 s390_do_profile(regs->psw.addr);
 #endif
 
-#ifdef __SMP__
+#ifdef CONFIG_SMP
        if(S390_lowcore.cpu_data.cpu_addr==boot_cpu_addr)
 #endif
        {
                do_timer(regs);
-#ifdef __SMP__
+#ifdef CONFIG_SMP
                write_unlock(&xtime_lock);
 #endif
        }
index a30c3896c65d540176dbb67faa5cf902e416e063..136218a6783f9cf31da97728ae947ed0ea29ee1f 100644 (file)
 
 void __delay(unsigned long loops)
 {
+        /*
+         * To end the bloody studid and useless discussion about the
+         * BogoMips number I took the liberty to define the __delay
+         * function in a way that that resulting BogoMips number will
+         * yield the megahertz number of the cpu. The important function
+         * is udelay and that is done using the tod clock. -- martin.
+         */
        __asm__ __volatile__(
-                "0: ahi  %0,-1\n"
-                "   jnm  0b"
-                : /* no outputs */ : "r" (loops) );
+                "0: brct %0,0b"
+                : /* no outputs */ : "r" (loops/2) );
 }
 
-inline void __const_udelay(unsigned long xloops)
+/*
+ * Waits for 'usecs' microseconds using the tod clock
+ */
+void __udelay(unsigned long usecs)
 {
+        uint64_t start_cc, end_cc;
 
-       __asm__("LR    3,%1\n\t"
-               "MR    2,%2\n\t"
-               "LR    %0,2\n\t"
-               : "=r" (xloops)
-               : "r" (xloops) , "r"  (loops_per_sec)
-               : "2" , "3");
-        __delay(xloops);
+        if (usecs == 0)
+                return;
+        asm volatile ("STCK %0" : "=m" (start_cc));
+        do {
+                asm volatile ("STCK %0" : "=m" (end_cc));
+        } while (((end_cc - start_cc)/4096) < usecs);
 }
 
-void __udelay(unsigned long usecs)
-{
-       __const_udelay(usecs * 0x000010c6);  /* 2**32 / 1000000 */
-}
index 2817e8375ff12d844955a645b0ca11f46f9d3ba4..7f777fbebb5886b578d0bf1b09f5f316414a6497 100644 (file)
@@ -74,24 +74,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         down(&mm->mmap_sem);
 
         vma = find_vma(mm, address);
-        if (!vma) {
-               printk("no vma for address %lX\n",address);
+        if (!vma)
                 goto bad_area;
-        }
         if (vma->vm_start <= address) 
                 goto good_area;
-        if (!(vma->vm_flags & VM_GROWSDOWN)) {
-                printk("VM_GROWSDOWN not set, but address %lX \n",address);
-                printk("not in vma %p (start %lX end %lX)\n",vma,
-                       vma->vm_start,vma->vm_end);
+        if (!(vma->vm_flags & VM_GROWSDOWN))
                 goto bad_area;
-        }
-        if (expand_stack(vma, address)) {
-                printk("expand of vma failed address %lX\n",address);
-                printk("vma %p (start %lX end %lX)\n",vma,
-                       vma->vm_start,vma->vm_end);
+        if (expand_stack(vma, address))
                 goto bad_area;
-        }
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
@@ -104,13 +94,8 @@ good_area:
                         break;
                 case 0x10:                                   /* not present*/
                 case 0x11:                                   /* not present*/
-                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
-                                printk("flags %X of vma for address %lX wrong \n",
-                                       vma->vm_flags,address);
-                                printk("vma %p (start %lX end %lX)\n",vma,
-                                       vma->vm_start,vma->vm_end);
+                        if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
                                 goto bad_area;
-                        }
                         break;
                 default:
                        printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF);  
index f63ff468bd1b4e14e82c718843b5c1306231897f..81cbdea5f2e081f11a3b013f7192a54d70f33a2d 100644 (file)
@@ -1,8 +1,8 @@
 all: dasdfmt
 
 dasdfmt: dasdfmt.c
-       $(CROSS_COMPILE)gcc -o $@ $^
-       $(STRIP) $@
+       $(CROSS_COMPILE)gcc -I$(HPATH) -o $@ $^
+       $(CROSS_COMPILE)strip $@
 
 clean:
        rm -f dasdfmt
index b082443223bc91b96c52ae57bc146378345c72c8..9cbf87ab79e8a9de481e51c4e5aba0028658c278 100644 (file)
@@ -3,8 +3,7 @@
 .SH NAME
 dasdfmt \- formatting of DSAD (ECKD) disk drives.
 .SH SYNOPSIS
-\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI]
-       \fIdiskSpec\fR
+\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR\r
 .SH DESCRIPTION
 \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
 for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
@@ -25,6 +24,10 @@ Increases verbosity.
 Start formatting without further user-confirmation.
 
 .TP
+\fB-L\fR \r
+Omit the writing of a disk label after formatting.\r
+\r
+.TP\r
 \fB-V\fR 
 Print version number and exit.
 
@@ -35,26 +38,17 @@ and always be a power of two. Due due some limitations in the driver,
 it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
 
 .TP
-\fIblockRange\fR
-This parameter specifies the number of the first and last block to be
-formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk
-is assumed. The \fIblockRange\fR can be specified in two different formats:
-.sp
-       \fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR
-.br
-or
-.br
-       \fB-r\fR \fIstartBlock\fR-\fIendBlock\fR
-.sp
-If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If
-\fIendBlock\fR is omitted, the last block of the disk is assumed.
+\fB-l\fR \fIdiskLabel\fR\r
+Specify the label to be written to disk after formatting. If no label is\r
+specified, a sensible default is used. \fIdiskLabel\fR is interpreted as\r
+ASCII string and is automatically converted to EBCDIC.\r
 
 .TP
 \fIdiskSpec\fR
 This parameter specified the device to be formatted. It also can be
 given in two variants:
 .sp
-       \fB-f\fR \fB/dev/dd\fR\fIX\fR
+       \fB-f\fR \fB/dev/dasd\fR\fIX\fR\r
 .br
 or
 .br
@@ -63,7 +57,7 @@ or
 The first form uses the commonly used
 .SM UNIX
 device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the VM vdev number.
+The second form uses simply the device number.\r
 
 .SH BUGS
 None so far ;-)
index 2fabd0cc3caea3806b1e0b9d2e04d95ed5c6b4d2..9f86a8f0477d5b92febf00f7aa3ad981f7074b8d 100644 (file)
@@ -12,6 +12,8 @@
  *   detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them 
  */
 
+/* #define _LINUX_BLKDEV_H */
+
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -31,7 +33,8 @@
 #undef __KERNEL__
 
 #include <linux/fs.h>
-#include <linux/dasd.h>
+#include <asm/dasd.h>
+#include <linux/hdreg.h>
 
 #define EXIT_MISUSE 1
 #define EXIT_BUSY 2
 #define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
 #define SLASHDEV "/dev/"
 #define PROC_DASD_DEVICES "/proc/dasd/devices"
-#define PROC_MOUNTS "/proc/mounts"  /* _PATH_MOUNTED is /etc/mtab - maybe bad */
+/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
+#define PROC_MOUNTS _PATH_MOUNTED
 #define PROC_SWAPS "/proc/swaps"
 #define DASD_DRIVER_NAME "dasd"
+#define LABEL_LENGTH 10
 #define PROC_LINE_LENGTH 80
 #define ERR_LENGTH 80
 
 char *prog_name;/*="dasdfmt";*/
 char tempfilename[]=TEMPFILENAME;
 
+__u8 _ascebc[256] =
+{
+ /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
+     0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
+ /*08  BS    HT    LF    VT    FF    CR    SO    SI */
+ /*              ->NL                               */
+     0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
+     0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
+ /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
+ /*                               ->IGS ->IRS ->IUS */
+     0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
+ /*20  SP     !     "     #     $     %     &     ' */
+     0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
+ /*28   (     )     *     +     ,     -    .      / */
+     0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
+ /*30   0     1     2     3     4     5     6     7 */
+     0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ /*38   8     9     :     ;     <     =     >     ? */
+     0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
+ /*40   @     A     B     C     D     E     F     G */
+     0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ /*48   H     I     J     K     L     M     N     O */
+     0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ /*50   P     Q     R     S     T     U     V     W */
+     0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
+ /*58   X     Y     Z     [     \     ]     ^     _ */
+     0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
+ /*60   `     a     b     c     d     e     f     g */
+     0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ /*68   h     i     j     k     l     m     n     o */
+     0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+ /*70   p     q     r     s     t     u     v     w */
+     0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
+ /*78   x     y     z     {     |     }     ~    DL */
+     0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
+ /*80*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*88*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*90*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*98*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*A8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*B8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*C8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*D8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E0        sz                                                */
+     0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*E8*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F0*/
+     0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ /*F8*/
+     0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
+};
+
+void convert_label(char *str)
+{
+       int i;
+       for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
+}
+
 void
 exit_usage(int exitcode)
 {
-       printf("Usage: %s [-htvyV] [-b <blocksize>] [<range>] <diskspec>\n\n",
-              prog_name);
+#ifdef RANGE_FORMATTING
+       printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \
+               "<diskspec>\n\n",prog_name);
+#else /* RANGE_FORMATTING */
+       printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \
+               "<diskspec>\n\n",prog_name);
+#endif /* RANGE_FORMATTING */
        printf("       -t means testmode\n");
        printf("       -v means verbose mode\n");
        printf("       -V means print version\n");
+       printf("       -L means don't write disk label\n");
+       printf("       <label> is a label which is converted to EBCDIC and " \
+               "written to disk\n");
        printf("       <blocksize> has to be power of 2 and at least 512\n");
+#ifdef RANGE_FORMATTING
        printf("       <range> is either\n");
        printf("           -s <start_track> -e <end_track>\n");
        printf("       or\n");
        printf("           -r <start_track>-<end_track>\n");
+#endif /* RANGE_FORMATTING */
        printf("       and <diskspec> is either\n");
        printf("           -f /dev/dasdX\n");
        printf("       or\n");
@@ -108,9 +199,9 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
                        PROC_DASD_DEVICES ": %s (do you have the /proc " \
                        "filesystem enabled?)\n",prog_name,strerror(errno));
 
-       fgets(line,sizeof(line),file); /* omit first line */
+       /*      fgets(line,sizeof(line),file); omit first line */ 
        while (fgets(line,sizeof(line),file)!=NULL) {
-               rc=sscanf(line,"%X%d%d",&d,&ma_i,&mi_i);
+               rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i);
                ma=ma_i;
                mi=mi_i;
                if ( (rc==3) &&
@@ -255,6 +346,7 @@ ask_user_for_data(format_data_t params)
        char *str;
        char output[60],o2[12];
 
+#ifdef RANGE_FORMATTING
        i=params.start_unit;
        do {
                params.start_unit=i;
@@ -286,6 +378,7 @@ ask_user_for_data(format_data_t params)
                        ASK_CHECK_PARAM(CHECK_END);
                }
        } while (rc!=1);
+#endif /* RANGE_FORMATTING */
 
        i=params.blksize;
        do {
@@ -364,12 +457,16 @@ check_mounted(int major, int minor)
 
 void
 do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-       int verbosity,int withoutprompt)
+       int verbosity,int writenolabel,int labelspec,
+       char *label,int withoutprompt)
 {
        int fd,rc;
        struct stat stat_buf;
        kdev_t minor_no,major_no;
        int devno;
+       int new_blksize;
+       unsigned int label_position;
+       struct hd_geometry new_geometry;
        char inp_buffer[5]; /* to contain yes */
 
        fd=open(dev_name,O_RDWR);
@@ -393,6 +490,10 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
        }
        check_mounted(major_no, minor_no);
        
+       if ((!writenolabel) && (!labelspec)) {
+               sprintf(label,"LNX1 x%04x",devno);
+       }
+       
        if ( ((withoutprompt)&&(verbosity>=1)) ||
                (!withoutprompt) ) {
                get_xno_from_xno(&devno,&major_no,&minor_no,
@@ -402,6 +503,11 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
                printf("   Device number of device : 0x%x\n",devno);
                printf("   Major number of device  : %u\n",major_no);
                printf("   Minor number of device  : %u\n",minor_no);
+               printf("   Labelling device        : %s\n",(writenolabel)?
+                       "no":"yes");
+               if (!writenolabel)
+                       printf("   Disk label              : %s\n",label);
+#ifdef RANGE_FORMATTING
                printf("   Start track             : %d\n" \
                        ,format_params.start_unit);
                printf("   End track               : ");
@@ -409,6 +515,7 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
                        printf("last track of disk\n");
                else
                        printf("%d\n",format_params.stop_unit);
+#endif /* RANGE_FORMATTING */
                printf("   Blocksize               : %d\n" \
                        ,format_params.blksize);
                if (testmode) printf("Test mode active, omitting ioctl.\n");
@@ -439,6 +546,56 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
                                "message:\n%s\n",prog_name,strerror(errno));
                printf("Finished formatting the device.\n");
 
+               if (!writenolabel) {
+                       if (verbosity>0)
+                               printf("Retrieving disk geometry... ");
+
+                       rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
+                       if (rc) {
+                               ERRMSG("%s: the ioctl call to get geometry " \
+                                       "returned with the following error " \
+                                       "message:\n%s\n",prog_name,
+                                       strerror(errno));
+                               goto reread;
+                       }
+       
+
+                       rc=ioctl(fd,BLKGETBSZ,&new_blksize);
+                       if (rc) {
+                               ERRMSG("%s: the ioctl call to get blocksize " \
+                                       "returned with the following error " \
+                                       "message:\n%s\n",prog_name,
+                                       strerror(errno));
+                               goto reread;
+                       }
+       
+                       if (verbosity>0) printf("done\n");
+
+                       label_position=new_geometry.start*new_blksize;
+       
+                       if (verbosity>0) printf("Writing label... ");
+                       convert_label(label);
+                       rc=lseek(fd,label_position,SEEK_SET);
+                       if (rc!=label_position) {
+                               ERRMSG("%s: lseek on the device to %i " \
+                                       "failed with the following error " \
+                                       "message:\n%s\n",prog_name,
+                                       label_position,strerror(errno));
+                               goto reread;
+                       }
+                       rc=write(fd,label,LABEL_LENGTH);
+                       if (rc!=LABEL_LENGTH) {
+                               ERRMSG("%s: writing the label only wrote %d " \
+                                       "bytes.\n",prog_name,rc);
+                               goto reread;
+                       }
+
+                       sync();
+                       sync();
+
+                       if (verbosity>0) printf("done\n");
+               }
+ reread:
                printf("Rereading the partition table... ");
                rc=ioctl(fd,BLKRRPART,NULL);
                if (rc) {
@@ -461,11 +618,13 @@ int main(int argc,char *argv[]) {
        int verbosity;
        int testmode;
        int withoutprompt;
+       int writenolabel,labelspec;
 
        char *dev_name;
        int devno;
        char *dev_filename,*devno_param_str,*range_param_str;
        char *start_param_str,*end_param_str,*blksize_param_str;
+       char label[LABEL_LENGTH+1];
        
        format_data_t format_params;
 
@@ -474,7 +633,7 @@ int main(int argc,char *argv[]) {
        char *endptr;
 
        char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-       int i1,i2;
+       int i,i1,i2;
        char *str;
 
        int start_specified,end_specified,blksize_specified;
@@ -492,6 +651,11 @@ int main(int argc,char *argv[]) {
        testmode=0;
        verbosity=0;
        withoutprompt=0;
+       writenolabel=0;
+       labelspec=0;
+       for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
+       label[LABEL_LENGTH]=0;
+
        start_specified=end_specified=blksize_specified=0;
        devfile_specified=devno_specified=range_specified=0;
 
@@ -500,7 +664,10 @@ int main(int argc,char *argv[]) {
        /* avoid error message generated by getopt */
        opterr=0;
 
-       while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) {
+#ifdef RANGE_FORMATTING
+       while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) {
+#endif /* RANGE_FORMATTING */
+       while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) {
                switch (oc) {
                case 'y':
                        withoutprompt=1;
@@ -525,6 +692,18 @@ int main(int argc,char *argv[]) {
                        printf("%s version 0.99\n",prog_name);
                        exit(0);
 
+               case 'l':
+                       strncpy(label,optarg,LABEL_LENGTH);
+                       if (strlen(optarg)<LABEL_LENGTH)
+                               label[strlen(optarg)]=' ';
+                       labelspec++;
+                       break;
+
+               case 'L':
+                       writenolabel++;
+                       break;
+
+#ifdef RANGE_FORMATTING
                case 's' :
                        start_param_str=optarg;
                        start_specified++;
@@ -535,6 +714,12 @@ int main(int argc,char *argv[]) {
                        end_specified++;
                        break;
 
+               case 'r' :
+                       range_param_str=optarg;
+                       range_specified++;
+                       break;
+#endif /* RANGE_FORMATTING */
+
                case 'b' :
                        blksize_param_str=optarg;
                        blksize_specified++;
@@ -549,10 +734,6 @@ int main(int argc,char *argv[]) {
                        dev_filename=optarg;
                        devfile_specified++;
                        break;
-               case 'r' :
-                       range_param_str=optarg;
-                       range_specified++;
-                       break;
                }
        }
 
@@ -604,6 +785,8 @@ int main(int argc,char *argv[]) {
        CHECK_SPEC_MAX_ONCE(start_specified,"start track");
        CHECK_SPEC_MAX_ONCE(end_specified,"end track");
        CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
+       CHECK_SPEC_MAX_ONCE(labelspec,"label");
+       CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
 
        if (devno_specified)
                PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
@@ -628,7 +811,7 @@ int main(int argc,char *argv[]) {
 
        /******* issue the real command and reread part table *******/
        do_format_dasd(dev_name,format_params,testmode,verbosity,
-               withoutprompt);
+               writenolabel,labelspec,label,withoutprompt);
 
        /*************** cleanup ********************************/
        if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
index 260ef122801d3b93950155867d0acca90dca8467..e5403aa6ab49b8e729e781782c9bbefef3648d37 100644 (file)
@@ -12,7 +12,7 @@
 #include <stdio.h>
 
 /* everything about the HWC terminal driver ioctl-commands */
-#include "../../../../drivers/s390/char/sclp_tty.h"
+#include "../../../../drivers/s390/char/hwc_tty.h"
 
 /* standard input, should be our HWC tty */
 #define DESCRIPTOR 0
index 513248245d5889d77d50229020fbbb9537d1354a..6cc01a4cafae9c4dbb189f18510ef6cff7f8e906 100644 (file)
@@ -57,7 +57,7 @@ CONFIG cf_options[] = {
 #define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
 #define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
 #define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
+#define GETARG(x) {int len=strlen(optarg);x=malloc(len+1);strncpy(x,optarg,len+1);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
 
 #define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
 #define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
index 39fe97ed758bbc0581d6d2c3f3eeae250cf2694d..01bb86f3eb3a9d1e9a161d34a00c86242b8ce055 100644 (file)
@@ -33,7 +33,7 @@
  * APM screenblank bug fixed Takashi Manabe <manabe@roy.dsl.tutics.tut.jp>
  *
  * Merge with the abstract console driver by Geert Uytterhoeven
- * <Geert.Uytterhoeven@cs.kuleuven.ac.be>, Jan 1997.
+ * <geert@linux-m68k.org>, Jan 1997.
  *
  *   Original m68k console driver modifications by
  *
index 2147b9b0649b8f66860378d4d32eaa1f79a33101..ef1a977221fcfdda9a6e4f7cc48812c08154a191 100644 (file)
@@ -637,6 +637,12 @@ static int fcif_probe(struct device *dev)
 #   define NEXT_DEV    (&tap0_dev)
 #endif
 
+#ifdef CONFIG_BONDING
+static struct device bonding_dev = { "bond0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, bond_init, };
+#    undef NEXT_DEV
+#    define NEXT_DEV    (&bonding_dev)
+#endif
+
 #ifdef CONFIG_LANMEDIA
 static struct device lmc_dev = { "lmc_dev", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, lmc_probe_fake, };
 #    undef NEXT_DEV
index 037fc8209387a7848e35ef4b822abf5a3cd1ccb8..88cd287494206ae036818ffa39d12256a77abb13 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * Amiga Linux/68k A2065 Ethernet Driver
  *
- * (C) Copyright 1995 by Geert Uytterhoeven
- *                      (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ * (C) Copyright 1995 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  * Fixes and tips by:
  *     - Janos Farkas (CHEXUM@sparta.banki.hu)
index 145bc694d256bbac9fc134a361a9fe2f3d07d621..db6e9e65d9683f5047bc7308de73c6e1cb3dde5f 100644 (file)
@@ -1,8 +1,7 @@
 /*
  * Amiga Linux/68k A2065 Ethernet Driver
  *
- * (C) Copyright 1995 by Geert Uytterhoeven
- *                     (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ * (C) Copyright 1995 by Geert Uytterhoeven <geert@linux-m68k.org>
  *
  * ---------------------------------------------------------------------------
  *
index 8a1cd4e9db2e788fe52f592842452620e44ab393..36fed97301286dd3087f9135a4efb1dca6a67074 100644 (file)
@@ -1,8 +1,7 @@
 /*
  *  Amiga Linux/m68k Ariadne Ethernet Driver
  *
- *  Â© Copyright 1995 by Geert Uytterhoeven
- *                    (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  Â© Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
  *                     Peter De Schrijver
  *                    (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
  *
index 796bbcba4c1cc21b0e60cf7bab5bc481685e0d91..2ba188134b299f742d9c27a49136fe28525384ac 100644 (file)
@@ -1,8 +1,7 @@
 /*
  *  Amiga Linux/m68k Ariadne Ethernet Driver
  *
- *  Â© Copyright 1995 by Geert Uytterhoeven
- *                    (Geert.Uytterhoeven@cs.kuleuven.ac.be)
+ *  Â© Copyright 1995 by Geert Uytterhoeven (geert@linux-m68k.org)
  *                     Peter De Schrijver
  *                    (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)
  *
index 7de7b39fe36962b09f5ca8f3de14e72072e8f204..be84bbb6b83cb790b21723b5e991dfb5a5beeab7 100644 (file)
@@ -71,8 +71,12 @@ static int bond_close(struct device *master)
        bonding_t *private = (struct bonding *) master->priv;
        slave_queue_t *queue = (struct slave_queue *) private->queue;
        slave_t *slave, *next;
+       unsigned long flags;
 
-       for( slave=queue->head; slave != NULL; slave=next) {
+       save_flags(flags);
+       cli();
+
+       for( slave=queue->head; slave != NULL; ) {
 #ifdef BONDING_DEBUG
                printk("freeing = %s\n", slave->dev->name);
 #endif
@@ -80,9 +84,12 @@ static int bond_close(struct device *master)
                slave->dev->slave = NULL;
                next = slave->next;
                kfree(slave);
-               queue->num_slaves++;
+               slave=next;
+               queue->num_slaves--;
        }
 
+       restore_flags(flags);
+
        MOD_DEC_USE_COUNT;
        return 0;
 }
@@ -97,7 +104,7 @@ static int bond_enslave(struct device *master, struct device *slave)
        bonding_t *private = (struct bonding *) master->priv;
        slave_queue_t *queue = (struct slave_queue *) private->queue;
        slave_t *new_slave;
-       int flags;
+       unsigned long flags;
        
        if (master == NULL || slave == NULL) 
                return -ENODEV;
@@ -121,14 +128,15 @@ static int bond_enslave(struct device *master, struct device *slave)
                return -EBUSY;
        }
                   
-       slave->slave = master;     /* save the master in slave->slave */
-       slave->flags |= IFF_SLAVE;
-
        if ((new_slave = kmalloc(sizeof(slave_t), GFP_KERNEL)) == NULL) {
+               restore_flags(flags);
                return -ENOMEM;
        }
        memset(new_slave, 0, sizeof(slave_t));
 
+       slave->slave = master;     /* save the master in slave->slave */
+       slave->flags |= IFF_SLAVE;
+
        new_slave->dev = slave;
 
        if (queue->head == NULL) {
@@ -240,6 +248,11 @@ static int bond_xmit(struct sk_buff *skb, struct device *dev)
        struct slave_queue *queue = bond->queue;
        int good = 0;
        
+       if(!queue->num_slaves) {
+               dev_kfree_skb(skb);
+               return 0;
+       }
+
        while (good == 0) {
                slave = queue->current_slave->dev;
                if (slave->flags & (IFF_UP|IFF_RUNNING)) {
index 2f9eb5bded5103a3481e7789466139d8e86fc3bb..7ec8407eaecd7b33b0b70ae3a0e5c6574247be44 100644 (file)
                           Fix bug in pci_probe() for 64 bit systems reported
                           by <belliott@accessone.com>.
       0.533   9-Jan-98    Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
-      0.534  24-Jan-98    Fix last (?) endian bug from 
-                           <Geert.Uytterhoeven@cs.kuleuven.ac.be>
+      0.534  24-Jan-98    Fix last (?) endian bug from <geert@linux-m68k.org>
       0.535  21-Feb-98    Fix Ethernet Address PROM reset bug for DC21040.
       0.536  21-Mar-98    Change pci_probe() to use the pci_dev structure.
                          **Incompatible with 2.0.x from here.**
index 00549b6b9d7724444b632f751e79aacc710a174a..007957df83d4c7912cfe5764a959bf165acc7a1d 100644 (file)
@@ -3,7 +3,7 @@
 /* also some code & lots of fixes by Timo Rossi (trossi@cc.jyu.fi)          */
 
 /* The code is mostly based on the linux/68k Ariadne driver                 */
-/* copyrighted by Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be) */
+/* copyrighted by Geert Uytterhoeven (geert@linux-m68k.org)                 */
 /* and Peter De Schrijver (Peter.DeSchrijver@linux.cc.kuleuven.ac.be)       */
 
 /* This file is subject to the terms and conditions of the GNU General      */
index 9cdca1f2a15122360a9d4c6093f6a6af98c4c33b..b8a092c54175323d7d8403e74db4f051f81ff6f9 100644 (file)
@@ -15,6 +15,7 @@ fi
 if [ "$CONFIG_MD_LINEAR" = "y" -o "$CONFIG_MD_STRIPED" = "y" ]; then
   bool '      Boot support (linear, striped)' CONFIG_MD_BOOT
 fi
+
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then
   int '   Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 8192
@@ -50,7 +51,6 @@ if [ "$CONFIG_NET" = "y" ]; then
   comment 'S/390 Network device support'
   bool 'Network device support' CONFIG_NETDEVICES
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
-    menu_option next_comment
     comment 'S390 Network devices'
     bool 'CTC device support' CONFIG_CTC
     bool 'IUCV device support (VM only)' CONFIG_IUCV
index 53e3710506c4de4a08fdc7ce2c83eeab69102321..ad92e36a1cccb56204ba191d10af5e4bdba5a54c 100644 (file)
@@ -11,7 +11,7 @@ all: io.o
 
 CFLAGS += 
 O_TARGET := io.o
-O_OBJS    :=         
+O_OBJS   := ccwcache.o
 M_OBJS   :=
 
 SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
@@ -21,7 +21,8 @@ MOD_SUB_DIRS += ./net ./block
 O_OBJS := block/s390-block.o \
   char/s390-char.o \
   misc/s390-misc.o \
-  net/s390-net.o 
+  net/s390-net.o \
+  ccwcache.o
 
 io.o: $(O_OBJS)
 
@@ -37,4 +38,5 @@ misc/s390-misc.o: dummy
 net/s390-net.o: dummy
        $(MAKE) -C net
 
+
 include $(TOPDIR)/Rules.make
index 5af8f3d54a552f500567eb3de887e3f52599474d..94d89876b69cfc19f4da5554afad34ee51462c2d 100644 (file)
@@ -7,18 +7,15 @@ M_OBJS   :=
 D_OBJS   :=
 
 ifeq ($(CONFIG_DASD),y)
-  O_OBJS += dasd.o dasd_ccwstuff.o dasd_erp.o dasd_setup.o
-  ifeq ($(CONFIG_PROC_FS),y)
-   O_OBJS += dasd_proc.o dasd_profile.o
-  endif 
+  O_OBJS += dasd.o
   ifeq ($(CONFIG_DASD_ECKD),y)
-   O_OBJS += dasd_eckd.o dasd_eckd_erp.o dasd_3990_erp.o dasd_9343_erp.o
+   O_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   O_OBJS += dasd_fba.o
+   O_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   O_OBJS += dasd_mdsk.o
+   O_OBJS += dasd_diag.o
   endif 
 #  ifeq ($(CONFIG_DASD_CKD),y)
 #   O_OBJS += dasd_ckd.o
@@ -27,21 +24,18 @@ endif
 
 ifeq ($(CONFIG_DASD),m)
   M_OBJS += dasd_mod.o
-  D_OBJS += dasd.o dasd_ccwstuff.o dasd_erp.o dasd_setup.o
-  ifeq ($(CONFIG_PROC_FS),y)
-   D_OBJS += dasd_proc.o dasd_profile.o
-  endif 
+  D_OBJS += dasd.o 
   ifeq ($(CONFIG_DASD_ECKD),y)
-   D_OBJS += dasd_eckd.o dasd_eckd_erp.o dasd_3990_erp.o dasd_9343_erp.o
+   D_OBJS += dasd_eckd.o  dasd_3990_erp.o dasd_9343_erp.o
   endif 
   ifeq ($(CONFIG_DASD_FBA),y)
-   D_OBJS += dasd_fba.o
+   D_OBJS += dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
   endif 
   ifeq ($(CONFIG_DASD_MDSK),y)
-   D_OBJS += dasd_mdsk.o
+   D_OBJS += dasd_diag.o
   endif 
 #  ifeq ($(CONFIG_DASD_CKD),y)
-#   D_OBJS += dasd_ckd.o
+#   O_OBJS += dasd_ckd.o
 #  endif 
 endif
 
index a09bc7e6b012b2a12bb173f3726d25598d8cb388..42107addd6077b8cee2ca08bdd90bd9b643de437 100644 (file)
@@ -3,11 +3,30 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes (starts July 2000)
+ * 07/03/00 Adapted code to compile with 2.2 and 2.4 kernels
+ * 07/05/00 Added some missing cases when shutting down a device
+ * 07/07/00 Fixed memory leak in ccw allocation
+            Adapted request function to make it work on 2.4
+ * 07/10/00 Added some code to the request function to dequeue requests
+            that cannot be handled due to errors
+ * 07/10/00 Moved linux/ccwcache.h to asm/
+ * 07/10/00 Fixed a bug when formatting a 'new' device       
+ * 07/10/00 Removed an annoying message from dasd_format 
+ * 07/11/00 Reanimated probeonly mode    
+ * 07/11/00 Reanimated autodetection mode
+ * 07/12/00 fixed a bug in module cleanup
+ * 07/12/00 fixed a bug in dasd_devices_open when having 'unknown' devices
+ * 07/13/00 fixed error message when having no device
+ * 07/13/00 added code for dynamic device recognition
  */
 
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
 #include <linux/tqueue.h>
 #include <linux/timer.h>
 #include <linux/malloc.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include <linux/ctype.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+#include <linux/blk.h>
+#include <asm/debug.h>
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/devfs_fs_kernel.h>
+#endif /* LINUX_IS_24 */
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif                         /* CONFIG_PROC_FS */
+
+#include <asm/atomic.h>
+#include <asm/delay.h>
 #include <asm/io.h>
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #include <asm/spinlock.h>
+#endif /* LINUX_IS_24 */
 #include <asm/semaphore.h>
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
-
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
+#include <asm/s390dyn.h>
 
-#include <linux/dasd.h>
-#include <linux/blk.h>
-
-#include "dasd_erp.h"
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
-
-#include "../../../arch/s390/kernel/debug.h"
-
-#define PRINTK_HEADER DASD_NAME":"
-
-#define DASD_SSCH_RETRIES 2
+#include "dasd.h"
+#ifdef CONFIG_DASD_ECKD
+#include "dasd_eckd.h"
+#endif                         /*  CONFIG_DASD_ECKD */
+#ifdef CONFIG_DASD_FBA
+#include "dasd_fba.h" 
+#endif                         /*  CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_MDSK
+#include "dasd_diag.h" 
+#endif                         /*  CONFIG_DASD_MDSK */
 
-/* This macro is a little tricky, but makes the code more easy to read... */
-#define MATCH(info,ct,cm,dt,dm) ( \
-(( info -> sid_data.cu_type  ct ) && ( info -> sid_data.cu_model cm )) && \
-(( info -> sid_data.dev_type dt ) && ( info -> sid_data.dev_model dm )) )
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct block_device_operations dasd_device_operations;
+#endif /* VERSION_CODE */
 
 #ifdef MODULE
+#define EXPORT_SYMTAB
 #include <linux/module.h>
 
-char *dasd[DASD_MAX_DEVICES] =
-{NULL,};
-#ifdef CONFIG_DASD_MDSK
-char *dasd_force_mdsk[DASD_MAX_DEVICES] =
-{NULL,};
-#endif
-
-kdev_t ROOT_DEV;
-
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver, Copyright 2000 IBM Corporation");
-MODULE_PARM (dasd, "1-" __MODULE_STRING (DASD_MAX_DEVICES) "s");
-#ifdef CONFIG_DASD_MDSK
-MODULE_PARM (dasd_force_mdsk, "1-" __MODULE_STRING (DASD_MAX_DEVICES) "s");
-#endif
-#endif
-
-/* Prototypes for the functions called from external */
-void dasd_partn_detect (int di);
-int devindex_from_devno (int devno);
-int dasd_is_accessible (int devno);
-void dasd_add_devno_to_ranges (int devno);
+MODULE_SUPPORTED_DEVICE("dasd");
+MODULE_PARM (dasd, "1-" __MODULE_STRING (256)"s");
+EXPORT_SYMBOL (dasd_discipline_enq);
+EXPORT_SYMBOL (dasd_discipline_deq);
+EXPORT_SYMBOL (dasd_start_IO);
+EXPORT_SYMBOL (dasd_int_handler);
+EXPORT_SYMBOL (dasd_alloc_request);
+EXPORT_SYMBOL (dasd_free_request);
+
+#else
+#endif                         /* MODULE */
 
-#ifdef CONFIG_DASD_MDSK
-extern int dasd_force_mdsk_flag[DASD_MAX_DEVICES];
-extern void do_dasd_mdsk_interrupt (struct pt_regs *regs, __u16 code);
-extern int dasd_parse_module_params (void);
-extern void (**ext_mdisk_int) (void);
+/* SECTION: Constant definitions to be used within this file */
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #endif
+#define PRINTK_HEADER DASD_NAME":"
 
-void dasd_debug (unsigned long tag);
-void dasd_profile_add (cqr_t *cqr);
-void dasd_proc_init (void);
-
-static int dasd_format (int dev, format_data_t * fdata);
-
-static struct file_operations dasd_device_operations;
-
-spinlock_t dasd_lock;          /* general purpose lock for the dasd driver */
-
-/* All asynchronous I/O should waint on this wait_queue */
-struct wait_queue *dasd_waitq = NULL;
-
-extern dasd_chanq_t *cq_head;
-extern int dasd_probeonly;
-
-debug_info_t *dasd_debug_info;
+#define DASD_QUEUE_LIMIT 10
+#define DASD_SSCH_RETRIES 5
+#define QUEUE_SECTORS 128
+
+/* SECTION: prototypes for static functions of dasd.c (try to eliminate!) */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static void do_dasd_request (request_queue_t *);
+#else
+static void do_dasd_request (void);
+#endif /* LINUX_IS_24 */
+static void dasd_do_chanq (void);
+static void schedule_request_fn (void (*func) (void));
+static int dasd_set_device_level (unsigned int, int, dasd_discipline_t *, int);
+static int dasd_oper_handler ( int irq, devreg_t *devreg );
+
+/* SECTION: managing setup of dasd_driver */
+typedef struct dasd_range_t {
+       unsigned int from;
+       unsigned int to;
+       char discipline[4];
+        struct dasd_range_t *next;
+} __attribute__ ((packed)) dasd_range_t;
+
+typedef struct dasd_devreg_t {
+        devreg_t devreg;
+        struct dasd_devreg_t *next;
+} dasd_devreg_t;
+
+static int dasd_probeonly = 1;
+static int dasd_autodetect = 1;
+static dasd_range_t *dasd_range_head = NULL;
+static dasd_devreg_t *dasd_devreg_head = NULL;
+
+static dasd_devreg_t *
+dasd_create_devreg ( int devno ) {
+        dasd_devreg_t *r = kmalloc ( sizeof(dasd_devreg_t), GFP_KERNEL);
+        memset (r,0,sizeof(dasd_devreg_t));
+        if ( r != NULL ) {
+                r -> devreg.ci.devno = devno;
+                r -> devreg.flag = DEVREG_TYPE_DEVNO;
+                r -> devreg.oper_func = dasd_oper_handler;
+        }
+        return r;
+}
 
-extern dasd_information_t **dasd_information;
+static void
+dasd_add_range (int from, int to)
+{
+        dasd_range_t *temp,*range;
+        int i;
 
-dasd_information_t *dasd_info[DASD_MAX_DEVICES] =
-{NULL,};
-static struct hd_struct dd_hdstruct[DASD_MAX_DEVICES << PARTN_BITS];
-static int dasd_blks[256] =
-{0,};
-static int dasd_secsize[256] =
-{0,};
-static int dasd_blksize[256] =
-{0,};
-static int dasd_maxsecs[256] =
-{0,};
+        range = (dasd_range_t *)kmalloc(sizeof(dasd_range_t),GFP_KERNEL);
+        if ( range == NULL )
+                return;
+        memset(range,0,sizeof(dasd_range_t));
+        range -> from = from;
+        if (to == 0) { /* single devno ? */
+                range -> to = from;
+        }  else {
+                range -> to = to;
+        }
 
-void
-dasd_geninit (struct gendisk *dd)
-{
+        /* chain current range to end of list */
+        if ( dasd_range_head == NULL ) {
+                dasd_range_head = range;
+        } else {
+                for ( temp = dasd_range_head; 
+                      temp && temp->next; 
+                      temp = temp->next );
+                temp->next = range;
+        }
+        /* allocate and chain devreg infos for the devnos... */
+        for ( i = range->from; i <= range->to; i ++ ){
+                dasd_devreg_t *reg = dasd_create_devreg(i);
+                s390_device_register(&reg->devreg);
+                reg->next = dasd_devreg_head;
+                dasd_devreg_head = reg;
+        }
 }
 
-struct gendisk dd_gendisk =
+static int
+dasd_strtoul (char *str, char **stra)
 {
-       major:MAJOR_NR,         /* Major number */
-       major_name:"dasd",      /* Major name */
-       minor_shift:PARTN_BITS, /* Bits to shift to get real from partn */
-       max_p:1 << PARTN_BITS,  /* Number of partitions per real */
-       max_nr:0,               /* number */
-       init:dasd_geninit,
-       part:dd_hdstruct,       /* hd struct */
-       sizes:dasd_blks,        /* sizes in blocks */
-       nr_real:0,
-       real_devices:NULL,      /* internal */
-       next:NULL               /* next */
-};
+       char *temp = str;
+       int val;
+       if (*temp == '0') {
+               temp++;         /* strip leading zero */
+               if (*temp == 'x')
+                       temp++; /* strip leading x */
+       }
+       val = simple_strtoul (temp, &temp, 16);         /* interpret anything as hex */
+       *stra = temp;
+       return val;
+}
 
-static atomic_t bh_scheduled = ATOMIC_INIT (0);
+char *dasd[256] = {NULL,}; /* maximum of 256 ranges supplied on parmline */
 
-void
-dasd_schedule_bh (void (*func) (void))
+#ifndef MODULE
+static void 
+dasd_split_parm_string ( char * str ) 
 {
-       static struct tq_struct dasd_tq =
-       {0,};
-       /* Protect against rescheduling, when already running */
-       if (atomic_compare_and_swap (0, 1, &bh_scheduled))
-               return;
-       dasd_tq.routine = (void *) (void *) func;
-       queue_task (&dasd_tq, &tq_immediate);
-       mark_bh (IMMEDIATE_BH);
-               return;
+        char *tmp=str;
+        int count = 0;
+        do {
+                char * end;
+                int len;
+                end = strchr(tmp,',');
+                if ( end == NULL ) { 
+                        len = strlen(tmp) + 1;
+                } else {
+                        len = (long) end - (long) tmp + 1;
+                        *end = '\0';
+                        end ++;
+                }
+                dasd[count] = kmalloc(len * sizeof(char),GFP_ATOMIC);
+                if ( dasd == NULL ) {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "No memory to store dasd= parameter no %d\n",count+1);
+                        break;
+                }
+                memset( dasd[count], 0, len * sizeof(char));
+                memcpy( dasd[count], tmp, len * sizeof(char));
+                count ++;
+                tmp = end;
+        } while ( tmp != NULL && *tmp != '\0' );
        }
 
-void
-sleep_done (struct semaphore *sem)
+static char dasd_parm_string[1024] = {0,};
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static int
+dasd_setup (char *str) 
 {
-       if (sem != NULL) {
-               up (sem);
-       }
+        static int first_time = 1;
+        if ( ! first_time ) {
+                *(dasd_parm_string+strlen(dasd_parm_string))=',';
+        }  else {
+                first_time = 0;
+       }
+        memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
+        return 1;
 }
-
+#else
 void
-sleep (int timeout)
+dasd_setup (char *str, int *ints) 
 {
-       struct semaphore sem = MUTEX_LOCKED;
-       struct timer_list timer;
-
-       init_timer (&timer);
-       timer.data = (unsigned long) &sem;
-       timer.expires = jiffies + timeout;
-       timer.function = (void (*)(unsigned long)) sleep_done;
-       printk (KERN_DEBUG PRINTK_HEADER
-               "Sleeping for timer tics %d\n", timeout);
-       add_timer (&timer);
-       down (&sem);
-       del_timer (&timer);
+        static int first_time = 1;
+        if ( ! first_time ) {
+                *(dasd_parm_string+strlen(dasd_parm_string))=',';
+        }  else {
+                first_time = 0;
+        }
+        memcpy(dasd_parm_string+strlen(dasd_parm_string),str,strlen(str)+1);
 }
+#endif /* LINUX_IS_24 */
 
-#ifdef CONFIG_DASD_ECKD
-extern dasd_operations_t dasd_eckd_operations;
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-extern dasd_operations_t dasd_fba_operations;
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-extern dasd_operations_t dasd_mdsk_operations;
-#endif                         /* CONFIG_DASD_MDSK */
 
-dasd_operations_t *dasd_disciplines[] =
-{
-#ifdef CONFIG_DASD_ECKD
-       &dasd_eckd_operations,
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-       &dasd_fba_operations,
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-       &dasd_mdsk_operations,
-#endif                         /* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-       &dasd_ckd_operations,
-#endif                         /* CONFIG_DASD_CKD */
-       NULL
-};
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+__setup("dasd=", dasd_setup);
+#endif /* LINUX_IS_24 */
 
-char *dasd_name[] =
-{
-#ifdef CONFIG_DASD_ECKD
-       "ECKD",
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-       "FBA",
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-       "MDSK",
-#endif                         /* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-       "CKD",
-#endif                         /* CONFIG_DASD_CKD */
-       "END"
-};
+#endif
 
-static int
-do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
+void
+dasd_parse (char **str) 
 {
-       int rc;
-       int di;
-       dasd_information_t *dev;
-
-       di = DEVICE_NR (inp->i_rdev);
-       if (!dasd_info[di]) {
-               PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
-               return -EINVAL;
-       }
-       if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
-               PRINT_DEBUG ("empty data ptr");
-               return -EINVAL;
-       }
-       dev = dasd_info[di];
-       if (!dev) {
-               PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
-               return -EINVAL;
-       }
-       PRINT_INFO ("ioctl 0x%08x %s'0x%x'%d(%d) on dev %d/%d (%d) with data %8lx\n", no,
-                   _IOC_DIR (no) == _IOC_NONE ? "0" :
-                   _IOC_DIR (no) == _IOC_READ ? "r" :
-                   _IOC_DIR (no) == _IOC_WRITE ? "w" :
-                   _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
-                   _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
-                   MAJOR (inp->i_rdev), MINOR (inp->i_rdev), di, data);
-
-       switch (no) {
-       case BLKGETSIZE:{       /* Return device size */
-                       int blocks = dasd_blks[MINOR (inp->i_rdev)] << 1;
-                       rc = copy_to_user ((long *) data,
-                                          &blocks,
-                                          sizeof (long));
+       char *temp;
+       int from, to;
+
+       if ( *str ) { 
+        dasd_probeonly = 0;
+       }
+        while (*str) {
+                temp = *str;
+               from = 0;
+               to = 0;
+                if ( strncmp ( *str,"autodetect",strlen("autodetect"))== 0) {
+                        dasd_autodetect = 1;
+                        printk (KERN_INFO "turning to autodetection mode\n");
+                        break;
+                } else if ( strncmp ( *str,"probeonly",strlen("probeonly"))== 0) {
+                        dasd_probeonly = 1;
+                        printk (KERN_INFO "turning to probeonly mode\n");
                        break;
+                } else {
+                        dasd_autodetect = 0;
+                        from = dasd_strtoul (temp, &temp);          
+                        if (*temp == '-') {
+                                temp++;
+                                to = dasd_strtoul (temp, &temp);
                }
-       case BLKFLSBUF:{
-                       rc = fsync_dev (inp->i_rdev);
-                       break;
+                        dasd_add_range (from, to);
                }
-       case BLKRAGET:{
-                       rc = copy_to_user ((long *) data,
-                                       read_ahead + MAJOR_NR, sizeof (long));
-                       break;
+                str ++;
                }
-       case BLKRASET:{
-                       rc = copy_from_user (read_ahead + MAJOR_NR,
-                                            (long *) data, sizeof (long));
-                       break;
                }
-       case BLKRRPART:{
-                       dasd_partn_detect (di);
-                       rc = 0;
+
+int
+devindex_from_devno (int devno)
+{
+       int devindex = 0;
+        dasd_range_t *temp;
+        for ( temp = dasd_range_head; temp; temp = temp->next ) {
+               if (devno < temp -> from || devno > temp -> to) {
+                       devindex += temp -> to - temp -> from + 1;
+               } else {
+                       devindex += devno - temp -> from;
                        break;
                }
-       case BIODASDRLB:{
-                       rc = copy_to_user ((int *) data,
-                                          &dasd_info[di]->sizes.label_block,
-                                          sizeof (int));
-                       break;
                }
-       case BLKGETBSZ:{
-                       rc = copy_to_user ((int *) data,
-                                          &dasd_info[di]->sizes.bp_block,
-                                          sizeof (int));
-                       break;
+        if ( temp == NULL ) 
+                return -ENODEV;
+       return devindex;
                }
-       case HDIO_GETGEO:{
-                       struct hd_geometry geo;
-                       dasd_disciplines[dev->type]->fill_geometry (di, &geo);
-                       rc = copy_to_user ((struct hd_geometry *) data, &geo,
-                                          sizeof (struct hd_geometry));
-                       break;
+
+/* SECTION: ALl needed for multiple major numbers */
+
+static major_info_t dasd_major_info[] =
+{
+       {
+               next:NULL /* &dasd_major_info[1] */ ,
+               request_fn:do_dasd_request,
+               read_ahead:8,
+               gendisk:
+               {
+                       major:94,
+                       major_name:DASD_NAME,
+                       minor_shift:DASD_PARTN_BITS,
+                       max_p:1 << DASD_PARTN_BITS,
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                       max_nr:DASD_PER_MAJOR,
+#endif /* LINUX_IS_24 */
+                       nr_real:DASD_PER_MAJOR,
                }
-               RO_IOCTLS (inp->i_rdev, data);
-       case BIODASDRSID:{
-                       rc = copy_to_user ((void *) data,
-                                          &(dev->info.sid_data),
-                                          sizeof (senseid_t));
-                       break;
                }
-       case BIODASDRWTB:{
-                       int offset = 0;
-                       int xlt;
-                       rc = copy_from_user (&xlt, (void *) data,
-                                            sizeof (int));
-#if 0
-                        PRINT_INFO("Xlating %d to",xlt);
-#endif
-                       if (rc)
-                               break;
-                       offset = dd_gendisk.part[MINOR (inp->i_rdev)].start_sect >>
-                           dev->sizes.s2b_shift;
-                       xlt += offset;
 #if 0
-                        printk(" %d \n",xlt);
-#endif
-                       rc = copy_to_user ((void *) data, &xlt,
-                                          sizeof (int));
-                       break;
-               }
-       case BIODASDFORMAT:{
-                       /* fdata == NULL is a valid arg to dasd_format ! */
-                       format_data_t *fdata = NULL;
-                       PRINT_WARN ("called format ioctl\n");
-                       if (data) {
-                               fdata = kmalloc (sizeof (format_data_t),
-                                                GFP_ATOMIC);
-                               if (!fdata) {
-                                       rc = -ENOMEM;
-                                       break;
-                               }
-                               rc = copy_from_user (fdata, (void *) data,
-                                                    sizeof (format_data_t));
-                               if (rc)
-                                       break;
-                       }
-                       rc = dasd_format (inp->i_rdev, fdata);
-                       if (fdata) {
-                               kfree (fdata);
+        ,
+       {
+               next:NULL,
+               request_fn:do_dasd_request,
+               read_ahead:8,
+               gendisk:
+               {
+                       major:95,
+                       major_name:DASD_NAME,
+                       minor_shift:DASD_PARTN_BITS,
+                       max_p:1 << DASD_PARTN_BITS,
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                       max_nr:DASD_PER_MAJOR,
+#endif /* LINUX_IS_24 */
+                       nr_real:DASD_PER_MAJOR,
                        }
-                       break;
                }
-       default:
-               PRINT_WARN ("unknown ioctl number %08x %08lx\n", no, BIODASDFORMAT);
-               rc = -EINVAL;
-               break;
-       }
-       return rc;
+#endif
+};
+
+static dasd_device_t *
+find_dasd_device (int devindex)
+{
+       major_info_t *major_info = dasd_major_info;
+       while (major_info && devindex > DASD_PER_MAJOR) {
+               devindex -= DASD_PER_MAJOR;
+               major_info = major_info->next;
+       }
+       if (!major_info)
+                return NULL;
+       return major_info->dasd_device[devindex];
 }
 
-static void
-dasd_end_request (struct request *req, int uptodate)
+static major_info_t *
+major_info_from_devindex (int devindex)
 {
-       struct buffer_head *bh;
-       FUNCTION_ENTRY ("dasd_end_request");
-#if DASD_PARANOIA > 2
-       if (!req) {
-               INTERNAL_CHECK ("end_request called with zero arg%s\n", "");
+       major_info_t *major_info = dasd_major_info;
+       while (major_info && devindex > DASD_PER_MAJOR) {
+               devindex -= DASD_PER_MAJOR;
+               major_info = major_info->next;
        }
-#endif                         /* DASD_PARANOIA */
-       while ((bh = req->bh) != NULL) {
-               req->bh = bh->b_reqnext;
-               bh->b_reqnext = NULL;
-               bh->b_end_io (bh, uptodate);
-       }
-       if (!end_that_request_first (req, uptodate, DEVICE_NAME)) {
-#ifndef DEVICE_NO_RANDOM
-               add_blkdev_randomness (MAJOR (req->rq_dev));
-#endif
-               DEVICE_OFF (req->rq_dev);
-               end_that_request_last (req);
+       return major_info;
        }
-       FUNCTION_EXIT ("dasd_end_request");
-       return;
+
+int
+major_from_devindex (int devindex)
+{
+       major_info_t *major_info = major_info_from_devindex (devindex);
+       return major_info->gendisk.major;
 }
 
-void
-dasd_wakeup (void)
+static int
+devindex_from_kdev_t (kdev_t dev)
 {
-       wake_up (&dasd_waitq);
+       int devindex = 0;
+       major_info_t *major_info = dasd_major_info;
+       while (major_info &&
+              MAJOR (dev) != major_info->gendisk.major) {
+               devindex += (1 << (MINORBITS - DASD_PARTN_BITS));
+               major_info = major_info->next;
+       }
+       if (!major_info)
+               devindex = -ENODEV;
+        devindex += MINOR(dev) >> DASD_PARTN_BITS;
+       return devindex;
 }
 
+/* SECTION: managing dasd disciplines */
 
-int
-dasd_watch_volume (int di)
-{
-        int rc = 0;
+static dasd_discipline_t *dasd_disciplines = NULL;
+static spinlock_t discipline_lock;
 
-        return rc;
-}
+/* 
+ * void dasd_discipline_enq (dasd_discipline_t * d)
+ */
 
 void 
-dasd_watcher (void) 
+dasd_discipline_enq (dasd_discipline_t * d)
 {
-        int i = 0;
-        int rc; 
-        do {
-                for ( i = 0; i < DASD_MAX_DEVICES; i++ ) {
-                        if ( dasd_info [i] ) {
-                                rc = dasd_watch_volume ( i );
-                        }
-                }
-                interruptible_sleep_on(&dasd_waitq);
-        } while(1);
+       spin_lock (&discipline_lock);
+       d->next = dasd_disciplines;
+       dasd_disciplines = d;
+       spin_unlock (&discipline_lock);
 }
 
+/* 
+ * int dasd_discipline_deq (dasd_discipline_t * d)
+ */
+
 int
-dasd_unregister_dasd (int di)
+dasd_discipline_deq (dasd_discipline_t * d)
 {
        int rc = 0;
-       int minor;
-       int i;
-
-       minor = di << PARTN_BITS;
-       if (!dasd_info[di]) {   /* devindex is not free */
-               INTERNAL_CHECK ("trying to free unallocated device %d\n", di);
-               return -ENODEV;
+       spin_lock (&discipline_lock);
+       if (dasd_disciplines == d) {
+               dasd_disciplines = dasd_disciplines->next;
+       } else {
+               dasd_discipline_t *b;
+               b = dasd_disciplines;
+               while (b && b->next != d)
+                       b = b->next;
+               if (b != NULL) {
+                       b->next = b->next->next;
+               } else {
+                       rc = -ENOENT;
+               }
        }
-       /* delete all that partition stuff */
-       for (i = 0; i < (1 << PARTN_BITS); i++) {
-               dasd_blks[minor] = 0;
-               dasd_secsize[minor + i] = 0;
-               dasd_blksize[minor + i] = 0;
-               dasd_maxsecs[minor + i] = 0;
-       }
-       /* reset DASD to unknown statuss */
-       atomic_set (&dasd_info[di]->status, DASD_INFO_STATUS_UNKNOWN);
-
-       free_irq (dasd_info[di]->info.irq, &(dasd_info[di]->dev_status));
-       if (dasd_info[di]->rdc_data)
-               kfree (dasd_info[di]->rdc_data);
-       kfree (dasd_info[di]);
-       PRINT_INFO ("%04d deleted from list of valid DASDs\n",
-                   dasd_info[di]->info.devno);
+       spin_unlock (&discipline_lock);
        return rc;
 }
 
-/* Below you find the functions already cleaned up */
-static dasd_type_t
-check_type (dev_info_t * info)
-{
-       dasd_type_t type = dasd_none;
-       int di;
+/* SECTION: (de)queueing of requests to channel program queues */
 
-       FUNCTION_ENTRY ("check_type");
-       di = devindex_from_devno (info->devno);
+/* 
+ * void dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
 
-#ifdef CONFIG_DASD_MDSK
-       if (MACHINE_IS_VM && dasd_force_mdsk_flag[di] == 1) {
-               type = dasd_mdsk;
+static void
+dasd_chanq_enq (dasd_chanq_t * q, ccw_req_t * cqr)
+{
+       if (q->head != NULL) {
+               q->tail->next = cqr;
        } else
-#endif                         /* CONFIG_DASD_MDSK */
+               q->head = cqr;
+       cqr->next = NULL;
+       q->tail = cqr;
+       q->queued_requests++;
+       atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
+}
 
-#ifdef CONFIG_DASD_ECKD
-       if (MATCH (info, == 0x3990, ||1, == 0x3390, ||1) ||
-           MATCH (info, == 0x9343, ||1, == 0x9345, ||1) ||
-           MATCH (info, == 0x3990, ||1, == 0x3380, ||1)) {
-               type = dasd_eckd;
-       } else
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-       if (MATCH (info, == 0x6310, ||1, == 0x9336, ||1)) {
-               type = dasd_fba;
-       } else
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-       if (MACHINE_IS_VM) {
-               type = dasd_mdsk;
-       } else
-#endif                         /* CONFIG_DASD_MDSK */
+/* 
+ * void dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
+
+static void
+dasd_chanq_enq_head (dasd_chanq_t * q, ccw_req_t * cqr)
        {
-               type = dasd_none;
+       cqr->next = q->head;
+       q->head = cqr;
+       if (q->tail == NULL)
+               q->tail = cqr;
+       q->queued_requests++;
+       atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
        }
 
-       FUNCTION_EXIT ("check_type");
-       return type;
-}
+/* 
+ * int dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
+ */
 
 static int
-dasd_read_characteristics (dasd_information_t * info)
+dasd_chanq_deq (dasd_chanq_t * q, ccw_req_t * cqr)
 {
-       int rc = 0;
-       int ct = 0;
-       dev_info_t *di;
-       dasd_type_t dt;
+       ccw_req_t *prev;
+
+       if (cqr == NULL)
+               return -ENOENT;
+       if (cqr == (ccw_req_t *) q->head) {
+               q->head = cqr->next;
+               if (q->head == NULL)
+                       q->tail = NULL;
+       } else {
+               prev = (ccw_req_t *) q->head;
+               while (prev && prev->next != cqr)
+                       prev = prev->next;
+               if (prev == NULL)
+                       return -ENOENT;
+               prev->next = cqr->next;
+               if (prev->next == NULL)
+                       q->tail = prev;
+       }
+       cqr->next = NULL;
+       q->queued_requests--;
+       return 0;
+}
 
-       FUNCTION_ENTRY ("read_characteristics");
-       if (info == NULL) {
-               return -ENODEV;
-       }
-       di = &(info->info);
-       if (di == NULL) {
-               return -ENODEV;
+/* SECTION: Handling of the queue of queues */
+
+#ifdef CONFIG_SMP
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static spinlock_t cq_lock;             /* spinlock for cq_head */
+#else
+static spinlock_t cq_lock = SPIN_LOCK_UNLOCKED;                /* spinlock for cq_head */
+#endif /* LINUX_IS_24 */
+#endif                         /* __SMP__ */
+static dasd_chanq_t *qlist_head = NULL;                /* head of queue of queues */
+
+/* 
+ * void qlist_enq (dasd_chanq_t * q)
+ * queues argument to head of the queue of queues
+ * and marks queue to be active
+ */
+
+static void
+qlist_enq (dasd_chanq_t * q)
+{
+       if (q == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER " NULL queue to be queued to queue of queues\n");
+               return;
        }
-       dt = check_type (di);
-       /* Some cross-checks, if the cu supports RDC */
-       if (MATCH (di, == 0x2835, ||1, ||1, ||1) ||
-           MATCH (di, == 0x3830, ||1, ||1, ||1) ||
-           MATCH (di, == 0x3830, ||1, ||1, ||1) ||
-           MATCH (di, == 0x3990, <=0x03, == 0x3380, <=0x0d)) {
-               PRINT_WARN ("Device %d (%x/%x at %x/%x) supports no RDC\n",
-                           info->info.irq,
-                           di->sid_data.dev_type,
-                           di->sid_data.dev_model,
-                           di->sid_data.cu_type,
-                           di->sid_data.cu_model);
-               return -EINVAL;
+       spin_lock (&cq_lock);
+       if (atomic_read (&q->flags) & DASD_CHANQ_ACTIVE) {
+               printk (KERN_WARNING PRINTK_HEADER " Queue already active");
        }
-       switch (dt) {
-#ifdef CONFIG_DASD_ECKD
-       case dasd_eckd:
-               ct = 64;
-               rc = read_dev_chars (info->info.irq,
-                                    (void *) &(info->rdc_data), ct);
-               break;
-#endif                         /*  CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-       case dasd_fba:
-               ct = 32;
-               rc = read_dev_chars (info->info.irq,
-                                    (void *) &(info->rdc_data), ct);
-               break;
-#endif                         /*  CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-       case dasd_mdsk:
-               ct = 0;
-               break;
-#endif                         /*  CONFIG_DASD_FBA */
-       default:
-               INTERNAL_ERROR ("don't know dasd type %d\n", dt);
-       }
-       if (rc) {
-               PRINT_WARN ("RDC resulted in rc=%d\n", rc);
-       }
-       FUNCTION_EXIT ("read_characteristics");
-       return rc;
+       atomic_set_mask (DASD_CHANQ_ACTIVE, &q->flags);
+       q->next_q = qlist_head;
+       qlist_head = q;
+       spin_unlock (&cq_lock);
 }
 
-/* How many sectors must be in a request to dequeue it ? */
-#define QUEUE_BLOCKS 25
-#define QUEUE_SECTORS (QUEUE_BLOCKS << dasd_info[di]->sizes.s2b_shift)
-
-/* How often to retry an I/O before raising an error */
-#define DASD_MAX_RETRIES 5
+/* 
+ * void qlist_deq (dasd_chanq_t * q)
+ * dequeues argument from the queue of queues
+ * and marks queue to be inactive
+ */
 
-static inline
- cqr_t *
-dasd_cqr_from_req (struct request *req)
+static void
+qlist_deq (dasd_chanq_t * q)
 {
-       cqr_t *cqr = NULL;
-       int di;
-       dasd_information_t *info;
-
-       if (!req) {
-               PRINT_ERR ("No request passed!");
-               return NULL;
-       }
-       di = DEVICE_NR (req->rq_dev);
-       info = dasd_info[di];
-       if (!info)
-               return NULL;
-       /* if applicable relocate block */
-       if (MINOR (req->rq_dev) & ((1 << PARTN_BITS) - 1)) {
-               req->sector +=
-                   dd_gendisk.part[MINOR (req->rq_dev)].start_sect;
-       }
-       /* Now check for consistency */
-       if (!req->nr_sectors) {
-               PRINT_WARN ("req: %p dev: %08x sector: %ld nr_sectors: %ld bh: %p\n",
-                    req, req->rq_dev, req->sector, req->nr_sectors, req->bh);
-               return NULL;
-       }
-       if (((req->sector + req->nr_sectors) >> 1) > info->sizes.kbytes) {
-               printk (KERN_ERR PRINTK_HEADER
-                       "Requesting I/O past end of device %d\n",
-                       di);
-               return NULL;
-       }
-       cqr = dasd_disciplines[info->type]->get_req_ccw (di, req);
-       if (!cqr) {
-               PRINT_WARN ("empty CQR generated\n");
-       } else {
-               cqr->req = req;
-               cqr->int4cqr = cqr;
-               cqr->devindex = di;
-#ifdef DASD_PROFILE
-               asm volatile ("STCK %0":"=m" (cqr->buildclk));
-#endif                         /* DASD_PROFILE */
-               ACS (cqr->status, CQR_STATUS_EMPTY, CQR_STATUS_FILLED);
+
+       if (qlist_head == NULL) {
+               printk (KERN_ERR PRINTK_HEADER "Channel queue is empty%s\n", "");
+               return;
+       }
+       if (q == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER " NULL queue to be dequeued from queue of queues\n");
+               return;
        }
-       return cqr;
+       spin_lock (&cq_lock);
+       if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
+               printk (KERN_WARNING PRINTK_HEADER " Queue not active\n");
+       } else if (qlist_head == q) {
+               qlist_head = q->next_q;
+       } else {
+               dasd_chanq_t *c = qlist_head;
+               while (c->next_q && c->next_q != q)
+                       c = c->next_q;
+               if (c->next_q == NULL)
+                       printk (KERN_WARNING PRINTK_HEADER " Queue %p not in queue of queues\n", q);
+               else
+                       c->next_q = q->next_q;
+       }
+       atomic_clear_mask (DASD_CHANQ_ACTIVE, &q->flags);
+       q->next_q = NULL;
+       spin_unlock (&cq_lock);
 }
 
-int
-dasd_start_IO (cqr_t * cqr)
+/* SECTION: All the gendisk stuff */
+
+
+static int
+dasd_partn_detect (int devindex)
 {
        int rc = 0;
-       int retries = DASD_SSCH_RETRIES;
-       int di, irq;
 
-       dasd_debug ((unsigned long) cqr);       /* cqr */
-
-       if (!cqr) {
-               PRINT_WARN ("(start_IO) no cqr passed\n");
-               return -EINVAL;
-       }
-#ifdef CONFIG_DASD_MDSK
-       if (cqr->magic == MDSK_MAGIC) {
-               return dasd_mdsk_start_IO (cqr);
-       }
-#endif                         /* CONFIG_DASD_MDSK */
-       if (cqr->magic != DASD_MAGIC && cqr->magic != ERP_MAGIC) {
-               PRINT_ERR ("(start_IO) magic number mismatch\n");
-               return -EINVAL;
+       major_info_t *major_info = major_info_from_devindex (devindex);
+       struct gendisk *dd = &major_info->gendisk;
+       int minor = ( devindex & 
+                      (( 1 << (MINORBITS-DASD_PARTN_BITS) ) - 1)) << dd->minor_shift;
+       struct dasd_device_t *device = find_dasd_device (devindex);
+        
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        register_disk(dd,
+                      MKDEV (dd->major, minor),
+                      1 << DASD_PARTN_BITS,
+                      &dasd_device_operations,
+                      (device->sizes.blocks << device->sizes.s2b_shift));
+#else
+        dd->sizes[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
+        resetup_one_dev(dd,minor>>DASD_PARTN_BITS);
+#endif /* LINUX_IS_24 */
+       return rc;
        }
-       ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-        di = cqr->devindex;
-       irq = dasd_info[di]->info.irq;
-       do {
-               asm volatile ("STCK %0":"=m" (cqr->startclk));
-               rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
-               switch (rc) {
-               case 0:
-                       if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT))
-                               atomic_set_mask (DASD_CHANQ_BUSY,
-                                                &dasd_info[di]->queue.flags);
-                       break;
-               case -ENODEV:
-                       PRINT_WARN ("cqr %p: 0x%04x error, %d retries left\n",
-                                   cqr, dasd_info[di]->info.devno, retries);
-                       break;
-               case -EIO:
-                       PRINT_WARN ("cqr %p: 0x%04x I/O, %d retries left\n",
-                                   cqr, dasd_info[di]->info.devno, retries);
-                       break;
-               case -EBUSY:    /* set up timer, try later */
 
-                       PRINT_WARN ("cqr %p: 0x%04x busy, %d retries left\n",
-                                   cqr, dasd_info[di]->info.devno, retries);
-                       break;
-               default:
+/* SECTION: Managing wrappers for ccwcache */
 
-                       PRINT_WARN ("cqr %p: 0x%04x %d, %d retries left\n",
-                                   cqr, rc, dasd_info[di]->info.devno,
-                                    retries);
-                       break;
+#define DASD_EMERGENCY_REQUESTS 16
+
+static ccw_req_t *dasd_emergency_req[DASD_EMERGENCY_REQUESTS]={NULL,};
+static spinlock_t dasd_emergency_req_lock = SPIN_LOCK_UNLOCKED;
+
+static void
+dasd_init_emergency_req ( void ) 
+{
+        int i;
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+          dasd_emergency_req[i] = (ccw_req_t*)get_free_page(GFP_KERNEL);
                }
-       } while (rc && --retries);
-       if (rc) {
-               ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
         }
-       return rc;
+
+static void
+dasd_cleanup_emergency_req ( void ) 
+{
+        int i;
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+                if (dasd_emergency_req[i])
+                        free_page((long)(dasd_emergency_req[i]));
+                else
+                        printk (KERN_WARNING PRINTK_HEADER "losing one page for 'in-use' emergency request\n");
+        }
 }
 
-static inline
-void
-dasd_end_cqr (cqr_t * cqr, int uptodate)
+ccw_req_t *
+dasd_alloc_request (char *magic, int cplength, int datasize)
 {
-       struct request *req = cqr->req;
-       asm volatile ("STCK %0":"=m" (cqr->endclk));
-#ifdef DASD_PROFILE
-       dasd_profile_add (cqr);
-#endif                         /* DASD_PROFILE */
-       dasd_chanq_deq (&dasd_info[cqr->devindex]->queue, cqr);
-        if (req) {
-                dasd_end_request (req, uptodate);
+        ccw_req_t *rv = NULL;
+        int i;
+        if ( ( rv = ccw_alloc_request(magic,cplength,datasize )) != NULL ) {
+                return rv;
         }
+        if ( cplength * sizeof(ccw1_t) + datasize + sizeof(ccw_req_t) > PAGE_SIZE ) {
+                return NULL;
+        }
+        spin_lock(&dasd_emergency_req_lock);
+        for ( i = 0; i < DASD_EMERGENCY_REQUESTS; i++) {
+                if ( dasd_emergency_req[i] != NULL ) {
+                        rv = dasd_emergency_req[i];
+                        dasd_emergency_req[i] = NULL;
+                }
+        }
+        spin_unlock(&dasd_emergency_req_lock);
+        if ( rv ) {
+                memset (rv,0, PAGE_SIZE);
+                rv -> cache = (kmem_cache_t *)(dasd_emergency_req + i);
+                strncpy ( (char *)(&rv->magic), magic, 4);
+                ASCEBC((char *)(&rv->magic),4);
+                rv -> cplength = cplength;
+                rv -> datasize = datasize;
+                rv -> data = (void *)((long)rv + PAGE_SIZE - datasize);
+                rv -> cpaddr = (ccw1_t *)((long)rv +  sizeof(ccw_req_t));
+        }
+        return rv;
 }
 
 void
-dasd_dump_sense (devstat_t * stat)
+dasd_free_request (ccw_req_t * request)
 {
-       int sl, sct;
-       if (!stat->flag | DEVSTAT_FLAG_SENSE_AVAIL) {
-               PRINT_INFO ("I/O status w/o sense data\n");
+        if ( request -> cache >= (kmem_cache_t *)dasd_emergency_req &&
+             request -> cache <= (kmem_cache_t *)(dasd_emergency_req + DASD_EMERGENCY_REQUESTS) ) {
+                *((ccw_req_t **)(request -> cache)) = request;
        } else {
-       printk (KERN_INFO PRINTK_HEADER
-                       "-------------------I/O result:-----------\n");
-       for (sl = 0; sl < 4; sl++) {
-               printk (KERN_INFO PRINTK_HEADER "Sense:");
-               for (sct = 0; sct < 8; sct++) {
-                       printk (" %2d:0x%02X", 8 * sl + sct,
-                               stat->ii.sense.data[8 * sl + sct]);
-               }
-               printk ("\n");
+                ccw_free_request(request);
        }
 }
+
+/* SECTION: Managing the device queues etc. */
+
+static atomic_t bh_scheduled = ATOMIC_INIT (0);
+static atomic_t request_fn_scheduled = ATOMIC_INIT (0);
+
+static void
+run_bh (void)
+{
+       atomic_set (&bh_scheduled, 0);
+       dasd_do_chanq ();
 }
 
-int
-register_dasd_last (int di)
+void
+dasd_schedule_bh ( void )
 {
-       int rc = 0;
-       int minor;
-       int i;
-
-       rc = dasd_disciplines[dasd_info[di]->type]->fill_sizes_last (di);
-       if (!rc) {
-               ACS (dasd_info[di]->status,
-                    DASD_INFO_STATUS_DETECTED, DASD_INFO_STATUS_FORMATTED);
-       } else {                /* -EMEDIUMTYPE: */
-               ACS (dasd_info[di]->status,
-                    DASD_INFO_STATUS_DETECTED, DASD_INFO_STATUS_ANALYSED);
-       }
-       PRINT_INFO ("%04X (dasd%c):%ld kB <- block: %d on sector %d B\n",
-                   dasd_info[di]->info.devno,
-                   'a' + di,
-                   dasd_info[di]->sizes.kbytes,
-                   dasd_info[di]->sizes.bp_block,
-                   dasd_info[di]->sizes.bp_sector);
-       minor = di << PARTN_BITS;
-       dasd_blks[minor] = dasd_info[di]->sizes.kbytes;
-       for (i = 0; i < (1 << PARTN_BITS); i++) {
-               dasd_secsize[minor + i] = dasd_info[di]->sizes.bp_sector;
-               dasd_blksize[minor + i] = dasd_info[di]->sizes.bp_block;
-               dasd_maxsecs[minor + i] = 252 << dasd_info[di]->sizes.s2b_shift;
+       static struct tq_struct bh_tq =
+       {0,};
+       /* Protect against rescheduling, when already running */
+       if (atomic_compare_and_swap (0, 1, &bh_scheduled))
+               return;
+       bh_tq.routine = (void *) (void *) run_bh;
+       queue_task (&bh_tq, &tq_immediate);
+       mark_bh (IMMEDIATE_BH);
+       return;
+}
+
+static void
+try_request_fn (void)
+{
+        long flags;
+        spin_lock_irqsave (&io_request_lock,flags);
+       atomic_set (&request_fn_scheduled, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        {
+          major_info_t *mi;
+          for (mi=dasd_major_info; mi != NULL; mi = mi->next ) {
+            do_dasd_request(BLK_DEFAULT_QUEUE(mi->gendisk.major));
        }
-       return rc;
+        }
+#else
+        do_dasd_request ();
+#endif /* LINUX_IS_24 */
+        spin_unlock_irqrestore (&io_request_lock,flags);
 }
 
-void
-dasd_partn_detect (int di)
+static void
+schedule_request_fn (void (*func) (void))
 {
-        int minor = di << PARTN_BITS;
-       while (atomic_read (&dasd_info[di]->status) !=
-              DASD_INFO_STATUS_FORMATTED) {
-                interruptible_sleep_on(&dasd_info[di]->wait_q);
+       static struct tq_struct req_tq =
+       {0,};
+       /* Protect against rescheduling, when already running */
+       if (func != try_request_fn) {
+               panic (PRINTK_HEADER "Programming error! must call schedule_request_fn (try_request_fn)\n");
        }
-       dd_gendisk.part[minor].nr_sects = dasd_info[di]->sizes.kbytes << 1;
-       resetup_one_dev (&dd_gendisk, di);
+       if (atomic_compare_and_swap (0, 1, &request_fn_scheduled))
+               return;
+       req_tq.routine = (void *) (void *) func;
+       queue_task (&req_tq, &tq_immediate);
+       mark_bh (IMMEDIATE_BH);
+       return;
 }
 
-void
-dasd_do_chanq (void)
+int
+dasd_start_IO (ccw_req_t * cqr)
 {
-       dasd_chanq_t *qp = NULL;
-       cqr_t *cqr, *next;
-        long flags;
-        int irq;
-        int tasks;
+       int rc = 0;
+       int retries = DASD_SSCH_RETRIES;
+       dasd_device_t *device = cqr->device;
+       int irq, devno;
+       int devindex, partn;
+       major_info_t *major_info;
+       struct request *req;
 
-       atomic_set (&bh_scheduled, 0);
-       dasd_debug (0xc4c40000);        /* DD */
-       for (qp = cq_head; qp != NULL;) {
-/* Get first request */
-               dasd_debug ((unsigned long) qp);
-               cqr = (cqr_t *) (qp->head);
-/* empty queue -> dequeue and proceed */
                if (!cqr) {
-                       dasd_chanq_t *nqp = qp->next_q;
-                       cql_deq (qp);
-                       qp = nqp;
-                       continue;
+               printk (KERN_WARNING PRINTK_HEADER "No request passed to start_io function");
+               return -EINVAL;
                }
-/* process all requests on that queue */
+       irq = device->devinfo.irq;
+       devno = device->devinfo.devno;
+       req = (struct request *) cqr->req;
+       devindex = devindex_from_kdev_t (req->rq_dev);
+       major_info = major_info_from_devindex (devindex);
+       partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+       if (strncmp ((char *) &cqr->magic, device->discipline->ebcname, 4)) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "0x%04X on sch %d = /dev/%s (%d:%d)"
+                       " magic number of ccw_req_t 0x%08lX doesn't match"
+                       " discipline 0x%08lX\n",
+                       devno, irq, device->name,
+                       major_from_devindex (devindex),
+                       devindex << DASD_PARTN_BITS,
+                       cqr->magic, *(long *) device->discipline->name);
+               return -EINVAL;
+       }
+       atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
                do {
-                        next = NULL;
-                       dasd_debug ((unsigned long) cqr);       /* cqr */
-                       if (cqr->magic != DASD_MAGIC &&
-                           cqr->magic != MDSK_MAGIC &&
-                           cqr->magic != ERP_MAGIC) {
-                               dasd_debug (0xc4c46ff2);        /* DD?2 */
-                               panic ( PRINTK_HEADER "do_cq:"
-                                       "magic mismatch %p -> %x\n", 
-                                       cqr, cqr -> magic);
-                                break;
+               asm volatile ("STCK %0":"=m" (cqr->startclk));
+               rc = do_IO (irq, cqr->cpaddr, (long) cqr, 0x00, cqr->options);
+               switch (rc) {
+               case 0:
+                        if (!(cqr->options & DOIO_WAIT_FOR_INTERRUPT)) {
+                               atomic_set_mask (DASD_CHANQ_BUSY, &device->queue.flags);
                        }
-                        irq = dasd_info[cqr->devindex]->info.irq;
-                        s390irq_spin_lock_irqsave (irq, flags);
-                       switch (atomic_read (&cqr->status)) {
-                       case CQR_STATUS_IN_IO:
-                                dasd_debug (0xc4c4c9d6);       /* DDIO */
-                                break;
-                       case CQR_STATUS_QUEUED:
-                                dasd_debug (0xc4c4e2e3);       /* DDST */
-                               if (dasd_start_IO (cqr) != 0) {
-                                  PRINT_WARN("start_io failed\n");
+                        if ( cqr->expires ) {
+                                cqr->expires += cqr->startclk;
                                 }
                                 break;
-                       case CQR_STATUS_ERROR:{
-                                dasd_debug (0xc4c4c5d9);       /* DDER */
-                                if ( ++ cqr->retries  < 2 ) {
-                                        atomic_set (&cqr->status,
-                                                    CQR_STATUS_QUEUED);
-                                        dasd_debug (0xc4c4e2e3);
-                                        if (dasd_start_IO (cqr) == 0) {
-                                                atomic_dec (&qp->
-                                                            dirty_requests);
-                                                break;
-                                        }
-                                }
-                                ACS (cqr->status,
-                                     CQR_STATUS_ERROR,
-                                     CQR_STATUS_FAILED);
+               case -ENODEV:
+                       printk (KERN_WARNING PRINTK_HEADER
+                           " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                               " appears not to be present %d retries left\n",
+                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+                               retries);
                                 break;
-                        }
-                       case CQR_STATUS_ERP_PEND:{
-                                       /* This case is entered, when an interrupt
-                                          ended with a condittion */
-                                       dasd_erp_action_t erp_action;
-                                       erp_t *erp = NULL;
-
-                                        if ( cqr -> magic != ERP_MAGIC ) {
-                                                erp = request_er ();
-                                                if (erp == NULL) {
-                                                        PRINT_WARN ("No memory for ERP%s\n", "");
-                                                        break;
-                                                }
-                                                memset (erp, 0, sizeof (erp_t));
-                                                erp->cqr.magic = ERP_MAGIC;
-                                                erp->cqr.int4cqr = cqr;
-                                                erp->cqr.devindex= cqr->devindex;
-                                                erp_action = dasd_erp_action (cqr);
-                                                if (erp_action) {
-                                                        PRINT_WARN ("Taking ERP action %p\n", erp_action);
-                                                        erp_action (erp);
-                                                }
-                                                dasd_chanq_enq_head(qp, (cqr_t *) erp);
-                                                next = (cqr_t *) erp;
-                                } else {
-                                                PRINT_WARN("ERP_ACTION failed\n");
-                                                ACS (cqr->status,
-                                                     CQR_STATUS_ERP_PEND,
-                                                    CQR_STATUS_FAILED);
-                                }
+               case -EIO:
+                       printk (KERN_WARNING PRINTK_HEADER
+                           " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                               " I/O error %d retries left\n",
+                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+                               retries);
                                 break;
-                        }
-                       case CQR_STATUS_ERP_ACTIVE:
+               case -EBUSY:    /* set up timer, try later */
+                       printk (KERN_WARNING PRINTK_HEADER
+                           " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                               " is busy %d retries left\n",
+                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+                               retries);
                                break;
-                       case CQR_STATUS_DONE:{
-                                next = cqr->next;
-                                if (cqr->magic == DASD_MAGIC) {
-                                        dasd_debug (0xc4c49692);
-                                } else if (cqr->magic == ERP_MAGIC) {
-                                        dasd_erp_action_t erp_postaction;
-                                        erp_t *erp = (erp_t *) cqr;
-                                        erp_postaction =
-                                                dasd_erp_postaction (erp);
-                                        if (erp_postaction)
-                                                erp_postaction (erp);
-                                        atomic_dec (&qp->dirty_requests);
-                                } else if (cqr->magic == MDSK_MAGIC) {
-                                } else {
-                                        PRINT_WARN ("unknown magic%s\n", "");
-                                }
-                                dasd_end_cqr (cqr, 1);
+               default:
+                       printk (KERN_WARNING PRINTK_HEADER
+                           " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                               " unknown return code %d, %d retries left."
+                         " Pls report this message to linux390@de.ibm.com\n",
+                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+                               rc, retries);
                                 break;
                         }
-                       case CQR_STATUS_FAILED: {
-                                next = cqr->next;
-                                if (cqr->magic == DASD_MAGIC) {
-                                        dasd_debug (0xc4c49692);
-                                } else if (cqr->magic == ERP_MAGIC) {
-                                        dasd_erp_action_t erp_postaction;
-                                        erp_t *erp = (erp_t *) cqr;
-                                        erp_postaction =
-                                                dasd_erp_postaction (erp);
-                                        if (erp_postaction)
-                                                erp_postaction (erp);
-                                } else if (cqr->magic == MDSK_MAGIC) {
-                                } else {
-                                        PRINT_WARN ("unknown magic%s\n", "");
+       } while (rc && retries--);
+       if (rc) {
+                atomic_compare_and_swap_debug (&cqr->status, 
+                                               CQR_STATUS_IN_IO, 
+                                               CQR_STATUS_ERROR);
                                 }
-                                dasd_end_cqr (cqr, 0);
-                                atomic_dec (&qp->dirty_requests);
-                                break;
+       return rc;
                         }
-                       default:
-                                PRINT_WARN ("unknown cqrstatus\n");
+
+static void
+dasd_end_request (struct request *req, int uptodate)
+{
+       struct buffer_head *bh;
+       while ((bh = req->bh) != NULL) {
+               req->bh = bh->b_reqnext;
+               bh->b_reqnext = NULL;
+               bh->b_end_io (bh, uptodate);
                        }
-                        s390irq_spin_unlock_irqrestore (irq, flags);
-               } while ((cqr = next) != NULL);
-               qp = qp->next_q;
+       if (!end_that_request_first (req, uptodate, DASD_NAME)) {
+#ifndef DEVICE_NO_RANDOM
+               add_blkdev_randomness (MAJOR (req->rq_dev));
+#endif
+               end_that_request_last (req);
        }
-       spin_lock (&io_request_lock);
-       do_dasd_request ();
-       spin_unlock (&io_request_lock);
-       dasd_debug (0xc4c46d6d);        /* DD__ */
+       return;
 }
 
-/* 
-   The request_fn is called from ll_rw_blk for any new request.
-   We use it to feed the chanqs.
-   This implementation assumes we are serialized by the io_request_lock.
- */
+#undef CURRENT
+#define CURRENT (blk_dev[major].current_request)
 
-#define QUEUE_THRESHOLD 5
-
-void
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static void
+do_dasd_request (request_queue_t * queue)
+#else
+static void
 do_dasd_request (void)
+#endif /* LINUX_IS_24 */
 {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+       struct request *req;
+        int go;
+#else
        struct request *req, *next, *prev;
-       cqr_t *cqr;
+#endif /* LINUX_IS_24 */
+       ccw_req_t *cqr;
        dasd_chanq_t *q;
        long flags;
-       int di, irq;
+       int devindex, irq, partn;
        int broken, busy;
+       dasd_device_t *device;
+       major_info_t *major_info;
+       int devno;
+        int major;
         
-       dasd_debug (0xc4d90000);        /* DR */
-       dasd_debug ((unsigned long) __builtin_return_address (0));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        {
+                if ( queue == NULL ) {
+                       printk(KERN_ERR PRINTK_HEADER "Null queue !!\n");
+                        return;
+                }
+                go = 1;
+                while (go && !list_empty (&queue->queue_head)) {
+                        req = blkdev_entry_next_request (&queue->queue_head);
+                        major = MAJOR(req->rq_dev);
+                        for (major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+                                if ( major_info->gendisk.major == major )
+                                        break;
+                        }
+                        if ( major_info == NULL ) {
+                                printk (KERN_ERR PRINTK_HEADER "No major_info\n");
+                                return;
+                        }
+#else
+        for ( major_info = dasd_major_info; major_info != NULL; major_info = major_info->next ) {
+                major = major_info->gendisk.major;
        prev = NULL;
        for (req = CURRENT; req != NULL; req = next) {
                next = req->next;
-               di = DEVICE_NR (req->rq_dev);
-               dasd_debug ((unsigned long) req);       /* req */
-               dasd_debug (0xc4d90000 +        /* DR## */
-                            ((((di/16)<9?(di/16)+0xf0:(di/16)+0xc1))<<8) +
-                            (((di%16)<9?(di%16)+0xf0:(di%16)+0xc1)));
-                irq = dasd_info[di]->info.irq;
-                s390irq_spin_lock_irqsave (irq, flags);
-                q = &dasd_info[di]->queue;
-               busy = atomic_read (&q->flags) & DASD_CHANQ_BUSY;
-               broken = atomic_read (&q->flags) & DASD_REQUEST_Q_BROKEN;
-               if (!busy ||
-                   (!broken &&
-                    (req->nr_sectors >= QUEUE_SECTORS))) {
+                        if (req == &blk_dev[major].plug) { /* remove plug if applicable */
+                                req->next = NULL;
                         if (prev) {
                                 prev->next = next;
                         } else {
                                 CURRENT = next;
                         }
-                       req->next = NULL;
-                       if (req == &blk_dev[MAJOR_NR].plug) {
-                                       dasd_debug (0xc4d99787); /* DRpg */
-                               goto cont;
+                                continue;
                        }
-                       cqr = dasd_cqr_from_req (req);
-                       if (!cqr) {
-                                       dasd_debug (0xc4d96ff1); /* DR?1 */
+#endif /* LINUX_IS_24 */
+                        devindex = devindex_from_kdev_t(req->rq_dev);
+                        if ( devindex < 0 ) {
+                                printk ( KERN_WARNING PRINTK_HEADER 
+                                         "requesting I/O on nonexistent device %d -> %d\n",
+                                         devindex,req->rq_dev);
                                dasd_end_request (req, 0);
-                               goto cont;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+                                       } else {
+                                        CURRENT = next;
                         }
-                        dasd_debug ((unsigned long) cqr);      /* cqr */
-                        dasd_chanq_enq (q, cqr);
-                       if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-                                cql_enq_head (q);
+#endif /* LINUX_IS_24 */
+                                continue;
                         }
-                       if (!busy) {
-                               atomic_clear_mask (DASD_REQUEST_Q_BROKEN,
-                                                  &q->flags);
-                               if ( atomic_read (&q->dirty_requests) == 0 ) {
-                                       if (dasd_start_IO (cqr) == 0) {
-                                       } else {
-                                               dasd_schedule_bh (dasd_do_chanq);
+                        device = find_dasd_device (devindex);
+                        if ( device == NULL ) {
+                                printk ( KERN_WARNING PRINTK_HEADER 
+                                         "requesting I/O on nonexistent device\n");
+                               dasd_end_request(req,0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+                                } else {
+                                        CURRENT = next;
+                                }
+#endif /* LINUX_IS_24 */
+                                continue;
+                        }
+                        irq = device->devinfo.irq;
+                        s390irq_spin_lock_irqsave (irq, flags);
+                        devno = device->devinfo.devno;
+                        q = & device->queue;
+                        busy = atomic_read (&q->flags) & DASD_CHANQ_BUSY;
+                        broken = atomic_read (&q->flags) & DASD_REQUEST_Q_BROKEN;
+                        partn = MINOR (req->rq_dev) & ((1 << major_info->gendisk.minor_shift) - 1);
+                        if ( ! busy ||
+                             ( ! broken &&
+                               (req->nr_sectors >= QUEUE_SECTORS))) {
+                                if (device->discipline == NULL) {
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " is not assigned to a discipline\n",
+                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS);
+                                        dasd_end_request (req, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                        blkdev_dequeue_request (req);
+#else
+                                        req->next = NULL;
+                                               if (prev) {
+                                                prev->next = next;
+                                       } else {
+                                                       CURRENT = next;
+                                        }
+#endif /* LINUX_IS_24 */       
+                                       s390irq_spin_unlock_irqrestore (irq, flags);
+                                       continue;
+                                }
+                                if (device->discipline->build_cp_from_req == NULL) {
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " discipline %s hast no builder function\n",
+                                                devno, irq, device->name,major, devindex << DASD_PARTN_BITS,
+                                                device->discipline->name);
+                                        dasd_end_request (req, 0);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                       blkdev_dequeue_request (req);
+#else
+                                       req->next = NULL;
+                                       if (prev) {
+                                               prev->next = next;
+                                       } else {
+                                               CURRENT = next;
+                                       }
+#endif /* LINUX_IS_24 */
+                                       s390irq_spin_unlock_irqrestore (irq, flags);
+                                       continue;                 
+                               }
+                                req->sector += major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
+                                cqr = device->discipline->build_cp_from_req (device, req);
+                                if (cqr == NULL) {
+                                        atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+                                        printk (KERN_WARNING PRINTK_HEADER
+                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                " Could not create channel program for request %p\n",
+                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS, req);
+                                /* put request back to queue*/
+                                        req->sector -= major_info->gendisk.part[MINOR(req->rq_dev)].start_sect;
+                                        s390irq_spin_unlock_irqrestore (irq, flags);
+                                        continue;
+                                } 
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                blkdev_dequeue_request (req);
+#else
+                                req->next = NULL;
+                                if (prev) {
+                                        prev->next = next;
+                                } else {
+                                        CURRENT = next;
+                                }
+#endif /* LINUX_IS_24 */
+                                dasd_chanq_enq (q, cqr);
+                                if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
+                                        qlist_enq (q);
                                 }
+                                if (!busy) {
+                                        atomic_clear_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+                                        if (atomic_read (&q->dirty_requests) == 0) {
+                                                if (device->discipline->start_IO == NULL) {
+                                                        printk (KERN_WARNING PRINTK_HEADER
+                                                                " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                                " dicsipline %s has no starter function\n",
+                                                                devno, irq, device->name, major, devindex << DASD_PARTN_BITS,
+                                                                device->discipline->name);
+                                                } else {
+                                                        if (device->discipline->start_IO (cqr) != 0) {
+                                                                printk (KERN_DEBUG PRINTK_HEADER
+                                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                                        " starting of request from req_fn failed, postponing\n",
+                                                                        devno, irq, device->name, major, devindex << DASD_PARTN_BITS);
+                                                                dasd_schedule_bh ();   /* initiate bh to run */
+                                                        }
+                                                }
+                                        } else {
+                                               dasd_schedule_bh();
+                                        } 
+                                }
+                        } else {
+                                atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                                go = 0;
+#else
+                                prev = req;
+#endif /* LINUX_IS_24 */
                         }
+                        s390irq_spin_unlock_irqrestore (irq, flags);
+                }
+        }
+        return;
+}
+
+static void
+dasd_do_chanq (void)
+{
+       dasd_chanq_t *qp = NULL;
+       dasd_chanq_t *nqp;
+       dasd_device_t *device;
+       ccw_req_t *cqr, *next;
+       long flags;
+       int irq;
+       int devno, devindex;
+       int rc = -1;
+       volatile int cqrstatus;
+
+       for (qp = qlist_head; qp != NULL; qp = nqp) {
+               /* Get first request */
+               cqr = (ccw_req_t *) (qp->head);
+               nqp = qp->next_q;
+/* empty queue -> dequeue and proceed */
+               if (!cqr) {
+                       qlist_deq (qp);
+                       continue;
+               }
+/* process all requests on that queue */
+               do {
+                       dasd_discipline_t *discipline;
+                       next = NULL;
+                       /* Sanity check... walk through disciplines */
+                       for (discipline = dasd_disciplines;
+                            discipline != NULL;
+                            discipline = discipline->next)
+                               if (!strncmp ((char *) &cqr->magic, discipline->ebcname, 4))
+                                       break;
+                       if (!discipline) {      /* 1st sanity check */
+                               panic (PRINTK_HEADER
+                                      "in dasd_do_chanq: magic no mismatch %p -> 0x%lX\n",
+                                      cqr, cqr->magic);
+                       }
+                       device = (dasd_device_t *) (cqr->device);
+                       if (discipline != device->discipline) {         /* 1st sanity check */
+                               printk (KERN_WARNING PRINTK_HEADER
+                                       "in dasd_do_chanq: discipline mismatch %p -> 0x%lX\n",
+                                       cqr, cqr->magic);
+                               discipline = device->discipline;
+                       }
+                       irq = device->devinfo.irq;
+                       devno = device->devinfo.devno;
+                       devindex = devindex_from_devno (devno);
+
+                       s390irq_spin_lock_irqsave (irq, flags);
+
+                       cqrstatus = atomic_read (&cqr->status);
+                       switch (cqrstatus) {
+                       case CQR_STATUS_QUEUED:
+                               if (discipline->start_IO &&
+                                   ((rc = discipline->start_IO (cqr)) == 0)) {
+                                } else {
+                                       printk (KERN_WARNING PRINTK_HEADER
+                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                               " Failing to start I/O operation with rc %d\n",
+                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+                                       switch (rc) {
+                                       case EBUSY:
+                                               if (cqr->retries--) {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " retrying %d retries left\n",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+                                                       break;
+                                               }
+                                       default:{       /* Fallthrough ?? */
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " Giving up this request!\n",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                       atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_FAILED);
+                                                       break;
+                                               }
+                                       }
+                               }
+                               break;
+                       case CQR_STATUS_IN_IO:{
+                                       unsigned long long now;
+                                       unsigned long long delta;
+
+                                       asm volatile ("STCK %0":"=m" (now));
+                                       if (cqr->expires && cqr->startclk &&
+                                           cqr->expires < now) {
+                                                delta = cqr->expires - cqr->startclk;
+                                               printk (KERN_ERR PRINTK_HEADER
+                                                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                       " I/O operation outstanding longer than %Ld usecs on req %p\n",
+                                                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, delta >> 12, cqr);
+                                               if ( cqr->retries-- ) {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " waiting %d more times\n",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, cqr->retries);
+                                                       cqr->expires += delta;
+                                                       break;
+                                               } else {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " You should disable that device by issueing '@#?!'\n",         /* FIXME */
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                       atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
+                                                       break;
+                                               }
+                                       }
+                                       break;
+                               }
+                       case CQR_STATUS_ERROR:{
+                                       dasd_erp_action_fn_t erp_action;
+                                       ccw_req_t *erp_cqr = NULL;
+                                       if (discipline->erp_action &&
+                                           ((erp_action = discipline->erp_action (cqr)) != NULL)) {
+                                                printk (KERN_WARNING PRINTK_HEADER
+                                                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                       " Taking error recovery action %p on req %p \n",
+                                                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_action,cqr);
+                                               erp_cqr = erp_action (cqr);
+                                       } else {
+                                               printk (KERN_WARNING PRINTK_HEADER
+                                                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                        " No error recovery action\n",
+                                                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                               atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+                                       }
+                                       if ( erp_cqr != NULL ) {
+                                               dasd_chanq_enq_head (qp, erp_cqr);
+                                               next = erp_cqr;         /* prefer execution of erp ccw */
+                                       }
+                                       break;
+                               }
+                       case CQR_STATUS_DONE:{
+                                        dasd_erp_postaction_fn_t erp_postaction;
+                                        next = cqr->next;
+                                       if (cqr->refers && cqr->function) {     /* we deal with an ERP */
+                                               if (discipline->erp_postaction &&
+                                                   ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " postprocessing successful error recovery action %p\n",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+                                                       erp_postaction (cqr, 1);
+                                                        atomic_dec (&device->queue.dirty_requests);
+                                               } else {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " No procedure to postprocess error recovery action"
+                                                                " giving up request",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                       atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+                                               }
+                                       } else if ( cqr->req ) {
+                                               asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                               dasd_end_request (cqr->req, 1);
+#ifdef DASD_PROFILE
+                                               dasd_profile_add (cqr);
+#endif                         /* DASD_PROFILE */
+                                       } 
+                                       dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr);
+                                       break;
+                               }
+                       case CQR_STATUS_FAILED:{
+                                       dasd_erp_postaction_fn_t erp_postaction;
+                                       next = cqr->next;
+                                       if (cqr->refers && cqr->function) {     /* we deal with an ERP */
+                                               if (discipline->erp_postaction &&
+                                                   ((erp_postaction = discipline->erp_postaction (cqr)) != NULL)) {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " postprocessing unsuccessful error recovery action %p\n",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, erp_postaction);
+                                                       erp_postaction (cqr, 0);
+                                                        atomic_dec (&device->queue.dirty_requests);
+
+                                               } else {
+                                                       printk (KERN_WARNING PRINTK_HEADER
+                                                               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                                               " No procedure to postprocess unsuccessful error recovery action"
+                                                        " giving up request",
+                                                               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+                                                       atomic_compare_and_swap_debug (&cqr->refers->status, CQR_STATUS_ERROR, CQR_STATUS_FAILED);
+                                               }
+                                       } else if (cqr->req) {
+                                               asm volatile ("STCK %0":"=m" (cqr->endclk));
+                                               dasd_end_request (cqr->req, 0);
+#ifdef DASD_PROFILE
+                                               dasd_profile_add (cqr);
+#endif                         /* DASD_PROFILE */
+                                       } else {
+                                               printk (KERN_WARNING PRINTK_HEADER
+                                                       "Internal error in " __FILE__ " on line %d."
+                                                       " inconsistent content of ccw_req_t"
+                                                       " refers = %p,function = %p, request = %p"
+                                                       " Pls send this message and your System.map to"
+                                                    " linux390@de.ibm.com\n",
+                                                       __LINE__, cqr->refers, cqr->function, cqr->req);
+                                       }
+                                       dasd_chanq_deq (&device->queue, cqr);
+                                        dasd_free_request(cqr);
+                                       break;
+                               }
+                       default:{
+                                       printk (KERN_WARNING PRINTK_HEADER
+                                               "Internal error in " __FILE__ " on line %d."
+                                         " inconsistent content of ccw_req_t"
+                                               " cqrstatus = %d"
+                                               " Pls send this message and your System.map to"
+                                               " linux390@de.ibm.com\n",
+                                               __LINE__, cqrstatus);
                        }
-                } else {
-                        dasd_debug (0xc4d9c2d9);       /* DRBR */
-                       atomic_set_mask (DASD_REQUEST_Q_BROKEN, &q->flags);
-                       prev = req;
                }
-        cont:
                 s390irq_spin_unlock_irqrestore (irq, flags);
+               } while ((cqr = next) != NULL);
        }
-       dasd_debug (0xc4d96d6d);        /* DR__ */
+       schedule_request_fn (try_request_fn);
+        return;
 }
 
 void
-dasd_handler (int irq, void *ds, struct pt_regs *regs)
+dasd_int_handler (int irq, void *ds, struct pt_regs *regs)
 {
        devstat_t *stat = (devstat_t *) ds;
        int ip;
-       cqr_t *cqr;
+       ccw_req_t *cqr;
        int done_fast_io = 0;
-       dasd_era_t era;
+       dasd_era_t era = dasd_era_fatal;
+       dasd_device_t *device;
+       int devno = -1, devindex = -1;
+        
+#undef ERP_DEBUG
+#ifdef ERP_DEBUG 
         static int counter = 0; 
+#endif
 
-       dasd_debug (0xc4c80000);        /* DH */
        if (!stat) {
                PRINT_ERR ("handler called without devstat");
                return;
        }
        ip = stat->intparm;
-       dasd_debug (ip);        /* intparm */
        if (!ip) {              /* no intparm: unsolicited interrupt */
-               dasd_debug (0xc4c8a489);        /* DHui */
                PRINT_INFO ("%04X caught unsolicited interrupt\n",
                            stat->devno);
                return;
        }
                if (ip & 0x80000001) {
-                       dasd_debug (0xc4c8a489);        /* DHui */
                PRINT_INFO ("%04X  caught spurious interrupt with parm %08x\n",
                            stat->devno, ip);
                        return;
                }
-               cqr = (cqr_t *) ip;
-       if (cqr->magic == DASD_MAGIC || cqr->magic == ERP_MAGIC) {
+       cqr = (ccw_req_t *) ip;
+       device = (dasd_device_t *) cqr->device;
+       devno = device->devinfo.devno;
+       devindex = devindex_from_devno (devno);
+       if (device == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                    " IRQ on devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                       " belongs to NULL device\n",
+                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+       }
+       if (device->devinfo.irq != irq) {
+               printk (KERN_WARNING PRINTK_HEADER
+                    " IRQ on devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                       " doesn't belong to device irq %d\n",
+                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS,
+                       device->devinfo.irq);
+               return;
+       }
+       if (device->discipline == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                       " is not assigned to a discipline\n",
+                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+       }
+       if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "0x%04X on sch %d : /dev/%s (%d:%d)"
+                       " magic number of ccw_req_t 0x%08lX doesn't match"
+                       " discipline 0x%08X\n",
+                       devno, irq, device->name,
+                       major_from_devindex (devindex),
+                       devindex << DASD_PARTN_BITS,
+                       cqr->magic, *(int *) (&device->discipline->name));
+               return;
+       }
                asm volatile ("STCK %0":"=m" (cqr->stopclk));
                if ((stat->cstat == 0x00 &&
                     stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) ||
-                   ((era = dasd_erp_examine (cqr, stat)) == dasd_era_none)) {
-                       dasd_debug (0xc4c89692);        /* DHok */
-#if 0
-                        if ( counter < 20 || cqr -> magic == ERP_MAGIC) {
-                                counter ++;
-#endif
-                                ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
-#if 0
-                        } else {
-                                counter=0;
-                                PRINT_WARN ("Faking I/O error\n");
-                                ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_ERP_PEND);
-                                atomic_inc (&dasd_info[cqr->devindex]->
-                                            queue.dirty_requests);
+           (device->discipline->examine_error &&
+            (era = device->discipline->examine_error (cqr, stat)) == dasd_era_none)) {
+#ifdef ERP_DEBUG
+                if ( ++counter % 137 == 0 ) {
+                        printk ( KERN_INFO PRINTK_HEADER "Faking I/O error to recover from\n");
+                        era = dasd_era_recover;
+                        stat->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
+                        stat->dstat |= 0x02;
+                        goto error_fake_done;
                         }
 #endif
-                       if (atomic_read (&dasd_info[cqr->devindex]->status) ==
-                           DASD_INFO_STATUS_DETECTED) {
-                               register_dasd_last (cqr->devindex);
-                                if ( dasd_info[cqr->devindex]->wait_q ) {
-                                        wake_up( &dasd_info[cqr->devindex]->
-                                                wait_q);
-                                }
-                       }
+               atomic_compare_and_swap_debug (&cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
+                atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                         &device->level);
                        if (cqr->next &&
                            (atomic_read (&cqr->next->status) ==
                             CQR_STATUS_QUEUED)) {
-                               dasd_debug (0xc4c8e2e3);        /* DHST */
                                if (dasd_start_IO (cqr->next) == 0) {
                                        done_fast_io = 1;
-                               } else {
                        }
                }
                } else {        /* only visited in case of error ! */
-               dasd_debug (0xc4c8c5d9);        /* DHER */
-                        dasd_dump_sense (stat);
-               if (!cqr->dstat)
-                       cqr->dstat = kmalloc (sizeof (devstat_t),
-                                             GFP_ATOMIC);
+#ifdef ERP_DEBUG
+        error_fake_done:
+#endif
+               if (cqr->dstat == NULL)
+                       cqr->dstat = kmalloc (sizeof (devstat_t), GFP_ATOMIC);
                if (cqr->dstat) {
                        memcpy (cqr->dstat, stat, sizeof (devstat_t));
                } else {
                                PRINT_ERR ("no memory for dstat\n");
                }
-                        atomic_inc (&dasd_info[cqr->devindex]->
-                                    queue.dirty_requests);
+               if (device->discipline &&
+                   device->discipline->dump_sense) {
+                       char *errmsg = device->discipline->dump_sense (device, cqr);
+                       if (errmsg != NULL) {
+                               printk ("%s", errmsg);
+                               free_page ((unsigned long) errmsg);
+                       } else {
+                               printk (KERN_WARNING PRINTK_HEADER
+                                       "No memory to dump error message\n");
+                       }
+               }
+               atomic_inc (&device->queue.dirty_requests);
                /* errorprocessing */
                        if (era == dasd_era_fatal) {
                                PRINT_WARN ("ERP returned fatal error\n");
-                               ACS (cqr->status,
+                       atomic_compare_and_swap_debug (&cqr->status,
                                     CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
                        } else {
-                                ACS (cqr->status,
-                                     CQR_STATUS_IN_IO, CQR_STATUS_ERP_PEND);
+                       atomic_compare_and_swap_debug (&cqr->status,
+                                                       CQR_STATUS_IN_IO, CQR_STATUS_ERROR);
                         }
        }
        if (done_fast_io == 0)
-               atomic_clear_mask (DASD_CHANQ_BUSY,
-                                  &dasd_info[cqr->devindex]->
-                                  queue.flags);
+               atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
         
-       if (cqr->flags & DASD_DO_IO_SLEEP) {
-               dasd_debug (0xc4c8a6a4);        /* DHwu */
-               dasd_wakeup ();
-       } else if (! (cqr->options & DOIO_WAIT_FOR_INTERRUPT) ){
-                dasd_debug (0xc4c8a293);       /* DHsl */
-                        dasd_schedule_bh (dasd_do_chanq);
-       } else {
-                dasd_debug (0x64686f6f);       /* DH_g */
-                dasd_debug (cqr->flags);       /* DH_g */
-        }
-        } else {
-                dasd_debug (0xc4c86ff1);       /* DH?1 */
-                PRINT_ERR ("handler:magic mismatch on %p %08x\n",
-                           cqr, cqr->magic);
-                return;
-        }
-       dasd_debug (0xc4c86d6d);        /* DHwu */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wake_up (&device->wait_q);
+#else
+       if (device->wait_q) {
+               wake_up (&device->wait_q);
+       }
+#endif /* LINUX_IS_24 */
+       dasd_schedule_bh ();
 }
 
-static int
-dasd_format (int dev, format_data_t * fdata)
-{
-       int rc;
-       int devindex = DEVICE_NR (dev);
-       dasd_chanq_t *q;
-       cqr_t *cqr;
-       int irq;
-       long flags;
-       PRINT_INFO ("%04X called format on %x\n",
-                   dasd_info[devindex]->info.devno, dev);
-       if (MINOR (dev) & (0xff >> (8 - PARTN_BITS))) {
-               PRINT_WARN ("Can't format partition! minor %x %x\n",
-                           MINOR (dev), 0xff >> (8 - PARTN_BITS));
-               return -EINVAL;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static wait_queue_head_t watcher_queue;
+#else
+static struct wait_queue watcher_queue_Qend = {NULL,};
+static struct wait_queue *watcher_queue = &watcher_queue_Qend;
+#endif /* LINUX_IS_24 */
+
+static void
+dasd_watcher (void)
+{
+       do {
+               dasd_schedule_bh ();
+               schedule_request_fn (try_request_fn);
+               interruptible_sleep_on_timeout (&watcher_queue, 5 * HZ);
+       } while (1);
+        }
+
+/* SECTION: Some stuff related to error recovery */
+
+ccw_req_t *
+default_erp_action (ccw_req_t * cqr)
+{
+       ccw_req_t *erp = ccw_alloc_request ((char *) &cqr->magic, 1, 0);
+
+       erp->cpaddr->cmd_code = CCW_CMD_NOOP;
+       erp->function = default_erp_action;
+       erp->refers = cqr;
+       erp->device = cqr->device;
+        erp->magic = cqr->magic;
+       atomic_set (&erp->status, CQR_STATUS_FILLED);
+        if ( cqr->startclk && cqr->expires )
+                cqr->expires -= cqr->startclk;
+        
+       if (cqr->retries++ <= 16) {
+                atomic_compare_and_swap_debug (&cqr->status,
+                                               CQR_STATUS_ERROR,
+                                              CQR_STATUS_QUEUED);
+        } else {
+               printk (KERN_WARNING PRINTK_HEADER "ERP retry count exceeded\n");
+               atomic_compare_and_swap_debug (&cqr->status,
+                                              CQR_STATUS_ERROR,
+                                              CQR_STATUS_FAILED);
        }
-       down (&dasd_info[devindex]->sem);
-       atomic_set (&dasd_info[devindex]->status,
-                   DASD_INFO_STATUS_UNKNOWN);
-       if (dasd_info[devindex]->open_count == 1) {
-               rc = dasd_disciplines[dasd_info[devindex]->type]->
-                   dasd_format (devindex, fdata);
-               if (rc) {
-                       PRINT_WARN ("Formatting failed rc=%d\n", rc);
-                       up (&dasd_info[devindex]->sem);
-                       return rc;
-               }
-       } else {
-               PRINT_WARN ("device is open! %d\n", dasd_info[devindex]->open_count);
-               up (&dasd_info[devindex]->sem);
+       return erp;
+}
+
+int
+default_erp_postaction (ccw_req_t * cqr, int success)
+{
+       int rc = 0;
+       if (cqr->refers == NULL || cqr->function == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "ERP postaction called for non ERP cqr\n");
                return -EINVAL;
        }
-#if DASD_PARANOIA > 1
-       if (!dasd_disciplines[dasd_info[devindex]->type]->fill_sizes_first) {
-               INTERNAL_CHECK ("No fill_sizes for dt=%d\n", dasd_info[devindex]->type);
-       } else
-#endif                         /* DASD_PARANOIA */
-       {
-               ACS (dasd_info[devindex]->status,
-                    DASD_INFO_STATUS_UNKNOWN, DASD_INFO_STATUS_DETECTED);
-               irq = dasd_info[devindex]->info.irq;
-               PRINT_INFO ("%04X reacessing, irq %x, index %d\n",
-                           get_devno_by_irq (irq), irq, devindex);
-               s390irq_spin_lock_irqsave (irq, flags);
-               q = &dasd_info[devindex]->queue;
-               cqr = dasd_disciplines[dasd_info[devindex]->type]->
-                   fill_sizes_first (devindex);
-               dasd_chanq_enq (q, cqr);
-               if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-                       cql_enq_head (q);
-               }
-               dasd_schedule_bh (dasd_do_chanq);
-               s390irq_spin_unlock_irqrestore (irq, flags);
-       }
-       up (&dasd_info[devindex]->sem);
+       if (cqr->function != default_erp_action) {
+               printk (KERN_WARNING PRINTK_HEADER
+                        "default ERP postaction called for non default ERP cqr\n");
+               return -EINVAL;
+        }
        return rc;
 }
 
+/* SECTION: The helpers of the struct file_operations */
+
 static int
-register_dasd (int irq, dasd_type_t dt, dev_info_t * info)
+dasd_format (dasd_device_t * device, format_data_t * fdata)
 {
        int rc = 0;
-       int di;
-       unsigned long flags;
-       dasd_chanq_t *q;
-       cqr_t *cqr;
-       static spinlock_t register_lock = SPIN_LOCK_UNLOCKED;
-       spin_lock (&register_lock);
-       FUNCTION_ENTRY ("register_dasd");
-       di = devindex_from_devno (info->devno);
-       if (di < 0) {
-               INTERNAL_CHECK ("Can't get index for devno %d\n", info->devno);
-               return -ENODEV;
-       }
-       if (dasd_info[di]) {    /* devindex is not free */
-               INTERNAL_CHECK ("reusing allocated deviceindex %d\n", di);
-               return -ENODEV;
-       }
-       dasd_info[di] = (dasd_information_t *)
-           kmalloc (sizeof (dasd_information_t), GFP_ATOMIC);
-       if (dasd_info[di] == NULL) {
-               PRINT_WARN ("No memory for dasd_info_t on irq %d\n", irq);
-               return -ENOMEM;
-       }
-       memset (dasd_info[di], 0, sizeof (dasd_information_t));
-       memcpy (&(dasd_info[di]->info), info, sizeof (dev_info_t));
-       spin_lock_init (&dasd_info[di]->queue.f_lock);
-       spin_lock_init (&dasd_info[di]->queue.q_lock);
-       dasd_info[di]->type = dt;
-       dasd_info[di]->irq = irq;
-       dasd_info[di]->sem = MUTEX;
-#ifdef CONFIG_DASD_MDSK
-       if (dt == dasd_mdsk) {
-               dasd_info[di]->rdc_data = kmalloc (
-                                sizeof (dasd_characteristics_t), GFP_ATOMIC);
-               if (!dasd_info[di]->rdc_data) {
-                       PRINT_WARN ("No memory for char on irq %d\n", irq);
-                       goto unalloc;
-               }
-               dasd_info[di]->rdc_data->mdsk.dev_nr = dasd_info[di]->
-                   info.devno;
-               dasd_info[di]->rdc_data->mdsk.rdc_len =
-                   sizeof (dasd_mdsk_characteristics_t);
-       } else
-#endif                         /* CONFIG_DASD_MDSK */
-       rc = dasd_read_characteristics (dasd_info[di]);
-       if (rc) {
-               PRINT_WARN ("RDC returned error %d\n", rc);
-               rc = -ENODEV;
-               goto unalloc;
-       }
-#if DASD_PARANOIA > 1
-       if (dasd_disciplines[dt]->ck_characteristics)
-#endif                         /* DASD_PARANOIA */
-               rc = dasd_disciplines[dt]->
-                   ck_characteristics (dasd_info[di]->rdc_data);
+       int devno = device->devinfo.devno;
+       int irq = device->devinfo.irq;
+       int devindex = devindex_from_devno (devno);
 
-       if (rc) {
-               INTERNAL_CHECK ("Discipline returned non-zero when"
-                               "checking device characteristics%s\n", "");
-               rc = -ENODEV;
-               goto unalloc;
-       }
-#ifdef CONFIG_DASD_MDSK
-       if (dt == dasd_mdsk) {
-
-       } else
-#endif                         /* CONFIG_DASD_MDSK */
-       rc = request_irq (irq, dasd_handler, 0, "dasd",
-                         &(dasd_info[di]->dev_status));
-       ACS (dasd_info[di]->status,
-            DASD_INFO_STATUS_UNKNOWN, DASD_INFO_STATUS_DETECTED);
-       if (rc) {
-#if DASD_PARANOIA > 0
+       if (device->open_count != 1) {
                printk (KERN_WARNING PRINTK_HEADER
-                       "Cannot register irq %d, rc=%d\n",
-                       irq, rc);
-#endif                         /* DASD_PARANOIA */
-               rc = -ENODEV;
-               goto unalloc;
-       }
-#if DASD_PARANOIA > 1
-       if (!dasd_disciplines[dt]->fill_sizes_first) {
-               INTERNAL_CHECK ("No fill_sizes for dt=%d\n", dt);
-               goto unregister;
-       }
-#endif                         /* DASD_PARANOIA */
-       irq = dasd_info[di]->info.irq;
-       PRINT_INFO ("%04X trying to access, irq %x, index %d\n",
-                   get_devno_by_irq (irq), irq, di);
-       s390irq_spin_lock_irqsave (irq, flags);
-       q = &dasd_info[di]->queue;
-       cqr = dasd_disciplines[dt]->fill_sizes_first (di);
-       dasd_chanq_enq (q, cqr);
-       if (!(atomic_read (&q->flags) & DASD_CHANQ_ACTIVE)) {
-               cql_enq_head (q);
-       }
-       if (dasd_start_IO (cqr) != 0) {
-               dasd_schedule_bh (dasd_do_chanq);
+                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                     " you shouldn't format a device that is already open\n",
+                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+               return -EINVAL;
        }
-       s390irq_spin_unlock_irqrestore (irq, flags);
-
-       goto exit;
-
-      unregister:
-       free_irq (irq, &(dasd_info[di]->dev_status));
-      unalloc:
-       kfree (dasd_info[di]);
-       dasd_info[di] = NULL;
-      exit:
-       spin_unlock (&register_lock);
-       FUNCTION_EXIT ("register_dasd");
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_RECOGNIZED,
+                               device->discipline,
+                               0);
+       if (device->discipline->format_device)
+          rc = device->discipline->format_device (device, fdata);
+               if (rc) {
+                printk (KERN_WARNING PRINTK_HEADER
+                        " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                       " Formatting failed with rc = %d\n",
+                       devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+                       return rc;
+               }
+       printk (KERN_WARNING PRINTK_HEADER
+               " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+               " Formatting finished successfully rc = %d\n",
+               devno, irq, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS, rc);
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                               device->discipline,
+                               0);
+        udelay(1500000);
+        dasd_set_device_level( device->devinfo.irq,
+                               DASD_DEVICE_LEVEL_ANALYSED,
+                               device->discipline,
+                               0);
        return rc;
 }
 
 static int
-probe_for_dasd (int irq)
+do_dasd_ioctl (struct inode *inp, /* unsigned */ int no, unsigned long data)
 {
-       int rc;
-       dev_info_t info;
-       dasd_type_t dt;
-
-       rc = get_dev_info_by_irq (irq, &info);
-
-       if (rc == -ENODEV) {    /* end of device list */
-               return rc;
-       } else if ((info.status & DEVSTAT_DEVICE_OWNED)) {
-               return -EBUSY;
-       } else if ((info.status & DEVSTAT_NOT_OPER)) {
-               return -ENODEV;
-       }
-#if DASD_PARANOIA > 2
-       else {
-               INTERNAL_CHECK ("unknown rc %d of get_dev_info", rc);
-               return rc;
+       int rc = 0;
+       int devindex = devindex_from_kdev_t (inp->i_rdev);
+       dasd_device_t *device = find_dasd_device (devindex);
+       major_info_t *major_info = major_info_from_devindex (devindex);
+        
+       if (!device) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "No device registered as 0x%04x (%d)\n",
+                       inp->i_rdev, devindex);
+               return -EINVAL;
        }
-#endif                         /* DASD_PARANOIA */
-
-       dt = check_type (&info);        /* make a first guess */
-
-       if (dt == dasd_none) {
-               return -ENODEV;
+       if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {
+               PRINT_DEBUG ("empty data ptr");
+               return -EINVAL;
        }
-               if (!dasd_is_accessible (info.devno)) {
-                       return -ENODEV;
+#if 0
+       printk (KERN_DEBUG PRINTK_HEADER
+               "ioctl 0x%08x %s'0x%x'%d(%d) on /dev/%s (%d:%d,"
+               " devno 0x%04X on irq %d) with data %8lx\n",
+               no,
+               _IOC_DIR (no) == _IOC_NONE ? "0" :
+               _IOC_DIR (no) == _IOC_READ ? "r" :
+               _IOC_DIR (no) == _IOC_WRITE ? "w" :
+               _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
+               _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+               device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev),
+               device->devinfo.devno, device->devinfo.irq,
+               data);
+#endif
+       switch (no) {
+       case BLKGETSIZE:{       /* Return device size */
+                       int blocks = blk_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)] << 1;
+                       rc = copy_to_user ((long *) data, &blocks, sizeof (long));
+                       break;
                }
-       if (!dasd_disciplines[dt]->ck_devinfo) {
-                       INTERNAL_ERROR ("no ck_devinfo function%s\n", "");
-                       return -ENODEV;
+       case BLKFLSBUF:{
+                       rc = fsync_dev (inp->i_rdev);
+                       break;
                }
-       rc = dasd_disciplines[dt]->ck_devinfo (&info);
-       if (rc) {
-                       return rc;
+       case BLKRAGET:{
+                       rc = copy_to_user ((long *) data, read_ahead + MAJOR (inp->i_rdev), sizeof (long));
+                       break;
                }
-       if (dasd_probeonly) {
-               PRINT_INFO ("%04X not enabled due to probeonly mode\n",
-                           info.devno);
-               dasd_add_devno_to_ranges (info.devno);
-                       return -ENODEV;
-       } else {
-               rc = register_dasd (irq, dt, &info);
-       }
-               if (rc) {
-               PRINT_WARN ("%04X not enabled due to errors\n",
-                           info.devno);
-               } else {
-               PRINT_INFO ("%04X is (dasd%c) minor %d (%s)\n",
-                                   info.devno,
-                           'a' + devindex_from_devno (info.devno),
-                              devindex_from_devno (info.devno) << PARTN_BITS,
-                                   dasd_name[dt]);
+       case BLKRASET:{
+                       rc = copy_from_user (read_ahead + MAJOR (inp->i_rdev), (long *) data, sizeof (long));
+                       break;
                }
+       case BLKRRPART:{
+                       dasd_partn_detect (devindex);
+                       rc = 0;
+                       break;
+               }
+       case BLKGETBSZ:{
+                       rc = copy_to_user ((int *) data, &blksize_size[MAJOR (inp->i_rdev)][MINOR (inp->i_rdev)],
+                                          sizeof (int));
+                       break;
+               }
+       case HDIO_GETGEO:{
+                       struct hd_geometry geo =
+                       {0,};
+                       if (device->discipline->fill_geometry)
+                               device->discipline->fill_geometry (device, &geo);
+                       rc = copy_to_user ((struct hd_geometry *) data, &geo,
+                                          sizeof (struct hd_geometry));
+                       break;
+               }
+#if ! (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+               RO_IOCTLS (inp->i_rdev, data);
+#endif /* LINUX_IS_24 */
+       case BIODASDRSID:{
+                       rc = copy_to_user ((void *) data,
+                                          &(device->devinfo.sid_data),
+                                          sizeof (senseid_t));
+                       break;
+               }
+       case BIODASDRWTB:{
+                       int offset = 0;
+                       int xlt;
 
-       return rc;
-}
-
-static int
-register_major (int major)
-{
-       int rc = 0;
-
-       FUNCTION_ENTRY ("register_major");
-       rc = register_blkdev (major, DASD_NAME, &dasd_device_operations);
-#if DASD_PARANOIA > 1
-       if (rc) {
-               PRINT_WARN ("registering major -> rc=%d aborting... \n", rc);
-               return rc;
+                       rc = copy_from_user (&xlt, (void *) data,
+                                            sizeof (int));
+                       if (rc)
+                               break;
+                       offset = major_info->gendisk.part[MINOR (inp->i_rdev)].start_sect >>
+                           device->sizes.s2b_shift;
+                       xlt += offset;
+                       rc = copy_to_user ((void *) data, &xlt,
+                                          sizeof (int));
+                       break;
+               }
+       case BIODASDFORMAT:{
+                       /* fdata == NULL is a valid arg to dasd_format ! */
+                       int partn;
+                       format_data_t *fdata = NULL;
+                       if (data) {
+                               fdata = kmalloc (sizeof (format_data_t),
+                                                GFP_ATOMIC);
+                               if (!fdata) {
+                                       rc = -ENOMEM;
+                                       break;
+                               }
+                               rc = copy_from_user (fdata, (void *) data,
+                                                    sizeof (format_data_t));
+                               if (rc)
+                                       break;
+                       }
+                       partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
+                       if (partn != 0) {
+                               printk (KERN_WARNING PRINTK_HEADER
+                                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                                    " Cannot low-level format a partition\n",
+                                       device->devinfo.devno, device->devinfo.irq, device->name,
+                                   MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
+                               return -EINVAL;
+                       }
+                       rc = dasd_format (device, fdata);
+                       if (fdata) {
+                               kfree (fdata);
+                       }
+                       break;
+               }
+       case BIODASDEXCP:{
+                       printk (KERN_WARNING PRINTK_HEADER
+                               "Unsupported ioctl BIODASDEXCP\n");
+                        break;
+               }
+        default:{
+          printk (KERN_WARNING PRINTK_HEADER
+                  "unknown ioctl 0x%08x %s'0x%x'%d(%d) on /dev/%s (%d:%d,"
+                  " devno 0x%04X on irq %d) with data %8lx\n",
+                  no,
+                  _IOC_DIR (no) == _IOC_NONE ? "0" :
+                  _IOC_DIR (no) == _IOC_READ ? "r" :
+                  _IOC_DIR (no) == _IOC_WRITE ? "w" :
+                  _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",
+                  _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),
+                  device->name, MAJOR (inp->i_rdev), MINOR (inp->i_rdev),
+                  device->devinfo.devno, device->devinfo.irq,
+                  data);
+          rc = -EINVAL;
+          break;
+               }
        }
-#endif                         /* DASD_PARANOIA */
-       blk_dev[major].request_fn = do_dasd_request;
-       FUNCTION_CONTROL ("successfully registered major: %d\n", major);
-       FUNCTION_EXIT ("register_major");
        return rc;
 }
 
-/* 
-   Below you find functions which are called from outside. Some of them may be
-   static, because they are called by their function pointers only. Thus static
-   modifier is to make sure, that they are only called via the kernel's methods
- */
+/* SECTION: The members of the struct file_operations */
 
 static int
 dasd_ioctl (struct inode *inp, struct file *filp,
            unsigned int no, unsigned long data)
-{
+       {
        int rc = 0;
-       FUNCTION_ENTRY ("dasd_ioctl");
        if ((!inp) || !(inp->i_rdev)) {
                return -EINVAL;
-       }
+               }
        rc = do_dasd_ioctl (inp, no, data);
-       FUNCTION_EXIT ("dasd_ioctl");
        return rc;
 }
 
@@ -1346,31 +1688,45 @@ static int
 dasd_open (struct inode *inp, struct file *filp)
 {
        int rc = 0;
-       dasd_information_t *dev;
-       FUNCTION_ENTRY ("dasd_open");
+       int devindex;
+       int partn;
+       dasd_device_t *device;
+       major_info_t *major_info;
+
        if ((!inp) || !(inp->i_rdev)) {
                return -EINVAL;
        }
-       dev = dasd_info[DEVICE_NR (inp->i_rdev)];
-       if (!dev) {
-               PRINT_DEBUG ("No device registered as %d (%d)\n",
-                           inp->i_rdev, DEVICE_NR (inp->i_rdev));
+       if ( dasd_probeonly ) {
+               printk ("\n" KERN_INFO PRINTK_HEADER "No access to device (%d:%d) due to probeonly mode\n",MAJOR(inp->i_rdev),MINOR(inp->i_rdev));
+               return -EPERM;
+       }
+       devindex = devindex_from_kdev_t (inp->i_rdev);
+       if (devindex < 0) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "No device registered as %d\n", inp->i_rdev);
+               return devindex;
+       }
+       device = find_dasd_device (devindex);
+       major_info = major_info_from_devindex (devindex);
+       partn = MINOR (inp->i_rdev) & ((1 << major_info->gendisk.minor_shift) - 1);
+       if (device == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "No device registered as %d\n", inp->i_rdev);
+               return -EINVAL;
+       }
+       if (atomic_read (&device->level) < DASD_DEVICE_LEVEL_RECOGNIZED ||
+           device->discipline == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       " devno 0x%04X on subchannel %d = /dev/%s (%d:%d)"
+                       " Cannot open unrecognized device\n",
+                    device->devinfo.devno, device->devinfo.irq, device->name,
+                       MAJOR (inp->i_rdev), MINOR (inp->i_rdev));
                return -EINVAL;
        }
-       down (&dev->sem);
-       up (&dev->sem);
 #ifdef MODULE
        MOD_INC_USE_COUNT;
 #endif                         /* MODULE */
-#if DASD_PARANOIA > 2
-       if (dev->open_count < 0) {
-               INTERNAL_ERROR ("open count cannot be less than 0: %d",
-                               dev->open_count);
-               return -EINVAL;
-       }
-#endif                         /* DASD_PARANOIA */
-       dev->open_count++;
-       FUNCTION_EXIT ("dasd_open");
+       device->open_count++;
        return rc;
 }
 
@@ -1378,37 +1734,38 @@ static int
 dasd_release (struct inode *inp, struct file *filp)
 {
        int rc = 0;
-       dasd_information_t *dev;
-       FUNCTION_ENTRY ("dasd_release");
+       dasd_device_t *device;
+       int devindex;
+
        if ((!inp) || !(inp->i_rdev)) {
                return -EINVAL;
        }
-       dev = dasd_info[DEVICE_NR (inp->i_rdev)];
-       if (!dev) {
-               PRINT_WARN ("No device registered as %d\n", inp->i_rdev);
+       devindex = devindex_from_kdev_t (inp->i_rdev);
+       device = find_dasd_device (devindex);
+       if (device == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "No device registered as %d:%d\n",
+                       MAJOR(inp->i_rdev),MINOR(inp->i_rdev));
                return -EINVAL;
        }
+       if(device->open_count--) {
 #ifdef MODULE
        MOD_DEC_USE_COUNT;
 #endif                         /* MODULE */
-#if DASD_PARANOIA > 2
-       if (!dev->open_count) {
-               PRINT_WARN ("device %d has not been opened before:\n",
-                           inp->i_rdev);
-       }
-#endif                         /* DASD_PARANOIA */
-       dev->open_count--;
-#if DASD_PARANOIA > 2
-       if (dev->open_count < 0) {
-               INTERNAL_ERROR ("open count cannot be less than 0: %d",
-                               dev->open_count);
-               return -EINVAL;
        }
-#endif                         /* DASD_PARANOIA */
-       FUNCTION_EXIT ("dasd_release");
        return rc;
 }
 
+/* SECTION: All that stuff related to major numbers */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct
+block_device_operations dasd_device_operations =
+{
+       ioctl:dasd_ioctl,
+       open:dasd_open,
+       release:dasd_release,
+};
+#else
 static struct
 file_operations dasd_device_operations =
 {
@@ -1419,156 +1776,894 @@ file_operations dasd_device_operations =
        open:dasd_open,
        release:dasd_release,
 };
+#endif /* LINUX_IS_24 */
 
-int
-dasd_init (void)
+static major_info_t *
+get_new_major_info (void)
+{
+       major_info_t *major_info = NULL;
+       major_info = kmalloc (sizeof (major_info_t), GFP_KERNEL);
+       if (major_info) {
+                major_info_t *temp = dasd_major_info;
+                while (temp->next)
+                        temp = temp->next;
+               temp->next = major_info;
+                
+               memset (major_info, 0, sizeof (major_info_t));
+               major_info->read_ahead = 8;
+               major_info->request_fn = do_dasd_request;
+                
+               major_info->gendisk.major_name = DASD_NAME;
+               major_info->gendisk.minor_shift = DASD_PARTN_BITS;
+               major_info->gendisk.max_p = 1 << DASD_PARTN_BITS;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+               major_info->gendisk.max_nr= 1 << DASD_PARTN_BITS;
+#endif /* LINUX_IS_24 */
+               major_info->gendisk.nr_real=DASD_PER_MAJOR;
+       }
+       return major_info;
+}
+
+static int
+dasd_register_major (major_info_t * major_info)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        request_queue_t *q;
+#endif /* LINUX_IS_24 */
+       int rc = 0;
+       int 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;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+       rc = devfs_register_blkdev (major, DASD_NAME, &dasd_device_operations);
+#else
+       rc = register_blkdev (major, DASD_NAME, &dasd_device_operations);
+#endif /* LINUX_IS_24 */
+       if (rc < 0) {
+               printk (KERN_WARNING PRINTK_HEADER
+                     "Cannot register to major no %d, rc = %d\n", major, rc);
+       return rc;
+       } else if (rc > 0) {
+               if (major == 0) {
+                       major = rc;
+                       rc = 0;
+               } else {
+                       printk (KERN_DEBUG PRINTK_HEADER
+                           "Unknown condition when registering major number."
+                         "Please report this line to Linux390@de.ibm.com\n");
+               }
+       } else {
+               if (major == 0) {
+                       printk (KERN_DEBUG PRINTK_HEADER
+                               "Unknown condition when registering to dynamic major number."
+                         "Please report this line to Linux390@de.ibm.com\n");
+
+               }
+       }
+        major_info->dasd_device = (dasd_device_t **) kmalloc( DASD_PER_MAJOR * sizeof(dasd_device_t*), 
+                                                              GFP_ATOMIC);
+        memset ( major_info->dasd_device ,0,DASD_PER_MAJOR * sizeof(dasd_device_t*));
+        blk_size[major] = major_info->blk_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->blk_size ,0,(1<<MINORBITS) * sizeof(int));
+        blksize_size[major] = major_info->blksize_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->blksize_size ,0,(1<<MINORBITS) * sizeof(int));
+        hardsect_size[major] = major_info->hardsect_size = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->hardsect_size ,0,(1<<MINORBITS) * sizeof(int));
+        max_sectors[major] = major_info->max_sectors = 
+                (int *) kmalloc( (1<<MINORBITS) * sizeof(int), GFP_ATOMIC);
+        memset ( major_info->max_sectors ,0,(1<<MINORBITS) * sizeof(int));
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        q = BLK_DEFAULT_QUEUE (major);
+        blk_init_queue (q, do_dasd_request);
+        blk_queue_headactive (BLK_DEFAULT_QUEUE (major), 0);
+#else
+       blk_dev[major].request_fn = major_info->request_fn;
+#endif /* LINUX_IS_24 */
+
+        
+       /* finally do the gendisk stuff */
+        major_info->gendisk.part = kmalloc ((1 << MINORBITS) * 
+                                            sizeof (struct hd_struct),
+                                            GFP_ATOMIC);
+        memset (major_info->gendisk.part,0,(1 << MINORBITS) * 
+                sizeof (struct hd_struct));
+       major_info->gendisk.major = major;
+       major_info->gendisk.next = gendisk_head;
+        major_info->gendisk.sizes = major_info->blk_size;
+       gendisk_head = &major_info->gendisk;
+       return major;
+}
+
+static int
+dasd_unregister_major (major_info_t * major_info)
 {
        int rc = 0;
-       int i;
+       int major;
+        struct gendisk *dd,*prev=NULL;
 
-       PRINT_INFO ("initializing...\n");
-       atomic_set (&bh_scheduled, 0);
-       spin_lock_init (&dasd_lock);
-#ifdef CONFIG_DASD_MDSK
-       /*
-        * enable service-signal external interruptions,
-        * Control Register 0 bit 22 := 1
-        * (besides PSW bit 7 must be set to 1 somewhere for external
-        * interruptions)
-        */
-       ctl_set_bit (0, 9);
-       register_external_interrupt (0x2603, do_dasd_mdsk_interrupt);
-#endif
-       dasd_debug_info = debug_register ("dasd", 1, 4);
-       /* First register to the major number */
+       if (major_info == NULL) {
+                return -EINVAL;
+       }
+       major = major_info->gendisk.major;
+       rc = unregister_blkdev (major, DASD_NAME);
+       if (rc < 0) {
+               printk (KERN_WARNING PRINTK_HEADER
+                        "Cannot unregister from major no %d, rc = %d\n", major, rc);
+               return rc;
+       } 
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        blk_dev[major].request_fn = NULL;
+#endif /* LINUX_IS_24 */
+        blk_size[major]= NULL;
+        blksize_size[major]= NULL;
+        hardsect_size[major]= NULL;
+        max_sectors[major]= NULL;
+
+        kfree(major_info->dasd_device);
+        kfree(major_info->blk_size);
+        kfree(major_info->blksize_size);
+        kfree(major_info->hardsect_size);
+        kfree(major_info->max_sectors);
+        kfree(major_info->gendisk.part);
+        
+       /* finally do the gendisk stuff */
+        for (dd = gendisk_head; dd ; dd = dd -> next ) {
+                if ( dd == &major_info->gendisk ) {
+                        if ( prev )
+                                prev->next = dd->next;
+                        else 
+                                gendisk_head = dd->next;
+                        break;
+                }
+                prev = dd;
+        }
+        if ( dd == NULL ) {
+                return -ENOENT;
+        }
+        if  ( major_info->gendisk.major > 128 )
+                kfree(major_info);
+       return rc;
+}
+/* SECTION: Management of device list */
 
-       rc = register_major (MAJOR_NR);
-#if DASD_PARANOIA > 1
-       if (rc) {
-               PRINT_WARN ("registering major_nr returned rc=%d\n", rc);
+/* This one is needed for naming 18000+ possible dasd devices */
+int
+dasd_device_name (char *str, int index, int partition, struct gendisk *hd)
+{
+       int len = 0;
+        char first,second,third;
+
+        if ( hd ) {
+                index = devindex_from_kdev_t (MKDEV(hd->major,index<<hd->minor_shift));
+}
+        third = index % 26;
+        second = (index / 26) % 27;
+       first = ((index / 26) / 27) % 27;
+
+       len = sprintf (str, "dasd");
+       if (first) {
+                len += sprintf (str + len, "%c", first + 'a' - 1 );
+       }
+       if (second) {
+                len += sprintf (str + len, "%c", second + 'a' - 1 );
+       }
+        len += sprintf (str + len, "%c", third + 'a' );
+       if (partition) {
+               if (partition > 9) {
+                       return -EINVAL;
+               } else {
+                       len += sprintf (str + len, "%d", partition);
+       }
+       }
+       str[len] = '\0';
+       return 0;
+}
+
+static void
+dasd_not_oper_handler ( int irq, int status ) {
+        int devno,devindex;
+        dasd_device_t *device;
+        devno = get_devno_by_irq(irq);
+        if ( devno < 0 ) {
+               printk (KERN_WARNING PRINTK_HEADER
+                         "not_oper_handler called on irq %d no devno!\n", irq);
+                return;
+       }
+        printk ( KERN_INFO PRINTK_HEADER
+                 "not_oper_handler called on irq %d devno %04X\n", irq,devno);
+        devindex = devindex_from_devno(devno);
+        device = find_dasd_device(devindex);
+        dasd_set_device_level( irq, DASD_DEVICE_LEVEL_UNKNOWN, NULL, 0 );
+       }
+
+static int
+dasd_enable_single_volume ( int irq ) {
+        int rc = 0;
+        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                               NULL, 0);
+       printk (KERN_INFO PRINTK_HEADER "waiting for response...\n");
+        {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                static wait_queue_head_t wait_queue;
+                init_waitqueue_head(&wait_queue);
+#else
+                static struct wait_queue *wait_queue = NULL;
+#endif /* LINUX_IS_24 */
+                interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
+        }
+        dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+                               NULL, 0);
+       return rc;
+}
+
+static int
+dasd_oper_handler ( int irq, devreg_t *devreg ) {
+        int devno;
+        int devindex;
+       int rc;
+        devno = get_devno_by_irq(irq);
+        if ( devno == -ENODEV )
+                return -ENODEV;
+        do {
+                devindex = devindex_from_devno(devno);
+                if ( dasd_autodetect ) {
+                        dasd_add_range(devno,0);
+                } else {
+               return -ENODEV;
+       }
+        } while ( devindex == -ENODEV );
+        rc = dasd_enable_single_volume(irq);
                return rc;
        }
-#endif /* DASD_PARANOIA */ read_ahead[MAJOR_NR] = 8;
-        blk_size[MAJOR_NR] = dasd_blks;
-       hardsect_size[MAJOR_NR] = dasd_secsize;
-       blksize_size[MAJOR_NR] = dasd_blksize;
-       max_sectors[MAJOR_NR] = dasd_maxsecs;
-#ifdef CONFIG_PROC_FS
-       dasd_proc_init ();
-#endif                         /* CONFIG_PROC_FS */
-       /* Now scan the device list for DASDs */
-       for (i = 0; i < NR_IRQS; i++) {
-               int irc;        /* Internal return code */
-               irc = probe_for_dasd (i);
-               switch (irc) {
-               case 0:
-                       break;
-               case -ENODEV:
-               case -EBUSY:
+
+/* 
+ * int
+ * dasd_set_device_level (unsigned int irq, int desired_level,
+ *                        dasd_discipline_t * discipline, int flags)
+ */
+
+static int
+dasd_set_device_level (unsigned int irq, int desired_level,
+                      dasd_discipline_t * discipline, int flags)
+{
+       int rc = 0;
+       int devno;
+       int devindex;
+       dasd_device_t *device;
+       int current_level;
+       major_info_t *major_info = NULL;
+       int i, minor;
+       ccw_req_t *cqr = NULL;
+        int ind;
+        dasd_discipline_t *temp;
+        struct gendisk *dd;
+
+       devno = get_devno_by_irq (irq);
+       if (devno < 0) {
+               printk (KERN_WARNING PRINTK_HEADER " no device appears to be connected to SCH %d\n", irq);
+               return -ENODEV;
+       }
+       devindex = devindex_from_devno (devno);
+       if (devindex < 0) {
+               printk (KERN_WARNING PRINTK_HEADER " device %d is not in list of known DASDs\n", irq);
+                       return -ENODEV;
+               }
+       device = find_dasd_device (devindex);
+        while ( (major_info = major_info_from_devindex (devindex)) == NULL ) {
+                if ((rc = dasd_register_major (major_info)) > 0) {
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Registered successfully to another major number: %u\n", rc);
+                } else {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "Couldn't register successfully to another major no\n");
+                        return -ERANGE;
+               }
+               }
+        ind = devindex & (DASD_PER_MAJOR-1);
+        device = major_info->dasd_device[ind];
+        if (!device) {         /* allocate device descriptor */
+                device = kmalloc (sizeof (dasd_device_t), GFP_ATOMIC);
+               if (!device) {
+                       printk (KERN_WARNING PRINTK_HEADER " No memory for device descriptor\n");
+                       goto nomem;
+               }
+               memset (device, 0, sizeof (dasd_device_t));
+                major_info->dasd_device[ind] = device;
+                dasd_device_name (device->name, devindex, 0,NULL);
+       }
+        device->kdev = MKDEV(major_info->gendisk.major,ind << DASD_PARTN_BITS);
+        device->major_info = major_info;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        init_waitqueue_head(&device->wait_q);
+#endif /* KERNEL_VERSION */
+        minor = MINOR(device->kdev);
+       current_level = atomic_read (&device->level);
+       if (desired_level > current_level) {
+               switch (current_level) {
+               case DASD_DEVICE_LEVEL_UNKNOWN: /* Find a discipline */
+                       rc = get_dev_info_by_irq (irq, &device->devinfo);
+                       if (rc < 0) {
+                               break;
+                       }
+                        for ( temp = dasd_disciplines; temp != NULL; temp = temp->next ) {
+                                if ( discipline == NULL || temp == discipline ) {
+                                        if (temp->id_check)
+                                                if (temp->id_check (&device->devinfo))
+                                                        continue;
+                                        if (temp->check_characteristics) {
+                                                if (temp->check_characteristics (device)) 
+                                                        continue;
+       }
+                                        discipline = temp;
+                                        break;
+                                }
+                        }
+                       if (discipline && !rc) {
+                               printk (KERN_INFO PRINTK_HEADER
+                                       " devno 0x%04X on subchannel %d (%s) is /dev/%s (%d:%d)\n",
+                                       devno, irq, discipline->name,
+                                        device->name, major_from_devindex (devindex),
+                                       (devindex % 64) << DASD_PARTN_BITS);
+               } else {
+                               break;
+               }
+                       device->discipline = discipline;
+                       if (device->discipline->int_handler) {
+                                s390_request_irq_special(irq, 
+                                                         device->discipline->int_handler, 
+                                                         dasd_not_oper_handler,
+                                                         0, 
+                                                         DASD_NAME, 
+                                                         &device->dev_status);
+                       }
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_UNKNOWN,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED);
+                       if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
+                               break;
+               case DASD_DEVICE_LEVEL_RECOGNIZED:      /* Fallthrough ?? */
+                       if (device->discipline->init_analysis) {
+                               cqr = device->discipline->init_analysis (device);
+                                if (cqr != NULL) {
+                                        dasd_chanq_enq (&device->queue, cqr);
+                                        if (device->discipline->start_IO) {
+                                                long flags;
+                                                s390irq_spin_lock_irqsave (irq, flags);
+                                                device->discipline->start_IO (cqr);
+                                                atomic_compare_and_swap_debug (&device->level,
+                                                                               DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                                               DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
+                                                s390irq_spin_unlock_irqrestore (irq, flags);
+}
+                                }
+                        } else {
+                                atomic_compare_and_swap_debug (& device->level,DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                               DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
+                        }
+                       if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+                               break;
+               case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:        /* Fallthrough ?? */
+                       return -EAGAIN;
+               case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:       /* Re-entering here ! */
+                        if (device->discipline->do_analysis) 
+                                if (device->discipline->do_analysis (device))
+                                       return -ENODEV;
+                       switch (device->sizes.bp_block) {
+                       case 512:
+                       case 1024:
+                       case 2048:
+                       case 4096:
+                               break;
+                       default:
+{
+                                       printk (KERN_INFO PRINTK_HEADER
+                                               "/dev/%s (devno 0x%04X): Detected invalid blocksize of %d bytes"
+                                               " Did you format the drive?\n",
+                                               device->name, devno, device->sizes.bp_block);
+                                       return -EMEDIUMTYPE;
+                        }
+                       }
+                       for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                if (i == 0)
+                                       major_info->blk_size[minor] = (device->sizes.blocks << device->sizes.s2b_shift) >> 1;
+                               else
+                                       major_info->blk_size[minor + i] = 0;
+                               major_info->hardsect_size[minor + i] = device->sizes.bp_block;
+                               major_info->blksize_size[minor + i] = device->sizes.bp_block;
+                                if (major_info->blksize_size[minor + i] < 1024 )
+                                        major_info->blksize_size[minor + i] = 1024;
+                                
+                               major_info->max_sectors[minor + i] = 200 << device->sizes.s2b_shift;    /* FIXME !!! */
+                       }
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                                       DASD_DEVICE_LEVEL_ANALYSED);
+                        dd = &major_info->gendisk;
+                        dd->sizes[minor] = ( device->sizes.blocks << 
+                                             device->sizes.s2b_shift) >> 1;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#ifndef MODULE
+                        if ( flags & 0x80 )
+#endif
+#endif /* KERNEL_VERSION */
+                                dasd_partn_detect(devindex);
+                       if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
+                               break;
+               case DASD_DEVICE_LEVEL_ANALYSED:        /* Fallthrough ?? */
+
                        break;
-               case -EMEDIUMTYPE:
-                       PRINT_WARN ("DASD not formatted%s\n", "");
+               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_PARTITIONED:     /* Fallthrough ?? */
+                        /* delete the partition information */
+                       for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                struct hd_struct *p = &major_info->gendisk.part[minor+i];
+                                p->start_sect = 0;
+                                p->nr_sects = 0;
+                                p->type = 0;
+                        }
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_PARTITIONED,
+                                                       DASD_DEVICE_LEVEL_ANALYSED);
+                       if (desired_level == DASD_DEVICE_LEVEL_ANALYSED)
+                               break;
+               case DASD_DEVICE_LEVEL_ANALYSED:        /* Fallthrough ?? */
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSED,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED);
+                        if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PREPARED)
+                                break;
+               case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
+                       for (i = 0; i < (1 << DASD_PARTN_BITS); i++) {
+                                major_info->blk_size[minor] = 0;
+                                major_info->hardsect_size[minor + i] = 0;
+                                major_info->blksize_size[minor + i] = 0;
+                                major_info->max_sectors[minor + i] = 0;
+                       }
+                        memset( &device->sizes,0,sizeof(dasd_sizes_t));
+                        atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PENDING);
+                       if (desired_level == DASD_DEVICE_LEVEL_ANALYSIS_PENDING)
+                               break;
+               case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:        /* Fallthrough ?? */
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED);
+                       if (desired_level == DASD_DEVICE_LEVEL_RECOGNIZED)
+                               break;
+               case DASD_DEVICE_LEVEL_RECOGNIZED:      /* Fallthrough ?? */
+                        if (device->discipline->int_handler) {
+                                free_irq (irq, &device->dev_status);
+                       }
+                       device->discipline = NULL;
+                       atomic_compare_and_swap_debug (&device->level,
+                                                       DASD_DEVICE_LEVEL_RECOGNIZED,
+                                                       DASD_DEVICE_LEVEL_UNKNOWN);
+                       if (desired_level == DASD_DEVICE_LEVEL_UNKNOWN)
+                               break;
+               case DASD_DEVICE_LEVEL_UNKNOWN: 
+                        break;
                default:
-                       INTERNAL_CHECK ("probe_for_dasd: unknown rc=%d", irc);
+                       printk (KERN_WARNING PRINTK_HEADER
+                               "Internal error in " __FILE__ " on line %d."
+                               " validate_dasd called from %p with "
+                               " desired_level = %d, current_level =%d"
+                               " Pls send this message and your System.map to"
+                               " linux390@de.ibm.com\n",
+                               __LINE__, __builtin_return_address (0),
+                               desired_level, current_level);
                        break;
                }
        }
-       FUNCTION_CONTROL ("detection loop completed %s partn check...\n", "");
-/* Finally do the genhd stuff */
-       dd_gendisk.next = gendisk_head;
-       gendisk_head = &dd_gendisk;
-       dasd_information = dasd_info;   /* to enable genhd to know about DASD */
-        tod_wait (1000000);
-
-       /* wait on root filesystem before detecting partitions */
-       if (MAJOR (ROOT_DEV) == DASD_MAJOR) {
-               int count = 10;
-               i = DEVICE_NR (ROOT_DEV);
-               if (dasd_info[i] == NULL) {
-                       panic ("root device not accessible\n");
-               }
-                while ((atomic_read (&dasd_info[i]->status) !=
-                        DASD_INFO_STATUS_FORMATTED) &&
-                       count ) {
-                        PRINT_INFO ("Waiting on root volume...%d seconds left\n", count);
-                       tod_wait (1000000);
-                       count--;
-               }
-               if (count == 0) {
-                       panic ("Waiting on root volume...giving up!\n");
+       if (rc) {
+               goto exit;
+       }
+      nomem:
+       rc = -ENOMEM;
+      exit:
+       return 0;
+}
+
+
+/* SECTION: Procfs stuff */
+typedef struct {
+        char *data;
+        int len;
+} tempinfo_t;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+static struct proc_dir_entry *dasd_proc_root_entry = NULL;
+#else
+static struct proc_dir_entry dasd_proc_root_entry =
+{
+       low_ino:0,
+       namelen:4,
+       name:"dasd",
+       mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
+       nlink:1,
+       uid:0,
+       gid:0,
+       size:0
+};
+#endif /* KERNEL_VERSION */
+static struct proc_dir_entry* dasd_devices_entry;
+
+
+static int
+dasd_devices_open (struct inode* inode, struct file*  file )
+{
+       int rc = 0;
+       int size = 0;
+       int len = 0;
+       major_info_t * temp = dasd_major_info;
+        tempinfo_t *info;
+
+       info = (tempinfo_t *)vmalloc(sizeof(tempinfo_t)); 
+        if( info == NULL ) {
+                printk ( KERN_WARNING "No memory available for data\n");
+                return -ENOMEM;
+       } else {
+                file->private_data = (void *)info;
+       }
+        while ( temp ) {
+                int i;
+                for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
+                        dasd_device_t *device = temp->dasd_device[i];
+                        if ( device ) {
+                               size+=128;
+                       }
                }
+               temp = temp->next;
        }
-       for (i = 0; i < DASD_MAX_DEVICES; i++) {
-               if (dasd_info[i]) {
-                       if (atomic_read (&dasd_info[i]->status) ==
-                           DASD_INFO_STATUS_FORMATTED) {
-                               dasd_partn_detect (i);
-                       } else {        /* start kernel thread for devices not ready now */
-                               kernel_thread (dasd_partn_detect, (void *) i,
-                                               CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+       temp = dasd_major_info;
+       info->data=(char*)vmalloc(size); /* FIXME! determine space needed in a better way */
+        if( size && info->data == NULL ) {
+               printk ( KERN_WARNING "No memory available for data\n");
+                vfree ( info );
+               return -ENOMEM;
+       }
+       while ( temp ) {
+               int i;
+               for ( i = 0; i < 1 << (MINORBITS - DASD_PARTN_BITS); i ++ ) {
+                       dasd_device_t *device = temp->dasd_device[i];
+                       if ( device ) {
+                               len += sprintf ( info->data + len,
+                                                "%04X(%s) at (%d:%d) is %7s:",
+                                                device->devinfo.devno,
+                                                device->discipline ? device->discipline->name : "none",
+                                                temp->gendisk.major,i<<DASD_PARTN_BITS,
+                                                device->name);
+                                switch ( atomic_read(&device->level) ) {
+                                case DASD_DEVICE_LEVEL_UNKNOWN:
+                                        len += sprintf ( info->data + len,"unknown\n");
+                                        break;
+                                case DASD_DEVICE_LEVEL_RECOGNIZED:
+                                        len += sprintf ( info->data + len,"passive");
+                                        len += sprintf ( info->data + len," at blocksize: %d, %d blocks, %d MB\n",
+                                                         device->sizes.bp_block,
+                                                         device->sizes.blocks,
+                                                         ((device->sizes.bp_block>>9)*device->sizes.blocks)>>11);
+                                        break;
+                                case DASD_DEVICE_LEVEL_ANALYSIS_PENDING:
+                                        len += sprintf ( info->data + len,"busy   \n");
+                                        break;
+                               case DASD_DEVICE_LEVEL_ANALYSIS_PREPARED:
+                                       len += sprintf ( info->data + len,"n/f    \n");
+                                       break;
+                                case DASD_DEVICE_LEVEL_ANALYSED:
+                                        len += sprintf ( info->data + len,"active ");
+                                        len += sprintf ( info->data + len," at blocksize: %d, %d blocks, %d MB\n",
+                                                         device->sizes.bp_block,
+                                                         device->sizes.blocks,
+                                                         ((device->sizes.bp_block>>9)*device->sizes.blocks)>>11);
+                                        break;
+                                default:
+                                        len += sprintf ( info->data + len,"no stat\n");
+                                        break;
+                                }
                        }
                }
+               temp = temp->next;
        }
+        info->len=len;
        return rc;
 }
 
-#ifdef MODULE
+#define MIN(a,b) ((a)<(b)?(a):(b))
 
-int
-init_module (void)
+static ssize_t 
+dasd_devices_read (  struct  file *file, char*   user_buf,  size_t  user_len, loff_t* offset )
+{
+        loff_t len;
+        tempinfo_t* p_info = (tempinfo_t*)file->private_data;
+
+        if(*offset >= p_info->len)
+        {
+                return 0; /* EOF */
+       }
+        else
+        {
+                len = MIN(user_len, (p_info->len - *offset));
+                copy_to_user(user_buf, &(p_info->data[*offset]), len);
+                (*offset) += len;
+                return len;  /* number of bytes "read" */
+       }
+}
+
+static int
+dasd_devices_close (struct inode* inode, struct file*  file)
 {
        int rc = 0;
+        tempinfo_t* p_info = (tempinfo_t*)file->private_data;
+        if ( p_info ) {
+                if ( p_info->data ) vfree(p_info->data);
+                vfree(p_info);
+       }
+       return rc;
+}
 
-       PRINT_INFO ("Initializing module\n");
-       rc = dasd_parse_module_params ();
-       if (rc == 0) {
-               PRINT_INFO ("module parameters parsed successfully\n");
-       } else {
-               PRINT_WARN ("parsing parameters returned rc=%d\n", rc);
+
+static struct file_operations dasd_devices_file_ops =
+{
+  NULL,          /* lseek */
+  dasd_devices_read,  /* read */
+  NULL, /* dasd_devices_write, */   /* write */
+  NULL,          /* readdir */
+  NULL,          /* select */
+  NULL,          /* ioctl */
+  NULL,          /* mmap */
+  dasd_devices_open,    /* open */
+  NULL,          /* flush */
+  dasd_devices_close,   /* close */
+};
+
+static struct inode_operations dasd_devices_inode_ops =
+{
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+  default_file_ops: &dasd_devices_file_ops /* file ops */
+#endif /* LINUX_IS_24 */
+};
+
+void
+dasd_proc_init (void)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        dasd_proc_root_entry = create_proc_entry("dasd", 
+                                                 S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR,
+                                                 &proc_root);
+        dasd_devices_entry = create_proc_entry("devices", 
+                                               S_IFREG | S_IRUGO | S_IWUSR,
+                                               dasd_proc_root_entry);
+#else
+       proc_register (&proc_root, &dasd_proc_root_entry);
+       dasd_devices_entry = (struct proc_dir_entry*)kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC);
+        if ( dasd_devices_entry) {
+                memset(dasd_devices_entry, 0, sizeof(struct proc_dir_entry));
+                dasd_devices_entry->name     = "devices";
+                dasd_devices_entry->namelen  = strlen("devices");
+                dasd_devices_entry->low_ino  = 0;
+                dasd_devices_entry->mode     = (S_IFREG | S_IRUGO | S_IWUSR);
+                dasd_devices_entry->nlink    = 1;
+                dasd_devices_entry->uid      = 0;
+                dasd_devices_entry->gid      = 0;
+                dasd_devices_entry->size     = 0;
+                dasd_devices_entry->get_info = NULL;
+                dasd_devices_entry->ops      = &dasd_devices_inode_ops;
+                proc_register(&dasd_proc_root_entry, dasd_devices_entry);
+        }
+#endif /* LINUX_IS_24 */
+}
+
+void
+dasd_proc_cleanup (void)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        remove_proc_entry("devices", dasd_proc_root_entry);
+        remove_proc_entry("dasd", &proc_root);
+#else
+        proc_unregister(&dasd_proc_root_entry, dasd_devices_entry->low_ino);
+       kfree(dasd_devices_entry);
+       proc_unregister (&proc_root, dasd_proc_root_entry.low_ino);
+#endif /* LINUX_IS_24 */
+}
+
+/* SECTION: Initializing the driver */
+
+int
+dasd_init (void)
+{
+       int rc = 0;
+       int irq;
+       int j;
+       major_info_t *major_info;
+        dasd_range_t *range;
+
+       printk (KERN_INFO PRINTK_HEADER "initializing...\n");
+        genhd_dasd_name = dasd_device_name;
+#ifndef MODULE
+        dasd_split_parm_string(dasd_parm_string);
+#endif /* ! MODULE */
+        dasd_parse(dasd);
+
+        dasd_proc_init();
+        dasd_init_emergency_req();
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        init_waitqueue_head(&watcher_queue);
+        spin_lock_init(&cq_lock);
+#endif /* LINUX_IS_24 */
+
+       for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+               if ((rc = dasd_register_major (major_info)) > 0) {
+                       printk (KERN_INFO PRINTK_HEADER
+                               "Registered successfully to major no %u\n", major_info->gendisk.major);
+               } else {
+                       printk (KERN_WARNING PRINTK_HEADER
+                               "Couldn't register successfully to major no %d\n", major_info->gendisk.major);
+       }
+               }
+        
+#ifdef CONFIG_DASD_ECKD
+       rc = dasd_eckd_init ();
+       if (rc==0)  {
+               printk (KERN_INFO PRINTK_HEADER
+                       "Registered ECKD discipline successfully\n");
        }
-       rc = dasd_init ();
+#endif                         /* CONFIG_DASD_ECKD */
+#ifdef CONFIG_DASD_FBA
+       rc = dasd_fba_init ();
        if (rc == 0) {
-               PRINT_INFO ("module initialized successfully\n");
-       } else {
-               PRINT_WARN ("initializing module returned rc=%d\n", rc);
+               printk (KERN_INFO PRINTK_HEADER
+                       "Registered FBA discipline successfully\n");
        }
-       FUNCTION_EXIT ("init_module");
+#endif                         /* CONFIG_DASD_FBA */
+#ifdef CONFIG_DASD_MDSK
+       rc = dasd_diag_init ();
+       if (rc == 0)  {
+               printk (KERN_INFO PRINTK_HEADER
+                       "Registered MDSK discipline successfully\n");
+       }
+#endif                         /* CONFIG_DASD_MDSK */
+       rc = 0;
+       for (range = dasd_range_head; range; range= range->next) {
+               for (j = range->from; j <= range->to; j++) {
+                       irq = get_irq_by_devno (j);
+                       if (irq >= 0)
+                               dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                                      NULL, 0);
+       }
+                       }
+        if ( dasd_autodetect ) {
+                for ( irq = get_irq_first(); irq != -ENODEV; irq = get_irq_next(irq) ) {
+                        int devno = get_devno_by_irq(irq);
+                        int index = devindex_from_devno(devno);
+                        if ( index == -ENODEV ) { /* not included in ranges */
+                                dasd_add_range (devno,0);
+                               dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                                      NULL, 0);
+               }
+       }
+}
+       printk (KERN_INFO PRINTK_HEADER "waiting for responses...\n");
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                static wait_queue_head_t wait_queue;
+                init_waitqueue_head(&wait_queue);
+#else
+                static struct wait_queue *wait_queue = NULL;
+#endif /* LINUX_IS_24 */
+                interruptible_sleep_on_timeout (&wait_queue, (5 * HZ) >> 1 );
+       }
+       for (range = dasd_range_head; range; range= range->next) {
+               for (j = range->from; j <= range->to; j++) {
+                       irq = get_irq_by_devno (j);
+                       if (irq >= 0) {
+                               dasd_set_device_level (irq, DASD_DEVICE_LEVEL_ANALYSED,
+                                                      NULL, 0);
+       }
+               }
+       }
+
+       printk (KERN_INFO PRINTK_HEADER "initialization completed\n");
        return rc;
 }
 
 void
-cleanup_module (void)
+cleanup_dasd (void)
 {
-       int rc = 0;
-       struct gendisk *genhd = gendisk_head, *prev = NULL;
+        int j,rc=0;
+        int irq;
+        major_info_t *major_info;
+        dasd_range_t *range,*next;
+        dasd_devreg_t *reg;
+
+       printk (KERN_INFO PRINTK_HEADER "shutting down\n");
 
-       PRINT_INFO ("trying to unload module \n");
+        dasd_proc_cleanup();
 
-       /* unregister gendisk stuff */
-       for (genhd = gendisk_head; genhd; prev = genhd, genhd = genhd->next) {
-               if (genhd == dd_gendisk) {
-                       if (prev)
-                               prev->next = genhd->next;
-                       else {
-                               gendisk_head = genhd->next;
+       for (range = dasd_range_head; range; range= range->next) {
+               for (j = range->from; j <= range->to; j++) {
+                       irq = get_irq_by_devno (j);
+                       if (irq >= 0) {
+                               dasd_set_device_level (irq, DASD_DEVICE_LEVEL_UNKNOWN,
+                                                      NULL, 0);
+                                kfree(find_dasd_device(devindex_from_devno(j)));
                        }
+               }
+       }
+       for (major_info = dasd_major_info; major_info; major_info = major_info->next) {
+               if ((rc = dasd_unregister_major (major_info)) == 0) {
+                       printk (KERN_INFO PRINTK_HEADER
+                               "Unregistered successfully from major no %u\n", major_info->gendisk.major);
+               } else {
+                       printk (KERN_WARNING PRINTK_HEADER
+                               "Couldn't unregister successfully from major no %d rc = %d\n", major_info->gendisk.major,rc);
+               }
+       }
+        dasd_cleanup_emergency_req();
+        
+        range = dasd_range_head;
+        while ( range ) {
+                next = range -> next;
+                kfree (range);
+                if ( next == NULL )
                        break;
+                else
+                        range = next;
                }
+        dasd_range_head = NULL;
+
+        while ( dasd_devreg_head ) {
+                reg = dasd_devreg_head->next;
+                kfree ( dasd_devreg_head );
+                dasd_devreg_head = reg;
        }
-       /* unregister devices */
-       for (i = 0; i = DASD_MAX_DEVICES; i++) {
-               if (dasd_info[i])
-                       dasd_unregister_dasd (i);
+       printk (KERN_INFO PRINTK_HEADER "shutdown completed\n");
        }
 
-       if (rc == 0) {
-               PRINT_INFO ("module unloaded successfully\n");
-       } else {
-               PRINT_WARN ("module unloaded with errors\n");
+#ifdef MODULE
+int
+init_module ( void )
+{
+        int rc=0;
+        return dasd_init(); 
+        return rc;
        }
+
+void 
+cleanup_module ( void ) 
+{
+        cleanup_dasd();
+        return;
 }
-#endif                         /* MODULE */
+#endif
 
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/s390/block/dasd.h b/drivers/s390/block/dasd.h
new file mode 100644 (file)
index 0000000..b77e731
--- /dev/null
@@ -0,0 +1,10 @@
+ccw_req_t *default_erp_action (ccw_req_t *);
+int default_erp_postaction ( ccw_req_t *, int);
+int dasd_start_IO (ccw_req_t * cqr);
+void dasd_int_handler (int , void *, struct pt_regs *);
+ccw_req_t * dasd_alloc_request (char *, int , int ) ;
+void dasd_free_request(ccw_req_t *);
+int (*genhd_dasd_name)(char*,int,int,struct gendisk*);
+
+
+
diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
new file mode 100644 (file)
index 0000000..75af18b
--- /dev/null
@@ -0,0 +1,105 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_3370_erp.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#define PRINTK_HEADER "dasd_erp(3370)"
+#endif /* PRINTK_HEADER */
+
+/*
+ * DASD_3370_ERP_EXAMINE 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recover error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+ *   'Chapter 7. 3370 Sense Data'.
+ *
+ * RETURN VALUES
+ *   dasd_era_none      no error 
+ *   dasd_era_fatal     for all fatal (unrecoverable errors)
+ *   dasd_era_recover   for all others.
+ */
+dasd_era_t
+dasd_3370_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+{
+       char *sense = stat->ii.sense.data;
+
+       /* check for successful execution first */
+       if ( stat->cstat == 0x00 &&
+             stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))             
+                return dasd_era_none;
+        if ( sense[0] & 0x80 ) { /* CMD reject */
+                return dasd_era_fatal;
+        }
+        if ( sense[0] & 0x40 ) { /* Drive offline */
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x20 ) { /* Bus out parity */
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x10 ) { /* equipment check */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x08 ) { /* data check */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[0] & 0x04 ) { /* overrun */
+                if ( sense[1] & 0x80 ) {
+                        return dasd_era_fatal;
+                }
+                return dasd_era_recover;
+        }
+        if ( sense[1] & 0x40 ) { /* invalid blocksize */
+                return dasd_era_fatal;
+        }
+        if ( sense[1] & 0x04 ) { /* file protected */
+                return dasd_era_recover;
+        }
+        if ( sense[1] & 0x01 ) { /* operation incomplete */
+                return dasd_era_recover;
+        }
+        if ( sense[2] & 0x80 ) { /* check data erroor */
+                return dasd_era_recover;
+        }
+        if ( sense[2] & 0x10 ) { /* Env. data present */
+                return dasd_era_recover;
+        }
+        /* examine the 24 byte sense data */
+        return dasd_era_recover;
+        
+}                              /* END dasd_3370_erp_examine */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index cd83650ce944dfceadf384fb48ad2c76ce23d70d..63d01f6601a5c0e8388c8d67ed53883d2a00f8af 100644 (file)
@@ -6,10 +6,13 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
-#include "dasd_erp.h"
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(3990)"
+#endif /* PRINTK_HEADER */
 
 /*
  * DASD_3990_ERP_EXAMINE_32 
@@ -95,7 +98,7 @@ dasd_3990_erp_examine_24 (char *sense)
  *   dasd_era_recover   for all others.
  */
 dasd_era_t
-dasd_3990_erp_examine (cqr_t * cqr, devstat_t * stat)
+dasd_3990_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
 
        char *sense = stat->ii.sense.data;
diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
new file mode 100644 (file)
index 0000000..2c04ca4
--- /dev/null
@@ -0,0 +1,64 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_9336_erp.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#define PRINTK_HEADER "dasd_erp(9336)"
+#endif /* PRINTK_HEADER */
+
+/*
+ * DASD_9336_ERP_EXAMINE 
+ *
+ * DESCRIPTION
+ *   Checks only for fatal/no/recover error. 
+ *   A detailed examination of the sense data is done later outside
+ *   the interrupt handler.
+ *
+ *   The logic is based on the 'IBM 3880 Storage Control Reference' manual
+ *   'Chapter 7. 9336 Sense Data'.
+ *
+ * RETURN VALUES
+ *   dasd_era_none      no error 
+ *   dasd_era_fatal     for all fatal (unrecoverable errors)
+ *   dasd_era_recover   for all others.
+ */
+dasd_era_t
+dasd_9336_erp_examine (ccw_req_t * cqr, devstat_t * stat)
+{
+       char *sense = stat->ii.sense.data;
+
+       /* check for successful execution first */
+       if (stat->cstat == 0x00 &&
+           stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+                return dasd_era_none;
+        
+        /* examine the 24 byte sense data */
+        return dasd_era_recover;
+        
+}                              /* END dasd_9336_erp_examine */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
index 7a0f0e6be9a0ca11b223bc447d83bc1b2695f1d8..5f7d6c5ede778ac8a74ee99ce196dbef3e733af4 100644 (file)
@@ -5,13 +5,16 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
-#include "dasd_erp.h"
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
 #define PRINTK_HEADER "dasd_erp(9343)"
+#endif /* PRINTK_HEADER */
 
 dasd_era_t
-dasd_9343_erp_examine (cqr_t * cqr, devstat_t * stat)
+dasd_9343_erp_examine (ccw_req_t * cqr, devstat_t * stat)
 {
        if (stat->cstat == 0x00 &&
            stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
diff --git a/drivers/s390/block/dasd_ccwstuff.c b/drivers/s390/block/dasd_ccwstuff.c
deleted file mode 100644 (file)
index 0d0a8a2..0000000
+++ /dev/null
@@ -1,546 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_ccwstuff.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- */
-
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-#include <linux/malloc.h>
-#include <asm/spinlock.h>
-#include <linux/dasd.h>
-#include <asm/atomic.h>
-
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd_ccw:"
-#define MAX_CP_POWER 9         /* Maximum allowed index */
-#define CP_PER_PAGE_POWER 9    /* Maximum index, fitting on page */
-
-#define get_free_pages __get_free_pages
-
-/* Stuff for the handling task_list */
-dasd_chanq_t *cq_head = NULL;  /* head of task_list */
-atomic_t chanq_tasks;
-
-/* Array of freelists for the channel programs' -space */
-static ccw1_t *ccwarea[CP_PER_PAGE_POWER + 1] =
-{NULL,};
-
-/* array of pages retrieved for internal use */
-#define MAX_DASD_PAGES 64
-static int dasd_page_count = 0;
-static long dasd_page[MAX_DASD_PAGES];
-
-#ifdef __SMP__
-static spinlock_t ccw_lock=SPIN_LOCK_UNLOCKED; /* spinlock for ccwareas */
-static spinlock_t cq_lock=SPIN_LOCK_UNLOCKED;  /* spinlock for cq_head */
-#endif                         /* __SMP__ */
-
-void
-ccwarea_enq (int index, ccw1_t * area)
-{
-       FUNCTION_ENTRY ("ccwarea_enq");
-#if DASD_PARANOIA > 2
-       if (!area) {
-               INTERNAL_CHECK ("zero area %s\n", "");
-       }
-       if (index > CP_PER_PAGE_POWER) {
-               INTERNAL_CHECK ("index too large %d\n", index);
-       }
-#endif
-       *(ccw1_t **) area = ccwarea[index];
-       ccwarea[index] = area;
-       FUNCTION_EXIT ("ccwarea_enq");
-       return;
-}
-
-ccw1_t *
-ccwarea_deq (int index)
-{
-       ccw1_t *cp;
-       FUNCTION_ENTRY ("ccwarea_deq");
-#if DASD_PARANOIA > 2
-       if (index > CP_PER_PAGE_POWER) {
-               INTERNAL_CHECK ("index too large %d\n", index);
-       }
-#endif
-       cp = ccwarea[index];
-       ccwarea[index] = *(ccw1_t **) ccwarea[index];
-#if DASD_PARANOIA > 2
-       if (!cp) {
-               INTERNAL_CHECK ("returning NULL %s\n", "");
-       }
-#endif
-       FUNCTION_EXIT ("ccwarea_deq");
-       return cp;
-}
-
-ccw1_t *
-request_cpa (int index)
-{
-       ccw1_t *freeblk;
-       FUNCTION_ENTRY ("request_cpa");
-       if (index > MAX_CP_POWER) {
-               INTERNAL_ERROR ("index too large %d\n", index);
-               freeblk = NULL;
-               goto exit;
-       }
-       if (index > CP_PER_PAGE_POWER) {
-               int pc = 1 << (index - CP_PER_PAGE_POWER);
-               do {
-                       freeblk = (ccw1_t *) get_free_pages (GFP_ATOMIC, index - CP_PER_PAGE_POWER);
-                       if (dasd_page_count + pc >= MAX_DASD_PAGES) {
-                               PRINT_WARN ("Requesting too many pages...");
-                       } else {
-                               int i;
-                               for (i = 0; i < pc; i++)
-                                       dasd_page[dasd_page_count++] =
-                                               (long) freeblk + i * PAGE_SIZE;
-                       }
-                       FUNCTION_CONTROL ("requesting index %d", index);
-                       if ( ! freeblk ) {
-                               panic ("No memory received\n");
-                       }
-               } while (!freeblk);
-               memset(freeblk,0,PAGE_SIZE<<(index-CP_PER_PAGE_POWER));
-               goto exit;
-       }
-       while (ccwarea[index] == NULL) {
-               ccw1_t *blk;
-               if (index == CP_PER_PAGE_POWER) {
-                       do {
-                               blk = (ccw1_t *) get_free_page (GFP_ATOMIC);
-                               if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-                                       PRINT_WARN ("Requesting too many pages...");
-                               } else {
-                                       dasd_page[dasd_page_count++] =
-                                               (long) blk;
-                               }
-                               if (blk == NULL) {
-                                       PRINT_WARN ("Can't allocate page!\n");
-                               }
-                       } while ( ! blk );
-                       memset(blk,0,PAGE_SIZE);
-                       ccwarea_enq (CP_PER_PAGE_POWER, blk);
-                       continue;
-               }
-               blk = request_cpa (index + 1);
-#if DASD_PARANOIA > 1
-               if (!blk) {
-                       PRINT_WARN ("retrieved NULL");
-               }
-#endif                         /* DASD_PARANOIA */
-               ccwarea_enq (index, blk);
-               ccwarea_enq (index, blk + (1 << index));
-       }
-#if DASD_PARANOIA > 2
-       if (!ccwarea[index]) {
-               INTERNAL_ERROR ("ccwarea is NULL\n%s", "");
-       }
-#endif                         /* DASD_PARANOIA */
-
-       freeblk = ccwarea_deq (index);
-#if DASD_PARANOIA > 1
-       if (!freeblk) {
-               INTERNAL_ERROR ("freeblk is NULL\n%s", "");
-       }
-#endif                         /* DASD_PARANOIA */
-      exit:
-       return freeblk;
-}
-
-ccw1_t *
-request_cp (int size)
-{
-       ccw1_t *freeblk;
-       int index;
-       int blksize;
-       /* Determine the index of ccwarea to look at */
-       for (index = 0, blksize = 1;
-            size > blksize;
-            index++, blksize = blksize << 1) {
-       }
-       if (index > MAX_CP_POWER) {
-               INTERNAL_ERROR ("index too large %d\n", index);
-       }
-       spin_lock (&ccw_lock);
-       freeblk = request_cpa (index);
-       spin_unlock (&ccw_lock);
-       if (freeblk == NULL) {
-               printk (KERN_WARNING PRINTK_HEADER
-                       "No way to deliver free ccw space\n");
-       }
-       return freeblk;
-}
-
-void
-release_cp (int size, ccw1_t * area)
-{
-       int index;
-       int blksize;
-       /* Determine the index of ccwarea to look at */
-       for (index = 0, blksize = 1;
-            size > blksize;
-            index++, blksize = blksize << 1) {
-       }
-       if (index > MAX_CP_POWER) {
-               INTERNAL_ERROR ("index too large %d\n", index);
-       } else if (index > CP_PER_PAGE_POWER) {
-               free_pages ((unsigned long) area,
-                           index - CP_PER_PAGE_POWER);
-               INTERNAL_CHECK ("large index used: %d\n", index);
-       } else {
-               spin_lock (&ccw_lock);
-               ccwarea_enq (index, area);
-               spin_unlock (&ccw_lock);
-       }
-       return;
-}
-
-/* ---------------------------------------------------------- */
-
-static cqr_t *cqrp = NULL;
-#ifdef __SMP__
-static spinlock_t cqr_lock=SPIN_LOCK_UNLOCKED;
-#endif                         /* __SMP__ */
-
-void
-cqf_enq (cqr_t * cqf)
-{
-       *(cqr_t **) cqf = cqrp;
-       cqrp = cqf;
-}
-
-cqr_t *
-cqf_deq (void)
-{
-       cqr_t *cqr = cqrp;
-       cqrp = *(cqr_t **) cqrp;
-       return cqr;
-}
-
-cqr_t *
-request_cq (void)
-{
-       cqr_t *cqr = NULL;
-       int i;
-       cqr_t *area;
-
-       spin_lock (&cqr_lock);
-       while (cqrp == NULL) {
-               do {
-                       area = (cqr_t *) get_free_page (GFP_ATOMIC);
-                       if (area == NULL) {
-                               printk (KERN_WARNING PRINTK_HEADER
-                                       "No memory for chanq area\n");
-                       }
-               } while ( ! area );
-               memset(area,0,PAGE_SIZE);
-               if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-                       PRINT_WARN ("Requesting too many pages...");
-               } else {
-                       dasd_page[dasd_page_count++] =
-                               (long) area;
-               }
-               for (i = 0; i < 4096 / sizeof (cqr_t); i++) {
-                               cqf_enq (area + i);
-               }
-       }
-       cqr = cqf_deq ();
-       spin_unlock (&cqr_lock);
-       return cqr;
-}
-
-void
-release_cq (cqr_t * cqr)
-{
-       spin_lock (&cqr_lock);
-       cqf_enq (cqr);
-       spin_unlock (&cqr_lock);
-       return;
-}
-
-/* ---------------------------------------------------------- */
-
-static erp_t *erpp = NULL;
-#ifdef __SMP__
-static spinlock_t erp_lock = SPIN_LOCK_UNLOCKED;
-#endif                         /* __SMP__ */
-
-void
-erf_enq (erp_t * cqf)
-{
-       *(erp_t **) cqf = erpp;
-       erpp = cqf;
-}
-
-erp_t *
-erf_deq (void)
-{
-       erp_t *erp = erpp;
-       erpp = *(erp_t **) erpp;
-       return erp;
-}
-
-erp_t *
-request_er (void)
-{
-       erp_t *erp = NULL;
-       int i;
-       erp_t *area;
-
-       spin_lock (&erp_lock);
-       while (erpp == NULL) {
-               do {
-                       area = (erp_t *) get_free_page (GFP_ATOMIC);
-                       if (area == NULL) {
-                               printk (KERN_WARNING PRINTK_HEADER
-                                       "No memory for chanq area\n");
-                       }
-               } while (!area);
-               memset (area, 0, PAGE_SIZE);
-               if (dasd_page_count + 1 >= MAX_DASD_PAGES) {
-                       PRINT_WARN ("Requesting too many pages...");
-               } else {
-                       dasd_page[dasd_page_count++] =
-                           (long) area;
-               }
-               for (i = 0; i < 4096 / sizeof (erp_t); i++) {
-                       erf_enq (area + i);
-               }
-       }
-       erp = erf_deq ();
-       spin_unlock (&erp_lock);
-       return erp;
-}
-
-void
-release_er (erp_t * erp)
-{
-       spin_lock (&erp_lock);
-       erf_enq (erp);
-       spin_unlock (&erp_lock);
-       return;
-}
-
-/* ----------------------------------------------------------- */
-cqr_t *
-request_cqr (int cpsize, int datasize)
-{
-       cqr_t *cqr = NULL;
-       cqr = request_cq ();
-       if (cqr == NULL) {
-               printk (KERN_WARNING PRINTK_HEADER __FILE__
-                       "No memory for chanq request\n");
-               goto exit;
-       }
-       memset (cqr, 0, sizeof (cqr_t));
-       cqr -> magic = DASD_MAGIC;
-       if (cpsize) {
-               cqr->cpaddr = request_cp (cpsize);
-               if (cqr->cpaddr == NULL) {
-                       printk (KERN_WARNING PRINTK_HEADER __FILE__
-                               "No memory for channel program\n");
-                       goto nocp;
-               }
-               cqr->cplength = cpsize;
-       }
-       if (datasize) {
-               do {
-                       cqr->data = (char *) kmalloc (datasize, GFP_ATOMIC);
-                       if (cqr->data == NULL) {
-                               printk (KERN_WARNING PRINTK_HEADER __FILE__
-                                       "No memory for cqr data area\n");
-                       }
-               } while (!cqr->data);
-               memset (cqr->data,0,datasize);
-       }
-       goto exit;
-      nocp:
-       release_cq (cqr);
-       cqr = NULL;
-      exit:
-       return cqr;
-}
-
-int
-release_cqr (cqr_t * cqr)
-{
-       int rc = 0;
-       if (cqr == NULL) {
-               rc = -ENOENT;
-               return rc;
-       }
-       if (cqr->data) {
-               kfree (cqr->data);
-       }
-       if (cqr->dstat) {
-               kfree (cqr->dstat);
-       }
-       if (cqr->cpaddr) {
-               release_cp (cqr->cplength, cqr->cpaddr);
-       }
-       cqr -> magic = dasd_MAGIC;
-       release_cq (cqr);
-       return rc;
-}
-
-/* ----------------------------------------------------------- */
-erp_t *
-allloc_erp (erp_t * erp, int cpsize, int datasize)
-{
-       if (cpsize) {
-               erp->cqr.cpaddr = request_cp (cpsize);
-               if (erp->cqr.cpaddr == NULL) {
-                       printk (KERN_WARNING PRINTK_HEADER __FILE__
-                               "No memory for channel program\n");
-                       goto nocp;
-               }
-               erp->cqr.cplength = cpsize;
-       }
-       if (datasize) {
-               do {
-                       erp->cqr.data = (char *) kmalloc (datasize, GFP_ATOMIC);
-                       if (erp->cqr.data == NULL) {
-                               printk (KERN_WARNING PRINTK_HEADER __FILE__
-                                       "No memory for ERP data area\n");
-                       }
-               } while (!erp->cqr.data);
-               memset (erp->cqr.data, 0, datasize);
-       }
-       goto exit;
-      nocp:
-       release_er (erp);
-       erp = NULL;
-      exit:
-       return erp;
-}
-
-int
-release_erp (erp_t * erp)
-{
-       int rc = 0;
-       if (erp == NULL) {
-               rc = -ENOENT;
-               return rc;
-       }
-       if (erp->cqr.data) {
-               kfree (erp->cqr.data);
-       }
-       if (erp->cqr.dstat) {
-               kfree (erp->cqr.dstat);
-       }
-       if (erp->cqr.cpaddr) {
-               release_cp (erp->cqr.cplength, erp->cqr.cpaddr);
-       }
-       erp->cqr.magic = dasd_MAGIC;
-       release_er (erp);
-       return rc;
-}
-
-/* -------------------------------------------------------------- */
-void
-dasd_chanq_enq (dasd_chanq_t * q, cqr_t * cqr)
-{
-       if (q->head != NULL) {
-               q->tail->next = cqr;
-       } else
-               q->head = cqr;
-       cqr->next = NULL;
-       q->tail = cqr;
-       q->queued_requests ++;
-       ACS (cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
-       }
-
-void
-dasd_chanq_enq_head (dasd_chanq_t * q, cqr_t * cqr)
-{
-       cqr->next = q->head;
-       q->head = cqr;
-       if (q->tail == NULL)
-               q->tail = cqr;
-       q->queued_requests++;
-       ACS (cqr->status, CQR_STATUS_FILLED, CQR_STATUS_QUEUED);
-}
-
-int
-dasd_chanq_deq (dasd_chanq_t * q, cqr_t * cqr)
-{
-       cqr_t *prev;
-
-       if (cqr == NULL)
-               return -ENOENT;
-       if (cqr == (cqr_t *) q->head) {
-               q->head = cqr->next;
-               if (q->head == NULL)
-                       q->tail = NULL;
-       } else {
-               prev = (cqr_t *) q->head; 
-               while (prev && prev->next != cqr)
-                       prev = prev->next;
-               if (prev == NULL)
-                       return -ENOENT;
-               prev->next = cqr->next;
-               if (prev->next == NULL)
-                       q->tail = prev;
-       }
-       cqr->next = NULL;
-       q->queued_requests --;
-       if (cqr->magic == ERP_MAGIC)
-               return release_erp ((erp_t *) cqr);
-       else
-       return release_cqr(cqr);
-}
-
-/* -------------------------------------------------------------------------- */
-void
-cql_enq_head (dasd_chanq_t * q)
-{
-       if (q == NULL) {
-               INTERNAL_ERROR ("NULL queue passed%s\n", "");
-               return;
-       }
-       if (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE) {
-               PRINT_WARN("Queue already active");
-               return;
-       }
-       spin_lock(&cq_lock);
-       atomic_set_mask(DASD_CHANQ_ACTIVE,&q->flags);
-       q->next_q = cq_head;
-       cq_head = q;
-       spin_unlock(&cq_lock);
-}
-
-void
-cql_deq (dasd_chanq_t * q)
-{
-       dasd_chanq_t *c;
-
-        if (cq_head == NULL) {
-                INTERNAL_ERROR ("Channel queue is empty%s\n", "");
-               return;
-       }
-       if (q == NULL) {
-               INTERNAL_ERROR ("NULL queue passed%s\n", "");
-               return;
-       }
-       spin_lock(&cq_lock);
-       if (! (atomic_read(&q->flags) & DASD_CHANQ_ACTIVE)) {
-               PRINT_WARN("Queue not active\n");
-       } else if (cq_head == q) {
-               cq_head = q->next_q;
-       } else {
-               c = cq_head;
-               while (c->next_q && c->next_q != q)
-                       c = c->next_q;
-               if (c->next_q != q)
-                       INTERNAL_ERROR ("Entry not in queue%s\n", "");
-               else
-                       c->next_q = q->next_q;
-       }
-       q->next_q = NULL;
-       atomic_clear_mask(DASD_CHANQ_ACTIVE,&q->flags);
-       spin_unlock(&cq_lock);
-}
diff --git a/drivers/s390/block/dasd_ccwstuff.h b/drivers/s390/block/dasd_ccwstuff.h
deleted file mode 100644 (file)
index 79a6807..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-extern atomic_t chanq_tasks;
-extern dasd_chanq_t *cq_head;
-
-cqr_t *request_cqr (int, int);
-int release_cqr (cqr_t *);
-erp_t *request_er (void);
-int release_er (erp_t *);
-int dasd_chanq_enq (dasd_chanq_t *, cqr_t *);
-int dasd_chanq_deq (dasd_chanq_t *, cqr_t *);
-void cql_enq_head (dasd_chanq_t * q);
-void cql_deq (dasd_chanq_t * q);
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
new file mode 100644 (file)
index 0000000..91a0448
--- /dev/null
@@ -0,0 +1,555 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_diag.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Based on.......: linux/drivers/s390/block/mdisk.c
+ * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <asm/debug.h>
+
+#include <linux/malloc.h>
+#include <linux/hdreg.h>       /* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
+
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "dasd.h"
+#include "dasd_diag.h"
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif                         /* PRINTK_HEADER */
+#define PRINTK_HEADER DASD_NAME"(diag):"
+
+dasd_discipline_t dasd_diag_discipline;
+
+
+
+typedef struct
+dasd_diag_private_t {
+        dasd_diag_characteristics_t rdc_data;
+       diag_rw_io_t iob;
+       diag_init_io_t iib;
+       unsigned long *label;
+} dasd_diag_private_t;
+
+static __inline__ int
+dia210 (void *devchar)
+{
+       int rc;
+
+       __asm__ __volatile__ ("    lr    2,%1\n"
+                              "    .long 0x83200210\n"
+                              "0:  ipm   %0\n"
+                              "    srl   %0,28"
+                              :"=d" (rc)
+                              :"d" ((void *) __pa (devchar))
+                              :"2");
+       return rc;
+}
+
+static __inline__ int
+dia250 (void *iob, int cmd)
+{
+       int rc;
+
+       __asm__ __volatile__ ("    lr    2,%1\n"
+                              "    lr    3,%2\n"
+                              "    .long 0x83230250\n"
+                              "    lr    %0,3"
+                              :"=d" (rc)
+                              :"d" ((void *) __pa (iob)), "d" (cmd)
+                              :"2", "3");
+       return rc;
+}
+
+static __inline__ int
+mdsk_init_io (dasd_device_t *device, int blocksize, int offset, int size)
+{
+        dasd_diag_private_t *private = (dasd_diag_private_t *)device->private;
+       diag_init_io_t *iib = &private->iib;
+       int rc;
+
+       memset (iib, 0, sizeof (diag_init_io_t));
+
+       iib->dev_nr = device->devinfo.devno;
+       iib->block_size = blocksize;
+       iib->offset = offset;
+       iib->start_block = 0;
+       iib->end_block = size;
+
+       rc = dia250 (iib, INIT_BIO);
+
+       return rc;
+}
+
+static __inline__ int
+mdsk_term_io (dasd_device_t *device)
+{
+        dasd_diag_private_t *private = (dasd_diag_private_t *)device->private;
+       diag_init_io_t *iib = &private->iib;
+       int rc;
+       
+       memset (iib, 0, sizeof (diag_init_io_t));
+       iib->dev_nr = device->devinfo.devno;
+       rc = dia250 (iib, TERM_BIO);
+       return rc;
+}
+
+int
+dasd_start_diag (ccw_req_t * cqr)
+{
+       int rc;
+       dasd_device_t *device = cqr->device;
+        dasd_diag_private_t *private;
+       diag_rw_io_t *iob;
+
+        private = (dasd_diag_private_t *)device->private;
+       iob = &private->iob;
+
+       iob->dev_nr = device->devinfo.devno;
+       iob->key = 0;
+       iob->flags = 2;
+       iob->block_count = cqr->cplength >> 1;
+       iob->interrupt_params = (u32) cqr;
+       iob->bio_list = __pa (cqr->cpaddr);
+
+       asm volatile ("STCK %0":"=m" (cqr->startclk));
+       rc = dia250 (iob, RW_BIO);
+       if (rc > 8) {
+               PRINT_WARN ("dia250 returned CC %d\n", rc);
+               atomic_compare_and_swap_debug(&cqr->status, 
+                                              CQR_STATUS_QUEUED, 
+                                              CQR_STATUS_ERROR);
+       } else {
+               if ( cqr->expires ) {
+                       cqr->expires += cqr->startclk;
+               }
+               atomic_compare_and_swap_debug(&cqr->status, 
+                                              CQR_STATUS_QUEUED, 
+                                              CQR_STATUS_IN_IO);
+                rc = 0;
+       }
+       return rc;
+}
+
+void 
+dasd_ext_handler (struct pt_regs *regs, __u16 code)
+{
+       ccw_req_t *cqr;
+       int ip = S390_lowcore.ext_params;
+       char status = *((char *) S390_lowcore.ext_params + 5);
+        dasd_device_t *device;
+       int done_fast_io = 0;
+        int devno,devindex;
+
+       if (!ip) {              /* no intparm: unsolicited interrupt */
+               printk ( KERN_WARNING PRINTK_HEADER
+                        "caught unsolicited interrupt\n");
+               return;
+       }
+       if (ip & 0x80000001) {
+               printk ( KERN_WARNING PRINTK_HEADER
+                        "caught spurious interrupt with parm %08x\n",
+                        ip);
+               return;
+       }
+       cqr = (ccw_req_t *) ip;
+       device = (dasd_device_t *) cqr->device;
+       devno = device->devinfo.devno;
+       devindex = devindex_from_devno (devno);
+       if (device == NULL) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       " INT on devno 0x%04X  = /dev/%s (%d:%d)"
+                       " belongs to NULL device\n",
+                       devno, device->name, major_from_devindex (devindex), devindex << DASD_PARTN_BITS);
+       }
+       if (strncmp (device->discipline->ebcname, (char *) &cqr->magic, 4)) {
+               printk (KERN_WARNING PRINTK_HEADER
+                       "0x%04X : /dev/%s (%d:%d)"
+                       " magic number of ccw_req_t 0x%08lX doesn't match"
+                       " discipline 0x%08X\n",
+                       devno, device->name,
+                       major_from_devindex (devindex),
+                       devindex << DASD_PARTN_BITS,
+                       cqr->magic, *(int *) (&device->discipline->name));
+               return;
+       }
+       asm volatile ("STCK %0":"=m" (cqr->stopclk));
+       switch (status) {
+       case 0x00:
+               atomic_compare_and_swap_debug (&cqr->status, 
+                                              CQR_STATUS_IN_IO, 
+                                              CQR_STATUS_DONE);
+               atomic_compare_and_swap (DASD_DEVICE_LEVEL_ANALYSIS_PENDING,
+                                        DASD_DEVICE_LEVEL_ANALYSIS_PREPARED,
+                                        &device->level);
+               if (cqr->next &&
+                   (atomic_read (&cqr->next->status) ==
+                    CQR_STATUS_QUEUED)) {
+                       if (dasd_start_diag (cqr->next) == 0) {
+                               done_fast_io = 1;
+                       }
+               }
+
+               break;
+       case 0x01:
+       case 0x02:
+       case 0x03:
+       default:
+               atomic_compare_and_swap_debug (&cqr->status, 
+                                              CQR_STATUS_IN_IO, 
+                                              CQR_STATUS_FAILED);
+               atomic_inc (&device->queue.dirty_requests);
+               break;
+       }
+       if (done_fast_io == 0)
+               atomic_clear_mask (DASD_CHANQ_BUSY, &device->queue.flags);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wake_up (&device->wait_q);
+#else
+       if (device->wait_q) {
+               wake_up (&device->wait_q);
+       }
+#endif /* LINUX_VERSION_CODE */
+       dasd_schedule_bh ();
+}
+
+static int
+dasd_diag_check_characteristics (struct dasd_device_t *device)
+{
+       int rc = 0;
+       int bsize;
+       int label_block;
+        dasd_diag_private_t *private;
+       dasd_diag_characteristics_t *rdc_data;
+        ccw_req_t *cqr;
+       long *label;
+        int sb;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+               device->private = kmalloc(sizeof(dasd_diag_private_t),GFP_KERNEL);
+               if ( device->private == NULL ) {
+                       printk ( KERN_WARNING PRINTK_HEADER
+                                "memory allocation failed for private data\n");
+                       return -ENOMEM;
+               }
+        }
+        private = (dasd_diag_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+       
+       rdc_data->dev_nr = device->devinfo.devno;
+       rdc_data->rdc_len = sizeof (dasd_diag_characteristics_t);
+       
+       if (dia210 (rdc_data) != 0) {
+         return -ENODEV;
+       }
+       if (rdc_data->vdev_class != DEV_CLASS_FBA &&
+           rdc_data->vdev_class != DEV_CLASS_ECKD &&
+           rdc_data->vdev_class != DEV_CLASS_CKD) {
+               return -ENODEV;
+       }
+#if 0
+       printk ( KERN_INFO PRINTK_HEADER 
+                "%04X: %04X on real %04X/%02X\n",
+                rdc_data->dev_nr,
+                rdc_data->vdev_type,
+                rdc_data->rdev_type,rdc_data->rdev_model);
+#endif
+       /* Figure out position of label block */
+       if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
+               label_block = 1;
+       } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
+                  private->rdc_data.vdev_class == DEV_CLASS_CKD) {
+               label_block = 2;
+       } else {
+               return -ENODEV;
+       }
+       private->label = (long *) get_free_page (GFP_KERNEL);
+        label = private->label;        
+       mdsk_term_io (device); /* first terminate all outstanding operations */
+       /* figure out blocksize of device */
+       for (bsize = 512; bsize <= PAGE_SIZE; bsize <<= 1) {
+                diag_bio_t *bio;
+                diag_rw_io_t *iob = &private ->iob;
+        
+                rc = mdsk_init_io (device, bsize, 0, 64);
+                if (rc > 4) {
+                        continue;
+               }
+                cqr = ccw_alloc_request (dasd_diag_discipline.name, 2,0);
+                if ( cqr == NULL ) {
+                        printk ( KERN_WARNING PRINTK_HEADER
+                                 "No memory to allocate initialization request\n");
+                        return -ENOMEM;
+                }
+                bio = (diag_bio_t *) (cqr->cpaddr);
+                memset (bio, 0, sizeof (diag_bio_t));
+                bio->type = MDSK_READ_REQ;
+                bio->block_number = label_block + 1;
+                bio->buffer = __pa (private->label);
+                cqr->device = device;
+                atomic_set (&cqr->status, CQR_STATUS_FILLED);
+                memset (iob, 0, sizeof(diag_rw_io_t));
+                iob->dev_nr      = rdc_data->dev_nr;
+                iob->key         = 0;
+                iob->flags       = 0;
+                iob->block_count = 1;
+                iob->interrupt_params = cqr;
+                iob->bio_list     = virt_to_phys(bio);
+                rc = dia250(iob,RW_BIO);
+                if ( rc == 0 ) {
+                        if (label[3] != bsize) {
+/*                                printk ( KERN_INFO PRINTK_HEADER 
+                                         "%04X mismatching blocksizes disk %d, reserved file %d\n", 
+                                         device->devinfo.devno, bsize, label[3]);
+*/  
+                              return -EINVAL; 
+                        }
+                        if (label[0] != 0xc3d4e2f1) {  /* CMS1 */
+/*                                PRINT_WARN ("volume %04X is not CMS formatted, accessing anyway\n", 
+                                            device->devinfo.devno);
+*/
+                                return -ENODEV;
+                        }
+                        if (label[13] == 0) {
+/*                                PRINT_WARN ("%04X is not reserved, accessing anyway\n",  
+                                  device->devinfo.devno); */
+                                return -ENODEV;
+                        }
+                        
+                        break;
+                }
+               mdsk_term_io (device);
+       }
+       device->sizes.bp_block = bsize;
+        device->sizes.s2b_shift = 0;   /* bits to shift 512 to get a block */
+       for (sb = 512; sb < bsize; sb = sb << 1)
+               device->sizes.s2b_shift++;
+
+       return rc;
+}
+
+
+static int
+dasd_diag_do_analysis (struct dasd_device_t *device)
+{
+       int sb;
+        dasd_diag_private_t *private = (dasd_diag_private_t *)device->private;
+
+       long *label = private->label;
+       
+       /* real size of the volume */
+        device->sizes.blocks = label[7];
+       
+        printk ( KERN_INFO PRINTK_HEADER 
+                 "/dev/%s (%04X): capacity (%dkB blks): %dkB\n",
+                 device->name, device->devinfo.devno,
+                 (device->sizes.bp_block>>10),
+                (device->sizes.blocks<<device->sizes.s2b_shift)>>1);
+       return 0;
+}
+
+
+static int
+dasd_diag_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
+{
+        int rc = 0;
+        dasd_diag_private_t *private = (dasd_diag_private_t *)device->private;
+       unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
+       unsigned long tracks = sectors >> 6;
+       unsigned long trk_rem = sectors & ((1<<6)-1); /* 64k per track */
+       unsigned long cyls = tracks >> 4;
+       unsigned long cyls_rem = tracks & ((1<<4)-1); /* 16 head per cyl */
+       
+        switch(device->sizes.bp_block) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+       geo->cylinders = cyls;
+       geo->heads = 16;
+       geo->sectors = 128 >> device->sizes.s2b_shift;
+       if (private->rdc_data.vdev_class == DEV_CLASS_FBA) {
+               geo->start = 1;
+       } else if (private->rdc_data.vdev_class == DEV_CLASS_ECKD ||
+                  private->rdc_data.vdev_class == DEV_CLASS_CKD) {
+               geo->start = 2;
+       } else {
+               return -EINVAL;
+       }
+        return rc;
+}
+
+static dasd_era_t
+dasd_diag_examine_error  (ccw_req_t *cqr, devstat_t * stat)
+{
+       return dasd_era_fatal;
+}
+
+static dasd_erp_action_fn_t 
+dasd_diag_erp_action ( ccw_req_t * cqr ) 
+{
+        return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_diag_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+       return NULL;
+}
+
+static ccw_req_t *
+dasd_diag_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+       ccw_req_t *rw_cp = NULL;
+       struct buffer_head *bh;
+       int rw_cmd;
+       int noblk = req->nr_sectors >> device->sizes.s2b_shift;
+       int byt_per_blk = device->sizes.bp_block;
+       int block;
+       diag_bio_t *bio;
+       int bhct;
+       long size;
+
+       if (!noblk) {
+               PRINT_ERR ("No blocks to read/write...returning\n");
+               return NULL;
+       }
+       if (req->cmd == READ) {
+               rw_cmd = MDSK_READ_REQ;
+       } else
+       if (req->cmd == WRITE)
+       {
+               rw_cmd = MDSK_WRITE_REQ;
+       }
+       bhct = 0;
+       for (bh = req->bh; bh; bh = bh->b_reqnext) {
+               if (bh->b_size > byt_per_blk)
+                       for (size = 0; size < bh->b_size; size += byt_per_blk)
+                               bhct++;
+               else
+                       bhct++;
+       }
+       /* Build the request */
+        rw_cp = dasd_alloc_request (dasd_diag_discipline.name, 2 * bhct, 0);
+       if (!rw_cp) {
+               return NULL;
+       }
+       bio = (diag_bio_t *) (rw_cp->cpaddr);
+       
+       block = req->sector >> device->sizes.s2b_shift;
+       for (bh = req->bh; bh; bh = bh->b_reqnext) {
+               if (bh->b_size >= byt_per_blk) {
+                       memset (bio, 0, sizeof (diag_bio_t));
+                       for (size = 0; size < bh->b_size; size += byt_per_blk) {
+                               bio->type = rw_cmd;
+                               bio->block_number = block + 1;
+                               bio->buffer = __pa (bh->b_data + size);
+                               bio++;
+                               block++;
+                       }
+               } else {
+                       PRINT_WARN ("Cannot fulfill request smaller than block\n");
+                       ccw_free_request (rw_cp);
+                       return NULL;
+               }
+       }
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
+       return rw_cp;
+}
+
+static char *
+dasd_diag_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
+{
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        int len;
+        if ( page == NULL ) {
+                return NULL;
+        }
+
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+                        
+
+        return page;
+}
+
+dasd_discipline_t dasd_diag_discipline = {
+       name :                          "DIAG",
+       ebcname :                       "DIAG",
+        check_characteristics:          dasd_diag_check_characteristics,
+        do_analysis:                    dasd_diag_do_analysis,          
+        fill_geometry:                  dasd_diag_fill_geometry,
+        start_IO:                       dasd_start_diag,           
+        examine_error:                  dasd_diag_examine_error,          
+        erp_action:                     dasd_diag_erp_action,             
+        erp_postaction:                 dasd_diag_erp_postaction,         
+        build_cp_from_req:              dasd_diag_build_cp_from_req,      
+        dump_sense:                     dasd_diag_dump_sense,            
+        int_handler:                    dasd_ext_handler            
+};
+
+int
+dasd_diag_init( void ) {
+        int rc = 0;
+        if ( MACHINE_IS_VM ) {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "%s discipline initializing\n", dasd_diag_discipline.name);
+          ASCEBC(dasd_diag_discipline.ebcname,4);
+          ctl_set_bit (0, 9);
+          register_external_interrupt (0x2603, dasd_ext_handler);
+          dasd_discipline_enq(&dasd_diag_discipline);
+        } else {
+          printk ( KERN_INFO PRINTK_HEADER
+                   "Machine is not VM: %s discipline not initializing\n", dasd_diag_discipline.name);
+          rc = -EINVAL;
+        }
+        return rc;
+}
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
new file mode 100644 (file)
index 0000000..d64a98c
--- /dev/null
@@ -0,0 +1,67 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_diag.h
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Based on.......: linux/drivers/s390/block/mdisk.h
+ * ...............: by Hartmunt Penner <hpenner@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
+
+#define MDSK_WRITE_REQ 0x01
+#define MDSK_READ_REQ  0x02
+
+#define INIT_BIO        0x00
+#define RW_BIO          0x01
+#define TERM_BIO        0x02
+
+#define DEV_CLASS_FBA   0x01
+#define DEV_CLASS_ECKD  0x04
+#define DEV_CLASS_CKD   0x04   
+
+typedef struct dasd_diag_characteristics_t {
+       u16 dev_nr;
+       u16 rdc_len;
+       u8 vdev_class;
+       u8 vdev_type;
+       u8 vdev_status;
+       u8 vdev_flags;
+       u8 rdev_class;
+       u8 rdev_type;
+       u8 rdev_model;
+       u8 rdev_features;
+} __attribute__ ((packed, aligned (4))) dasd_diag_characteristics_t;
+
+typedef struct diag_bio_t {
+       u8 type;
+       u8 status;
+       u16 spare1;
+       u32 block_number;
+       u32 alet;
+       u32 buffer;
+} __attribute__ ((packed, aligned (8))) diag_bio_t;
+
+typedef struct diag_init_io_t{
+       u16 dev_nr;
+       u16 spare1[11];
+       u32 block_size;
+       u32 offset;
+       u32 start_block;
+       u32 end_block;
+       u32 spare2[6];
+} __attribute__ ((packed, aligned (8))) diag_init_io_t;
+
+
+typedef struct diag_rw_io_t{
+       u16 dev_nr;
+       u16 spare1[11];
+       u8 key;
+       u8 flags;
+       u16 spare2;
+       u32 block_count;
+       u32 alet;
+       u32 bio_list;
+       u32 interrupt_params;
+       u32 spare3[5];
+} __attribute__ ((packed, aligned (8))) diag_rw_io_t;
+
+int dasd_diag_init(void);
index 7238b24af79dd6bae307acdfe68c94d866cb6697..3e18eba06cb2e09f70bc4e02f4edbac29f54c815 100644 (file)
@@ -3,26 +3,33 @@
  * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
  * Bugreports.to..: <Linux390@de.ibm.com>
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+
+ * History of changes (starts July 2000)
+ * 07/11/00 Enabled rotational position sensing
  */
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
+#include <asm/debug.h>
 
 #include <linux/malloc.h>
-#include <linux/dasd.h>
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#include <asm/ebcdic.h>
 #include <asm/io.h>
-
 #include <asm/irq.h>
 
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
+#include "dasd.h"
+#include "dasd_eckd.h"
+
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(eckd):"
+#define PRINTK_HEADER DASD_NAME"(eckd):"
 
 #define ECKD_C0(i) (i->home_bytes)
 #define ECKD_F(i) (i -> formula)
 #define ECKD_F7(i) (i -> factor7)
 #define ECKD_F8(i) (i -> factor8)
 
-#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
-
-#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
+#define DASD_ECKD_CCW_WRITE 0x05
+#define DASD_ECKD_CCW_READ 0x06
 #define DASD_ECKD_CCW_WRITE_HOME_ADDRESS 0x09
-
-#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
-#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
-
+#define DASD_ECKD_CCW_READ_HOME_ADDRESS 0x0a
 #define DASD_ECKD_CCW_READ_COUNT 0x12
-#define DASD_ECKD_CCW_READ 0x06
-#define DASD_ECKD_CCW_READ_MT 0x86
-#define DASD_ECKD_CCW_WRITE 0x05
-#define DASD_ECKD_CCW_WRITE_MT 0x85
+#define DASD_ECKD_CCW_WRITE_RECORD_ZERO 0x15
+#define DASD_ECKD_CCW_READ_RECORD_ZERO 0x16
+#define DASD_ECKD_CCW_WRITE_CKD 0x1d
 #define DASD_ECKD_CCW_READ_CKD 0x1e
+#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
+#define DASD_ECKD_CCW_WRITE_MT 0x85
+#define DASD_ECKD_CCW_READ_MT 0x86
 #define DASD_ECKD_CCW_READ_CKD_MT 0x9e
-#define DASD_ECKD_CCW_WRITE_CKD 0x1d
 #define DASD_ECKD_CCW_WRITE_CKD_MT 0x9d
 
-typedef
-struct {
-       __u16 cyl;
-       __u16 head;
-} __attribute__ ((packed))
-
-ch_t;
-
-typedef
-struct {
-       __u16 cyl;
-       __u16 head;
-       __u32 sector;
-} __attribute__ ((packed))
-
-chs_t;
-
-typedef
-struct {
-       __u16 cyl;
-       __u16 head;
-       __u8 record;
-} __attribute__ ((packed))
-
-chr_t;
-
-typedef
-struct {
-       __u16 cyl;
-       __u16 head;
-       __u32 sector;
-} geom_t;
-
-typedef struct {
-       struct {
-               struct {
-                       unsigned char identifier:2;
-                       unsigned char token_id:1;
-                       unsigned char sno_valid:1;
-                       unsigned char subst_sno:1;
-                       unsigned char recNED:1;
-                       unsigned char emuNED:1;
-                       unsigned char reserved:1;
-               } __attribute__ ((packed)) flags;
-               __u8 descriptor;
-               __u8 dev_class;
-               __u8 reserved;
-               unsigned char dev_type[6];
-               unsigned char dev_model[3];
-               unsigned char HDA_manufacturer[3];
-               unsigned char HDA_location[2];
-               unsigned char HDA_seqno[12];
-               __u16 ID;
-       } __attribute__ ((packed)) ned1;
-       struct {
-               struct {
-                       unsigned char identifier:2;
-                       unsigned char token_id:1;
-                       unsigned char sno_valid:1;
-                       unsigned char subst_sno:1;
-                       unsigned char recNED:1;
-                       unsigned char emuNED:1;
-                       unsigned char reserved:1;
-               } __attribute__ ((packed)) flags;
-               __u8 descriptor;
-               __u8 reserved[2];
-               unsigned char dev_type[6];
-               unsigned char dev_model[3];
-               unsigned char DASD_manufacturer[3];
-               unsigned char DASD_location[2];
-               unsigned char DASD_seqno[12];
-               __u16 ID;
-       } __attribute__ ((packed)) ned2;
-       struct {
-               struct {
-                       unsigned char identifier:2;
-                       unsigned char token_id:1;
-                       unsigned char sno_valid:1;
-                       unsigned char subst_sno:1;
-                       unsigned char recNED:1;
-                       unsigned char emuNED:1;
-                       unsigned char reserved:1;
-               } __attribute__ ((packed)) flags;
-               __u8 descriptor;
-               __u8 reserved[2];
-               unsigned char cont_type[6];
-               unsigned char cont_model[3];
-               unsigned char cont_manufacturer[3];
-               unsigned char cont_location[2];
-               unsigned char cont_seqno[12];
-               __u16 ID;
-       } __attribute__ ((packed)) ned3;
-       struct {
-               struct {
-                       unsigned char identifier:2;
-                       unsigned char token_id:1;
-                       unsigned char sno_valid:1;
-                       unsigned char subst_sno:1;
-                       unsigned char recNED:1;
-                       unsigned char emuNED:1;
-                       unsigned char reserved:1;
-               } __attribute__ ((packed)) flags;
-               __u8 descriptor;
-               __u8 reserved[2];
-               unsigned char cont_type[6];
-               unsigned char empty[3];
-               unsigned char cont_manufacturer[3];
-               unsigned char cont_location[2];
-               unsigned char cont_seqno[12];
-               __u16 ID;
-       } __attribute__ ((packed)) ned4;
-       unsigned char ned5[32];
-       unsigned char ned6[32];
-       unsigned char ned7[32];
-       struct {
-               struct {
-                       unsigned char identifier:2;
-                       unsigned char reserved:6;
-               } __attribute__ ((packed)) flags;
-               __u8 selector;
-               __u16 interfaceID;
-               __u32 reserved;
-               __u16 subsystemID;
-               struct {
-                       unsigned char sp0:1;
-                       unsigned char sp1:1;
-                       unsigned char reserved:5;
-                       unsigned char scluster:1;
-               } __attribute__ ((packed)) spathID;
-               __u8 unit_address;
-               __u8 dev_ID;
-               __u8 dev_address;
-               __u8 adapterID;
-               __u16 link_address;
-               struct {
-                       unsigned char parallel:1;
-                       unsigned char escon:1;
-                       unsigned char reserved:1;
-                       unsigned char ficon:1;
-                       unsigned char reserved2:4;
-               } __attribute__ ((packed)) protocol_type;
-               struct {
-                       unsigned char PID_in_236:1;
-                       unsigned char reserved:7;
-               } __attribute__ ((packed)) format_flags;
-               __u8 log_dev_address;
-               unsigned char reserved2[12];
-       } __attribute__ ((packed)) neq;
-
-} __attribute__ ((packed))
-
-eckd_confdata_t;
-
-typedef
-struct {
-       struct {
-               unsigned char perm:2;   /* Permissions on this extent */
-               unsigned char reserved:1;
-               unsigned char seek:2;   /* Seek control */
-               unsigned char auth:2;   /* Access authorization */
-               unsigned char pci:1;    /* PCI Fetch mode */
-       } __attribute__ ((packed)) mask;
-       struct {
-               unsigned char mode:2;   /* Architecture mode */
-               unsigned char ckd:1;    /* CKD Conversion */
-               unsigned char operation:3;      /* Operation mode */
-               unsigned char cfw:1;    /* Cache fast write */
-               unsigned char dfw:1;    /* DASD fast write */
-       } __attribute__ ((packed)) attributes;
-       __u16 short blk_size;   /* Blocksize */
-       __u16 fast_write_id;
-       __u8 unused;
-       __u8 reserved;
-       ch_t beg_ext;
-       ch_t end_ext;
-} __attribute__ ((packed, aligned (32)))
-
-DE_eckd_data_t;
-
-typedef
-struct {
-       struct {
-               unsigned char orientation:2;
-               unsigned char operation:6;
-       } __attribute__ ((packed)) operation;
-       struct {
-               unsigned char last_bytes_used:1;
-               unsigned char reserved:6;
-               unsigned char read_count_suffix:1;
-       } __attribute__ ((packed)) auxiliary;
-       __u8 unused;
-       __u8 count;
-       ch_t seek_addr;
-       chr_t search_arg;
-       __u8 sector;
-       __u16 length;
-} __attribute__ ((packed, aligned (32)))
-
-LO_eckd_data_t;
-
-/* Stuff for handling home addresses */
-typedef struct {
-       __u8 skip_control[14];
-       __u16 cell_number;
-       __u8 physical_addr[3];
-       __u8 flag;
-       ch_t track_addr;
-       __u8 reserved;
-       __u8 key_length;
-       __u8 reserved2[2];
-} __attribute__ ((packed, aligned (32)))
-
-eckd_home_t;
-
-dasd_era_t dasd_eckd_erp_examine (cqr_t *, devstat_t *);
-
-static unsigned int
+dasd_discipline_t dasd_eckd_discipline;
+
+typedef struct
+dasd_eckd_private_t {
+        dasd_eckd_characteristics_t rdc_data;
+        dasd_eckd_confdata_t conf_data;
+        eckd_count_t count_area;
+} dasd_eckd_private_t;
+
+static inline unsigned int
 round_up_multiple (unsigned int no, unsigned int mult)
 {
        int rem = no % mult;
        return (rem ? no - rem + mult : no);
-/*      return (no % mult ? no - (no % mult) + mult : no); */
 }
 
-static unsigned int
+static inline unsigned int
 ceil_quot (unsigned int d1, unsigned int d2)
 {
        return (d1 + (d2 - 1)) / d2;
 }
 
-static int
+static inline int
 bytes_per_record (dasd_eckd_characteristics_t * rdc,
                  int kl,       /* key length */
                  int dl /* data length */ )
@@ -330,7 +127,7 @@ bytes_per_track (dasd_eckd_characteristics_t * rdc)
        return *(unsigned int *) (rdc->byte_per_track) >> 8;
 }
 
-static unsigned int
+static inline unsigned int
 recs_per_track (dasd_eckd_characteristics_t * rdc,
                unsigned int kl, unsigned int dl)
 {
@@ -368,26 +165,26 @@ recs_per_track (dasd_eckd_characteristics_t * rdc,
        return rpt;
 }
 
-static
-void
+static inline void
 define_extent (ccw1_t * de_ccw,
               DE_eckd_data_t * data,
               int trk,
               int totrk,
               int cmd,
-              dasd_information_t * info)
+              dasd_device_t *device)
 {
        ch_t geo, beg, end;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
 
-       geo.cyl = info->rdc_data->eckd.no_cyl;
-       geo.head = info->rdc_data->eckd.trk_per_cyl;
+       geo.cyl = private->rdc_data.no_cyl;
+       geo.head = private->rdc_data.trk_per_cyl;
        beg.cyl = trk / geo.head;
        beg.head = trk % geo.head;
        end.cyl = totrk / geo.head;
        end.head = totrk % geo.head;
 
        memset (de_ccw, 0, sizeof (ccw1_t));
-       de_ccw->cmd_code = CCW_DEFINE_EXTENT;
+       de_ccw->cmd_code = DASD_ECKD_CCW_DEFINE_EXTENT;
        de_ccw->count = 16;
        de_ccw->cda = (void *) __pa (data);
 
@@ -436,14 +233,15 @@ locate_record (ccw1_t * lo_ccw,
               int rec_on_trk,
               int no_rec,
               int cmd,
-              dasd_information_t * info)
+              dasd_device_t * device)
 {
-       ch_t geo =
-       {info->rdc_data->eckd.no_cyl,
-        info->rdc_data->eckd.trk_per_cyl};
-       ch_t seek =
-       {trk / (geo.head), trk % (geo.head)};
-       int reclen = info->sizes.bp_block;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+       ch_t geo = {private->rdc_data.no_cyl,
+                    private->rdc_data.trk_per_cyl};
+       ch_t seek ={trk / (geo.head), trk % (geo.head)};
+       int reclen = device->sizes.bp_block;
+        int sector;
+
        memset (lo_ccw, 0, sizeof (ccw1_t));
        lo_ccw->cmd_code = DASD_ECKD_CCW_LOCATE_RECORD;
        lo_ccw->count = 16;
@@ -499,100 +297,310 @@ locate_record (ccw1_t * lo_ccw,
        default:
                INTERNAL_ERROR ("unknown opcode 0x%x\n", cmd);
        }
+        switch ( private -> rdc_data.dev_type == 0x3390 ) {
+        case 0x3390: {
+                int dn,d;
+                dn = ceil_quot(reclen + 6,232);
+                d = 9 + ceil_quot(reclen + 6 * (dn + 1),34);
+                sector = (49 + (rec_on_trk - 1) * ( 10 + d ))/8;
+                break;
+        }
+        case 0x3380: {
+                int d;
+                d = 7 + ceil_quot(reclen + 12, 32);
+                sector = (39 + (rec_on_trk - 1) * ( 8 + d ))/7;
+                break;
+        }
+        case 0x9345:
+        default:
+                sector = 0;
+        }
+        data -> sector = sector;
        memcpy (&(data->seek_addr), &seek, sizeof (ch_t));
        memcpy (&(data->search_arg), &seek, sizeof (ch_t));
        data->search_arg.record = rec_on_trk;
        data->count += no_rec;
 }
 
-void
-dasd_eckd_print_error (devstat_t * stat)
+static int 
+dasd_eckd_id_check ( dev_info_t *info )
 {
-       int sct, sl;
-       char *sense = stat->ii.sense.data;
-       PRINT_WARN ("IRQ on devno %x: with intparm:%x DS:0x%02x CS:0x%02x\n",
-                   stat->devno, stat->intparm, stat->dstat, stat->cstat);
-       PRINT_WARN ("Failing CCW: %p\n", (ccw1_t *) stat->cpa);
-       for (sl = 0; sl < 4; sl++) {
-               PRINT_DEBUG ("Sense:");
-               for (sct = 0; sct < 8; sct++) {
-                       printk (" %2d:0x%02x",
-                               8 * sl + sct, sense[8 * sl + sct]);
+        if ( info->sid_data.cu_type == 0x3990 )
+                if ( info->sid_data.dev_type == 0x3390 )
+                        return 0;
+        if ( info->sid_data.cu_type == 0x3990 )
+                if ( info->sid_data.dev_type == 0x3380 )
+                        return 0;
+        if ( info->sid_data.cu_type == 0x9343 )
+                if ( info->sid_data.dev_type == 0x9345 )
+                        return 0;
+        return -ENODEV;
                }
-               printk ("\n");
+
+static int
+dasd_eckd_check_characteristics (struct dasd_device_t *device)
+{
+        int rc = -ENODEV;
+        void *conf_data;
+        void *rdc_data;
+        int conf_len;
+        dasd_eckd_private_t *private;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+          device->private = kmalloc(sizeof(dasd_eckd_private_t),GFP_KERNEL);
+          if ( device->private == NULL ) {
+            printk ( KERN_WARNING PRINTK_HEADER
+                     "memory allocation failed for private data\n");
+            return -ENOMEM;
+          }
+        }
+        private = (dasd_eckd_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+        rc = read_dev_chars (device->devinfo.irq, &rdc_data , 64);
+        if ( rc ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read device characteristics returned error %d\n",rc);
+                return rc;
        }
-       if (sense[27] & 0x80) { /* 32 Byte Sense Data */
-               PRINT_INFO ("Sense Data is 32 Byte information\n");
-               PRINT_INFO ("Format: %x Exception class %x\n",
-                           sense[6] & 0x0f, sense[22] >> 4);
-       } else {                /* 24 Byte Sense Data */
-               PRINT_INFO ("Sense Data is 24 Byte information\n");
-               PRINT_INFO ("FMT: %x MSG %x, %s MSGb to SYSOP\n",
-                           sense[7] >> 4, sense[7] & 0x0f,
-                           sense[1] & 0x10 ? "" : "no");
+       printk ( KERN_INFO PRINTK_HEADER 
+                 "%04X on sch %d: %04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d\n",
+                 device->devinfo.devno, device->devinfo.irq,
+                 private->rdc_data.dev_type, private->rdc_data.dev_model,
+                 private->rdc_data.cu_type, private->rdc_data.cu_model.model,
+                 private->rdc_data.no_cyl, private->rdc_data.trk_per_cyl,
+                 private->rdc_data.sec_per_trk);
+        rc = read_conf_data(device->devinfo.irq, &conf_data, &conf_len, LPM_ANYPATH );
+        if ( rc ) {
+                if ( rc == -EOPNOTSUPP )
+                        return 0;
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read configuration data returned error %d\n",rc);
+                return rc;
        }
+        if ( conf_len != sizeof(dasd_eckd_confdata_t)) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "sizes of configuration data mismatch %d (read) vs %ld (expected)\n",
+                         conf_len, sizeof(dasd_eckd_confdata_t));
+                return rc;
+        }
+        if ( conf_data == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "No configuration data retrieved\n");
+                return -ENOMEM;
+        }
+        memcpy (&private->conf_data,conf_data,sizeof(dasd_eckd_confdata_t));
+       printk ( KERN_INFO PRINTK_HEADER 
+                 "%04X on sch %d: %04X/%02X (CU: %04X/%02X): Configuration data read\n",
+                 device->devinfo.devno, device->devinfo.irq,
+                 private->rdc_data.dev_type, private->rdc_data.dev_model,
+                 private->rdc_data.cu_type, private->rdc_data.cu_model.model);
+        device->sizes.bp_block = 4096;
+        device->sizes.s2b_shift = 3;
+        device->sizes.blocks = ( private->rdc_data.no_cyl * 
+                                 private->rdc_data.trk_per_cyl *
+                                 recs_per_track (&private->rdc_data, 
+                                                 0, device->sizes.bp_block));
+        return 0;
 }
 
-int
-dasd_eckd_format_track (int di, int trk, int bs)
+static ccw_req_t *
+dasd_eckd_init_analysis (struct dasd_device_t *device)
 {
-       int rc = 0;
-       int i;
-       int flags = 0x00;       /* FORMAT_R0 = 0x01, FORMAT_HA = 0x03 */
-        dasd_information_t * info=dasd_info[di];
-       cqr_t *fcp;
+       ccw_req_t *cqr = NULL;
+       ccw1_t *ccw;
        DE_eckd_data_t *DE_data;
        LO_eckd_data_t *LO_data;
-       eckd_count_t *ct_data;
-       eckd_count_t *r0_data;
-       ccw1_t *last_ccw;
-        int retries = 5;
-
-       int rpt = recs_per_track (&(info->rdc_data->eckd), 0, bs);
-       int cyl = trk / info->rdc_data->eckd.trk_per_cyl;
-       int head = trk % info->rdc_data->eckd.trk_per_cyl;
-
-       fcp = request_cqr (2 + 1 + rpt,
-                          sizeof (DE_eckd_data_t) +
-                          sizeof (LO_eckd_data_t) +
-                          (rpt + 1) * sizeof (eckd_count_t));
-        fcp -> devindex=di;
-       DE_data = (DE_eckd_data_t *) fcp->data;
-       LO_data = (LO_eckd_data_t *) (((long) DE_data) +
-                                     sizeof (DE_eckd_data_t));
-       r0_data = (eckd_count_t *) (((long) LO_data) +
-                                   sizeof (LO_eckd_data_t));
-       ct_data = (eckd_count_t *) (((long) r0_data) +
-                                   sizeof (eckd_count_t));
+       eckd_count_t *count_data = &(((dasd_eckd_private_t *)(device->private))->count_area);
+
+        cqr = ccw_alloc_request (dasd_eckd_discipline.name, 3, sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t));
+        if ( cqr == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "No memory to allocate initialization request\n");
+                return NULL;
+        }
+       DE_data = cqr->data;
+       LO_data = cqr->data + sizeof (DE_eckd_data_t);
+       ccw = cqr->cpaddr;
+       define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, device);
+       ccw->flags = CCW_FLAG_CC;
+       ccw++;
+       locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, device);
+       ccw->flags = CCW_FLAG_CC;
+       ccw++;
+       ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
+       ccw->count = 8;
+       ccw->cda = (void *) __pa (count_data);
+       cqr->device = device;
+       atomic_set (&cqr->status, CQR_STATUS_FILLED);
+        
+        return cqr;
+}
+
+static int
+dasd_eckd_do_analysis (struct dasd_device_t *device)
+{
+        int rc = 0;
+       int sb, rpt;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+       int bs = private->count_area.dl;
+
+        memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
+        switch ( bs ) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+               device->sizes.bp_block = bs;
+                break;
+        default:
+                printk ( KERN_INFO PRINTK_HEADER 
+                         "/dev/%s (%04X): invalid blocksize %d\n"
+                         KERN_INFO PRINTK_HEADER 
+                         "/dev/%s (%04X): capacity (at 4kB blks): %dkB at %dkB/trk\n",
+                         device->name, device->devinfo.devno,bs,
+                         device->name, device->devinfo.devno,
+                         ( private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
+                          recs_per_track (&private->rdc_data, 0, 4096)),
+                        recs_per_track (&private->rdc_data, 0, 4096));
+               return -EMEDIUMTYPE;
+       }
+       device->sizes.s2b_shift = 0;    /* bits to shift 512 to get a block */
+       for (sb = 512; sb < bs; sb = sb << 1)
+               device->sizes.s2b_shift++;
+        
+       rpt = recs_per_track (&private->rdc_data, 0, device->sizes.bp_block);
+        device->sizes.blocks = ( private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
+                                 recs_per_track (&private->rdc_data, 0, device->sizes.bp_block));
+                
+        printk ( KERN_INFO PRINTK_HEADER 
+                 "/dev/%s (%04X): capacity (%dkB blks): %dkB at %dkB/trk\n",
+                 device->name, device->devinfo.devno,
+                 (device->sizes.bp_block>>10),
+                 ( private->rdc_data.no_cyl * private->rdc_data.trk_per_cyl *
+                   recs_per_track (&private->rdc_data, 0, device->sizes.bp_block)*
+                   (device->sizes.bp_block>>9))>>1,
+                 ( recs_per_track (&private->rdc_data, 0, device->sizes.bp_block)*device->sizes.bp_block) >> 10);
+       return 0;
+        
+        return rc;
+}
+
+static int
+dasd_eckd_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
+{
+        int rc = 0;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+        switch(device->sizes.bp_block) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+       geo->cylinders = private->rdc_data.no_cyl;
+       geo->heads = private->rdc_data.trk_per_cyl;
+       geo->sectors = recs_per_track (&(private->rdc_data), 0, device->sizes.bp_block);
+       geo->start = 2;
+        return rc;
+}
+
+static inline int
+dasd_eckd_format_track (dasd_device_t *device, int trk, int bs, int flags)
+{
+       int rc = 0;
+       int i;
+       ccw_req_t *fcp = NULL;
+       DE_eckd_data_t *DE_data = NULL;
+       LO_eckd_data_t *LO_data = NULL;
+       eckd_count_t *ct_data = NULL;
+       eckd_count_t *r0_data = NULL;
+        eckd_home_t *ha_data = NULL;
+       ccw1_t *last_ccw = NULL;
+        void * last_data = NULL;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+       int retries;
+
+       int rpt = recs_per_track (&(private->rdc_data), 0, bs);
+       int cyl = trk / private->rdc_data.trk_per_cyl;
+       int head = trk % private->rdc_data.trk_per_cyl;
+        int wrccws = rpt;
+        int datasize = sizeof (DE_eckd_data_t) + sizeof (LO_eckd_data_t);
+        
+        switch ( flags ) {
+        case 0x00:
+        case 0x01:
+        case 0x03:
+          break;
+        default:
+          return -EINVAL;
+        }
+        
+        if ( flags & 0x1 ) {
+          wrccws++;
+          datasize += sizeof(eckd_count_t);
+        }
+        if ( flags & 0x2 ) {
+          wrccws++;
+          datasize += sizeof(eckd_home_t);
+        }
+       fcp = ccw_alloc_request (dasd_eckd_discipline.name, 
+                                 wrccws + 2,
+                                 datasize+rpt*sizeof(eckd_count_t));
+       fcp->device = device;
+
+        last_data = fcp->data;
+       DE_data = (DE_eckd_data_t *) last_data;
+        last_data = (void*)(DE_data +1);
+       LO_data = (LO_eckd_data_t *) last_data;
+        last_data = (void*)(LO_data +1);
+        if ( flags & 0x2 ) {
+          ha_data = (eckd_home_t *) last_data;
+          last_data = (void*)(ha_data +1);
+        }
+        if ( flags & 0x1 ) {
+          r0_data = (eckd_count_t *) last_data;
+          last_data = (void*)(r0_data +1);
+        }
+       ct_data = (eckd_count_t *)last_data;
+
        last_ccw = fcp->cpaddr;
+
        switch (flags) {
        case 0x03:
                define_extent (last_ccw, DE_data, trk, trk,
-                              DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+                               DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
-               locate_record (last_ccw, LO_data, trk, 0, rpt,
-                              DASD_ECKD_CCW_WRITE_HOME_ADDRESS, info);
+               locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                              DASD_ECKD_CCW_WRITE_HOME_ADDRESS, device);
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
                break;
        case 0x01:
                define_extent (last_ccw, DE_data, trk, trk,
-                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
-               locate_record (last_ccw, LO_data, trk, 0, rpt,
-                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, info);
+               locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                              DASD_ECKD_CCW_WRITE_RECORD_ZERO, device);
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
+               memset (r0_data, 0, sizeof (eckd_count_t));
                break;
        case 0x00:
                define_extent (last_ccw, DE_data, trk, trk,
-                              DASD_ECKD_CCW_WRITE_CKD, info);
+                              DASD_ECKD_CCW_WRITE_CKD, device);
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
-               locate_record (last_ccw, LO_data, trk, 0, rpt,
-                              DASD_ECKD_CCW_WRITE_CKD, info);
+               locate_record (last_ccw, LO_data, trk, 0, wrccws,
+                              DASD_ECKD_CCW_WRITE_CKD, device);
                 LO_data->length = bs;
                last_ccw->flags = CCW_FLAG_CC;
                last_ccw++;
@@ -606,7 +614,6 @@ dasd_eckd_format_track (int di, int trk, int bs)
                return -EINVAL;
        }
        if (flags & 0x01) {     /* write record zero */
-               memset (r0_data, 0, sizeof (eckd_count_t));
                r0_data->cyl = cyl;
                r0_data->head = head;
                r0_data->record = 0;
@@ -632,89 +639,204 @@ dasd_eckd_format_track (int di, int trk, int bs)
                last_ccw->cda = (void *) __pa (ct_data + i);
        }
        (last_ccw - 1)->flags &= ~(CCW_FLAG_CC | CCW_FLAG_DC);
-        fcp -> devindex = di;
-        fcp -> flags = DASD_DO_IO_SLEEP;
+       fcp->device = device;
         do {
-               struct wait_queue wait =
-               {current, NULL};
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+                DECLARE_WAITQUEUE (wait,current);
+#else
+                struct wait_queue wait = {current, NULL};
+#endif /* LINUX_VERSION_CODE */
                 unsigned long flags;
-                int irq;
                 int cs;
 
-                irq = dasd_info[fcp->devindex]->info.irq;
-                s390irq_spin_lock_irqsave (irq, flags);
+                retries = 1;
+               s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
                 atomic_set(&fcp->status,CQR_STATUS_QUEUED);
-                rc = dasd_start_IO ( fcp );
-                add_wait_queue (&dasd_waitq, &wait);
                 do {
-                        current->state = TASK_UNINTERRUPTIBLE;
-                        s390irq_spin_unlock_irqrestore (irq, flags);
+                        rc = dasd_eckd_discipline.start_IO (fcp);
+                } while ( rc && retries-- );
+                if ( rc && retries == 0 )
+                        break;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+               add_wait_queue (&device->wait_q, &wait);
+#endif /* LINUX_VERSION_CODE */
+               do {
+                       current->state = TASK_INTERRUPTIBLE;
+                       s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
                         schedule ();
-                        s390irq_spin_lock_irqsave (irq, flags);
-                } while (((cs = atomic_read (&fcp->status)) !=
-                          CQR_STATUS_DONE) &&
-                         (cs != CQR_STATUS_ERROR));
-                remove_wait_queue (&dasd_waitq, &wait);
-               s390irq_spin_unlock_irqrestore (irq, flags);
-
-                retries --;
+                       s390irq_spin_lock_irqsave (device->devinfo.irq, flags);
+                        cs = atomic_read (&fcp->status);
+               } while ((cs != CQR_STATUS_DONE) && (cs != CQR_STATUS_ERROR));
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+               remove_wait_queue (&device->wait_q, &wait);
+#endif /* LINUX_VERSION_CODE */
+               s390irq_spin_unlock_irqrestore (device->devinfo.irq, flags);
        } while ( (rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)) &&
-                  retries);
-        if ((rc || (atomic_read(&fcp->status) != CQR_STATUS_DONE)))
+                 retries--);
+       if ( retries == 0 )
                 rc = -EIO;
-       release_cqr (fcp);
+       ccw_free_request (fcp);
        return rc;
 }
 
-int
-dasd_eckd_ck_devinfo (dev_info_t * info)
+static int
+dasd_eckd_format_device (struct dasd_device_t *device, struct format_data_t *fdata)
 {
-       return 0;
+        int rc = 0;
+       int i;
+       format_data_t fd;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+        int last_track =private->rdc_data.no_cyl*private->rdc_data.trk_per_cyl-1;
+        int intensity;
+        kdev_t kdev = device->kdev;
+        int nr_tracks, blocksize;
+
+       if (fdata==NULL) {
+               fd.start_unit = 0;
+               fd.stop_unit = last_track;
+               fd.blksize = 4096;
+       } else {
+               memcpy (&fd, fdata, sizeof (format_data_t));
+               if (fd.stop_unit == -1) {
+                       fd.stop_unit = last_track;
+               }
+               if (fd.blksize == 0) {
+                       fd.blksize = 4096;
+               }
+       }
+       if (fd.start_unit > fd.stop_unit) {
+               return -EINVAL;
+       }
+       if (fd.start_unit > last_track ) {
+               return -EINVAL;
+       }
+       if (fd.stop_unit > last_track ) {
+               return -EINVAL;
+       }
+        switch(fd.blksize) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+        fd.intensity = 0x0;
+        intensity = fd.intensity;
+        set_blocksize(kdev, fd.blksize);
+       printk (KERN_INFO PRINTK_HEADER
+                "Formatting device %04X from track %d to %d with bs %d\n",
+                device->devinfo.devno,fd.start_unit, fd.stop_unit, fd.blksize);
+        nr_tracks = fd.stop_unit-fd.start_unit+1;
+       for (i = 0; i <= nr_tracks; i++) {
+               /* print 20 messages per format cmd at all */
+                if ( i % (nr_tracks / 20) == 0 ) { 
+                        printk (KERN_INFO PRINTK_HEADER
+                                "Format %04X Cylinder: %d Track %d Intensity %d\n", 
+                                device->devinfo.devno,
+                                (i+fd.start_unit) / private->rdc_data.trk_per_cyl,
+                                (i+fd.start_unit) % private->rdc_data.trk_per_cyl,
+                                intensity);
+                }
+                do {
+                        if ( i == 0 ) {
+                                blocksize = 8;
+                        } else {
+                                blocksize = fd.blksize;
+                        }
+                        rc = dasd_eckd_format_track (device, 
+                                                     (i % nr_tracks) + fd.start_unit , 
+                                                     blocksize, intensity);
+                                /* fix VM controlled minidisk */
+                        if ( rc ) {
+                                if ( intensity ) {
+                                        intensity = intensity >> 1;
+                                }
+                                printk (KERN_WARNING PRINTK_HEADER
+                                        "decreasing format intensity to %d\n", 
+                                        intensity);
+                        }
+                } while ( rc && intensity > 0);
+                if (rc) {
+                        printk (KERN_WARNING PRINTK_HEADER
+                                "Formatting of device %04X Cylinder %d Track %d failed...exiting\n",
+                                device->devinfo.devno,
+                                i / private->rdc_data.trk_per_cyl,
+                                i % private->rdc_data.trk_per_cyl);
+                        break;
+               }
+       }
+       printk ( KERN_INFO PRINTK_HEADER
+                 "Formatting of device %04X completed from track %d to %d with bs %d\n",
+                 device->devinfo.devno, fd.start_unit, fd.stop_unit, fd.blksize);
+        return rc;
 }
 
-cqr_t *
-dasd_eckd_build_req (int devindex,
-                    struct request * req)
+static dasd_era_t
+dasd_eckd_examine_error  (ccw_req_t *cqr, devstat_t * stat)
 {
-       cqr_t *rw_cp = NULL;
-       ccw1_t *ccw;
+        dasd_device_t *device = (dasd_device_t *)cqr->device;
+        if (stat->cstat == 0x00 &&
+           stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+               return dasd_era_none;
+        
+       switch (device->devinfo.sid_data.cu_model) {
+       case 0x3990:
+               return dasd_3990_erp_examine (cqr, stat);
+       case 0x9343:
+               return dasd_9343_erp_examine (cqr, stat);
+       default:
+               return dasd_era_recover;
+       }
+}
 
-       DE_eckd_data_t *DE_data;
-       LO_eckd_data_t *LO_data;
-       struct buffer_head *bh;
+static dasd_erp_action_fn_t 
+dasd_eckd_erp_action ( ccw_req_t * cqr ) 
+{
+        return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_eckd_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+       return NULL;
+}
+
+static ccw_req_t *
+dasd_eckd_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+        ccw_req_t *rw_cp = NULL;
        int rw_cmd;
-       dasd_information_t *info = dasd_info[devindex];
-       int blk_per_trk = recs_per_track (&(info->rdc_data->eckd),
-                                         0, info->sizes.bp_block);
-       int byt_per_blk = info->sizes.bp_block;
-       int btrk = (req->sector >> info->sizes.s2b_shift) / blk_per_trk;
-       int etrk = ((req->sector + req->nr_sectors - 1) >>
-                   info->sizes.s2b_shift) / blk_per_trk;
        int bhct;
        long size;
+        ccw1_t *ccw;
+       DE_eckd_data_t *DE_data;
+       LO_eckd_data_t *LO_data;
+       struct buffer_head *bh;
+        dasd_eckd_private_t *private = (dasd_eckd_private_t *)device->private;
+       int byt_per_blk = device->sizes.bp_block;
+        int shift = device->sizes.s2b_shift;
+       int blk_per_trk = recs_per_track (&(private->rdc_data), 0, byt_per_blk);
+       int btrk = (req->sector >> shift) / blk_per_trk;
+       int etrk = ((req->sector + req->nr_sectors - 1) >> shift) / blk_per_trk;
 
        if (req->cmd == READ) {
                rw_cmd = DASD_ECKD_CCW_READ_MT;
-       } else
-#if DASD_PARANOIA > 2
-       if (req->cmd == WRITE)
-#endif                         /* DASD_PARANOIA */
-       {
+       } else if (req->cmd == WRITE) {
                rw_cmd = DASD_ECKD_CCW_WRITE_MT;
-       }
-#if DASD_PARANOIA > 2
-       else {
+       } else {
                PRINT_ERR ("Unknown command %d\n", req->cmd);
                return NULL;
        }
-#endif                         /* DASD_PARANOIA */
        /* Build the request */
-#if 0
-       PRINT_INFO ("req %d %d %d %d\n", devindex, req->cmd, req->sector, req->nr_sectors);
-#endif
        /* count bhs to prevent errors, when bh smaller than block */
        bhct = 0;
-
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
                if (bh->b_size > byt_per_blk)
                        for (size = 0; size < bh->b_size; size += byt_per_blk)
@@ -723,7 +845,8 @@ dasd_eckd_build_req (int devindex,
                        bhct++;
        }
 
-       rw_cp = request_cqr (2 + bhct,
+       rw_cp = dasd_alloc_request (dasd_eckd_discipline.name,
+                                   2 + bhct,
                             sizeof (DE_eckd_data_t) +
                             sizeof (LO_eckd_data_t));
         if ( ! rw_cp ) {
@@ -733,14 +856,11 @@ dasd_eckd_build_req (int devindex,
        LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
        ccw = rw_cp->cpaddr;
 
-       define_extent (ccw, DE_data, btrk, etrk, rw_cmd, info);
+       define_extent (ccw, DE_data, btrk, etrk, rw_cmd, device);
        ccw->flags = CCW_FLAG_CC;
        ccw++;
-       locate_record (ccw, LO_data, btrk,
-                      (req->sector >> info->sizes.s2b_shift) %
-                      blk_per_trk + 1,
-                      req->nr_sectors >> info->sizes.s2b_shift,
-                      rw_cmd, info);
+       locate_record (ccw, LO_data, btrk, (req->sector >> shift) % blk_per_trk + 1,
+                      req->nr_sectors >> shift, rw_cmd, device);
        ccw->flags = CCW_FLAG_CC;
        for (bh = req->bh; bh != NULL;) {
                if (bh->b_size > byt_per_blk) {
@@ -764,203 +884,94 @@ dasd_eckd_build_req (int devindex,
        }
                        if (size != byt_per_blk) {
                                PRINT_WARN ("Cannot fulfill small request %d vs. %d (%d sects)\n", size, byt_per_blk, req->nr_sectors);
-                               release_cqr (rw_cp);
+                               ccw_free_request (rw_cp);
                return NULL;
        }
                        ccw->flags = CCW_FLAG_CC;
                }
        }
        ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
        return rw_cp;
 }
 
-void
-dasd_eckd_print_char (dasd_characteristics_t * i)
+static char *
+dasd_eckd_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-        dasd_eckd_characteristics_t * c = 
-                (dasd_eckd_characteristics_t *)i;
-       PRINT_INFO ("%x/%x (%x/%x) Cyl: %d Head: %d Sec: %d \n",
-                   c->dev_type, c->dev_model,
-                   c->cu_type, c->cu_model.model,
-                   c->no_cyl, c->trk_per_cyl,
-                   c->sec_per_trk);
-       PRINT_INFO ("Estimate: %d Byte/trk %d byte/kByte %d kByte/trk \n",
-                   bytes_per_track (c),
-                   bytes_per_record (c, 0, 1024),
-                   recs_per_track (c, 0, 1024));
-};
-
-int
-dasd_eckd_ck_char (dasd_characteristics_t * i)
-{
-       int rc = 0;
-       dasd_eckd_print_char (i);
-       return rc;
-}
-
-int
-dasd_eckd_format (int devindex, format_data_t * fdata)
-{
-       int rc = 0;
-       int i;
-       dasd_information_t *info = dasd_info[devindex];
-       format_data_t fd;
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        devstat_t *stat = &device->dev_status;
+       char *sense = stat->ii.sense.data;
+        int len,sl,sct;
 
-       if (!fdata) {
-               fd.start_unit = 0;
-               fd.stop_unit = info->rdc_data->eckd.no_cyl *
-                        info->rdc_data->eckd.trk_per_cyl - 1;
-               fd.blksize = 4096;
-       } else {
-               memcpy (&fd, fdata, sizeof (format_data_t));
-               if ( fd.stop_unit == -1 ) {
-                        fd.stop_unit = info->rdc_data->eckd.no_cyl *
-                                info->rdc_data->eckd.trk_per_cyl - 1;
-               }
-                if ( fd.blksize == 0 ) {
-                        fd.blksize = 4096;
-                }
-       }
-        PRINT_INFO("Formatting device %d from %d to %d with bs %d\n",
-                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
-        if ( fd.start_unit > fd.stop_unit ) {
-                PRINT_WARN ("start unit .gt. stop unit\n");
-                return -EINVAL;
+        if ( page == NULL ) {
+                return NULL;
         }
-        if ( (fd.start_unit > info->rdc_data->eckd.no_cyl *
-              info->rdc_data->eckd.trk_per_cyl - 1) ) {
-                PRINT_WARN ("start unit beyond end of disk\n");
-                return -EINVAL;
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                         "in req: %p CS: 0x%02X DS: 0x%02X\n",
+                         req,stat->cstat,stat->dstat);
+        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                         "Failing CCW: %p\n", (void *)stat->cpa);
+        if ( stat->flag & DEVSTAT_FLAG_SENSE_AVAIL ) {
+                for (sl = 0; sl < 4; sl++) {
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "Sense:");
+                        for (sct = 0; sct < 8; sct++) {
+                                len += sprintf ( page + len," %2d:0x%02x",
+                                                 8 * sl + sct, sense[8 * sl + sct]);
         }
-        if ( (fd.stop_unit > info->rdc_data->eckd.no_cyl *
-              info->rdc_data->eckd.trk_per_cyl - 1) ) {
-                PRINT_WARN ("stop unit beyond end of disk\n");
-                return -EINVAL;
-        }
-        switch (fd.blksize) {
-        case 512:
-        case 1024:
-        case 2048:
-        case 4096:
-                break;
-        default:
-                PRINT_WARN ("invalid blocksize\n");
-                return -EINVAL;
-        }
-       for (i = fd.start_unit; i <= fd.stop_unit; i++) {
-                /* print 20 messages per disk at all */
-                if ( ! ( i % (info->rdc_data->eckd.trk_per_cyl  *
-                                (info->rdc_data->eckd.no_cyl / 20 ) )))  {
-                        PRINT_INFO ("Format %d Cylinder: %d\n",devindex,
-                                    i/info->rdc_data->eckd.trk_per_cyl);
+                        len += sprintf ( page + len,"\n");
                 }
-               rc = dasd_eckd_format_track (devindex, i, fd.blksize);
-               if (rc) {
-                       PRINT_WARN ("Formatting of Track %d failed...exiting\n", i);
-                       break;
+                if (sense[27] & 0x80) {        
+                        /* 24 Byte Sense Data */
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "24 Byte: %x MSG %x, %s MSGb to SYSOP\n",
+                                         sense[7] >> 4, sense[7] & 0x0f,
+                                         sense[1] & 0x10 ? "" : "no");
+                } else {               
+                        /* 32 Byte Sense Data */
+                        len += sprintf ( page + len, KERN_WARNING PRINTK_HEADER 
+                                         "32 Byte: Format: %x Exception class %x\n",
+                                         sense[6] & 0x0f, sense[22] >> 4);
                }
        }
-        PRINT_INFO("Formated device %d from %d to %d with bs %d\n",
-                   devindex,fd.start_unit,fd.stop_unit,fd.blksize);
-       return rc;
+        return page;
 }
 
-cqr_t *
-dasd_eckd_fill_sizes_first (int di)
-{
-       cqr_t *rw_cp = NULL;
-       ccw1_t *ccw;
-       DE_eckd_data_t *DE_data;
-       LO_eckd_data_t *LO_data;
-       dasd_information_t *info = dasd_info[di];
-       eckd_count_t *count_data = &(info->private.eckd.count_data);
-
-       dasd_info[di]->sizes.label_block = 2;
-
-       rw_cp = request_cqr (3,
-                            sizeof (DE_eckd_data_t) +
-                            sizeof (LO_eckd_data_t));
-       DE_data = rw_cp->data;
-       LO_data = rw_cp->data + sizeof (DE_eckd_data_t);
-       ccw = rw_cp->cpaddr;
-       define_extent (ccw, DE_data, 0, 0, DASD_ECKD_CCW_READ_COUNT, info);
-       ccw->flags = CCW_FLAG_CC;
-       ccw++;
-       locate_record (ccw, LO_data, 0, 1, 1, DASD_ECKD_CCW_READ_COUNT, info);
-       ccw->flags = CCW_FLAG_CC;
-       ccw++;
-       ccw->cmd_code = DASD_ECKD_CCW_READ_COUNT;
-       ccw->count = 8;
-       ccw->cda = (void *) __pa (count_data);
-       rw_cp->devindex = di;
-       atomic_set (&rw_cp->status, CQR_STATUS_FILLED);
-       return rw_cp;
-}
+dasd_discipline_t dasd_eckd_discipline = {
+       name :                          "ECKD",
+       ebcname :                       "ECKD",
+        id_check:                       dasd_eckd_id_check,          
+        check_characteristics:          dasd_eckd_check_characteristics,
+        init_analysis:                  dasd_eckd_init_analysis,
+        do_analysis:                    dasd_eckd_do_analysis,          
+        fill_geometry:                  dasd_eckd_fill_geometry,
+        start_IO:                       dasd_start_IO,           
+        format_device:                  dasd_eckd_format_device,          
+        examine_error:                  dasd_eckd_examine_error,          
+        erp_action:                     dasd_eckd_erp_action,             
+        erp_postaction:                 dasd_eckd_erp_postaction,         
+        build_cp_from_req:              dasd_eckd_build_cp_from_req,      
+        dump_sense:                     dasd_eckd_dump_sense,            
+        int_handler:                    dasd_int_handler            
+};
 
 int
-dasd_eckd_fill_sizes_last (int devindex)
-{
-       int sb,rpt;
-       dasd_information_t *in = dasd_info[devindex];
-       int bs = in->private.eckd.count_data.dl;
-       if (bs <= 0) {
-                PRINT_INFO("Cannot figure out blocksize. did you format the disk?\n");
-                memset (&(in -> sizes), 0, sizeof(dasd_sizes_t ));
-                return -EMEDIUMTYPE;
-       } else {
-               in->sizes.bp_block = bs;
-       }
-       in->sizes.bp_sector = in->sizes.bp_block;
-        
-       if (bs & 511) {
-               PRINT_INFO ("Probably no Linux formatted device!\n");
-               return -EMEDIUMTYPE;
-       }
-       in->sizes.s2b_shift = 0; /* bits to shift 512 to get a block */
-       for (sb = 512; sb < bs; sb = sb << 1)
-                in->sizes.s2b_shift++;
-        
-       in->sizes.blocks = in->rdc_data->eckd.no_cyl *
-                in->rdc_data->eckd.trk_per_cyl *
-                recs_per_track (&(in->rdc_data->eckd), 0, bs);
-
-        in->sizes.kbytes = ( in->sizes.blocks << in->sizes.s2b_shift) >> 1;
-
-        rpt = recs_per_track (&(in->rdc_data->eckd), 0, in->sizes.bp_block),
+dasd_eckd_init( void ) {
+        int rc = 0;
+        printk ( KERN_INFO PRINTK_HEADER
+                 "%s discipline initializing\n", dasd_eckd_discipline.name);
+        ASCEBC(dasd_eckd_discipline.ebcname,4);
+        dasd_discipline_enq(&dasd_eckd_discipline);
         
-       PRINT_INFO ("Verified: %d B/trk %d B/Blk(%d B) %d Blks/trk %d kB/trk \n",
-                   bytes_per_track (&(in->rdc_data->eckd)),
-                    bytes_per_record (&(in->rdc_data->eckd), 0, 
-                                      in->sizes.bp_block),
-                    in->sizes.bp_block,
-                    rpt,
-                    (rpt << in->sizes.s2b_shift) >> 1);
-                    return 0;
-}
-
-void
-dasd_eckd_fill_geometry (int di, struct hd_geometry *geo)
-{
-       dasd_information_t *info = dasd_info[di];
-       geo->cylinders = info->rdc_data->eckd.no_cyl;
-       geo->heads = info->rdc_data->eckd.trk_per_cyl;
-       geo->sectors = recs_per_track (&(info->rdc_data->eckd),
-                                      0, info->sizes.bp_block);
-       geo->start = info->sizes.label_block + 1;
+        return rc;
 }
 
-dasd_operations_t dasd_eckd_operations =
-{
-       ck_devinfo:dasd_eckd_ck_devinfo,
-       get_req_ccw:dasd_eckd_build_req,
-       ck_characteristics:dasd_eckd_ck_char,
-       fill_sizes_first:dasd_eckd_fill_sizes_first,
-       fill_sizes_last:dasd_eckd_fill_sizes_last,
-       dasd_format:dasd_eckd_format,
-       fill_geometry:dasd_eckd_fill_geometry,
-       erp_examine:dasd_eckd_erp_examine
-};
-
 /*
  * Overrides for Emacs so that we follow Linus's tabbing style.
  * Emacs will notice this stuff at the end of the file and automatically
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
new file mode 100644 (file)
index 0000000..fd713ef
--- /dev/null
@@ -0,0 +1,286 @@
+#ifndef DASD_ECKD_H
+#define DASD_ECKD_H
+
+typedef 
+struct eckd_count_t {
+       __u16 cyl;
+       __u16 head;
+       __u8 record;
+       __u8 kl;
+       __u16 dl;
+} __attribute__ ((packed)) eckd_count_t;
+
+typedef
+struct ch_t {
+       __u16 cyl;
+       __u16 head;
+} __attribute__ ((packed)) ch_t;
+
+typedef
+struct chs_t {
+       __u16 cyl;
+       __u16 head;
+       __u32 sector;
+} __attribute__ ((packed)) chs_t;
+
+typedef
+struct chr_t {
+       __u16 cyl;
+       __u16 head;
+       __u8 record;
+} __attribute__ ((packed)) chr_t;
+
+typedef
+struct geom_t {
+       __u16 cyl;
+       __u16 head;
+       __u32 sector;
+} __attribute__ ((packed)) geom_t;
+
+typedef struct eckd_home_t {
+       __u8 skip_control[14];
+       __u16 cell_number;
+       __u8 physical_addr[3];
+       __u8 flag;
+       ch_t track_addr;
+       __u8 reserved;
+       __u8 key_length;
+       __u8 reserved2[2];
+} __attribute__ ((packed)) eckd_home_t;
+
+typedef
+struct DE_eckd_data_t {
+       struct {
+               unsigned char perm:2;   /* Permissions on this extent */
+               unsigned char reserved:1;
+               unsigned char seek:2;   /* Seek control */
+               unsigned char auth:2;   /* Access authorization */
+               unsigned char pci:1;    /* PCI Fetch mode */
+       } __attribute__ ((packed)) mask;
+       struct {
+               unsigned char mode:2;   /* Architecture mode */
+               unsigned char ckd:1;    /* CKD Conversion */
+               unsigned char operation:3;      /* Operation mode */
+               unsigned char cfw:1;    /* Cache fast write */
+               unsigned char dfw:1;    /* DASD fast write */
+       } __attribute__ ((packed)) attributes;
+       __u16 short blk_size;   /* Blocksize */
+       __u16 fast_write_id;
+       __u8 unused;
+       __u8 reserved;
+       ch_t beg_ext;
+       ch_t end_ext;
+} __attribute__ ((packed)) DE_eckd_data_t;
+
+typedef
+struct LO_eckd_data_t {
+       struct {
+               unsigned char orientation:2;
+               unsigned char operation:6;
+       } __attribute__ ((packed)) operation;
+       struct {
+               unsigned char last_bytes_used:1;
+               unsigned char reserved:6;
+               unsigned char read_count_suffix:1;
+       } __attribute__ ((packed)) auxiliary;
+       __u8 unused;
+       __u8 count;
+       ch_t seek_addr;
+       chr_t search_arg;
+       __u8 sector;
+       __u16 length;
+} __attribute__ ((packed)) LO_eckd_data_t;
+
+typedef
+struct dasd_eckd_characteristics_t {
+       __u16 cu_type;
+       struct {
+               unsigned char support:2;
+               unsigned char async:1;
+               unsigned char reserved:1;
+               unsigned char cache_info:1;
+               unsigned char model:3;
+       } __attribute__ ((packed)) cu_model;
+       __u16 dev_type;
+       __u8 dev_model;
+       struct {
+               unsigned char mult_burst:1;
+               unsigned char RT_in_LR:1;
+               unsigned char reserved1:1;
+               unsigned char RD_IN_LR:1;
+               unsigned char reserved2:4;
+               unsigned char reserved3:8;
+               unsigned char defect_wr:1;
+               unsigned char reserved4:2;
+               unsigned char striping:1;
+               unsigned char reserved5:4;
+               unsigned char cfw:1;
+               unsigned char reserved6:2;
+               unsigned char cache:1;
+               unsigned char dual_copy:1;
+               unsigned char dfw:1;
+               unsigned char reset_alleg:1;
+               unsigned char sense_down:1;
+       } __attribute__ ((packed)) facilities;
+       __u8 dev_class;
+       __u8 unit_type;
+       __u16 no_cyl;
+       __u16 trk_per_cyl;
+       __u8 sec_per_trk;
+       __u8 byte_per_track[3];
+       __u16 home_bytes;
+       __u8 formula;
+       union {
+               struct {
+                       __u8 f1;
+                       __u16 f2;
+                       __u16 f3;
+               } __attribute__ ((packed)) f_0x01;
+               struct {
+                       __u8 f1;
+                       __u8 f2;
+                       __u8 f3;
+                       __u8 f4;
+                       __u8 f5;
+               } __attribute__ ((packed)) f_0x02;
+       } __attribute__ ((packed)) factors;
+       __u16 first_alt_trk;
+       __u16 no_alt_trk;
+       __u16 first_dia_trk;
+       __u16 no_dia_trk;
+       __u16 first_sup_trk;
+       __u16 no_sup_trk;
+       __u8 MDR_ID;
+       __u8 OBR_ID;
+       __u8 director;
+       __u8 rd_trk_set;
+       __u16 max_rec_zero;
+       __u8 reserved1;
+       __u8 RWANY_in_LR;
+       __u8 factor6;
+       __u8 factor7;
+       __u8 factor8;
+       __u8 reserved2[3];
+       __u8 reserved3[10];
+} __attribute__ ((packed)) dasd_eckd_characteristics_t;
+
+typedef struct dasd_eckd_confdata_t {
+       struct {
+               struct {
+                       unsigned char identifier:2;
+                       unsigned char token_id:1;
+                       unsigned char sno_valid:1;
+                       unsigned char subst_sno:1;
+                       unsigned char recNED:1;
+                       unsigned char emuNED:1;
+                       unsigned char reserved:1;
+               } __attribute__ ((packed)) flags;
+               __u8 descriptor;
+               __u8 dev_class;
+               __u8 reserved;
+               unsigned char dev_type[6];
+               unsigned char dev_model[3];
+               unsigned char HDA_manufacturer[3];
+               unsigned char HDA_location[2];
+               unsigned char HDA_seqno[12];
+               __u16 ID;
+       } __attribute__ ((packed)) ned1;
+       struct {
+               struct {
+                       unsigned char identifier:2;
+                       unsigned char token_id:1;
+                       unsigned char sno_valid:1;
+                       unsigned char subst_sno:1;
+                       unsigned char recNED:1;
+                       unsigned char emuNED:1;
+                       unsigned char reserved:1;
+               } __attribute__ ((packed)) flags;
+               __u8 descriptor;
+               __u8 reserved[2];
+               unsigned char dev_type[6];
+               unsigned char dev_model[3];
+               unsigned char DASD_manufacturer[3];
+               unsigned char DASD_location[2];
+               unsigned char DASD_seqno[12];
+               __u16 ID;
+       } __attribute__ ((packed)) ned2;
+       struct {
+               struct {
+                       unsigned char identifier:2;
+                       unsigned char token_id:1;
+                       unsigned char sno_valid:1;
+                       unsigned char subst_sno:1;
+                       unsigned char recNED:1;
+                       unsigned char emuNED:1;
+                       unsigned char reserved:1;
+               } __attribute__ ((packed)) flags;
+               __u8 descriptor;
+               __u8 reserved[2];
+               unsigned char cont_type[6];
+               unsigned char cont_model[3];
+               unsigned char cont_manufacturer[3];
+               unsigned char cont_location[2];
+               unsigned char cont_seqno[12];
+               __u16 ID;
+       } __attribute__ ((packed)) ned3;
+       struct {
+               struct {
+                       unsigned char identifier:2;
+                       unsigned char token_id:1;
+                       unsigned char sno_valid:1;
+                       unsigned char subst_sno:1;
+                       unsigned char recNED:1;
+                       unsigned char emuNED:1;
+                       unsigned char reserved:1;
+               } __attribute__ ((packed)) flags;
+               __u8 descriptor;
+               __u8 reserved[2];
+               unsigned char cont_type[6];
+               unsigned char empty[3];
+               unsigned char cont_manufacturer[3];
+               unsigned char cont_location[2];
+               unsigned char cont_seqno[12];
+               __u16 ID;
+       } __attribute__ ((packed)) ned4;
+       unsigned char ned5[32];
+       unsigned char ned6[32];
+       unsigned char ned7[32];
+       struct {
+               struct {
+                       unsigned char identifier:2;
+                       unsigned char reserved:6;
+               } __attribute__ ((packed)) flags;
+               __u8 selector;
+               __u16 interfaceID;
+               __u32 reserved;
+               __u16 subsystemID;
+               struct {
+                       unsigned char sp0:1;
+                       unsigned char sp1:1;
+                       unsigned char reserved:5;
+                       unsigned char scluster:1;
+               } __attribute__ ((packed)) spathID;
+               __u8 unit_address;
+               __u8 dev_ID;
+               __u8 dev_address;
+               __u8 adapterID;
+               __u16 link_address;
+               struct {
+                       unsigned char parallel:1;
+                       unsigned char escon:1;
+                       unsigned char reserved:1;
+                       unsigned char ficon:1;
+                       unsigned char reserved2:4;
+               } __attribute__ ((packed)) protocol_type;
+               struct {
+                       unsigned char PID_in_236:1;
+                       unsigned char reserved:7;
+               } __attribute__ ((packed)) format_flags;
+               __u8 log_dev_address;
+               unsigned char reserved2[12];
+       } __attribute__ ((packed)) neq;
+} __attribute__ ((packed)) dasd_eckd_confdata_t;
+
+int dasd_eckd_init( void );
+
+#endif /* DASD_ECKD_H */
index 7516b0f3b06431207c2a25a3978c36d9ac97cc2f..f5f98433ad5a527b85d3cc9a80f9bef0313c8357 100644 (file)
@@ -5,7 +5,7 @@
  * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
  */
 
-#include <linux/dasd.h>
+#include <asm/dasd.h>
 #include "dasd_erp.h"
 
 #define PRINTK_HEADER "dasd_erp(eckd)"
@@ -14,16 +14,4 @@ dasd_era_t
 dasd_eckd_erp_examine (cqr_t * cqr, devstat_t * stat)
 {
 
-       if (stat->cstat == 0x00 &&
-           stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
-               return dasd_era_none;
-
-       switch (dasd_info[cqr->devindex]->info.sid_data.cu_model) {
-       case 0x3990:
-               return dasd_3990_erp_examine (cqr, stat);
-       case 0x9343:
-               return dasd_9343_erp_examine (cqr, stat);
-       default:
-               return dasd_era_recover;
-       }
 }
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
deleted file mode 100644 (file)
index 3b9194b..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_erp.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- */
-
-#include <asm/irq.h>
-#include <linux/dasd.h>
-#include "dasd_erp.h"
-
-#define PRINTK_HEADER "dasd_erp"
-
-dasd_era_t
-dasd_erp_examine (cqr_t * cqr, devstat_t * stat)
-{
-       int rc;
-       if (stat->cstat == 0x00 &&
-           stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) {
-               PRINT_WARN ("No error detected\n");
-               rc = dasd_era_none;
-       } else if (!(stat->flag & DEVSTAT_FLAG_SENSE_AVAIL)) {
-               PRINT_WARN ("No sense data available, try to recover anyway\n");
-               rc = dasd_era_recover;
-       } else
-#if DASD_PARANOIA > 1
-       if (!dasd_disciplines[dasd_info[cqr->devindex]->type]->
-                erp_examine) {
-               INTERNAL_CHECK ("No erp_examinator for dt=%d\n",
-                               dasd_info[cqr->devindex]->type);
-               rc = dasd_era_fatal;
-       } else
-#endif
-       {
-               PRINT_WARN ("calling examinator\n");
-               rc = dasd_disciplines[dasd_info[cqr->devindex]->type]->
-                       erp_examine (cqr, stat);
-       }
-       PRINT_WARN("ERP action code = %d\n",rc);
-       return rc;
-}
-
-void
-default_erp_action (erp_t * erp)
-{
-       cqr_t *cqr = erp->cqr.int4cqr;
-       ccw1_t *cpa = request_cp(1,0);
-
-       memset (cpa,0,sizeof(ccw1_t));
-
-       cpa -> cmd_code = CCW_CMD_NOOP;
-       
-       ((cqr_t *) erp)->cpaddr = cpa;
-       if (cqr->retries++ <= 16) {
-               ACS (cqr->status,
-                    CQR_STATUS_ERP_PEND,
-                    CQR_STATUS_QUEUED);
-       } else {
-               PRINT_WARN ("ERP retry count exceeded\n");
-               ACS (cqr->status,
-                    CQR_STATUS_ERP_PEND,
-                    CQR_STATUS_FAILED);
-       }
-       atomic_set (&(((cqr_t *) erp)->status), CQR_STATUS_FILLED);
-}
-
-dasd_erp_action_t
-dasd_erp_action (struct cqr_t *cqr)
-{
-       return default_erp_action;
-}
-
-dasd_erp_action_t
-dasd_erp_postaction (struct erp_t * erp)
-{
-       return NULL;
-}
diff --git a/drivers/s390/block/dasd_erp.h b/drivers/s390/block/dasd_erp.h
deleted file mode 100644 (file)
index 256489d..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_erp.h
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
- */
-
-#ifndef DASD_ERP_H
-#define DASD_ERP_H
-
-typedef enum {
-       dasd_era_fatal = -1,    /* no chance to recover              */
-       dasd_era_none = 0,      /* don't recover, everything alright */
-       dasd_era_msg = 1,       /* don't recover, just report...     */
-       dasd_era_recover = 2    /* recovery action recommended       */
-} dasd_era_t;
-
-#include "dasd_types.h"
-
-typedef struct erp_t {
-       struct cqr_t cqr;
-} __attribute__ ((packed)) 
-
-erp_t;
-
-typedef void (*dasd_erp_action_t) (erp_t *);
-
-dasd_era_t dasd_erp_examine (struct cqr_t *, devstat_t *);
-dasd_erp_action_t dasd_erp_action (struct cqr_t *);
-dasd_erp_action_t dasd_erp_postaction (struct erp_t *);
-
-#endif                         /* DASD_ERP_H */
index c748b5db87648189a188b412e4e31d7d1a5f116a..15d309d69f7ea46e8ce1972101cafa694d2bf181 100644 (file)
@@ -1,68 +1,51 @@
+/* 
+ * File...........: linux/drivers/s390/block/dasd_fba.c
+ * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+ * Bugreports.to..: <Linux390@de.ibm.com>
+ * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
+ */
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-
-#ifdef MODULE
-#include <linux/module.h>
-#endif                         /* MODULE */
+#include <asm/debug.h>
 
 #include <linux/malloc.h>
-#include <linux/dasd.h>
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
+#include <linux/blk.h>
+#include <asm/ccwcache.h>
+#include <asm/dasd.h>
 
+#include <asm/ebcdic.h>
 #include <asm/io.h>
-
 #include <asm/irq.h>
 
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
+#include "dasd.h"
+#include "dasd_fba.h"
 
-#define DASD_FBA_CCW_LOCATE 0x43
-#define DASD_FBA_CCW_READ   0x42
-#define DASD_FBA_CCW_WRITE  0x41
 
 #ifdef PRINTK_HEADER
 #undef PRINTK_HEADER
 #endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(fba):"
-
-typedef
-struct {
-       struct {
-               unsigned char perm:2;   /* Permissions on this extent */
-               unsigned char zero:2;   /* Must be zero */
-               unsigned char da:1;     /* usually zero */
-               unsigned char diag:1;   /* allow diagnose */
-               unsigned char zero2:2;  /* zero */
-       } __attribute__ ((packed)) mask;
-       unsigned char zero;     /* Must be zero */
-       unsigned short blk_size;        /* Blocksize */
-       unsigned long ext_loc;  /* Extent locator */
-       unsigned long ext_beg;  /* logical number of block 0 in extent */
-       unsigned long ext_end;  /* logocal number of last block in extent */
-} __attribute__ ((packed, aligned (32)))
-
-DE_fba_data_t;
-
-typedef
-struct {
-       struct {
-               unsigned char zero:4;
-               unsigned char cmd:4;
-       } __attribute__ ((packed)) operation;
-       unsigned char auxiliary;
-       unsigned short blk_ct;
-       unsigned long blk_nr;
-} __attribute__ ((packed, aligned (32)))
-
-LO_fba_data_t;
-
-static void
+#define PRINTK_HEADER DASD_NAME"(fba):"
+
+#define DASD_FBA_CCW_WRITE 0x41
+#define DASD_FBA_CCW_READ 0x42
+#define DASD_FBA_CCW_LOCATE 0x43
+#define DASD_FBA_CCW_DEFINE_EXTENT 0x63
+
+dasd_discipline_t dasd_fba_discipline;
+
+typedef struct
+dasd_fba_private_t {
+        dasd_fba_characteristics_t rdc_data;
+} dasd_fba_private_t;
+
+static inline void
 define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
               int blksize, int beg, int nr)
 {
        memset (DE_data, 0, sizeof (DE_fba_data_t));
-       ccw->cmd_code = CCW_DEFINE_EXTENT;
+       ccw->cmd_code = DASD_FBA_CCW_DEFINE_EXTENT;
        ccw->count = 16;
        ccw->cda = (void *) __pa (DE_data);
        if (rw == WRITE)
@@ -76,7 +59,7 @@ define_extent (ccw1_t * ccw, DE_fba_data_t * DE_data, int rw,
        DE_data->ext_end = nr - 1;
 }
 
-static void
+static inline void
 locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
               int block_ct)
 {
@@ -94,46 +77,174 @@ locate_record (ccw1_t * ccw, LO_fba_data_t * LO_data, int rw, int block_nr,
        LO_data->blk_ct = block_ct;
 }
 
-int
-dasd_fba_ck_devinfo (dev_info_t * info)
+
+static int 
+dasd_fba_id_check ( dev_info_t *info )
 {
+       if ( info->sid_data.cu_type == 0x3880 ) 
+                if ( info->sid_data.dev_type == 0x3370 )
+                        return 0;
+        if ( info->sid_data.cu_type == 0x6310 )
+                if ( info->sid_data.dev_type == 0x9336 )
        return 0;
+        return -ENODEV;
+}
+
+static int
+dasd_fba_check_characteristics (struct dasd_device_t *device)
+{
+        int rc = -ENODEV;
+        void *rdc_data;
+        dasd_fba_private_t *private;
+
+        if ( device == NULL ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Null device pointer passed to characteristics checker\n");
+                return -ENODEV;
+        }
+        if ( device->private == NULL ) {
+               device->private = kmalloc(sizeof(dasd_fba_private_t),GFP_KERNEL);
+               if ( device->private == NULL ) {
+                       printk ( KERN_WARNING PRINTK_HEADER
+                                "memory allocation failed for private data\n");
+                       return -ENOMEM;
+               }
+        }
+        private = (dasd_fba_private_t *)device->private;
+        rdc_data = (void *)&(private->rdc_data);
+        rc = read_dev_chars (device->devinfo.irq, &rdc_data , 32);
+        if ( rc ) {
+                printk ( KERN_WARNING PRINTK_HEADER
+                         "Read device characteristics returned error %d\n",rc);
+                return rc;
+        }
+       printk ( KERN_INFO PRINTK_HEADER 
+                "%04X on sch %d: %04X/%02X(CU:%04X/%02X) %dMB at(%d B/blk)\n",
+                 device->devinfo.devno, device->devinfo.irq,
+                 device->devinfo.sid_data.dev_type, device->devinfo.sid_data.dev_model,
+                 device->devinfo.sid_data.cu_type, device->devinfo.sid_data.cu_model,
+                (private->rdc_data.blk_bdsa * 
+                 (private->rdc_data.blk_size >> 9)) >> 11,
+                private->rdc_data.blk_size);
+        return 0;
 }
 
-cqr_t *
-dasd_fba_build_req (int devindex,
-                   struct request * req)
+static int
+dasd_fba_do_analysis (struct dasd_device_t *device)
 {
-       cqr_t *rw_cp = NULL;
-       ccw1_t *ccw;
+       int rc = 0;
+       int sb;
+        dasd_fba_private_t *private = (dasd_fba_private_t *)device->private;
+       int bs = private->rdc_data.blk_size;
+
+        memset (&(device->sizes), 0, sizeof (dasd_sizes_t));
+        switch ( bs ) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+               device->sizes.bp_block = bs;
+                break;
+        default:
+                printk ( KERN_INFO PRINTK_HEADER 
+                         "/dev/%s (%04X): unknown blocksize %d\n",
+                         device->name, device->devinfo.devno,bs);
+               return -EMEDIUMTYPE;
+       }
+       device->sizes.s2b_shift = 0;    /* bits to shift 512 to get a block */
+       for (sb = 512; sb < bs; sb = sb << 1)
+               device->sizes.s2b_shift++;
+       
+       device->sizes.blocks = (private->rdc_data.blk_bdsa);
 
-       DE_fba_data_t *DE_data;
-       LO_fba_data_t *LO_data;
-       struct buffer_head *bh;
+       return rc;
+}
+
+static int
+dasd_fba_fill_geometry(struct dasd_device_t *device, struct hd_geometry *geo)
+{
+        int rc = 0;
+       unsigned long sectors = device->sizes.blocks << device->sizes.s2b_shift;
+       unsigned long tracks = sectors >> 6;
+       unsigned long trk_rem = sectors & ((1<<6)-1);
+       unsigned long cyls = tracks >> 4;
+       unsigned long cyls_rem = tracks & ((1<<4)-1);
+
+        switch(device->sizes.bp_block) {
+        case 512:
+        case 1024:
+        case 2048:
+        case 4096:
+                break;
+        default:
+                return -EINVAL;
+        }
+       geo->cylinders = cyls;
+       geo->heads = 16;
+       geo->sectors = 128 >> device->sizes.s2b_shift;
+       geo->start = 1;
+        return rc;
+}
+
+static dasd_era_t
+dasd_fba_examine_error  (ccw_req_t *cqr, devstat_t * stat)
+{
+        dasd_device_t *device = (dasd_device_t *)cqr->device;
+        if (stat->cstat == 0x00 &&
+           stat->dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
+               return dasd_era_none;
+        
+       switch (device->devinfo.sid_data.dev_model) {
+       case 0x3370:
+               return dasd_3370_erp_examine (cqr, stat);
+       case 0x9336:
+               return dasd_9336_erp_examine (cqr, stat);
+       default:
+               return dasd_era_recover;
+       }
+}
+
+static dasd_erp_action_fn_t 
+dasd_fba_erp_action ( ccw_req_t * cqr ) 
+{
+        return default_erp_action;
+}
+
+static dasd_erp_postaction_fn_t
+dasd_fba_erp_postaction (ccw_req_t * cqr)
+{
+        if ( cqr -> function == default_erp_action)
+                return default_erp_postaction;
+        printk ( KERN_WARNING PRINTK_HEADER
+                 "unknown ERP action %p\n",
+                 cqr -> function);
+       return NULL;
+}
+
+static ccw_req_t *
+dasd_fba_build_cp_from_req (dasd_device_t *device, struct request *req)
+{
+        ccw_req_t *rw_cp = NULL;
        int rw_cmd;
-       int byt_per_blk = dasd_info[devindex]->sizes.bp_block;
        int bhct;
        long size;
+        ccw1_t *ccw;
+       DE_fba_data_t *DE_data;
+       LO_fba_data_t *LO_data;
+       struct buffer_head *bh;
+        dasd_fba_private_t *private = (dasd_fba_private_t *)device->private;
+       int byt_per_blk = device->sizes.bp_block;
 
-       if (!req->nr_sectors) {
-               PRINT_ERR ("No blocks to write...returning\n");
-               return NULL;
-       }
        if (req->cmd == READ) {
                rw_cmd = DASD_FBA_CCW_READ;
-       } else
-#if DASD_PARANOIA > 2
-       if (req->cmd == WRITE)
-#endif                         /* DASD_PARANOIA */
-       {
+       } else if (req->cmd == WRITE) {
                rw_cmd = DASD_FBA_CCW_WRITE;
-       }
-#if DASD_PARANOIA > 2
-       else {
+       } else {
                PRINT_ERR ("Unknown command %d\n", req->cmd);
                return NULL;
        }
-#endif                         /* DASD_PARANOIA */
+       /* Build the request */
+       /* count bhs to prevent errors, when bh smaller than block */
        bhct = 0;
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
                if (bh->b_size > byt_per_blk)
@@ -143,8 +254,8 @@ dasd_fba_build_req (int devindex,
                        bhct++;
        }
 
-       /* Build the request */
-       rw_cp = request_cqr (2 + bhct,
+       rw_cp = dasd_alloc_request (dasd_fba_discipline.name,
+                                   2 + bhct,
                             sizeof (DE_fba_data_t) +
                             sizeof (LO_fba_data_t));
        if (!rw_cp) {
@@ -160,11 +271,12 @@ dasd_fba_build_req (int devindex,
        ccw++;
        locate_record (ccw, LO_data, req->cmd, 0, req->nr_sectors);
        ccw->flags = CCW_FLAG_CC;
+
        for (bh = req->bh; bh;) {
                if (bh->b_size > byt_per_blk) {
                        for (size = 0; size < bh->b_size; size += byt_per_blk) {
                                ccw++;
-                               if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+                               if (private->rdc_data.mode.bits.data_chain) {
                                        ccw->flags = CCW_FLAG_DC;
                                } else {
                                        ccw->flags = CCW_FLAG_CC;
@@ -177,11 +289,11 @@ dasd_fba_build_req (int devindex,
                } else {        /* group N bhs to fit into byt_per_blk */
                        for (size = 0; bh != NULL && size < byt_per_blk;) {
                                ccw++;
-                               if (dasd_info[devindex]->rdc_data->fba.mode.bits.data_chain) {
+                               if (private->rdc_data.mode.bits.data_chain) {
                                        ccw->flags = CCW_FLAG_DC;
                                } else {
                                        PRINT_WARN ("Cannot chain chunks smaller than one block\n");
-                                       release_cqr (rw_cp);
+                                       ccw_free_request (rw_cp);
                                        return NULL;
                                }
                                ccw->cmd_code = rw_cmd;
@@ -193,164 +305,80 @@ dasd_fba_build_req (int devindex,
                        ccw->flags = CCW_FLAG_CC;
                        if (size != byt_per_blk) {
                                PRINT_WARN ("Cannot fulfill request smaller than block\n");
-                               release_cqr (rw_cp);
+                               ccw_free_request (rw_cp);
                                return NULL;
                        }
                }
        }
        ccw->flags &= ~(CCW_FLAG_DC | CCW_FLAG_CC);
+
+        rw_cp->device = device;
+        rw_cp->expires = 5 * 0xf424000; /* 5 seconds */
+        rw_cp->req = req;
+        atomic_compare_and_swap_debug(&rw_cp->status,CQR_STATUS_EMPTY,CQR_STATUS_FILLED);
        return rw_cp;
 }
 
-void
-dasd_fba_print_char (dasd_characteristics_t * ct)
-{
-       dasd_fba_characteristics_t *c =
-       (dasd_fba_characteristics_t *) ct;
-       PRINT_INFO ("%d blocks of %d bytes %d MB\n",
-                   c->blk_bdsa, c->blk_size,
-                   (c->blk_bdsa * (c->blk_size >> 9)) >> 11);
-       PRINT_INFO ("%soverrun, %s mode, data chains %sallowed\n"
-                   "%sremovable, %sshared\n",
-                   (c->mode.bits.overrunnable ? "" : "no "),
-                   (c->mode.bits.burst_byte ? "burst" : "byte"),
-                   (c->mode.bits.data_chain ? "" : "not "),
-                   (c->features.bits.removable ? "" : "not "),
-                   (c->features.bits.shared ? "" : "not "));
-};
-
-int
-dasd_fba_ck_char (dasd_characteristics_t * rdc)
+static char *
+dasd_fba_dump_sense(struct dasd_device_t *device, ccw_req_t *req)
 {
-       int rc = 0;
-       dasd_fba_print_char (rdc);
-       return rc;
+        char *page = (char *)get_free_page(GFP_KERNEL);
+        int len;
+        if ( page == NULL ) {
+                return NULL;
 }
 
-cqr_t *
-dasd_fba_fill_sizes_first (int di)
-{
-       cqr_t *rw_cp = NULL;
-       ccw1_t *ccw;
-       DE_fba_data_t *DE_data;
-       LO_fba_data_t *LO_data;
-       dasd_information_t *info = dasd_info[di];
-       static char buffer[8];
-
-       dasd_info[di]->sizes.label_block = 1;
+        len = sprintf ( page, KERN_WARNING PRINTK_HEADER 
+                        "device %04X on irq %d: I/O status report:\n",
+                        device->devinfo.devno,device->devinfo.irq);
+                        
 
-       rw_cp = request_cqr (3,
-                            sizeof (DE_fba_data_t) +
-                            sizeof (LO_fba_data_t));
-       DE_data = rw_cp->data;
-       LO_data = rw_cp->data + sizeof (DE_fba_data_t);
-       ccw = rw_cp->cpaddr;
-       define_extent (ccw, DE_data, READ, info->sizes.bp_block, 1, 1);
-       ccw->flags = CCW_FLAG_CC;
-       ccw++;
-       locate_record (ccw, LO_data, READ, 0, 1);
-       ccw->flags = CCW_FLAG_CC;
-       ccw++;
-       ccw->cmd_code = DASD_FBA_CCW_READ;
-       ccw->flags = CCW_FLAG_SLI;
-       ccw->count = 8;
-       ccw->cda = (void *) __pa (buffer);
-       rw_cp->devindex = di;
-       atomic_set (&rw_cp->status, CQR_STATUS_FILLED);
-       return rw_cp;
+        return page;
 }
 
-int
-dasd_fba_fill_sizes_last (int devindex)
-{
-       int rc = 0;
-       int sb;
-       dasd_information_t *info = dasd_info[devindex];
-
-       info->sizes.bp_sector = info->rdc_data->fba.blk_size;
-       info->sizes.bp_block = info->sizes.bp_sector;
-
-       info->sizes.s2b_shift = 0;      /* bits to shift 512 to get a block */
-       for (sb = 512; sb < info->sizes.bp_sector; sb = sb << 1)
-               info->sizes.s2b_shift++;
-
-       info->sizes.blocks = (info->rdc_data->fba.blk_bdsa);
-
-       if (info->sizes.s2b_shift >= 1)
-               info->sizes.kbytes = info->sizes.blocks <<
-                   (info->sizes.s2b_shift - 1);
-       else
-               info->sizes.kbytes = info->sizes.blocks >>
-                   (-(info->sizes.s2b_shift - 1));
-
-       return rc;
-}
+dasd_discipline_t dasd_fba_discipline = {
+       name :                          "FBA ",
+       ebcname :                       "FBA ",
+        id_check:                       dasd_fba_id_check,          
+        check_characteristics:          dasd_fba_check_characteristics,
+        do_analysis:                    dasd_fba_do_analysis,          
+        fill_geometry:                  dasd_fba_fill_geometry,
+        start_IO:                       dasd_start_IO,           
+        examine_error:                  dasd_fba_examine_error,          
+        erp_action:                     dasd_fba_erp_action,             
+        erp_postaction:                 dasd_fba_erp_postaction,         
+        build_cp_from_req:              dasd_fba_build_cp_from_req,      
+        dump_sense:                     dasd_fba_dump_sense,            
+        int_handler:                    dasd_int_handler            
+};
 
 int
-dasd_fba_format (int devindex, format_data_t * fdata)
-{
+dasd_fba_init( void ) {
        int rc = 0;
+        printk ( KERN_INFO PRINTK_HEADER
+                 "%s discipline initializing\n", dasd_fba_discipline.name);
+        ASCEBC(dasd_fba_discipline.ebcname,4);
+        dasd_discipline_enq(&dasd_fba_discipline);
+
        return rc;
 }
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
 
-void
-dasd_fba_fill_geometry (int di, struct hd_geometry *geo)
-{
-       int bfactor, nr_sectors, sec_size;
-       int trk_cap, trk_low, trk_high, tfactor, nr_trks, trk_size;
-       int cfactor, nr_cyls, cyl_size;
-       int remainder;
-
-       dasd_information_t *info = dasd_info[di];
-       PRINT_INFO ("FBA has no geometry! Faking one...\n%s", "");
-
-       /* determine the blocking factor of sectors */
-       for (bfactor = 8; bfactor > 0; bfactor--) {
-               remainder = info->rdc_data->fba.blk_bdsa % bfactor;
-               PRINT_INFO ("bfactor %d remainder %d\n", bfactor, remainder);
-               if (!remainder)
-                       break;
-       }
-       nr_sectors = info->rdc_data->fba.blk_bdsa / bfactor;
-       sec_size = info->rdc_data->fba.blk_size * bfactor;
-       
-       geo -> sectors = bfactor;
-
-       /* determine the nr of sectors per track */
-       trk_cap = (64 * 1 << 10) / sec_size;    /* 64k in sectors */
-       trk_low = trk_cap * 2 / 3;
-       trk_high = trk_cap * 4 / 3;
-       for (tfactor = trk_high; tfactor > trk_low; tfactor--) {
-               PRINT_INFO ("remainder %d\n", remainder);
-               remainder = nr_sectors % bfactor;
-               if (!remainder)
-                       break;
-       }
-       nr_trks = nr_sectors / tfactor;
-       trk_size = sec_size * tfactor;
-
-       /* determine the nr of trks per cylinder */
-       for (cfactor = 31; cfactor > 0; cfactor--) {
-               PRINT_INFO ("remainder %d\n", remainder);
-               remainder = nr_trks % bfactor;
-               if (!remainder)
-                       break;
-       }
-       nr_cyls = nr_trks / cfactor;
-       sec_size = info->rdc_data->fba.blk_size * bfactor;
-
-       geo -> heads = nr_trks;
-       geo -> cylinders = nr_cyls;
-       geo -> start = info->sizes.label_block + 1;
-}
 
-dasd_operations_t dasd_fba_operations =
-{
-       ck_devinfo:dasd_fba_ck_devinfo,
-       get_req_ccw:dasd_fba_build_req,
-       ck_characteristics:dasd_fba_ck_char,
-       fill_sizes_first:dasd_fba_fill_sizes_first,
-       fill_sizes_last:dasd_fba_fill_sizes_last,
-       dasd_format:dasd_fba_format,
-       fill_geometry:dasd_fba_fill_geometry
-};
diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h
new file mode 100644 (file)
index 0000000..1891592
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DASD_FBA_H
+#define DASD_FBA_H
+
+typedef 
+struct DE_fba_data_t {
+       struct {
+               unsigned char perm:2;   /* Permissions on this extent */
+               unsigned char zero:2;   /* Must be zero */
+               unsigned char da:1;     /* usually zero */
+               unsigned char diag:1;   /* allow diagnose */
+               unsigned char zero2:2;  /* zero */
+       } __attribute__ ((packed)) mask;
+       __u8 zero;      /* Must be zero */
+       __u16 blk_size; /* Blocksize */
+       __u32 ext_loc;  /* Extent locator */
+       __u32 ext_beg;  /* logical number of block 0 in extent */
+       __u32 ext_end;  /* logocal number of last block in extent */
+} __attribute__ ((packed)) DE_fba_data_t;
+
+typedef 
+struct LO_fba_data_t {
+       struct {
+               unsigned char zero:4;
+               unsigned char cmd:4;
+       } __attribute__ ((packed)) operation;
+       __u8 auxiliary;
+       __u16 blk_ct;
+       __u32 blk_nr;
+} __attribute__ ((packed)) LO_fba_data_t; 
+
+
+typedef 
+struct dasd_fba_characteristics_t {
+       union {
+               __u8 c;
+               struct {
+                       unsigned char reserved:1;
+                       unsigned char overrunnable:1;
+                       unsigned char burst_byte:1;
+                       unsigned char data_chain:1;
+                       unsigned char zeros:4;
+               } __attribute__ ((packed)) bits;
+       } __attribute__ ((packed)) mode;
+       union {
+               __u8 c;
+               struct {
+                       unsigned char zero0:1;
+                       unsigned char removable:1;
+                       unsigned char shared:1;
+                       unsigned char zero1:1;
+                       unsigned char mam:1;
+                       unsigned char zeros:3;
+               } __attribute__ ((packed)) bits;
+       } __attribute__ ((packed)) features;
+       __u8 dev_class;
+       __u8 unit_type;
+       __u16 blk_size;
+       __u32 blk_per_cycl;
+       __u32 blk_per_bound;
+       __u32 blk_bdsa;
+       __u32 reserved0;
+       __u16 reserved1;
+       __u16 blk_ce;
+       __u32 reserved2;
+       __u16 reserved3;
+} __attribute__ ((packed)) dasd_fba_characteristics_t;
+
+int dasd_fba_init( void );
+
+#endif /* DASD_FBA_H */
diff --git a/drivers/s390/block/dasd_mdsk.c b/drivers/s390/block/dasd_mdsk.c
deleted file mode 100644 (file)
index 14220f4..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-#include <linux/dasd.h>
-#include <linux/malloc.h>
-#include <linux/ctype.h>
-#include "dasd_types.h"
-#include "dasd_ccwstuff.h"
-#include "dasd_mdsk.h"
-
-#ifdef PRINTK_HEADER
-#undef PRINTK_HEADER
-#endif                         /* PRINTK_HEADER */
-#define PRINTK_HEADER "dasd(mdsk):"
-
-int dasd_is_accessible (int devno);
-void dasd_insert_range (int start, int end);
-
-/*
- * The device characteristics function
- */
-static __inline__ int
-dia210 (void *devchar)
-{
-       int rc;
-
-       asm volatile ("    lr    2,%1\n"
-                     "    .long 0x83200210\n"
-                     "    ipm   %0\n"
-                     "    srl   %0,28"
-                     :"=d" (rc)
-                     :"d" ((void *) __pa (devchar))
-                     :"2");
-       return rc;
-}
-
-static __inline__ int
-dia250 (void *iob, int cmd)
-{
-       int rc;
-
-       asm volatile ("    lr    2,%1\n"
-                     "    lr    3,%2\n"
-                     "    .long 0x83230250\n"
-                     "    lr    %0,3"
-                     :"=d" (rc)
-                     :"d" ((void *) __pa (iob)), "d" (cmd)
-                     :"2", "3");
-       return rc;
-}
-
-/*
- * Init of minidisk device
- */
-
-static __inline__ int
-mdsk_init_io (int di, int blocksize, int offset, int size)
-{
-       mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
-       int rc;
-
-       memset (iib, 0, sizeof (mdsk_init_io_t));
-
-       iib->dev_nr = dasd_info[di]->info.devno;
-       iib->block_size = blocksize;
-       iib->offset = offset;
-       iib->start_block = 0;
-       iib->end_block = size;
-
-       rc = dia250 (iib, INIT_BIO);
-
-       return rc;
-}
-
-/*
- * release of minidisk device
- */
-
-static __inline__ int
-mdsk_term_io (int di)
-{
-       mdsk_init_io_t *iib = &(dasd_info[di]->private.mdsk.iib);
-       int rc;
-
-       memset (iib, 0, sizeof (mdsk_init_io_t));
-       iib->dev_nr = dasd_info[di]->info.devno;
-       rc = dia250 (iib, TERM_BIO);
-       return rc;
-}
-
-void dasd_do_chanq (void);
-void dasd_schedule_bh (void (*func) (void));
-int register_dasd_last (int di);
-
-int
-dasd_mdsk_start_IO (cqr_t * cqr)
-{
-       int rc;
-       mdsk_rw_io_t *iob = &(dasd_info[cqr->devindex]->private.mdsk.iob);
-
-       iob->dev_nr = dasd_info[cqr->devindex]->info.devno;
-       iob->key = 0;
-       iob->flags = 2;
-       iob->block_count = cqr->cplength >> 1;
-       iob->interrupt_params = (u32) cqr;
-       iob->bio_list = __pa (cqr->cpaddr);
-
-       asm volatile ("STCK %0":"=m" (cqr->startclk));
-       rc = dia250 (iob, RW_BIO);
-       if (rc > 8) {
-               PRINT_WARN ("dia250 returned CC %d\n", rc);
-               ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_ERROR);
-       } else {
-               ACS (cqr->status, CQR_STATUS_QUEUED, CQR_STATUS_IN_IO);
-               atomic_dec (&chanq_tasks);
-       }
-       return rc;
-}
-
-void 
-do_dasd_mdsk_interrupt (struct pt_regs *regs, __u16 code)
-{
-       int intparm = S390_lowcore.ext_params;
-       char status = *((char *) S390_lowcore.ext_params + 5);
-       cqr_t *cqr = (cqr_t *) intparm;
-       if (!intparm)
-               return;
-       if (cqr->magic != MDSK_MAGIC) {
-               panic ("unknown magic number\n");
-       }
-       asm volatile ("STCK %0":"=m" (cqr->stopclk));
-       if (atomic_read (&dasd_info[cqr->devindex]->status) ==
-           DASD_INFO_STATUS_DETECTED) {
-               register_dasd_last (cqr->devindex);
-       }
-       switch (status) {
-       case 0x00:
-               ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_DONE);
-               break;
-       case 0x01:
-       case 0x02:
-       case 0x03:
-       default:
-               ACS (cqr->status, CQR_STATUS_IN_IO, CQR_STATUS_FAILED);
-               atomic_inc (&dasd_info[cqr->devindex]->
-                           queue.dirty_requests);
-               break;
-       }
-       atomic_inc (&chanq_tasks);
-       dasd_schedule_bh (dasd_do_chanq);
-}
-
-cqr_t *
-dasd_mdsk_build_req (int devindex,
-                    struct request *req)
-{
-       cqr_t *rw_cp = NULL;
-       struct buffer_head *bh;
-       int rw_cmd;
-       dasd_information_t *info = dasd_info[devindex];
-       int noblk = req->nr_sectors >> info->sizes.s2b_shift;
-       int byt_per_blk = info->sizes.bp_block;
-       int block;
-       mdsk_bio_t *bio;
-       int bhct;
-       long size;
-
-       if (!noblk) {
-               PRINT_ERR ("No blocks to write...returning\n");
-               return NULL;
-       }
-       if (req->cmd == READ) {
-               rw_cmd = MDSK_READ_REQ;
-       } else
-#if DASD_PARANOIA > 2
-       if (req->cmd == WRITE)
-#endif                         /* DASD_PARANOIA */
-       {
-               rw_cmd = MDSK_WRITE_REQ;
-       }
-#if DASD_PARANOIA > 2
-       else {
-               PRINT_ERR ("Unknown command %d\n", req->cmd);
-               return NULL;
-       }
-#endif                         /* DASD_PARANOIA */
-       bhct = 0;
-       for (bh = req->bh; bh; bh = bh->b_reqnext) {
-               if (bh->b_size > byt_per_blk)
-                       for (size = 0; size < bh->b_size; size += byt_per_blk)
-                               bhct++;
-               else
-                       bhct++;
-       }
-       /* Build the request */
-       rw_cp = request_cqr (MDSK_BIOS (bhct), 0);
-       if (!rw_cp) {
-               return NULL;
-       }
-       rw_cp->magic = MDSK_MAGIC;
-       bio = (mdsk_bio_t *) (rw_cp->cpaddr);
-
-       block = req->sector >> info->sizes.s2b_shift;
-       for (bh = req->bh; bh; bh = bh->b_reqnext) {
-               if (bh->b_size >= byt_per_blk) {
-                       memset (bio, 0, sizeof (mdsk_bio_t));
-                       for (size = 0; size < bh->b_size; size += byt_per_blk) {
-                               bio->type = rw_cmd;
-                               bio->block_number = block + 1;
-                               bio->buffer = __pa (bh->b_data + size);
-                               bio++;
-                               block++;
-                       }
-               } else {
-                       PRINT_WARN ("Cannot fulfill request smaller than block\n");
-                       release_cqr (rw_cp);
-                       return NULL;
-               }
-       }
-       return rw_cp;
-}
-
-int
-dasd_mdsk_ck_devinfo (dev_info_t * info)
-{
-       int rc = 0;
-
-       dasd_mdsk_characteristics_t devchar =
-       {0,};
-
-       devchar.dev_nr = info->devno;
-       devchar.rdc_len = sizeof (dasd_mdsk_characteristics_t);
-
-       if (dia210 (&devchar) != 0) {
-               return -ENODEV;
-       }
-       if (devchar.vdev_class == DEV_CLASS_FBA ||
-           devchar.vdev_class == DEV_CLASS_ECKD ||
-           devchar.vdev_class == DEV_CLASS_CKD) {
-               return 0;
-       } else {
-               return -ENODEV;
-       }
-       return rc;
-}
-
-int
-dasd_mdsk_ck_characteristics (dasd_characteristics_t * dchar)
-{
-       int rc = 0;
-       dasd_mdsk_characteristics_t *devchar =
-       (dasd_mdsk_characteristics_t *) dchar;
-
-       if (dia210 (devchar) != 0) {
-               return -ENODEV;
-       }
-       if (devchar->vdev_class != DEV_CLASS_FBA &&
-           devchar->vdev_class != DEV_CLASS_ECKD &&
-           devchar->vdev_class != DEV_CLASS_CKD) {
-               return -ENODEV;
-       }
-       return rc;
-}
-
-cqr_t *
-dasd_mdsk_fill_sizes_first (int di)
-{
-       cqr_t *cqr = NULL;
-       dasd_information_t *info = dasd_info[di];
-       mdsk_bio_t *bio;
-       int bsize;
-       int rc;
-       /* Figure out position of label block */
-       if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_FBA) {
-               info->sizes.label_block = 1;
-       } else if (info->rdc_data->mdsk.vdev_class == DEV_CLASS_ECKD ||
-                  info->rdc_data->mdsk.vdev_class == DEV_CLASS_CKD) {
-               dasd_info[di]->sizes.label_block = 2;
-       } else {
-               return NULL;
-       }
-
-       /* figure out blocksize of device */
-       mdsk_term_io (di);
-       for (bsize = 512; bsize <= PAGE_SIZE; bsize = bsize << 1) {
-               rc = mdsk_init_io (di, bsize, 0, 64);
-               if (rc <= 4) {
-                       break;
-               }
-       }
-       if (bsize > PAGE_SIZE) {
-               PRINT_INFO ("Blocksize larger than 4096??\n");
-               rc = mdsk_term_io (di);
-               return NULL;
-       }
-       dasd_info[di]->sizes.bp_sector = bsize;
-
-       info->private.mdsk.label = (long *) get_free_page (GFP_KERNEL);
-       cqr = request_cqr (MDSK_BIOS (1), 0);
-       cqr->magic = MDSK_MAGIC;
-       bio = (mdsk_bio_t *) (cqr->cpaddr);
-       memset (bio, 0, sizeof (mdsk_bio_t));
-       bio->type = MDSK_READ_REQ;
-       bio->block_number = info->sizes.label_block + 1;
-       bio->buffer = __pa (info->private.mdsk.label);
-       cqr->devindex = di;
-       atomic_set (&cqr->status, CQR_STATUS_FILLED);
-
-       return cqr;
-}
-
-int
-dasd_mdsk_fill_sizes_last (int di)
-{
-       int sb;
-       dasd_information_t *info = dasd_info[di];
-       long *label = info->private.mdsk.label;
-       int bs = info->private.mdsk.iib.block_size;
-
-       info->sizes.s2b_shift = 0;      /* bits to shift 512 to get a block */
-       for (sb = 512; sb < bs; sb = sb << 1)
-               info->sizes.s2b_shift++;
-
-       if (label[3] != bs) {
-               PRINT_WARN ("%04X mismatching blocksizes\n", info->info.devno);
-               atomic_set (&dasd_info[di]->status,
-                           DASD_INFO_STATUS_DETECTED);
-               return -EINVAL;
-       }
-       if (label[0] != 0xc3d4e2f1) {   /* CMS1 */
-               PRINT_WARN ("%04X is not CMS formatted\n", info->info.devno);
-       }
-       if (label[13] == 0) {
-               PRINT_WARN ("%04X is not reserved\n", info->info.devno);
-       }
-       /* defaults for first partition */
-       info->private.mdsk.setup.size =
-           (label[7] - 1 - label[13]) * (label[3] >> 9) >> 1;
-       info->private.mdsk.setup.blksize = label[3];
-       info->private.mdsk.setup.offset = label[13] + 1;
-
-       /* real size of the volume */
-       info->sizes.bp_block = label[3];
-       info->sizes.kbytes = label[7] * (label[3] >> 9) >> 1;
-
-       if (info->sizes.s2b_shift >= 1)
-               info->sizes.blocks = info->sizes.kbytes >>
-                   (info->sizes.s2b_shift - 1);
-       else
-               info->sizes.blocks = info->sizes.kbytes <<
-                   (-(info->sizes.s2b_shift - 1));
-
-       PRINT_INFO ("%ld kBytes in %d blocks of %d Bytes\n",
-                   info->sizes.kbytes,
-                   info->sizes.blocks,
-                   info->sizes.bp_sector);
-       return 0;
-
-}
-
-dasd_operations_t dasd_mdsk_operations =
-{
-       ck_devinfo:dasd_mdsk_ck_devinfo,
-       get_req_ccw:dasd_mdsk_build_req,
-       ck_characteristics:dasd_mdsk_ck_characteristics,
-       fill_sizes_first:dasd_mdsk_fill_sizes_first,
-       fill_sizes_last:dasd_mdsk_fill_sizes_last,
-       dasd_format:NULL
-};
diff --git a/drivers/s390/block/dasd_mdsk.h b/drivers/s390/block/dasd_mdsk.h
deleted file mode 100644 (file)
index b135ced..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef DASD_MDSK_H
-#define DASD_MDSK_H
-
-#define MDSK_WRITE_REQ 0x01
-#define MDSK_READ_REQ  0x02
-
-#define INIT_BIO        0x00
-#define RW_BIO          0x01
-#define TERM_BIO        0x02
-
-#define DEV_CLASS_FBA   0x01
-#define DEV_CLASS_ECKD   0x02  /* sure ?? */
-#define DEV_CLASS_CKD   0x04   /* sure ?? */
-
-#define MDSK_BIOS(x) (2*(x))
-
-typedef struct mdsk_dev_char_t {
-       u8 type;
-       u8 status;
-       u16 spare1;
-       u32 block_number;
-       u32 alet;
-       u32 buffer;
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_bio_t;
-
-typedef struct {
-       u16 dev_nr;
-       u16 spare1[11];
-       u32 block_size;
-       u32 offset;
-       u32 start_block;
-       u32 end_block;
-       u32 spare2[6];
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_init_io_t;
-
-typedef struct {
-       u16 dev_nr;
-       u16 spare1[11];
-       u8 key;
-       u8 flags;
-       u16 spare2;
-       u32 block_count;
-       u32 alet;
-       u32 bio_list;
-       u32 interrupt_params;
-       u32 spare3[5];
-} __attribute__ ((packed, aligned (8))) 
-
-mdsk_rw_io_t;
-
-typedef struct {
-       long vdev;
-       long size;
-       long offset;
-       long blksize;
-       int force_mdsk;
-} mdsk_setup_data_t;
-
-#endif
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
deleted file mode 100644 (file)
index 2489fa2..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
-  Structure of the proc filesystem:
-  /proc/dasd/
-  /proc/dasd/devices                  # List of devices
-  /proc/dasd/ddabcd                   # Device node for devno abcd            
-  /proc/dasd/ddabcd1                  # Device node for partition abcd  
-  /proc/dasd/abcd                     # Device information for devno abcd
-*/
-
-#include <linux/proc_fs.h>
-
-#include <linux/dasd.h>
-
-#include "dasd_types.h"
-
-int dasd_proc_read_devices ( char *, char **, off_t, int, int);
-#ifdef DASD_PROFILE
-extern int dasd_proc_read_statistics ( char *, char **, off_t, int, int);
-extern int dasd_proc_read_debug ( char *, char **, off_t, int, int);
-#endif /* DASD_PROFILE */
-
-struct proc_dir_entry dasd_proc_root_entry =
-{
-       low_ino:0,
-       namelen:4,
-       name:"dasd",
-       mode:S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-       nlink:1,
-       uid:0,
-       gid:0,
-       size:0
-};
-
-struct proc_dir_entry dasd_proc_devices_entry =
-{
-       low_ino:0,
-       namelen:7,
-       name:"devices",
-       mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-       nlink:1,
-       uid:0,
-       gid:0,
-       size:0,
-       get_info:&dasd_proc_read_devices,
-};
-
-#ifdef DASD_PROFILE
-struct proc_dir_entry dasd_proc_stats_entry =
-{
-       low_ino:0,
-       namelen:10,
-       name:"statistics",
-       mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-       nlink:1,
-       uid:0,
-       gid:0,
-       size:0,
-       get_info:&dasd_proc_read_statistics
-};
-
-struct proc_dir_entry dasd_proc_debug_entry =
-{
-       low_ino:0,
-       namelen:5,
-       name:"debug",
-       mode:S_IFREG | S_IRUGO | S_IXUGO | S_IWUSR | S_IWGRP,
-       nlink:1,
-       uid:0,
-       gid:0,
-       size:0,
-       get_info:&dasd_proc_read_debug
-};
-#endif /* DASD_PROFILE */
-
-struct proc_dir_entry dasd_proc_device_template =
-{
-       0,
-       6,"dd????",
-       S_IFBLK | S_IRUGO | S_IWUSR | S_IWGRP,
-       1,0,0,
-       0,
-       NULL,
-};
-
-void
-dasd_proc_init ( void )
-{
-       proc_register( & proc_root, & dasd_proc_root_entry);
-       proc_register( & dasd_proc_root_entry, & dasd_proc_devices_entry);
-#ifdef DASD_PROFILE
-       proc_register( & dasd_proc_root_entry, & dasd_proc_stats_entry); 
-       proc_register( & dasd_proc_root_entry, & dasd_proc_debug_entry); 
-#endif /* DASD_PROFILE */
-}
-
-int 
-dasd_proc_read_devices ( char * buf, char **start, off_t off, int len, int d)
-{
-       int i;
-       len = sprintf ( buf, "dev# MAJ minor node        Format\n");
-       for ( i = 0; i < DASD_MAX_DEVICES; i++ ) {
-               dasd_information_t *info = dasd_info[i];
-               if ( ! info ) 
-                       continue;
-               if ( len >= PAGE_SIZE - 80 )
-                       len += sprintf ( buf + len, "terminated...\n");
-               len += sprintf ( buf + len,
-                                "%04X %3d %5d /dev/dasd%c",
-                                dasd_info[i]->info.devno,
-                                DASD_MAJOR,
-                                i << PARTN_BITS,
-                                'a' + i );
-               switch (atomic_read (&info->status)) {
-               case DASD_INFO_STATUS_UNKNOWN:
-                       len += sprintf (buf + len, " unknown");
-                       break;
-               case DASD_INFO_STATUS_DETECTED:
-                       len += sprintf (buf + len, "   avail");
-                       break;
-               case DASD_INFO_STATUS_ANALYSED:
-                       len += sprintf (buf + len, "     n/f");
-                       break;
-               default:
-                       len += sprintf (buf + len, " %7d",
-                                        info->sizes.bp_block);
-               }
-               len += sprintf ( buf + len, "\n");
-       } 
-       return len;
-}
-
-void 
-dasd_proc_add_node (int di) 
-{
-}
diff --git a/drivers/s390/block/dasd_profile.c b/drivers/s390/block/dasd_profile.c
deleted file mode 100644 (file)
index 71400d0..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-
-#include <linux/mm.h>
-#include <asm/spinlock.h>
-
-#include <linux/dasd.h>
-
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd_profile:"
-
-static long dasd_io_reqs=0; /* number of requests processed at all */
-static long dasd_io_secs[16]; /* histogram of request's sizes */
-static long dasd_io_times[16]; /* histogram of requests's times */
-static long dasd_io_timps[16]; /* histogram of requests's times per sector */
-static long dasd_io_time1[16]; /* histogram of time from build to start */
-static long dasd_io_time2[16]; /* histogram of time from start to irq */
-static long dasd_io_time2ps[16]; /* histogram of time from start to irq */
-static long dasd_io_time3[16]; /* histogram of time from irq to end */
-
-void
-dasd_profile_add ( cqr_t *cqr )
-{
-       int ind;
-       long strtime,irqtime,endtime,tottime;
-       long tottimeps,sectors;
-       long help;
-       if ( ! cqr -> req ) 
-         return;
-       sectors = cqr -> req -> nr_sectors;
-       strtime = ((cqr->startclk - cqr->buildclk) >> 12);
-       irqtime = ((cqr->stopclk - cqr->startclk) >> 12);
-       endtime = ((cqr->endclk - cqr->stopclk) >> 12);
-       tottime = ((cqr->endclk - cqr->buildclk) >> 12);
-       tottimeps = tottime / sectors;
-
-       if (! dasd_io_reqs ++){
-         for ( ind = 0; ind < 16; ind ++) {
-               dasd_io_secs[ind] = 0;
-               dasd_io_times[ind]=0;
-               dasd_io_timps[ind]=0;
-               dasd_io_time1[ind]=0;
-               dasd_io_time2[ind]=0;
-               dasd_io_time2ps[ind]=0;
-               dasd_io_time3[ind]=0;
-         }
-       };
-       
-       for ( ind = 0, help = sectors >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_secs[ind] ++;
-
-       for ( ind = 0, help = tottime >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_times[ind] ++;
-
-       for ( ind = 0, help = tottimeps >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_timps[ind] ++;
-
-       for ( ind = 0, help = strtime >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_time1[ind] ++;
-
-       for ( ind = 0, help = irqtime >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_time2[ind] ++;
-
-       for ( ind = 0, help = (irqtime/sectors) >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_time2ps[ind] ++;
-
-       for ( ind = 0, help = endtime >> 3; 
-             ind < 15 && help; 
-             help = help >> 1,ind ++);
-       dasd_io_time3[ind] ++;
-}
-
-int 
-dasd_proc_read_statistics ( char * buf, char **start, 
-                           off_t off, int len, int d)
-{
-       int i;
-       int shift, help;
-       
-       for ( shift = 0, help = dasd_io_reqs; 
-             help > 8192; 
-             help = help >> 1,shift ++);
-       len = sprintf ( buf, "%ld dasd I/O requests\n", dasd_io_reqs); 
-       len += sprintf ( buf+len, "__<4 ___8 __16 __32 __64 _128 _256 _512 __1k __2k __4k __8k _16k _32k _64k >64k\n");
-       len += sprintf ( buf+len, "Histogram of sizes (512B secs)\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_secs[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O times\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_times[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O times per sector\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_timps[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O time till ssch\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_time1[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_time2[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O time between ssch and irq per sector\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_time2ps[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       len += sprintf ( buf+len, "Histogram of I/O time between irq and end\n");
-       for ( i = 0; i < 16; i ++) {
-               len += sprintf ( buf+len, "%4ld ",dasd_io_time3[i] >> shift );
-       }
-       len += sprintf ( buf+len, "\n");
-       return len;
-}
-typedef
-struct {
-       union {
-               unsigned long long  clock;
-               struct {
-                       unsigned int ts1;
-                       unsigned int ts2 : 20;
-                       unsigned int unused : 8;
-                       unsigned int cpu : 4;
-               } __attribute__ ((packed)) s;
-       } __attribute__ ((packed)) u;
-       unsigned long caller_address;
-       unsigned long tag;
-} __attribute__ ((packed))
-
-dasd_debug_entry;
-
-static dasd_debug_entry *dasd_debug_area = NULL;
-static dasd_debug_entry *dasd_debug_actual;
-static spinlock_t debug_lock = SPIN_LOCK_UNLOCKED;
-
-void 
-dasd_debug ( unsigned long tag )
-{
-       long flags;
-       dasd_debug_entry *d;
-       /* initialize in first call ... */
-       if ( ! dasd_debug_area ) {
-               dasd_debug_actual = dasd_debug_area = 
-                   (dasd_debug_entry *) get_free_page (GFP_ATOMIC);
-               if ( ! dasd_debug_area ) {
-                       PRINT_WARN("No debug area allocated\n");
-                       return;
-               }
-               memset (dasd_debug_area,0,PAGE_SIZE);
-       }
-       /* renormalize to page */
-       spin_lock_irqsave(&debug_lock,flags);
-       dasd_debug_actual = (dasd_debug_entry *)
-               ( (unsigned long) dasd_debug_area +
-                 ( ( (unsigned long)dasd_debug_actual -
-                     (unsigned long)dasd_debug_area ) % PAGE_SIZE ) );
-       d = dasd_debug_actual ++;
-       spin_unlock_irqrestore(&debug_lock,flags);
-       /* write CPUID to lowest 12 bits of clock... */
-       __asm__ __volatile__ ( "STCK  %0"
-                              :"=m" (d->u.clock));
-       d->tag = tag;
-       d->caller_address = (unsigned long) __builtin_return_address (0);
-       d->u.s.cpu = smp_processor_id();
-}
-
-int 
-dasd_proc_read_debug ( char * buf, char **start, 
-                      off_t off, int len, int dd)
-{
-       dasd_debug_entry *d;
-       char tag[9] =
-       {0,};
-       long flags;
-       spin_lock_irqsave(&debug_lock,flags);
-       len = 0;
-               for( d = dasd_debug_area; 
-            len < 4068 ;
-            d ++ ) {
-               if ( *(char*)(&d->tag) == 'D' ) {
-                       memcpy(tag,&(d->tag),4);
-                       tag[4]=0;
-               } else {
-                       sprintf (tag, "%08lx", d->tag);
-                       tag[8]=0;
-               }
-               len += sprintf ( buf+len,
-                               "%x %08x%05x %08lx (%8s)\n",
-                                d->u.s.cpu, d->u.s.ts1, d->u.s.ts2,
-                                d->caller_address,tag);
-       }
-       spin_unlock_irqrestore(&debug_lock,flags);
-       return len;
-}
diff --git a/drivers/s390/block/dasd_setup.c b/drivers/s390/block/dasd_setup.c
deleted file mode 100644 (file)
index 504273a..0000000
+++ /dev/null
@@ -1,343 +0,0 @@
-/* 
- * File...........: linux/drivers/s390/block/dasd_setup.c
- * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                : Utz Bacher <utz.bacher@de.ibm.com>
- * Bugreports.to..: <Linux390@de.ibm.com>
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
- */
-
-#include <linux/ctype.h>
-#include <linux/malloc.h>
-
-#include <linux/dasd.h>
-#include "dasd_types.h"
-
-#define PRINTK_HEADER "dasd(setup):"
-
-#define MIN(a,b) (((a)<(b))?(a):(b))
-
-static int dasd_autodetect = 0;
-int dasd_probeonly = 1;
-static int dasd_count = 0;
-static int dasd_devno[DASD_MAX_DEVICES] =
-{0,};
-int dasd_force_mdsk_flag[DASD_MAX_DEVICES] =
-{0,};
-
-extern char *dasd[DASD_MAX_DEVICES];
-#ifdef CONFIG_DASD_MDSK
-extern char *dasd_force_mdsk[DASD_MAX_DEVICES];
-#endif
-
-typedef struct dasd_range {
-       int from, to;
-       struct dasd_range *next;
-} dasd_range;
-
-static dasd_range *first_range = NULL;
-
-void 
-dasd_add_devno_to_ranges (int devno)
-{
-       dasd_range *p, *prev;
-       for (p = first_range; p; prev = p, p = prev->next) {
-               if (devno >= p->from && devno <= p->to) {
-                       PRINT_WARN ("devno %04X already in range %04X-%04X\n",
-                                   devno, p->from, p->to);
-                       return;
-               }
-               if (devno == (p->from - 1)) {
-                       p->from--;
-                       return;
-               }
-               if (devno == (p->to + 1)) {
-                       p->to++;
-                       return;
-               }
-       }
-       prev = kmalloc (sizeof (dasd_range), GFP_ATOMIC);
-       prev->from = prev->to = devno;
-       if (!first_range) {
-               first_range = prev;
-       }
-       return;
-}
-
-int
-dasd_proc_print_probed_ranges (char *buf, char **start, off_t off, int len, int d)
-{
-       dasd_range *p;
-       len = sprintf (buf, "Probed ranges of the DASD driver\n");
-       for (p = first_range; p; p = p->next) {
-               if (len >= PAGE_SIZE - 80)
-                       len += sprintf (buf + len, "terminated...\n");
-               if (p != first_range) {
-                       len += sprintf (buf + len, ",");
-               }
-               if (p->from == p->to) {
-                       len += sprintf (buf + len, "%04x", p->from);
-               } else {
-                       len += sprintf (buf + len, "%04x-%04x",
-                                       p->from, p->to);
-               }
-       }
-       len += sprintf (buf + len, "\n");
-       return len;
-}
-
-static int
-dasd_get_hexdigit (char c)
-{
-       if ((c >= '0') && (c <= '9'))
-               return c - '0';
-       if ((c >= 'a') && (c <= 'f'))
-               return c + 10 - 'a';
-       if ((c >= 'A') && (c <= 'F'))
-               return c + 10 - 'A';
-       return -1;
-}
-
-/* sets the string pointer after the next comma */
-static void
-dasd_scan_for_next_comma (char **strptr)
-{
-       while (((**strptr) != ',') && (**strptr))
-               (*strptr)++;
-
-       /* set the position AFTER the comma */
-       if (**strptr == ',')
-               (*strptr)++;
-}
-
-/*sets the string pointer after the next comma, if a parse error occured */
-static int
-dasd_get_next_int (char **strptr)
-{
-       int j, i = -1;          /* for cosmetic reasons first -1, then 0 */
-       if (isxdigit (**strptr)) {
-               for (i = 0; isxdigit (**strptr);) {
-                       i <<= 4;
-                       j = dasd_get_hexdigit (**strptr);
-                       if (j == -1) {
-                               PRINT_ERR ("no integer: skipping range.\n");
-                               dasd_scan_for_next_comma (strptr);
-                               i = -1;
-                               break;
-                       }
-                       i += j;
-                       (*strptr)++;
-                       if (i > 0xffff) {
-                               PRINT_ERR (" value too big, skipping range.\n");
-                               dasd_scan_for_next_comma (strptr);
-                               i = -1;
-                               break;
-                       }
-               }
-       }
-       return i;
-}
-
-int
-devindex_from_devno (int devno)
-{
-       int i;
-       if (dasd_probeonly) {
-               return 0;
-       }
-       for (i = 0; i < dasd_count; i++) {
-               if (dasd_devno[i] == devno)
-                       return i;
-       }
-       if (dasd_autodetect) {
-               if (dasd_count < DASD_MAX_DEVICES) {
-                       dasd_devno[dasd_count] = devno;
-                       return dasd_count++;
-               }
-               return -EOVERFLOW;
-       }
-       return -ENODEV;
-}
-
-/* returns 1, if dasd_no is in the specified ranges, otherwise 0 */
-int
-dasd_is_accessible (int devno)
-{
-       return (devindex_from_devno (devno) >= 0);
-}
-
-/* dasd_insert_range skips ranges, if the start or the end is -1 */
-void
-dasd_insert_range (int start, int end)
-{
-       int curr;
-       if (dasd_count >= DASD_MAX_DEVICES) {
-               PRINT_ERR (" too many devices specified, ignoring some.\n");
-               return;
-       }
-       if ((start == -1) || (end == -1)) {
-               PRINT_ERR
-                   ("invalid format of parameter, skipping range\n");
-               return;
-       }
-       if (end < start) {
-               PRINT_ERR (" ignoring range from %x to %x - start value " \
-                          "must be less than end value.\n", start, end);
-               return;
-       }
-/* concurrent execution would be critical, but will not occur here */
-       for (curr = start; curr <= end; curr++) {
-               if (dasd_is_accessible (curr)) {
-                       PRINT_WARN (" %x is already in list as device %d\n",
-                                   curr, devindex_from_devno (curr));
-               }
-               dasd_devno[dasd_count] = curr;
-               dasd_count++;
-               if (dasd_count >= DASD_MAX_DEVICES) {
-                       PRINT_ERR (" too many devices specified, ignoring some.\n");
-                       break;
-               }
-       }
-       PRINT_INFO (" added dasd range from %x to %x.\n",
-                   start, dasd_devno[dasd_count - 1]);
-
-}
-
-void
-dasd_setup (char *str, int *ints)
-{
-       int devno, devno2;
-       static const char *adstring = "autodetect";
-       static const char *prstring = "probeonly";
-       if (!strncmp (str, prstring,
-                     MIN (strlen (str), strlen (prstring)))) {
-               dasd_autodetect = 1;
-               return;
-       }
-       if (!strncmp (str, adstring,
-                     MIN (strlen (str), strlen (adstring)))) {
-               dasd_autodetect = 1;
-               dasd_probeonly = 0;
-               return;
-       }
-       dasd_probeonly = 0;
-       while (*str && *str != 1) {
-               if (!isxdigit (*str)) {
-                       str++;  /* to avoid looping on two commas */
-                       PRINT_ERR (" kernel parameter in invalid format.\n");
-                       continue;
-               }
-               devno = dasd_get_next_int (&str);
-
-               /* range was skipped? -> scan for comma has been done */
-               if (devno == -1)
-                       continue;
-
-               if (*str == ',') {
-                       str++;
-                       dasd_insert_range (devno, devno);
-                       continue;
-               }
-               if (*str == '-') {
-                       str++;
-                       devno2 = dasd_get_next_int (&str);
-                       if (devno2 == -1) {
-                               PRINT_ERR (" invalid character in " \
-                                          "kernel parameters.");
-                       } else {
-                               dasd_insert_range (devno, devno2);
-                       }
-                       dasd_scan_for_next_comma (&str);
-                       continue;
-               }
-               if (*str == 0) {
-                       dasd_insert_range (devno, devno);
-                       break;
-               }
-               PRINT_ERR (" unexpected character in kernel parameter, " \
-                          "skipping range.\n");
-       }
-}
-#ifdef CONFIG_DASD_MDSK
-int dasd_force_mdsk_flag[DASD_MAX_DEVICES];
-
-/*
- * Parameter parsing function, called from init/main.c
- * size    : size in kbyte
- * offset  : offset after which minidisk is available
- * blksize : blocksize minidisk is formated
- * Format is: mdisk=<vdev>,<vdev>,...
- */
-void
-dasd_mdsk_setup (char *str, int *ints)
-{
-       int devno, devno2;
-       int di, i;
-
-       while (*str && *str != 1) {
-               if (!isxdigit (*str)) {
-                       str++;  /* to avoid looping on two commas */
-                       PRINT_ERR (" kernel parameter in invalid format.\n");
-                       continue;
-               }
-               devno = dasd_get_next_int (&str);
-
-               /* range was skipped? -> scan for comma has been done */
-               if (devno == -1)
-                       continue;
-
-               if (*str == ',') {
-                       str++;
-                       di = devindex_from_devno (devno);
-                       if (di >= DASD_MAX_DEVICES) {
-                               return;
-                       } else if (di < 0)
-                               dasd_insert_range (devno, devno);
-                       dasd_force_mdsk_flag[di] = 1;
-                       continue;
-               }
-               if (*str == '-') {
-                       str++;
-                       devno2 = dasd_get_next_int (&str);
-                       if (devno2 == -1) {
-                               PRINT_ERR (" invalid character in " \
-                                          "kernel parameters.");
-                       } else {
-                               for (i = devno; i <= devno2; i++) {
-                                       di = devindex_from_devno (i);
-                                       if (di >= DASD_MAX_DEVICES) {
-                                               return;
-                                       } else if (di < 0)
-                                               dasd_insert_range (i, i);
-                                       dasd_force_mdsk_flag[di] = 1;
-                               }
-                       }
-                       dasd_scan_for_next_comma (&str);
-                       continue;
-               }
-               if (*str == 0) {
-                       di = devindex_from_devno (devno);
-                       if (di >= DASD_MAX_DEVICES) {
-                               return;
-                       } else if (di < 0)
-                               dasd_insert_range (devno, devno);
-                       dasd_force_mdsk_flag[di] = 1;
-                       break;
-               }
-               PRINT_ERR (" unexpected character in kernel parameter, " \
-                          "skipping range.\n");
-       }
-}
-#endif
-
-#ifdef MODULE
-int
-dasd_parse_module_params (void)
-{
-       while (dasd)
-               dasd_setup (dasd, NULL);
-#ifdef CONFIG_DASD_MDSK
-       while (dasd_force_mdsk)
-               dasd_mdsk_setup (dasd_force_mdsk, NULL);
-#endif
-}
-#endif
diff --git a/drivers/s390/block/dasd_types.h b/drivers/s390/block/dasd_types.h
deleted file mode 100644 (file)
index 97bb8fa..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-
-/*
- * File...........: linux/drivers/s390/block/dasd_types.h
- * Author.........: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Created........: 08/31/1999
- * Last Modified..: 09/29/1999
- * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
-
- * List of Changes:
- - Initial Release as of 09/29/1999
-
- * Description
-
- * Restrictions
-
- * Known Bugs
-
- * Todo-List
-
- */
-
-#ifndef DASD_TYPES_H
-#define DASD_TYPES_H
-
-#include <linux/dasd.h>
-
-#include <linux/blkdev.h>
-
-#include <linux/hdreg.h>
-
-#include <asm/irq.h>
-
-#include "dasd_mdsk.h"
-
-#define ACS(where,from,to) if (atomic_compare_and_swap (from, to, &where)) {\
-       PRINT_WARN ("%s/%d atomic %s from %d(%s) to %d(%s) failed, was %d\n",\
-                   __FILE__,__LINE__,#where,from,#from,to,#to,\
-                    atomic_read (&where));\
-        atomic_set(&where,to);}
-
-#define CCW_DEFINE_EXTENT 0x63
-#define CCW_LOCATE_RECORD 0x43
-#define CCW_READ_DEVICE_CHARACTERISTICS 0x64
-
-typedef
-enum {
-       dasd_none = -1,
-#ifdef CONFIG_DASD_ECKD
-       dasd_eckd,
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_FBA
-       dasd_fba,
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_MDSK
-       dasd_mdsk,
-#endif                         /* CONFIG_DASD_MDSK */
-#ifdef CONFIG_DASD_CKD
-       dasd_ckd,
-#endif                         /* CONFIG_DASD_CKD */
-       dasd_end
-} dasd_type_t;
-
-typedef
-struct {
-       union {
-               __u8 c;
-               struct {
-                       unsigned char reserved:1;
-                       unsigned char overrunnable:1;
-                       unsigned char burst_byte:1;
-                       unsigned char data_chain:1;
-                       unsigned char zeros:4;
-               } __attribute__ ((packed)) bits;
-       } __attribute__ ((packed)) mode;
-       union {
-               __u8 c;
-               struct {
-                       unsigned char zero0:1;
-                       unsigned char removable:1;
-                       unsigned char shared:1;
-                       unsigned char zero1:1;
-                       unsigned char mam:1;
-                       unsigned char zeros:3;
-               } __attribute__ ((packed)) bits;
-       } __attribute__ ((packed)) features;
-       __u8 dev_class;
-       __u8 unit_type;
-       __u16 blk_size;
-       __u32 blk_per_cycl;
-       __u32 blk_per_bound;
-       __u32 blk_bdsa;
-       __u32 reserved0;
-       __u16 reserved1;
-       __u16 blk_ce;
-       __u32 reserved2;
-       __u16 reserved3;
-} __attribute__ ((packed, aligned (32))) 
-
-dasd_fba_characteristics_t;
-
-typedef
-struct {
-       __u16 cu_type;
-       struct {
-               unsigned char support:2;
-               unsigned char async:1;
-               unsigned char reserved:1;
-               unsigned char cache_info:1;
-               unsigned char model:3;
-       } __attribute__ ((packed)) cu_model;
-       __u16 dev_type;
-       __u8 dev_model;
-       struct {
-               unsigned char mult_burst:1;
-               unsigned char RT_in_LR:1;
-               unsigned char reserved1:1;
-               unsigned char RD_IN_LR:1;
-               unsigned char reserved2:4;
-               unsigned char reserved3:8;
-               unsigned char defect_wr:1;
-               unsigned char reserved4:2;
-               unsigned char striping:1;
-               unsigned char reserved5:4;
-               unsigned char cfw:1;
-               unsigned char reserved6:2;
-               unsigned char cache:1;
-               unsigned char dual_copy:1;
-               unsigned char dfw:1;
-               unsigned char reset_alleg:1;
-               unsigned char sense_down:1;
-       } __attribute__ ((packed)) facilities;
-       __u8 dev_class;
-       __u8 unit_type;
-       __u16 no_cyl;
-       __u16 trk_per_cyl;
-       __u8 sec_per_trk;
-       __u8 byte_per_track[3];
-       __u16 home_bytes;
-       __u8 formula;
-       union {
-               struct {
-                       __u8 f1;
-                       __u16 f2;
-                       __u16 f3;
-               } __attribute__ ((packed)) f_0x01;
-               struct {
-                       __u8 f1;
-                       __u8 f2;
-                       __u8 f3;
-                       __u8 f4;
-                       __u8 f5;
-               } __attribute__ ((packed)) f_0x02;
-       } __attribute__ ((packed)) factors;
-       __u16 first_alt_trk;
-       __u16 no_alt_trk;
-       __u16 first_dia_trk;
-       __u16 no_dia_trk;
-       __u16 first_sup_trk;
-       __u16 no_sup_trk;
-       __u8 MDR_ID;
-       __u8 OBR_ID;
-       __u8 director;
-       __u8 rd_trk_set;
-       __u16 max_rec_zero;
-       __u8 reserved1;
-       __u8 RWANY_in_LR;
-       __u8 factor6;
-       __u8 factor7;
-       __u8 factor8;
-       __u8 reserved2[3];
-       __u8 reserved3[10];
-} __attribute__ ((packed, aligned (32))) 
-
-dasd_eckd_characteristics_t;
-
-typedef struct {
-       u16 dev_nr;
-       u16 rdc_len;
-       u8 vdev_class;
-       u8 vdev_type;
-       u8 vdev_status;
-       u8 vdev_flags;
-       u8 rdev_class;
-       u8 rdev_type;
-       u8 rdev_model;
-       u8 rdev_features;
-} __attribute__ ((packed, aligned (32)))
-
-dasd_mdsk_characteristics_t;
-
-/* eckd count area */
-typedef struct {
-       __u16 cyl;
-       __u16 head;
-       __u8 record;
-       __u8 kl;
-       __u16 dl;
-} __attribute__ ((packed))
-
-eckd_count_t;
-
-#ifdef CONFIG_DASD_CKD
-struct dasd_ckd_characteristics {
-       char info[64];
-};
-
-#endif                         /* CONFIG_DASD_CKD */
-
-typedef
-union {
-       char __attribute__ ((aligned (32))) bytes[64];
-#ifdef CONFIG_DASD_FBA
-       dasd_fba_characteristics_t fba;
-#endif                         /* CONFIG_DASD_FBA */
-#ifdef CONFIG_DASD_CKD
-       struct dasd_ckd_characteristics ckd;
-#endif                         /* CONFIG_DASD_CKD */
-#ifdef CONFIG_DASD_ECKD
-       dasd_eckd_characteristics_t eckd;
-#endif                         /* CONFIG_DASD_ECKD */
-#ifdef CONFIG_DASD_MDSK
-       dasd_mdsk_characteristics_t mdsk;
-#endif                         /* CONFIG_DASD_ECKD */
-} __attribute__ ((aligned (32))) 
-
-dasd_characteristics_t;
-
-#define CQR_STATUS_EMPTY  0x00
-#define CQR_STATUS_FILLED 0x01
-#define CQR_STATUS_QUEUED 0x02
-#define CQR_STATUS_IN_IO  0x04
-#define CQR_STATUS_DONE   0x08
-#define CQR_STATUS_ERROR  0x10
-#define CQR_STATUS_ERP_PEND  0x20
-#define CQR_STATUS_ERP_ACTIVE  0x40
-#define CQR_STATUS_FAILED 0x80
-
-#define CQR_FLAGS_SLEEP   0x01
-#define CQR_FLAGS_WAIT    0x02
-#define CQR_FLAGS_NOLOCK  0x04
-#define CQR_FLAGS_NORETRY 0x08
-
-typedef
-struct cqr_t {
-       unsigned int    magic;    /* magic number should be "DASD" */
-       atomic_t status;        /* current status of request */
-       unsigned short retries; /* counter for retry in error case */
-       unsigned short cplength;/* Length of channel program  (CP) */
-       unsigned short devindex;/* device number */
-       unsigned short flags;    /* Flags for execution */
-       
-       void * data;            /* additional data area for CP */
-       ccw1_t *cpaddr;         /* Address of CP */
-       struct request *req;    /* backpointer to struct request */
-       struct cqr_t *next;     /* forward chain in chanq */
-       struct cqr_t *int4cqr;  /* which cqr ist the nect PCI for? */
-       unsigned long long buildclk;
-       unsigned long long startclk;
-       unsigned long long stopclk;
-       unsigned long long endclk;
-       devstat_t *dstat;       /* savearea for devstat */
-       spinlock_t lock;
-       int options;
-} __attribute__ ((packed)) 
-
-cqr_t;
-
-typedef
-struct {
-       unsigned long int kbytes;
-       unsigned int bp_sector;
-       unsigned int bp_block;
-       unsigned int blocks;
-       unsigned int s2b_shift;
-       unsigned int label_block;
-} dasd_sizes_t;
-
-#define DASD_CHANQ_ACTIVE 0x01
-#define DASD_CHANQ_BUSY 0x02
-#define DASD_REQUEST_Q_BROKEN 0x04
-
-typedef
-struct dasd_chanq_t {
-       volatile cqr_t *head;
-       volatile cqr_t *tail;
-       spinlock_t q_lock;      /* lock for queue operations */
-       spinlock_t f_lock;      /* lock for flag operations */
-       int queued_requests;
-       atomic_t flags;
-       atomic_t dirty_requests;
-       struct dasd_chanq_t *next_q;    /* pointer to next queue */
-} __attribute__ ((packed, aligned (16))) 
-
-dasd_chanq_t;
-
-#define DASD_INFO_STATUS_UNKNOWN 0x00  /* nothing known about DASD */
-#define DASD_INFO_STATUS_DETECTED 0x01 /* DASD identified as DASD, irq taken */
-#define DASD_INFO_STATUS_ANALYSED 0x02 /* first block read, filled sizes */
-#define DASD_INFO_STATUS_FORMATTED 0x04                /* identified valid format */
-#define DASD_INFO_STATUS_PARTITIONED 0x08      /* identified partitions */
-
-typedef
-struct dasd_information_t {
-       devstat_t dev_status;
-       dasd_characteristics_t *rdc_data;
-       dasd_volume_label_t *label;
-       dasd_type_t type;
-       dev_info_t info;
-       dasd_sizes_t sizes;
-       dasd_chanq_t queue;
-       int open_count;
-       spinlock_t lock;
-       struct semaphore sem;
-       atomic_t status;
-       int irq;
-       mdsk_setup_data_t *mdsk_setup;
-       struct proc_dir_entry *proc_device;
-       union {
-               struct {
-                       eckd_count_t count_data;
-               } eckd;
-               struct {
-                       char dummy;
-               } fba;
-               struct {
-                       mdsk_init_io_t iib;
-                       mdsk_rw_io_t iob;
-                       mdsk_setup_data_t setup;
-                       long *label;
-               } mdsk;
-               struct {
-                       char dummy;
-               } ckd;
-       } private;
-       struct wait_queue *wait_q;
-} dasd_information_t;
-
-extern dasd_information_t *dasd_info[];
-
-#include "dasd_erp.h"
-
-typedef
-struct {
-       int (*ck_devinfo) (dev_info_t *);
-       cqr_t *(*get_req_ccw) (int, struct request *);
-       int (*ck_characteristics) (dasd_characteristics_t *);
-       cqr_t *(*fill_sizes_first) (int);
-       int (*fill_sizes_last) (int);
-       int (*dasd_format) (int, format_data_t *);
-       void (*fill_geometry) (int, struct hd_geometry *);
-        dasd_era_t (*erp_examine) (cqr_t *, devstat_t *);
-} dasd_operations_t;
-
-extern dasd_operations_t *dasd_disciplines[];
-
-/* Prototypes */
-int dasd_start_IO (cqr_t * cqr);
-
-#endif                         /* DASD_TYPES_H */
diff --git a/drivers/s390/ccwcache.c b/drivers/s390/ccwcache.c
new file mode 100644 (file)
index 0000000..7c5b758
--- /dev/null
@@ -0,0 +1,381 @@
+/* 
+   * File...........: linux/drivers/s390/block/ccwcache.c
+   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+   * Bugreports.to..: <Linux390@de.ibm.com>
+   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
+   
+   * History of changes
+   * 07/10/00 moved ccwcache.h from linux/ to asm/
+ */
+
+#include <linux/malloc.h>
+#include <asm/debug.h>
+#include <asm/ccwcache.h>
+
+#include <asm/ebcdic.h>
+#include <asm/spinlock.h>
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif
+#define PRINTK_HEADER "ccwcache"
+
+#ifdef MODULE
+MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
+MODULE_DESCRIPTION ("Linux on S/390 CCW cache,"
+                   "Copyright 2000 IBM Corporation");
+EXPORT_NO_SYMBOLS; 
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
+#endif /* MODULE */
+
+
+/* pointer to list of allocated requests */
+static ccw_req_t *ccwreq_actual = NULL;
+
+/* pointer to debug area */
+static debug_info_t *debug_area = NULL;
+
+/* SECTION: Handling of the dynamically allocated kmem slabs */
+
+/* a name template for the cache-names */
+static char ccw_name_template[] = "ccwcache-\0\0\0\0"; /* fill name with zeroes! */
+/* the cache's names */
+static char ccw_cache_name[CCW_NUMBER_CACHES][sizeof(ccw_name_template)+1]; 
+/* the caches itself*/
+static kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES]; 
+
+/* SECTION: (de)allocation of ccw_req_t */
+
+/* 
+ * void dechain ( ccw_req_t *request )
+ * dechains the request from the ringbuffer
+ */
+
+static void 
+dechain ( ccw_req_t *request )
+{
+       /* Sanity checks */
+       if ( request == NULL ) {
+               printk( KERN_WARNING PRINTK_HEADER
+                       "Trying to deallocate NULL request\n");
+               return;
+       }
+       /* first deallocate request from list of allocates requests */
+       if ( request -> int_next && request -> int_prev ) {
+               if ( request -> int_next == request -> int_prev ) {
+                       ccwreq_actual = NULL;
+               } else {
+                       if ( ccwreq_actual == request ) {
+                               ccwreq_actual = request->int_next;
+                       }
+                       request->int_prev->int_next = request->int_next;
+                       request->int_next->int_prev = request->int_prev;
+               }
+       } else if ( request -> int_next || request -> int_prev ) {
+       }
+       return;
+}
+
+/* 
+ * ccw_req_t *ccw_alloc_request ( int cplength, int datasize )
+ * allocates a ccw_req_t, that 
+ * - can hold a CP of cplength CCWS
+ * - can hold additional data up to datasize 
+ */
+ccw_req_t *
+ccw_alloc_request ( char *magic, int cplength, int datasize )
+{
+       ccw_req_t * request = NULL;
+       int cachind = 0;
+       int size_needed = 0;
+
+       debug_text_event ( debug_area, 1, "ALLC");
+       if ( magic ) {
+               debug_text_event ( debug_area, 1, magic);
+       }
+       debug_event ( debug_area, 1, cplength);
+       debug_event ( debug_area, 1, datasize);
+
+       /* Sanity checks */
+       if ( cplength == 0 ) {
+               printk (KERN_DEBUG PRINTK_HEADER
+                       "called ccw_alloc_request with cplength of 0 from %p\n",
+                            __builtin_return_address(0));
+               return NULL;
+       }
+       if ( (cplength << 3 ) > PAGE_SIZE ) {
+               printk(KERN_WARNING PRINTK_HEADER
+                      "Channel program to large to fit on one page\n");
+               return NULL;
+       }
+       if ( datasize > PAGE_SIZE ) {
+               printk(KERN_WARNING PRINTK_HEADER
+                      "Data size to large to fit on one page\n");
+               return NULL;
+       }
+       
+       /* Try to keep things together in memory */
+       if ( sizeof (ccw_req_t) + 
+            (((datasize + 7) >> 3) << 3) +  /* align upper end of data to 8 */
+            (cplength << 3 ) < PAGE_SIZE ) {
+               /* All fit on one page, is preferred. */
+               size_needed = sizeof (ccw_req_t) + datasize + (cplength << 3 );
+       } else if ( sizeof (ccw_req_t) + (cplength << 3 ) < PAGE_SIZE ) {
+               /* Try to keep CCWs with request */
+               size_needed = sizeof (ccw_req_t) + (cplength << 3 );
+       } else if ( sizeof (ccw_req_t) + datasize < PAGE_SIZE ) {
+               /* Try to keep at least the data with request */
+               size_needed = sizeof (ccw_req_t) + datasize;
+       } else {
+               /* Fall back to hold only the request in cache */
+               size_needed = sizeof (ccw_req_t);
+       }
+       /* determine cache index for the requested size */
+       for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
+          if ( size_needed < (SMALLEST_SLAB << cachind) ) 
+                       break;
+       }
+       /* Try to fulfill the request from a cache */
+       while (  cachind < CCW_NUMBER_CACHES ) { /* Now try to get an entry from a cache above or equal to cachind */
+         if ( ccw_cache[cachind] == NULL ){
+           printk("cache=%p index %d\n",cachind,cachind);
+         }
+         request = kmem_cache_alloc ( ccw_cache[cachind], GFP_ATOMIC );
+         if ( request != NULL ) {
+           memset ( request, 0, (SMALLEST_SLAB << cachind));
+           request->cache = ccw_cache[cachind];
+           break;
+         } else {
+           printk (KERN_DEBUG PRINTK_HEADER "Proceeding to next cache");
+         }
+         cachind++;
+       } 
+       /* if no success, fall back to kmalloc */
+       if ( request == NULL ) {
+         printk (KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc");
+               request = kmalloc ( sizeof(ccw_req_t), GFP_ATOMIC );
+               if ( request != NULL ) {
+                       memset ( request, 0, sizeof(ccw_req_t));
+               }
+       }
+       /* Initialize request */
+       if ( request == NULL ) {  
+               printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate request");
+       } else {
+               if ( request -> cache != NULL ) {
+                       /* Three cases when coming from a cache */
+                       if ( sizeof (ccw_req_t) + 
+                            (((datasize + 7) >> 3) << 3) +
+                            (cplength << 3 ) < 
+                            PAGE_SIZE ) {
+                               request->data= (void*)(request + 1);
+                               request->cpaddr= (ccw1_t *)(((((long)(request + 1))+ 
+                                                            datasize + 7)
+                                                           >> 3) << 3);
+                       } else if ( sizeof (ccw_req_t) + (cplength << 3 ) < 
+                                   PAGE_SIZE ) {
+                               request->cpaddr=(ccw1_t *)(((((long)(request)) + 
+                                                            sizeof(ccw_req_t) + 7)
+                                                           >> 3) << 3);
+                       } else if ( sizeof (ccw_req_t) + datasize < PAGE_SIZE ) {
+                               request->data= (void *)(request + 1);
+                       } else {} 
+               }
+               /* Have the rest be done by kmalloc */
+               if ( request -> cpaddr == NULL ) {
+                       printk(KERN_DEBUG PRINTK_HEADER "Falling back to kmalloc for CCW area\n");
+                       request->cpaddr=(ccw1_t *) kmalloc(sizeof(ccw1_t) * cplength,
+                                                         GFP_ATOMIC);
+                       if ( request -> cpaddr == NULL ) {
+                               printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate ccw area\n");
+                               ccw_free_request(request);
+                               return NULL;
+                       }
+               }
+               if ( request -> data == NULL ) {
+                       printk(KERN_DEBUG PRINTK_HEADER"Falling back to kmalloc for data area\n");
+                       request->data=(void *)kmalloc(datasize, GFP_ATOMIC);
+                       if ( request -> data == NULL ) {
+                               printk(KERN_WARNING PRINTK_HEADER "Couldn't allocate data area\n");
+                               ccw_free_request(request);
+                               return NULL;
+                       }
+               }
+               memset ( request->data,0,datasize );
+               memset ( request->cpaddr,0,cplength*sizeof(ccw1_t) );
+               if ( magic ) {
+                       strncpy ( (char *)(&request->magic), magic, 4);
+               }
+               else {
+                       strncpy ( (char *)(&request->magic), "CCWC", 4);
+               }
+               ASCEBC((char *)(&request->magic),4);
+               request -> cplength = cplength;
+               request -> datasize = datasize;
+               /* enqueue request to list of allocated requests */
+               if ( ccwreq_actual == NULL ) { /* queue empty */
+                       ccwreq_actual = request;
+                       request->int_prev = ccwreq_actual;
+                       request->int_next = ccwreq_actual;
+               } else {
+                       request->int_next = ccwreq_actual;
+                       request->int_prev = ccwreq_actual->int_prev;
+                       request->int_prev->int_next = request;
+                       request->int_next->int_prev = request;
+               }
+       }
+       debug_event ( debug_area, 1, (long)request);
+       return request;
+}
+
+/* 
+ * void ccw_free_request ( ccw_req_t * )
+ * deallocates the ccw_req_t, given as argument
+ */
+
+void
+ccw_free_request ( ccw_req_t * request )
+{
+       int cachind;
+       int slabsize;
+
+       debug_text_event ( debug_area, 1, "FREE");
+       debug_event ( debug_area, 1, (long)request);
+       /* Sanity checks */
+       if ( request == NULL ) {
+               printk(KERN_DEBUG PRINTK_HEADER"Trying to deallocate NULL request\n");
+               return;
+       }
+       if ( request -> cache == NULL ) {
+               printk (KERN_WARNING PRINTK_HEADER "Deallocating uncached request\n");
+               if ( request -> data ) {
+                       kfree ( request -> data );
+               }
+               if ( request ->cpaddr ) {
+                       kfree ( request -> cpaddr );
+               }
+               dechain ( request);
+               kfree ( request );
+       } else {
+               /* Find which area has been allocated by kmalloc */
+               for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ )
+                       if ( request->cache == ccw_cache[cachind] )
+                               break;
+               if ( request->cache != ccw_cache[cachind] ) {
+                       printk(KERN_WARNING PRINTK_HEADER"Cannot find cache in list\n");
+               }
+               slabsize = SMALLEST_SLAB << cachind;
+               if ( request -> data &&
+                    (((unsigned long)(request -> data) >
+                      ((unsigned long)request) + slabsize) ||
+                     ((unsigned long)(request -> data) < 
+                      ((unsigned long)request)))) {
+                       kfree ( request -> data );
+               }
+               if ( request ->cpaddr &&
+                    (((unsigned long)(request -> cpaddr) >
+                      ((unsigned long)request) + slabsize) ||
+                     (unsigned long)(request -> cpaddr) < 
+                     ((unsigned long)request))) {
+                       kfree ( request -> cpaddr );
+               }
+               dechain ( request);
+               kmem_cache_free(request -> cache, request);
+       }
+}
+
+/* SECTION: initialization and cleanup functions */
+
+/* 
+ * ccwcache_init
+ * called as an initializer function for the ccw memory management
+ */
+
+int
+ccwcache_init (void)
+{
+       int rc = 0;
+       int cachind;
+
+       /* allocate a debug area */
+       debug_area = debug_register( "ccwcache", 2, 4);
+       if ( ! debug_area ) {
+               printk ( KERN_WARNING PRINTK_HEADER"cannot allocate debug area\n" );
+       } else {
+               printk (KERN_DEBUG PRINTK_HEADER "debug area is 0x%8p\n", debug_area );
+       }
+       debug_text_event ( debug_area, 0, "INIT");
+       
+       /* First allocate the kmem caches */
+       for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
+               int slabsize = SMALLEST_SLAB << cachind;
+               debug_text_event ( debug_area, 1, "allc");
+               debug_event ( debug_area, 1, slabsize);
+               sprintf ( ccw_cache_name[cachind], 
+                         "%s%d%c", ccw_name_template, slabsize, 0);
+               ccw_cache[cachind] = kmem_cache_create( ccw_cache_name[cachind], 
+                                                       slabsize, 0,
+                                                       SLAB_HWCACHE_ALIGN, 
+                                                       NULL, NULL );
+               debug_event ( debug_area, 1, (long)ccw_cache[cachind]);
+               if ( ! ccw_cache [cachind] ) {
+                       printk (KERN_WARNING PRINTK_HEADER "Allocation of CCW cache failed\n");
+               }
+       }
+       return rc;
+}
+
+/* 
+ * ccwcache_cleanup
+ * called as a cleanup function for the ccw memory management
+ */
+
+void
+ccwcache_cleanup (void)
+{
+       int cachind;
+
+       /* Shrink the caches, if available */
+       for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
+               if ( ccw_cache[cachind] ) {
+                       if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
+                               ccw_cache[cachind] = NULL;
+                       }
+               }
+       }
+       debug_unregister( debug_area ,"ccwcache");
+}
+
+#ifdef MODULE
+int
+init_module ( void )
+{
+       int rc;
+       int i;
+       rc = ccwcache_init();
+       for ( i = 0; i < 200; i ++) {
+               PRINT_INFO ("allocated %p\n",ccw_alloc_request("test",i,200-i));
+       }
+       return rc;
+}
+
+void
+cleanup_module ( void )
+{
+       while ( ccwreq_actual ) {
+               PRINT_INFO ("freeing %p\n",ccwreq_actual -> int_next);
+               ccw_free_request( ccwreq_actual -> int_next );
+               if ( ccwreq_actual ) {
+                       PRINT_INFO ("freeing %p\n",ccwreq_actual -> int_prev);
+                       ccw_free_request( ccwreq_actual -> int_prev );
+               }
+               if ( ccwreq_actual ) {
+                       PRINT_INFO ("freeing %p\n",ccwreq_actual);
+                       ccw_free_request( ccwreq_actual);
+               }
+       }
+       ccwcache_cleanup();
+}
+#endif /* MODULE */
index 4cb1bc3b71e3abeb0b7a9083d64098f5af5babf7..bfd9b95566d44cec0c2bef08f43f1bd1d01c6c27 100644 (file)
@@ -30,8 +30,9 @@
 #define RAW3215_INBUF_SIZE  256              /* input buffer size */
 #define RAW3215_MIN_SPACE   128              /* minimum free space for wakeup */
 #define RAW3215_MIN_WRITE   1024      /* min. length for immediate output */
-#define RAW3215_MAX_CCWLEN  3968      /* max. bytes to write with one ccw */
-#define RAW3215_NR_CCWS            ((RAW3215_BUFFER_SIZE/RAW3215_MAX_CCWLEN)+2)
+#define RAW3215_MAX_BYTES   3968      /* max. bytes to write with one ssch */
+#define RAW3215_MAX_NEWLINE 50        /* max. lines to write with one ssch */
+#define RAW3215_NR_CCWS            3
 #define RAW3215_TIMEOUT            HZ/10     /* time for delayed output */
 
 #define RAW3215_FIXED      1         /* 3215 console device is not be freed */
@@ -60,7 +61,8 @@ typedef enum {
  */
 typedef struct _raw3215_req {
        raw3215_type type;            /* type of the request */
-       int start, end;               /* start/end index into output buffer */
+       int start, len;               /* start index & len in output buffer */
+        int delayable;                /* indication to wait for more data */
        int residual;                 /* residual count for read request */
        ccw1_t ccws[RAW3215_NR_CCWS]; /* space for the channel program */
        struct _raw3215_info *info;   /* pointer to main structure */
@@ -74,6 +76,7 @@ typedef struct _raw3215_info {
        char *inbuf;                  /* pointer to input buffer */
        int head;                     /* first free byte in output buffer */
        int count;                    /* number of bytes in output buffer */
+        int written;                  /* number of bytes in write requests */
        devstat_t devstat;            /* device status structure for do_IO */
        struct tty_struct *tty;       /* pointer to tty structure if present */
        struct tq_struct tqueue;      /* task queue to bottom half */
@@ -104,7 +107,7 @@ __initfunc(void con3215_setup(char *str, char *ints))
 {
         int vdev;
 
-        vdev = simple_strtoul(str,&str,16);
+        vdev = simple_strtoul(str,&str,10);
         if (vdev >= 0 && vdev < 65536)
                 raw3215_condevice = vdev;
         return;
@@ -140,61 +143,83 @@ extern inline void raw3215_free_req(raw3215_req *req) {
 }
 
 /*
- * Get a write request structure. That is either a new or the last
- * queued write request. The request structure is set up in 
- * raw3215_mk_write_ccw.
+ * Set up a read request that reads up to 160 byte from the 3215 device.
+ * If there is a queued read request it is used, but that shouldn't happen
+ * because a 3215 terminal won't accept a new read before the old one is
+ * completed.
  */
-static raw3215_req *raw3215_mk_write_req(raw3215_info *raw)
+static void raw3215_mk_read_req(raw3215_info *raw)
 {
        raw3215_req *req;
+        ccw1_t *ccw;
 
-       /* check if there is a queued write request */
-       req = raw->queued_write;
+       /* there can only be ONE read request at a time */
+       req = raw->queued_read;
        if (req == NULL) {
-               /* no queued write request, use new req structure */
+               /* no queued read request, use new req structure */
                req = raw3215_alloc_req();
-               req->type = RAW3215_WRITE;
+               req->type = RAW3215_READ;
                req->info = raw;
-               req->start = raw->head;
-       } else
-               raw->queued_write = NULL;
-       return req;
+                raw->queued_read = req;
+       }
+
+        ccw = req->ccws;
+        ccw->cmd_code = 0x0A; /* read inquiry */
+        ccw->flags = 0x20;    /* ignore incorrect length */
+        ccw->count = 160;
+        ccw->cda = (void *) virt_to_phys(raw->inbuf);
 }
 
 /*
- * Get a read request structure. If there is a queued read request
- * it is used, but that shouldn't happen because a 3215 terminal
- * won't accept a new read before the old one is completed.
+ * Set up a write request with the information from the main structure.
+ * A ccw chain is created that writes as much as possible from the output
+ * buffer to the 3215 device. If a queued write exists it is replaced by
+ * the new, probably lengthened request.
  */
-static raw3215_req *raw3215_mk_read_req(raw3215_info *raw)
+static void raw3215_mk_write_req(raw3215_info *raw)
 {
        raw3215_req *req;
+       ccw1_t *ccw;
+       int len, count, ix, lines;
 
-       /* there can only be ONE read request at a time */
-       req = raw->queued_read;
+        if (raw->count <= raw->written)
+                return;
+        /* check if there is a queued write request */
+        req = raw->queued_write;
        if (req == NULL) {
-               /* no queued read request, use new req structure */
+                /* no queued write request, use new req structure */
                req = raw3215_alloc_req();
-               req->type = RAW3215_READ;
+                req->type = RAW3215_WRITE;
                req->info = raw;
-       } else
-               raw->queued_read = NULL;
-       return req;
+                raw->queued_write = req;
+        } else {
+                raw->written -= req->len;
 }
 
+       ccw = req->ccws;
+        req->start = (raw->head - raw->count + raw->written) &
+                     (RAW3215_BUFFER_SIZE - 1);
 /*
- * Set up a write request with the information from the main structure.
- * A ccw chain is created that writes everything in the output buffer
- * to the 3215 device.
+         * now we have to count newlines. We can at max accept
+         * RAW3215_MAX_NEWLINE newlines in a single ssch due to
+         * a restriction in VM
  */
-static int raw3215_mk_write_ccw(raw3215_info *raw, raw3215_req *req)
-{
-       ccw1_t *ccw;
-       int len, count, ix;
+        lines = 0;
+        ix = req->start;
+        while (lines < RAW3215_MAX_NEWLINE && ix != raw->head) {
+                if (raw->buffer[ix] == '\n')
+                        lines++;
+                ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1);
+        }
+       len = ((ix - 1 - req->start) & (RAW3215_BUFFER_SIZE - 1)) + 1;
+        if (len > RAW3215_MAX_BYTES)
+                len = RAW3215_MAX_BYTES;
+        req->len = len;
+        raw->written += len;
+
+        /* set the indication if we should try to enlarge this request */
+        req->delayable = (ix == raw->head) && (len < RAW3215_MIN_WRITE);
 
-       ccw = req->ccws;
-       req->end = (raw->head - 1) & (RAW3215_BUFFER_SIZE - 1);
-       len = ((req->end - req->start) & (RAW3215_BUFFER_SIZE - 1)) + 1;
        ix = req->start;
        while (len > 0) {
                if (ccw > req->ccws)
@@ -203,8 +228,7 @@ static int raw3215_mk_write_ccw(raw3215_info *raw, raw3215_req *req)
                ccw->flags = 0x20;    /* ignore incorrect length ind.  */
                ccw->cda =
                        (void *) virt_to_phys(raw->buffer + ix);
-               count = (len > RAW3215_MAX_CCWLEN) ? 
-                       RAW3215_MAX_CCWLEN : len;
+               count = len;
                if (ix + count > RAW3215_BUFFER_SIZE)
                        count = RAW3215_BUFFER_SIZE-ix;
                ccw->count = count;
@@ -212,21 +236,17 @@ static int raw3215_mk_write_ccw(raw3215_info *raw, raw3215_req *req)
                ix = (ix + count) & (RAW3215_BUFFER_SIZE - 1);
                ccw++;
        }
-       return len;
-}
-
 /*
- * Set up a read request that reads up to 160 byte from the 3215 device.
+         * Add a NOP to the channel program. 3215 devices are purely
+         * emulated and its much better to avoid the channel end 
+         * interrupt in this case.
  */
-static void raw3215_mk_read_ccw(raw3215_info *raw, raw3215_req *req)
-{
-       ccw1_t *ccw;
-
-       ccw = req->ccws;
-       ccw->cmd_code = 0x0A; /* read inquiry */
-       ccw->flags = 0x20;    /* ignore incorrect length */
-       ccw->count = 160;
-       ccw->cda = (void *) virt_to_phys(raw->inbuf);
+        if (ccw > req->ccws)
+                ccw[-1].flags |= 0x40; /* use command chaining */
+        ccw->cmd_code = 0x03; /* NOP */
+        ccw->flags = 0;
+        ccw->cda = 0;
+        ccw->count = 1;
 }
 
 /*
@@ -277,6 +297,7 @@ static void raw3215_timeout(unsigned long __data)
        if (raw->flags & RAW3215_TIMER_RUNS) {
                del_timer(&raw->timer);
                raw->flags &= ~RAW3215_TIMER_RUNS;
+                raw3215_mk_write_req(raw);
                raw3215_start_io(raw);
        }
        s390irq_spin_unlock_irqrestore(raw->irq, flags);
@@ -295,7 +316,7 @@ extern inline void raw3215_try_io(raw3215_info *raw)
        if (raw->queued_read != NULL)
                raw3215_start_io(raw);
        else if (raw->queued_write != NULL) {
-               if (raw->count >= RAW3215_MIN_WRITE ||
+               if ((raw->queued_write->delayable == 0) ||
                    (raw->flags & RAW3215_FLUSHING)) {
                        /* execute write requests bigger than minimum size */
                        raw3215_start_io(raw);
@@ -327,7 +348,8 @@ static void raw3215_softint(void *data)
 
        raw = (raw3215_info *) data;
        s390irq_spin_lock_irqsave(raw->irq, flags);
-       raw3215_try_io((raw3215_info *) data);
+        raw3215_mk_write_req(raw);
+        raw3215_try_io(raw);
         raw->flags &= ~RAW3215_BH_PENDING;
        s390irq_spin_unlock_irqrestore(raw->irq, flags);
        /* Check for pending message from raw3215_irq */
@@ -415,9 +437,7 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                if ((raw = raw3215_find_info(irq)) == NULL)
                        return;              /* That shouldn't happen ... */
                /* Setup a read request */
-               req = raw3215_mk_read_req(raw);
-               raw3215_mk_read_ccw(raw, req);
-               raw->queued_read = req;
+               raw3215_mk_read_req(raw);
                 if (MACHINE_IS_P390)
                         memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
                 raw3215_sched_bh(raw);
@@ -425,7 +445,8 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
        case 0x08:
        case 0x0C:
                /* Channel end interrupt. */
-               raw = req->info;
+               if ((raw = req->info) == NULL)
+                        return;              /* That shouldn't happen ... */
                if (req->type == RAW3215_READ) {
                        /* store residual count, then wait for device end */
                        req->residual = stat->rescnt;
@@ -434,7 +455,8 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                        break;
        case 0x04:
                /* Device end interrupt. */
-               raw = req->info;
+                if ((raw = req->info) == NULL)
+                        return;              /* That shouldn't happen ... */
                if (req->type == RAW3215_READ && raw->tty != NULL) {
                        tty = raw->tty;
                        count = 160 - req->residual;
@@ -493,8 +515,8 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                                tty_flip_buffer_push(raw->tty);
                        }
                } else if (req->type == RAW3215_WRITE) {
-                       raw->count -= ((req->end - req->start) &
-                                      (RAW3215_BUFFER_SIZE - 1)) + 1;
+                       raw->count -= req->len;
+                        raw->written -= req->len;
                }
                raw->flags &= ~RAW3215_WORKING;
                raw3215_free_req(req);
@@ -511,11 +533,11 @@ static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
                        /* Strange interrupt, I'll do my best to clean up */
                 if ((raw = raw3215_find_info(irq)) == NULL)
                         return;              /* That shouldn't happen ... */
-                if (raw == NULL) break;
                if (req != NULL && req->type != RAW3215_FREE) {
-                       if (req->type == RAW3215_WRITE) 
-                               raw->count -= ((req->end - req->start) &
-                                                   (RAW3215_BUFFER_SIZE-1))+1;
+                       if (req->type == RAW3215_WRITE) {
+                               raw->count -= req->len;
+                                raw->written -= req->len;
+                        }
                         raw->flags &= ~RAW3215_WORKING;
                         raw3215_free_req(req);
                        }
@@ -536,7 +558,6 @@ static int
 raw3215_write(raw3215_info *raw, const char *str,
              int from_user, unsigned int length)
 {
-       raw3215_req *req;
        unsigned long flags;
        int ret, c;
        int count;
@@ -550,14 +571,15 @@ raw3215_write(raw3215_info *raw, const char *str,
 
                while (RAW3215_BUFFER_SIZE - raw->count < count) {
                        /* there might be a request pending */
+                        raw3215_mk_write_req(raw);
                        raw3215_try_io(raw);
                        if (wait_cons_dev(raw->irq) != 0) {
                                /* that shouldn't happen */
                                raw->count = 0;
+                                raw->written = 0;
                        } 
                }
 
-               req = raw3215_mk_write_req(raw);
                /* copy string to output buffer and convert it to EBCDIC */
                if (from_user) {
                        while (1) {
@@ -598,12 +620,12 @@ raw3215_write(raw3215_info *raw, const char *str,
                                ret += c;
                        }
                }
-               raw3215_mk_write_ccw(raw, req);
-               raw->queued_write = req;
+                if (!(raw->flags & RAW3215_WORKING)) {
+                        raw3215_mk_write_req(raw);
                /* start or queue request */
                raw3215_try_io(raw);
+                }
                s390irq_spin_unlock_irqrestore(raw->irq, flags);
-
        }
 
        return ret;
@@ -614,27 +636,28 @@ raw3215_write(raw3215_info *raw, const char *str,
  */
 static void raw3215_putchar(raw3215_info *raw, unsigned char ch)
 {
-       raw3215_req *req;
        unsigned long flags;
 
        s390irq_spin_lock_irqsave(raw->irq, flags);
        while (RAW3215_BUFFER_SIZE - raw->count < 1) {
                /* there might be a request pending */
+                raw3215_mk_write_req(raw);
                raw3215_try_io(raw);
                if (wait_cons_dev(raw->irq) != 0) {
                        /* that shouldn't happen */
                        raw->count = 0;
+                        raw->written = 0;
                }
        }
 
-       req = raw3215_mk_write_req(raw);
        raw->buffer[raw->head] = (char) _ascebc[(int) ch];
        raw->head = (raw->head + 1) & (RAW3215_BUFFER_SIZE - 1);
        raw->count++;
-       raw3215_mk_write_ccw(raw, req);
-       raw->queued_write = req;
+        if (!(raw->flags & RAW3215_WORKING)) {
+                raw3215_mk_write_req(raw);
        /* start or queue request */
        raw3215_try_io(raw);
+        }
        s390irq_spin_unlock_irqrestore(raw->irq, flags);
 }
 
@@ -781,6 +804,7 @@ void con3215_unblank(void)
                if (wait_cons_dev(raw->irq) != 0) {
                        /* that shouldn't happen */
                        raw->count = 0;
+                        raw->written = 0;
                }
                raw->flags &= ~RAW3215_FLUSHING;
        }
index 5e3944c4ba7f1f15d312316893dc7e3f0dbaca51..d32cad5ef2483179ef09178289d6872efc5e2cf3 100644 (file)
@@ -73,8 +73,6 @@ hwc_tty_open (struct tty_struct *tty,
        return 0;
 }
 
-#if 0
-
 static void 
 hwc_tty_close (struct tty_struct *tty,
                            struct file *filp)
@@ -84,11 +82,13 @@ hwc_tty_close (struct tty_struct *tty,
                        "do not close hwc tty because of wrong device number");
                return;
        }
+       if (tty->count > 1)
+               return;
+
        hwc_tty_data.tty = NULL;
 
        hwc_unregister_calls (&(hwc_tty_data.calls));
 }
-#endif
 
 static int 
 hwc_tty_write_room (struct tty_struct *tty)
@@ -316,7 +316,7 @@ hwc_tty_init (void)
        hwc_tty_driver.termios_locked = hwc_tty_termios_locked;
 
        hwc_tty_driver.open = hwc_tty_open;
-       hwc_tty_driver.close = NULL /* hwc_tty_close */;
+       hwc_tty_driver.close = hwc_tty_close;
        hwc_tty_driver.write = hwc_tty_write;
        hwc_tty_driver.put_char = hwc_tty_put_char;
        hwc_tty_driver.flush_chars = hwc_tty_flush_chars;
index dbe3cf2c96410307a75896f55ec2e84b93d1e49e..1b7580ad98129ecca8db904bd3a91719740840e1 100644 (file)
@@ -35,7 +35,7 @@
  *    0.50  Initial release shipped
  *    0.51  Bug fixes
  *          - CTC / ESCON network device can now handle up to 64 channels 
- *          - 3088-61 info message supperssed - CISCO 7206 - CLAW - ESCON 
+ *          - 3088-61 info message suppressed - CISCO 7206 - CLAW - ESCON 
  *          - 3088-62 info message suppressed - OSA/D   
  *          - channel: def ffffffed ... error message suppressed 
  *          - CTC / ESCON device was not recoverable after a lost connection with 
  *    0.52  Bug fixes 
  *          - Subchannel check message enhanced 
  *          - Read / Write retry routine check for CTC_STOP added  
+ *    0.53  Enhancement 
+ *          - Connect time changed from 150 to 300 seconds
+ *            This gives more a better chance to connect during IPL 
+ *    0.54  Bug fixes 
+ *          - Out of memory message enhanced 
+ *          - Zero buffer problem in ctc_irq_hb solved
+ *            A zero buffer could bring the ctc_irq_bh into a sk buffer allocation loop,
+ *            which could end in a out of memory situation.  
+ *    0.55  Bug fixes 
+ *          - Connect problems with systems which IPL later
+ *            SystemA is IPLed and issues a IFCONFIG ctcx against systemB which is currently
+ *            not available. When systemB comes up it is nearly inpossible to setup a 
+ *            connection.  
  */
 #include <linux/version.h>
 #include <linux/init.h>
@@ -617,6 +630,7 @@ static int ctc_buffer_alloc(struct channel *ctc) {
                         kfree(p);
                         return -ENOMEM;
                 }
+                p->block->length = 0; 
         }
    
         if (ctc->free_anchor == NULL) 
@@ -912,9 +926,14 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
         struct  ctc_priv  *privptr = NULL;
         net_device        *dev = NULL;    
         
-        ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+       /* ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI | CCW_FLAG_CC, 0, NULL},
+                                               {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}};    */
+                                               
+       ccw1_t            ccw_set_x_mode[2] = {{CCW_CMD_SET_EXTENDED, CCW_FLAG_SLI , 0, NULL},
                                                {CCW_CMD_NOOP, CCW_FLAG_SLI, 0, NULL}}; 
 
+
+
         devstat_t *devstat = ((devstat_t *)initparm);
 
         /* Bypass all 'unsolicited interrupts' */
@@ -990,6 +1009,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
                 case CTC_START_SELECT:
                         if (!ctc->flag & CTC_WRITE) {
                                 ctc->state = CTC_START_READ_TEST;
+                                ctc->free_anchor->block->length = 0;    
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc;
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1000,7 +1020,8 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
                         } else {
                                 ctc->state = CTC_START_WRITE_TEST;
                                 /* ADD HERE THE RIGHT PACKET TO ISSUE A ROUND TRIP - PART 1 */
-                                ctc->ccw[1].count = 0;
+                                ctc->free_anchor->block->length = 0;    
+                                ctc->ccw[1].count = 2;              /* Transfer only length */
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc; 
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags);
@@ -1072,6 +1093,7 @@ static void ctc_irq_handler (int irq, void *initparm, struct pt_regs *regs)
                         ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
 
                         if (ctc->free_anchor != NULL) {  
+                                ctc->free_anchor->block->length = 0;
                                 ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
                                 parm = (__u32) ctc;
                                 rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1195,8 +1217,9 @@ static void ctc_irq_bh (struct channel *ctc)
 
         while (ctc->proc_anchor != NULL) { 
 
-                lp = &ctc->proc_anchor->block->data;
+                if (ctc->proc_anchor->block->length != 0) {
 
+                        lp = &ctc->proc_anchor->block->data;
                 while ((__u8 *) lp < (__u8 *) &ctc->proc_anchor->block->length + ctc->proc_anchor->block->length) {
                         data_len = lp->length - PACKET_HEADER_LENGTH;
                         skb = dev_alloc_skb(data_len); 
@@ -1210,10 +1233,11 @@ static void ctc_irq_bh (struct channel *ctc)
                                 privptr->stats.rx_packets++;
                         } else {
                                 privptr->stats.rx_dropped++; 
-                                printk(KERN_WARNING "%s: is low on memory\n",dev->name);
+                                        printk(KERN_WARNING "%s: is low on memory (sk buffer)\n",dev->name);
                         }
                         (__u8 *)lp += lp->length;
                 }
+                }
 
                 s390irq_spin_lock_irqsave(ctc->irq, saveflags);
                 ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
@@ -1251,6 +1275,7 @@ static void ctc_read_retry (struct channel *ctc)
         if (ctc->state == CTC_STOP)
                 return;
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
+        ctc->free_anchor->block->length = 0;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->free_anchor->block);
         parm = (__u32) ctc; 
         rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1276,8 +1301,15 @@ static void ctc_write_retry (struct channel *ctc)
 #endif 
         if (ctc->state == CTC_STOP)
                 return;
+        while (ctc->proc_anchor != NULL) { 
+                ctc->proc_anchor->block->length = 0;
+                ctc_buffer_swap(&ctc->proc_anchor, &ctc->free_anchor);
+        } 
+
+        ctc_buffer_swap(&ctc->free_anchor, &ctc->proc_anchor);
         s390irq_spin_lock_irqsave(ctc->irq, saveflags);
-        ctc->ccw[1].count = 0;
+        ctc->ccw[1].count = 2;
         ctc->ccw[1].cda  = (char *)virt_to_phys(ctc->proc_anchor->block);
         parm = (__u32) ctc; 
         rc = do_IO (ctc->irq, &ctc->ccw[0], parm, 0xff, flags );
@@ -1354,7 +1386,7 @@ static int ctc_open(net_device *dev)
                 init_timer(&timer);
                 timer.function = (void *)ctc_timer; 
                 timer.data = (__u32)&privptr->channel[i];
-                timer.expires = jiffies + 150*HZ;                        /* time to connect with the remote side */
+                timer.expires = jiffies + 300*HZ;                        /* time to connect with the remote side */
                 add_timer(&timer);
 
                 s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
@@ -1382,13 +1414,13 @@ static int ctc_open(net_device *dev)
                 printk(KERN_INFO "%s: remote side is currently not ready\n", dev->name);
                 
                 for (i = 0; i < 2;  i++) {
-                        s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
+                     /* s390irq_spin_lock_irqsave(privptr->channel[i].irq, saveflags);
                         parm = (unsigned long) &privptr->channel[i];
                         privptr->channel[i].state = CTC_STOP;
-                        rc = halt_IO(privptr->channel[i].irq, parm, flags);
+                        rc = halt_IO(privptr->channel[i].irq, parm, flags); /
                         s390irq_spin_unlock_irqrestore(privptr->channel[i].irq, saveflags);
                         if (rc != 0)
-                                ccw_check_return_code(dev, rc);
+                                ccw_check_return_code(dev, rc);     */
                         for (j = 0; j < CTC_BLOCKS;  j++) 
                                 ctc_buffer_free(&privptr->channel[i]);
                 }
@@ -1421,7 +1453,6 @@ static void ctc_timer (struct channel *ctc)
 static int ctc_release(net_device *dev)
 {   
         int                rc;
-        int                x; 
         int                i;
         int                j;
         __u8               flags = 0x00;
index a2d2994c4cdc330d2cd65d3c289ae908427b2690..fcac4037c8fe50b45a4efb509e2670b1b43502b1 100644 (file)
@@ -7,8 +7,10 @@
  *    Author(s): Stefan Hegewald <hegewald@de.ibm.com>
  *               Hartmut Penner <hpenner@de.ibm.com> 
  * 
+ *    \r
  *    2.3 Updates Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  *                Martin Schwidefsky (schwidefsky@de.ibm.com)
+ *                Alan Altmark (Alan_Altmark@us.ibm.com)
  *                
 
  */
 
 
 
-
 #define DEBUG123
 #define MAX_DEVICES  10
 
+
 extern char _ascebc[];
 
 /* 
@@ -496,8 +498,6 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
   /* get own buffer: */
   extern_int_buffer = (INTERRUPT_T*) iucv_ext_int_buffer;
   
-  netif_enter_interrupt(dev);        /* lock ! */
-  
 #ifdef DEBUG
   printk(  "iucv: do_iucv_interrupt %x received; pathid: %02X\n",
           extern_int_buffer->iptype,extern_int_buffer->ippathid);
@@ -505,6 +505,14 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
   dumpit((char *)&extern_int_buffer[0],40);
 #endif
   
+  if (extern_int_buffer->iptype == 0x01)
+    dev = get_device_from_userid(&((char*) extern_int_buffer)[8]);
+  else
+    dev = get_device_from_pathid(extern_int_buffer->ippathid);
+
+  netif_enter_interrupt(dev);        /* lock ! */
+  privptr = (struct iucv_priv *)(dev->priv);
+  
   switch (extern_int_buffer->iptype)
     {
     case 0x01: /* connection pending ext interrrupt */
@@ -519,11 +527,7 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
        iucv_retrieve_buffer(glob_command_buffer);
        break;
       }
-#ifdef DEBUG
-      dumpit(&((char *)extern_int_buffer)[8],8);
-#endif
-      dev = get_device_from_userid(&((char*)extern_int_buffer)[8]);
-      privptr = (struct iucv_priv *)(dev->priv);
+
       privptr->pathid =  extern_int_buffer->ippathid;
       
 #ifdef DEBUG
@@ -542,8 +546,6 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
       if( extern_int_buffer->ipmsgtag !=0)
        {
          /* get ptr's to kernel struct with local & broadcast address */
-         dev = get_device_from_pathid(extern_int_buffer->ippathid);
-         privptr = (struct iucv_priv *)(dev->priv);
          indev = dev->ip_ptr;
          inaddr = (struct in_ifaddr*) indev->ifa_list;
        }
@@ -595,8 +597,6 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
                   (unsigned int)extern_int_buffer->ipaudit);
        }
       /* a transmission is over: tell we are no more busy */
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
       privptr->stats.tx_packets++;
       netif_wake_queue(dev);                /* transmission is no longer busy*/
       break;
@@ -607,8 +607,6 @@ void do_iucv_interrupt(struct pt_regs *regs, __u16 code)
 #ifdef DEBUG
       printk(  "message pending.\n");
 #endif
-      dev = get_device_from_pathid(extern_int_buffer->ippathid);
-      privptr = (struct iucv_priv *)(dev->priv);
       rcvptr = &privptr->receive_buffer[0];
       
       /* re-set receive buffer */
index 719a93d20c31ab78e445dec7f05086dc68f69173..a0312f958612c409a153c708ac3eeeb079effe03 100644 (file)
@@ -38,7 +38,7 @@ static __inline__ void atomic_set(atomic_t *v, int i)
 {
         __asm__ __volatile__("st  %1,%0\n\t"
                              "bcr 15,0"
-                             : : "m" (*v), "d" (i) : "memory");
+                             : "=m" (*v) : "d" (i) );
 }
 
 static __inline__ void atomic_add(int i, atomic_t *v)
@@ -48,7 +48,7 @@ static __inline__ void atomic_add(int i, atomic_t *v)
                              "   ar    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
@@ -58,7 +58,7 @@ static __inline__ void atomic_sub(int i, atomic_t *v)
                              "   sr    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (i) : "0", "1" );
+                             : "+m" (*v) : "d" (i) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
@@ -68,7 +68,7 @@ static __inline__ void atomic_inc(volatile atomic_t *v)
                              "   ahi   1,1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1" );
+                             : "+m" (*v) : : "0", "1", "cc" );
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
@@ -79,7 +79,7 @@ static __inline__ int atomic_inc_return(volatile atomic_t *v)
                              "   ahi   %1,1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i;
 }
 
@@ -90,7 +90,7 @@ static __inline__ void atomic_dec(volatile atomic_t *v)
                              "   ahi   1,-1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : : "0", "1" );
+                             : "+m" (*v) : : "0", "1", "cc" );
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
@@ -101,7 +101,7 @@ static __inline__ int atomic_dec_return(volatile atomic_t *v)
                              "   ahi   %1,-1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i;
 }
 
@@ -113,7 +113,7 @@ static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
                              "   ahi   %1,-1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0");
+                             : "+m" (*v), "=&d" (i) : : "0", "cc");
         return i == 0;
 }
 
@@ -124,7 +124,7 @@ static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
                              "   nr    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (~(mask)) : "0", "1" );
+                             : "+m" (*v) : "d" (~(mask)) : "0", "1", "cc" );
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
@@ -134,7 +134,7 @@ static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
                              "   or    1,%1\n"
                              "   cs    0,1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v) : "d" (mask) : "0", "1" );
+                             : "+m" (*v) : "d" (mask) : "0", "1", "cc" );
 }
 
 /*
@@ -153,7 +153,7 @@ atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
                 "0:"
                 : "=&r" (retval), "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "memory", "cc");
+                : "cc");
         return retval;
 }
 
@@ -169,13 +169,13 @@ atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
                 "   jl  0b\n"
                 : "+m" (*v)
                 : "d" (expected_oldval) , "d" (new_val)
-                : "memory", "cc", "1");
+                : "cc", "1");
 }
 
 /*
  * Increase and test if atomic counter > 0
  */
-extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v)
+extern __inline__ int atomic_inc_and_test_greater_zero(atomic_t *v)
 {
         int i;
         __asm__ __volatile__("   l     0,%0\n"
@@ -183,9 +183,16 @@ extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v)
                              "   ahi   %1,1\n"
                              "   cs    0,%1,%0\n"
                              "   jl    0b"
-                             : "+m" (*v), "=&d" (i) : : "0" );
+                             : "+m" (*v), "=&d" (i) : : "0", "cc" );
         return i > 0;
 }
 
+#define atomic_compare_and_swap_debug(where,from,to) \
+if (atomic_compare_and_swap ((from), (to), (where))) {\
+       printk (KERN_WARNING"%s/%d atomic counter:%s couldn't be changed from %d(%s) to %d(%s), was %d\n",\
+               __FILE__,__LINE__,#where,(from),#from,(to),#to,atomic_read (where));\
+        atomic_set(where,(to));\
+}
+
 #endif                                 /* __ARCH_S390_ATOMIC __            */
 
index 7c1f03f14d0ec1dd004fd4541ea2b6c8461f3b01..b852baeea70d426354de9561a5792545d9c2d87d 100644 (file)
@@ -79,8 +79,8 @@ extern __inline__ void set_bit_cs(int nr, volatile void * addr)
              "   nr    1,%0\n"         /* make shift value */
              "   xr    %0,1\n"
              "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   lhi   2,1\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   sll   2,0(1)\n"       /* make OR mask */
              "   l     %0,0(%1)\n"
              "0: lr    1,%0\n"         /* CS loop starts here */
@@ -109,8 +109,8 @@ extern __inline__ void clear_bit_cs(int nr, volatile void * addr)
              "   nr    1,%0\n"         /* make shift value */
              "   xr    %0,1\n"
              "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   lhi   2,1\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   sll   2,0(1)\n"
              "   x     2,%2\n"         /* make AND mask */
              "   l     %0,0(%1)\n"
@@ -139,8 +139,8 @@ extern __inline__ void change_bit_cs(int nr, volatile void * addr)
              "   nr    1,%0\n"         /* make shift value */
              "   xr    %0,1\n"
              "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   lhi   2,1\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   sll   2,0(1)\n"       /* make XR mask */
              "   l     %0,0(%1)\n"
              "0: lr    1,%0\n"         /* CS loop starts here */
@@ -168,8 +168,8 @@ extern __inline__ int test_and_set_bit_cs(int nr, volatile void * addr)
              "   nr    1,%0\n"         /* make shift value */
              "   xr    %0,1\n"
              "   srl   %0,3\n"
-             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   lhi   2,1\n"
+             "   la    %1,0(%0,%1)\n"  /* calc. address for CS */
              "   sll   2,0(1)\n"       /* make OR mask */
              "   l     %0,0(%1)\n"
              "0: lr    1,%0\n"         /* CS loop starts here */
@@ -788,7 +788,6 @@ extern int __inline__ ffs (int x)
 #define ext2_test_bit(nr, addr)      test_bit((nr)^24, addr)
 extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
 {
-        static const int mask = 0xffL;
         int res;
 
         if (!size)
@@ -806,6 +805,7 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
                 "   j    4f\n"
                 "1: l    1,0(2,%2)\n"
                 "   sll  2,3(0)\n"
+                "   lhi  0,0xff\n"
                 "   ahi  2,24\n"
                 "   tmh  1,0xFFFF\n"
                 "   jo   2f\n"
@@ -815,13 +815,12 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
                 "   jo   3f\n"
                 "   ahi  2,-8\n"
                 "   srl  1,8\n"
-                "3: n    1,%3\n"
-                "   ic   1,0(1,%4)\n"
-                "   n    1,%3\n"
+                "3: nr   1,0\n"
+                "   ic   1,0(1,%3)\n"
                 "   ar   2,1\n"
                 "4: lr   %0,2"
                 : "=d" (res) : "a" (size), "a" (vaddr),
-                  "m" (mask), "a" (&_zb_findmap)
+                  "a" (&_zb_findmap)
                   : "cc", "0", "1", "2" );
         return (res < size) ? res : size;
 }
@@ -829,17 +828,6 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size)
 extern __inline__ int 
 ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
 {
-        static const int mask = 0xffL;
-        static unsigned long orword[32] = {
-               0x00000000, 0x01000000, 0x03000000, 0x07000000,
-               0x0f000000, 0x1f000000, 0x3f000000, 0x7f000000,
-               0xff000000, 0xff010000, 0xff030000, 0xff070000,
-                0xff0f0000, 0xff1f0000, 0xff3f0000, 0xff7f0000,
-               0xffff0000, 0xffff0100, 0xffff0300, 0xffff0700,
-               0xffff0f00, 0xffff1f00, 0xffff3f00, 0xffff7f00,
-               0xffffff00, 0xffffff01, 0xffffff03, 0xffffff07,
-               0xffffff0f, 0xffffff1f, 0xffffff3f, 0xffffff7f
-       };
         unsigned long *addr = vaddr;
         unsigned long *p = addr + (offset >> 5);
         unsigned long word;
@@ -849,23 +837,29 @@ ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
                 return size;
 
         if (bit) {
-               word = *p | orword[bit];
+                __asm__("   ic   %0,0(%1)\n"
+                        "   icm  %0,2,1(%1)\n"
+                        "   icm  %0,4,2(%1)\n"
+                        "   icm  %0,8,3(%1)"
+                        : "=&a" (word) : "a" (p) );
+               word >>= bit;
+                res = bit;
                 /* Look for zero in first longword */
-                __asm__("   lhi  %0,24\n"
-                       "   tmh  %1,0xFFFF\n"
-                       "   jo   0f\n"
-                       "   ahi  %0,-16\n"
+                __asm__("   lhi  0,0xff\n"
+                        "   tml  %1,0xffff\n"
+                       "   jno   0f\n"
+                       "   ahi  %0,16\n"
                        "   srl  %1,16\n"
-                       "0: tml  %1,0xFF00\n"
-                       "   j  1f\n"
-                       "   ahi  %0,-8\n"
+                       "0: tml  %1,0x00ff\n"
+                       "   jno  1f\n"
+                       "   ahi  %0,8\n"
                        "   srl  %1,8\n"
-                       "1: n    %1,%2\n"
-                       "   ic   %1,0(%1,%3)\n"
+                       "1: nr   %1,0\n"
+                       "   ic   %1,0(%1,%2)\n"
                        "   alr  %0,%1"
-                       : "=&d" (res), "+&d" (word)
-                       : "m" (mask), "a" (&_zb_findmap)
-                       : "cc" );
+                       : "+&d" (res), "+&d" (word)
+                       : "a" (&_zb_findmap)
+                       : "cc", "0" );
                 if (res < 32)
                        return (p - addr)*32 + res;
                 p++;
diff --git a/include/asm-s390/ccwcache.h b/include/asm-s390/ccwcache.h
new file mode 100644 (file)
index 0000000..477f794
--- /dev/null
@@ -0,0 +1,88 @@
+/* 
+   * File...........: linux/drivers/s390/block/ccwcache.c
+   * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
+   * Bugreports.to..: <Linux390@de.ibm.com>
+   * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000
+ */
+#ifndef CCWCACHE_H
+#define CCWCACHE_H
+#include <linux/slab.h>
+#include <asm/irq.h>
+
+#ifndef __KERNEL__
+#define kmem_cache_t void
+#endif /* __KERNEL__ */
+/* 
+ * smalles slab to be allocated (DASD_MINIMUM_CCW CCWs + metadata) 
+ */
+
+typedef struct ccw_req_t {
+       /* these identify the request */
+       unsigned long magic;    /* magic number */
+       atomic_t status;        /* reflecting the status of this request */
+       unsigned long long expires;     /* clock value, when request expires */
+
+       /* these are important for executing the requests */
+       ccw1_t *cpaddr;         /* address of channel program */
+       void *data;             /* pointer to data area */
+       void *req;              /* pointer to originating request */
+       struct ccw_req_t *next; /* pointer to next ccw_req_t in queue */
+
+       int options;            /* options for execution */
+       int cplength;           /* length of the channel program in CCWs */
+       int datasize;           /* amount of additional data in bytes */
+       devstat_t *dstat;       /* The device status in case of an error */
+
+       /* these are important for recovering erroneous requests */
+       int retries;            /* A retry counter to be set when filling */
+       devstat_t *devstat;     /* Keeping the device status */
+       struct ccw_req_t *refers;       /* Does this request refer to another one? */
+       void *function; /* refers to the originating ERP action */ ;
+
+       /* these are for profiling purposes */
+       unsigned long long buildclk;    /* TOD-clock of request generation */
+       unsigned long long startclk;    /* TOD-clock of request start */
+
+       unsigned long long stopclk;     /* TOD-clock of request interrupt */
+       unsigned long long endclk;      /* TOD-clock of request termination */
+
+       /* these are for internal use */
+       struct ccw_req_t *int_next;     /* for internal queueing */
+       struct ccw_req_t *int_prev;     /* for internal queueing */
+       kmem_cache_t *cache;    /* the cache this data comes from */
+       void *device;           /* index of the device the req is for */
+
+} __attribute__ ((packed,aligned(4))) ccw_req_t;
+
+/* 
+ * ccw_req_t -> status can be:
+ */
+#define CQR_STATUS_EMPTY  0x00 /* request is empty */
+#define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */
+#define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */
+#define CQR_STATUS_IN_IO  0x04 /* request is currently in IO */
+#define CQR_STATUS_DONE   0x08 /* request is completed sucessfully */
+#define CQR_STATUS_ERROR  0x10 /* request is completed with error */
+#define CQR_STATUS_FAILED 0x20 /* request is finally failed */
+
+#ifdef __KERNEL__
+#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\
+ sizeof(struct ccw_req_t) <= 256 ? 256 :\
+ sizeof(struct ccw_req_t) <= 512 ? 512 :\
+ sizeof(struct ccw_req_t) <= 1024 ? 1024 : 2048)
+
+/* SMALLEST_SLAB(1),... PAGE_SIZE(CCW_NUMBER_CACHES) */
+#define CCW_NUMBER_CACHES (sizeof(struct ccw_req_t) <= 128 ? 6 :\
+ sizeof(struct ccw_req_t) <= 256 ? 5 :\
+ sizeof(struct ccw_req_t) <= 512 ? 4 :\
+ sizeof(struct ccw_req_t) <= 1024 ? 3 : 2)
+
+int ccwcache_init (void);
+
+ccw_req_t *ccw_alloc_request (char *magic, int cplength, int datasize);
+void ccw_free_request (ccw_req_t * request);
+#endif /* __KERNEL__ */
+#endif                         /* CCWCACHE_H */
+
+
+
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
new file mode 100644 (file)
index 0000000..2678fbd
--- /dev/null
@@ -0,0 +1,253 @@
+
+#ifndef DASD_H
+#define DASD_H
+
+/* First of all the external stuff */
+#include <linux/ioctl.h>
+#include <linux/major.h>
+#include <linux/wait.h>
+#include <asm/ccwcache.h>
+/* #include <linux/blkdev.h> */
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+#include <linux/devfs_fs_kernel.h>
+#endif /* LINUX_IS_24 */
+
+#define IOCTL_LETTER 'D'
+/* Format the volume or an extent */
+#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
+/* Disable the volume (for Linux) */
+#define BIODASDDISABLE _IO(IOCTL_LETTER,1) 
+/* Enable the volume (for Linux) */
+#define BIODASDENABLE  _IO(IOCTL_LETTER,2) 
+/* Stuff for reading and writing the Label-Area to/from user space */
+#define BIODASDGTVLBL  _IOR(IOCTL_LETTER,3,dasd_volume_label_t)
+#define BIODASDSTVLBL  _IOW(IOCTL_LETTER,4,dasd_volume_label_t)
+#define BIODASDRWTB    _IOWR(IOCTL_LETTER,5,int)
+#define BIODASDRSID    _IOR(IOCTL_LETTER,6,senseid_t)
+#define BIODASDRLB     _IOR(IOCTL_LETTER,7,int)
+#define BLKGETBSZ      _IOR(IOCTL_LETTER,8,int)
+#define BIODASDEXCP    _IOWR(IOCTL_LETTER,9,ccw_req_t)
+
+#define DASD_NAME "dasd"
+#define DASD_PARTN_BITS 2
+#define PARTN_BITS DASD_PARTN_BITS
+#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS))
+
+/* 
+ * struct format_data_t
+ * represents all data necessary to format a dasd
+ */
+typedef struct format_data_t {
+       int start_unit; /* from track */
+       int stop_unit;  /* to track */
+       int blksize;    /* sectorsize */
+        int intensity;  /* 0: normal, 1:record zero, 3:home address */
+} __attribute__ ((packed)) format_data_t;
+
+#define DASD_FORMAT_DEFAULT_START_UNIT 0
+#define DASD_FORMAT_DEFAULT_STOP_UNIT -1
+#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1
+#define DASD_FORMAT_DEFAULT_INTENSITY -1
+
+#ifdef __KERNEL__
+
+typedef enum {
+       dasd_era_fatal = -1,    /* no chance to recover              */
+       dasd_era_none = 0,      /* don't recover, everything alright */
+       dasd_era_msg = 1,       /* don't recover, just report...     */
+       dasd_era_recover = 2    /* recovery action recommended       */
+} dasd_era_t;
+
+/* 
+ * struct dasd_sizes_t
+ * represents all data needed to access dasd with properly set up sectors
+ */
+typedef
+struct dasd_sizes_t {
+       unsigned int blocks;
+       unsigned int bp_block;
+       unsigned int s2b_shift;
+} __attribute__ ((packed)) dasd_sizes_t;
+
+/* 
+ * struct dasd_chanq_t 
+ * represents a queue of channel programs related to a single device
+ */
+typedef
+struct dasd_chanq_t {
+       ccw_req_t *head;
+       ccw_req_t *tail;
+       struct dasd_chanq_t *next_q;    /* pointer to next queue */
+       int queued_requests;
+       atomic_t flags;
+       atomic_t dirty_requests;
+} __attribute__ ((packed)) dasd_chanq_t;
+
+#define DASD_CHANQ_BUSY 0x01
+#define DASD_CHANQ_ACTIVE 0x02
+#define DASD_REQUEST_Q_BROKEN 0x04
+
+struct dasd_device_t;
+
+typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr);
+typedef int (*dasd_erp_postaction_fn_t) (ccw_req_t * cqr, int);
+
+typedef int (*dasd_ck_id_fn_t) (dev_info_t *);
+typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *);
+typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *);
+typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *);
+typedef int (*dasd_io_starter_fn_t) (ccw_req_t *);
+typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *);
+typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat);
+typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *);
+typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *);
+typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *);
+typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *);
+
+typedef struct dasd_discipline_t {
+       char ebcname[8]; /* a name used for tagging and printks */
+        char name[8];          /* a name used for tagging and printks */
+
+       struct dasd_discipline_t *next; /* used for list of disciplines */
+
+       dasd_ck_id_fn_t id_check;       /* to check sense data */
+       dasd_ck_characteristics_fn_t check_characteristics;     /* to check the characteristics */
+       dasd_init_analysis_fn_t init_analysis;  /* to start the analysis of the volume */
+       dasd_do_analysis_fn_t do_analysis;      /* to complete the analysis of the volume */
+       dasd_fill_geometry_fn_t fill_geometry;  /* to set up hd_geometry */
+       dasd_io_starter_fn_t start_IO;
+        dasd_format_fn_t format_device;                /* to format the device */
+       dasd_error_examine_fn_t examine_error;
+       dasd_error_analyse_fn_t erp_action;
+       dasd_erp_analyse_fn_t erp_postaction;
+        dasd_cp_builder_fn_t build_cp_from_req;
+        dasd_dump_sense_fn_t dump_sense;
+        dasd_int_handler_fn_t int_handler;
+} __attribute__   ((packed)) dasd_discipline_t;
+
+typedef struct major_info_t {
+       struct major_info_t *next;
+       struct dasd_device_t **dasd_device;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+       void (*request_fn) (request_queue_t *);
+#else
+       void (*request_fn) (void);
+#endif /* LINUX_IS_24 */
+       int read_ahead;
+       int *blk_size;
+       int *hardsect_size;
+       int *blksize_size;
+       int *max_sectors;
+       struct gendisk gendisk;
+} __attribute__ ((packed)) major_info_t;
+
+typedef struct dasd_device_t {
+       dev_info_t devinfo;
+       dasd_discipline_t *discipline;
+       atomic_t level;
+        int open_count;
+        kdev_t kdev;
+        major_info_t *major_info;
+       struct dasd_chanq_t queue;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        wait_queue_head_t wait_q;
+        request_queue_t *request_queue;
+#else
+        struct wait_queue wait;
+        struct wait_queue *wait_q;
+#endif /* LINUX_IS_24 */
+        dasd_sizes_t sizes;
+       devstat_t dev_status;
+       char *characteristics;
+        char name[16]; /* The name of the device in /dev */
+       char *private;  /* to be used by the discipline internally */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
+        devfs_handle_t devfs_entry;
+#endif /* LINUX_IS_24 */
+}  dasd_device_t;
+
+/* dasd_device_t.level can be: */
+#define DASD_DEVICE_LEVEL_UNKNOWN 0x00
+#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01
+#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02
+#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04
+#define DASD_DEVICE_LEVEL_ANALYSED 0x08
+#define DASD_DEVICE_LEVEL_PARTITIONED 0x10
+
+typedef
+union {
+       char bytes[512];
+       struct {
+               /* 80 Bytes of Label data */
+               char identifier[4];     /* e.g. "LNX1", "VOL1" or "CMS1" */
+               char label[6];  /* Given by user */
+               char security;
+               char vtoc[5];   /* Null in "LNX1"-labelled partitions */
+               char reserved0[5];
+               long ci_size;
+               long blk_per_ci;
+               long lab_per_ci;
+               char reserved1[4];
+               char owner[0xe];
+               char no_part;
+               char reserved2[0x1c];
+               /* 16 Byte of some information on the dasd */
+               short blocksize;
+               char nopart;
+               char unused;
+               long unused2[3];
+               /* 7*10 = 70 Bytes of partition data */
+               struct {
+                       char type;
+                       long start;
+                       long size;
+                       char unused;
+               } part[7];
+       } __attribute__ ((packed)) label;
+} dasd_volume_label_t;
+
+typedef union {
+       struct {
+               unsigned long no;
+               unsigned int ct;
+       } __attribute__ ((packed)) input;
+       struct {
+               unsigned long noct;
+       } __attribute__ ((packed)) output;
+} __attribute__ ((packed)) dasd_xlate_t;
+
+int dasd_init (void);
+/* int dasd_device_name (char *, int, int, struct gendisk *); */
+void dasd_discipline_enq (dasd_discipline_t *);
+int dasd_discipline_deq(dasd_discipline_t *);
+int dasd_start_IO (ccw_req_t *);
+void dasd_int_handler (int , void *, struct pt_regs *);
+
+#endif /* __KERNEL__ */
+
+#endif                         /* DASD_H */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4 
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h
new file mode 100644 (file)
index 0000000..48f40cb
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <asm/spinlock.h>
+
+#ifdef __KERNEL__
+
+#define MAX_DEBUG_AREAS 16
+
+#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+
+typedef struct
+{
+  union
+  {
+    struct
+    {
+      unsigned long long cpuid:4;
+      unsigned long long clock:60;
+    }
+    fields;
+    unsigned long long stck;
+  }
+  id;
+  void *caller;
+  union
+  {
+    unsigned long tag;
+    char text[4];
+  }
+  tag;
+}
+debug_entry_t;
+
+typedef struct
+{
+  char *name;
+  int level;
+  int nr_areas;
+  int page_order;
+  debug_entry_t **areas;
+  int active_area;
+  int *active_entry;
+  spinlock_t lock;
+}
+debug_info_t;
+
+int debug_init (void);
+debug_info_t *debug_register (char *name, int pages_index, int nr_areas);
+void debug_unregister (debug_info_t * id, char *name);
+void debug_event (debug_info_t * id, int level, unsigned int tag);
+void debug_text_event (debug_info_t * id, int level, char tag[4]);
+void debug_exception (debug_info_t * id, int level, unsigned int tag);
+void debug_text_exception (debug_info_t * id, int level, char tag[4]);
+
+/*
+   define the debug levels:
+   - 0 No debugging output to console or syslog
+   - 1 Log internal errors to syslog, ignore check conditions 
+   - 2 Log internal errors and check conditions to syslog
+   - 3 Log internal errors to console, log check conditions to syslog
+   - 4 Log internal errors and check conditions to console
+   - 5 panic on internal errors, log check conditions to console
+   - 6 panic on both, internal errors and check conditions
+ */
+
+#ifndef DEBUG_LEVEL
+#define DEBUG_LEVEL 4
+#endif
+
+#define INTERNAL_ERRMSG(x,y...) "E" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_WRNMSG(x,y...) "W" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_INFMSG(x,y...) "I" __FILE__ "%d: " x, __LINE__, y
+#define INTERNAL_DEBMSG(x,y...) "D" __FILE__ "%d: " x, __LINE__, y
+
+#if DEBUG_LEVEL > 0
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
+#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
+#else
+#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
+#endif                         /* DASD_DEBUG */
+
+#if DASD_DEBUG > 4
+#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 2
+#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) )
+#elif DASD_DEBUG > 0
+#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) )
+#else
+#define INTERNAL_ERROR(x...)
+#endif                         /* DASD_DEBUG */
+
+#if DASD_DEBUG > 5
+#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 3
+#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) )
+#elif DASD_DEBUG > 1
+#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) )
+#else
+#define INTERNAL_CHECK(x...)
+#endif                         /* DASD_DEBUG */
+
+#undef DEBUG_MALLOC
+#ifdef DEBUG_MALLOC
+void *b;
+#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
+#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
+#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
+#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
+#endif                         /* DEBUG_MALLOC */
+
+#endif                         /* __KERNEL__ */
+#endif                         /* DEBUG_H */
index 87ac553910a7e04332c5c35fda75f37fda3ed1ec..357fdb835a1f0d336b2b271985b5ec477a92282a 100644 (file)
 #define _S390_DELAY_H
 
 extern void __udelay(unsigned long usecs);
-extern void __const_udelay(unsigned long usecs);
 extern void __delay(unsigned long loops);
 
-#define udelay(n) (__builtin_constant_p(n) ? \
-       __const_udelay((n) * 0x10c6ul) : \
-       __udelay(n))
+#define udelay(n) __udelay(n)
 
 #endif /* defined(_S390_DELAY_H) */
index 782166d168303541fdad9bb8080af1dbed8c61a6..9fb7b8ff8cbbdd02f229c72cd7960226a5e0353c 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __irq_h
 #define __irq_h
 
+#ifdef __KERNEL__
 #include <asm/hardirq.h>
 
 /*
@@ -9,6 +10,8 @@
 #define __MAX_SUBCHANNELS 65536
 #define NR_IRQS           __MAX_SUBCHANNELS
 
+#define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */
+
 #define INVALID_STORAGE_AREA ((void *)(-1 - 0x3FFF ))
 
 extern int disable_irq(unsigned int);
@@ -68,6 +71,8 @@ typedef struct {
                                    /*  ... in an operand exception.       */
    } __attribute__ ((packed)) pmcw_t;
 
+#endif /* __KERNEL__ */
+
 /*
  * subchannel status word
  */
@@ -130,6 +135,8 @@ typedef struct {
 #define SCHN_STAT_INTF_CTRL_CHK  0x02
 #define SCHN_STAT_CHAIN_CHECK    0x01
 
+#ifdef __KERNEL__
+
 /*
  * subchannel information block
  */
@@ -139,6 +146,8 @@ typedef struct {
       char mda[12];            /* model dependent area */
    } schib_t __attribute__ ((packed,aligned(4)));
 
+#endif /* __KERNEL__ */
+
 typedef struct {
       char            cmd_code;/* command code */
       char            flags;   /* flags, like IDA adressing, etc. */
@@ -164,6 +173,8 @@ typedef struct {
 #define CCW_CMD_SET_PGID        0xAF
 #define CCW_CMD_SENSE_ID        0xE4
 
+#ifdef __KERNEL__
+
 #define SENSE_MAX_COUNT         0x20
 
 /*
@@ -197,6 +208,8 @@ typedef struct {
       ccw1_t        *cpa;      /* channel program address */
    }  __attribute__ ((packed,aligned(4))) orb_t;
 
+#endif /* __KERNEL__ */
+
 typedef struct {
       unsigned int res0  : 4;  /* reserved */
       unsigned int pvrf  : 1;  /* path-verification-required flag */
@@ -284,6 +297,8 @@ typedef struct {
       char   ecw[32];          /* extended control word */
    } irb_t __attribute__ ((aligned(4)));
 
+#ifdef __KERNEL__
+
 /*
  * TPI info structure
  */
@@ -323,6 +338,8 @@ typedef struct {
       ciw_t    ciw[16];            /* variable # of CIWs */
    }  __attribute__ ((packed,aligned(4))) senseid_t;
 
+#endif /* __KERNEL__ */
+
 /*
  * sense data
  */
@@ -331,6 +348,7 @@ typedef struct {
       unsigned char data[32];  /* sense data */
    } sense_t;
 
+
 /*
  * device status area, to be provided by the device driver
  *  when calling request_irq() as parameter "dev_id", later
@@ -367,16 +385,20 @@ typedef struct {
 #define DEVSTAT_CLEAR_FUNCTION     0x00000100
 #define DEVSTAT_PCI                0x00000200
 #define DEVSTAT_SUSPENDED          0x00000400
+#define DEVSTAT_UNKNOWN_DEV        0x00000800
 #define DEVSTAT_FINAL_STATUS       0x80000000
 
 #define INTPARM_STATUS_PENDING     0xFFFFFFFF
 
+#ifdef __KERNEL__
+
 typedef  void (* io_handler_func1_t) ( int  irq,
                                        devstat_t *devstat,
                                        struct pt_regs *rgs);
 
 typedef  void (* io_handler_func_t) ( int  irq,
-                                      __u32 intparm );
+                                      void           *devstat,
+                                      struct pt_regs *rgs);
 
 typedef  void ( * not_oper_handler_func_t)( int irq,
                                             int status );
@@ -777,7 +799,7 @@ static inline void irq_exit(int cpu, unsigned int irq)
  * x86 profiling function, SMP safe. We might want to do this in
  * assembly totally?
  */
-extern unsigned long _stext;
+extern char _stext;
 static inline void s390_do_profile (unsigned long addr)
 {
         if (prof_buffer && current->pid) {
@@ -808,6 +830,7 @@ static inline void s390_do_profile (unsigned long addr)
 
 #define s390irq_spin_unlock_irqrestore(irq,flags) \
         spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+#endif /* __KERNEL__ */
 
 #endif
 
index 8b1100290ec1cb1402264375108932a0f2ec3d86..c33fcfef42de10defa1a7614bb716099534affd8 100644 (file)
@@ -86,7 +86,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
         __flush_tlb_one(vma->vm_mm,va);
 }
 #else
-#define flush_tlb_page(vma, va) flush_tlb_all()
+#define flush_tlb_page(vma, va) flush_tlb_mm(vma->vm_mm)
 #endif
 
 static inline void flush_tlb_range(struct mm_struct *mm,
@@ -171,7 +171,7 @@ static inline void flush_tlb_page(struct vm_area_struct * vma,
        __flush_tlb_one(vma->vm_mm,va);
 }
 #else
-#define flush_tlb_page(vma, va) flush_tlb_all()
+#define flush_tlb_page(vma, va) flush_tlb_mm(vma->vm_mm)
 #endif
 
 static inline void flush_tlb_range(struct mm_struct * mm,
@@ -281,6 +281,7 @@ static inline void flush_tlb_range(struct mm_struct * mm,
 #define _PAGE_PRESENT   0x001          /* Software                         */
 #define _PAGE_ACCESSED  0x002          /* Software accessed                */
 #define _PAGE_DIRTY     0x004          /* Software dirty                   */
+#define _PAGE_WRITE     0x008          /* Software write-access allowed    */
 #define _PAGE_RO        0x200          /* HW read-only                     */
 #define _PAGE_INVALID   0x400          /* HW invalid                       */
 
@@ -305,19 +306,21 @@ static inline void flush_tlb_range(struct mm_struct * mm,
 
 #define _SEGMENT_TABLE  (_USER_SEG_TABLE_LEN|0x80000000)
 #define _KERNSEG_TABLE  (_KERNEL_SEG_TABLE_LEN)
+
 /*
  * No mapping available
  */
 #define PAGE_NONE       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_INVALID)
-#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_WRITE | _PAGE_RO)
 #define PAGE_COPY       __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
 #define PAGE_READONLY   __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO)
-#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define PAGE_KERNEL     __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_WRITE | _PAGE_DIRTY)
 
 /*
  * The S390 can't do page protection for execute, and considers that the same are read.
  * Also, write permissions imply read permissions. This is the closest we can get..
  */
+         /*xwr*/
 #define __P000  PAGE_NONE
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_COPY
@@ -434,7 +437,7 @@ extern inline void pgd_clear(pgd_t * pgdp)      { }
  * The following only work if pte_present() is true.
  * Undefined behaviour if not..
  */
-extern inline int pte_write(pte_t pte)          { return !(pte_val(pte) & _PAGE_RO); }
+extern inline int pte_write(pte_t pte)          { return pte_val(pte) & _PAGE_WRITE; }
 extern inline int pte_dirty(pte_t pte)          { return pte_val(pte) & _PAGE_DIRTY; }
 extern inline int pte_young(pte_t pte)          { return pte_val(pte) & _PAGE_ACCESSED; }
 
@@ -447,11 +450,17 @@ extern inline pte_t pte_mkread(pte_t pte)       { pte_val(pte) &= _PAGE_INVALID;
 extern inline pte_t pte_mkexec(pte_t pte)       { pte_val(pte) &= _PAGE_INVALID; return pte; }
 */
 
-extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) |= _PAGE_RO; return pte; }
-extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) &= ~_PAGE_RO ; return pte; }
+extern inline int __pte_set_ro(int pte)         { if ((pte & (_PAGE_WRITE|_PAGE_DIRTY)) == (_PAGE_WRITE|_PAGE_DIRTY))
+                                                      pte &= ~_PAGE_RO;
+                                                  else
+                                                      pte |= _PAGE_RO;
+                                                  return pte; }
+
+extern inline pte_t pte_wrprotect(pte_t pte)    { pte_val(pte) = __pte_set_ro(pte_val(pte) & ~_PAGE_WRITE); return pte; }
+extern inline pte_t pte_mkwrite(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) | _PAGE_WRITE); return pte; }
 
-extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
-extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+extern inline pte_t pte_mkclean(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) & ~_PAGE_DIRTY); return pte; }
+extern inline pte_t pte_mkdirty(pte_t pte)      { pte_val(pte) = __pte_set_ro(pte_val(pte) | _PAGE_DIRTY); return pte; }
 
 extern inline pte_t pte_mkold(pte_t pte)        { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
 extern inline pte_t pte_mkyoung(pte_t pte)      { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
index 86e076f4f29b2be83389698087ccd387be784100..8c7651a7d9709d90a638ba78c42de47d0197da12 100644 (file)
@@ -167,13 +167,33 @@ extern inline unsigned long thread_saved_pc(struct thread_struct *t)
 static inline void disabled_wait(unsigned long code)
 {
         char psw_buffer[2*sizeof(psw_t)];
+        char ctl_buf[4];
         psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
                                   & -sizeof(psw_t));
 
         dw_psw->mask = 0x000a0000;
         dw_psw->addr = code;
-        /* load disabled wait psw, the processor is dead afterwards */
-        asm volatile ("lpsw 0(%0)" : : "a" (dw_psw));
+        /* 
+         * Store status and then load disabled wait psw,
+         * the processor is dead afterwards
+         */
+
+        asm volatile ("    stctl 0,0,0(%1)\n"
+                      "    ni    0(%1),0xef\n" /* switch off protection */
+                      "    lctl  0,0,0(%1)\n"
+                      "    stpt  0xd8\n"       /* store timer */
+                      "    stckc 0xe0\n"       /* store clock comparator */
+                      "    stpx  0x108\n"      /* store prefix register */
+                      "    stam  0,15,0x120\n" /* store access registers */
+                      "    std   0,0x160\n"    /* store f0 */
+                      "    std   2,0x168\n"    /* store f2 */
+                      "    std   4,0x170\n"    /* store f4 */
+                      "    std   6,0x178\n"    /* store f6 */
+                      "    stm   0,15,0x180\n" /* store general registers */
+                      "    stctl 0,15,0x1c0\n" /* store control registers */
+                      "    oi    0x1c0,0x10\n" /* fake protection bit */
+                      "    lpsw 0(%0)"
+                      : : "a" (dw_psw), "a" (&ctl_buf));
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
index 2582667cac3613e242efd935b265bad91e3e1234..c817d23b3ba74f43e1b806f9de7f7b229d92ac1e 100644 (file)
@@ -70,6 +70,15 @@ static __inline__ void add_to_list(list **lhead,list *member)
        *lhead=member;
 }
 
+static __inline__ list *remove_listhead(list **lhead)
+{
+       list *oldhead=*lhead;
+
+       if(oldhead)
+               *lhead=(*lhead)->next;
+       return(oldhead);
+}
+
 static __inline__ void add_to_list_tail(list **lhead,list *member)
 {
        list *curr,*prev;
index e63f73be15d3f936e640776c1f6033313f125f2b..570b24e0b8c92d902d26feac38ab4d4e020246d1 100644 (file)
@@ -52,7 +52,8 @@ typedef struct _ioinfo {
            unsigned int  repnone   : 1;  /* don't call IRQ handler on interrupt */
            unsigned int  newreq    : 1;  /* new register interface */
            unsigned int  dval      : 1;  /* device number valid */
-           unsigned int  unused    : (sizeof(unsigned int)*8 - 23); /* unused */
+           unsigned int  unknown   : 1;  /* unknown device - if SenseID failed */
+           unsigned int  unused    : (sizeof(unsigned int)*8 - 24); /* unused */
               } __attribute__ ((packed)) flags;
         } ui;
 
index 4aee2321d242808abd9117aca40ea51f37d0a0f6..55f39915640f81d5649bdc05d6a4b94989bcb83e 100644 (file)
@@ -44,6 +44,7 @@
 #define MACHINE_HAS_CSP  (MACHINE_FLAGS & 8)
 
 #define RAMDISK_ORIGIN            0x800000
+#define RAMDISK_SIZE              0x800000
 #define RAMDISK_BLKSIZE           0x1000
 #define RAMDISK_IMAGE_START_MASK  0x07FF
 #define RAMDISK_PROMPT_FLAG       0x8000
index 9358601024a9fbb3c681c4308f3e9a888dbd55cb..f0a2530292db4d29a0fc22f77bb0ede96147043f 100644 (file)
@@ -94,12 +94,13 @@ typedef struct {
 
 extern inline void spin_lock(spinlock_t *lp)
 {
-       __asm__ __volatile("    basr  1,0\n"
-                          "0:  slr   0,0\n"
+        __asm__ __volatile("    bras  1,1f\n"
+                           "0:  diag  0,0,68\n"
+                           "1:  slr   0,0\n"
                           "    cs    0,1,%1\n"
-                          "    jl    0b"
+                           "    jl    0b\n"
                           : "=m" (lp->lock)
-                          : "0" (lp->lock) : "0", "1");
+                           : "0" (lp->lock) : "0", "1", "cc" );
 }
 
 extern inline int spin_trylock(spinlock_t *lp)
@@ -109,7 +110,7 @@ extern inline int spin_trylock(spinlock_t *lp)
                           "    basr  1,0\n"
                           "0:  cs    %1,1,%0"
                           : "=m" (lp->lock), "=&d" (result)
-                          : "0" (lp->lock) : "1");
+                          : "0" (lp->lock) : "1", "cc" );
        return !result;
 }
 
@@ -119,7 +120,7 @@ extern inline void spin_unlock(spinlock_t *lp)
 {
        __asm__ __volatile("    xc 0(4,%0),0(%0)\n"
                            "    bcr 15,0"
-                          : /* no output */ : "a" (lp) );
+                          : /* no output */ : "a" (lp) : "memory", "cc" );
 }
                
 #define spin_lock_irq(lock) \
@@ -156,37 +157,43 @@ extern void _write_unlock(rwlock_t *rw);
 
 #define read_lock(rw)   \
         asm volatile("   l     2,%0\n"   \
-                     "0: sll   2,1\n"    \
-                     "   srl   2,1\n"     /* clear high (=write) bit */ \
-                     "   lr    3,2\n"    \
-                     "   ahi   3,1\n"     /* one more reader */ \
+                     "   j     1f\n"     \
+                     "0: diag  0,0,68\n" \
+                     "1: la    2,0(2)\n"  /* clear high (=write) bit */ \
+                     "   la    3,1(2)\n"  /* one more reader */ \
                      "   cs    2,3,%0\n"  /* try to write new value */ \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define read_unlock(rw) \
         asm volatile("   l     2,%0\n"   \
-                     "0: lr    3,2\n"    \
+                     "   j     1f\n"     \
+                     "0: diag  0,0,68\n" \
+                     "1: lr    3,2\n"    \
                      "   ahi   3,-1\n"    /* one less reader */ \
                      "   cs    2,3,%0\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define write_lock(rw) \
         asm volatile("   lhi   3,1\n"    \
                      "   sll   3,31\n"    /* new lock value = 0x80000000 */ \
-                     "0: slr   2,2\n"     /* old lock value must be 0 */ \
+                     "   j     1f\n"     \
+                     "0: diag  0,0,68\n" \
+                     "1: slr   2,2\n"     /* old lock value must be 0 */ \
                      "   cs    2,3,%0\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define write_unlock(rw) \
         asm volatile("   slr   3,3\n"     /* new lock value = 0 */ \
-                     "0: lhi   2,1\n"    \
+                     "   j     1f\n"     \
+                     "0: diag  0,0,68\n" \
+                     "1: lhi   2,1\n"    \
                      "   sll   2,31\n"    /* old lock value must be 0x80000000 */ \
                      "   cs    2,3,%0\n" \
                      "   jl    0b"       \
-                     : "+m" ((rw)->lock) : : "2", "3" );
+                     : "+m" ((rw)->lock) : : "2", "3", "cc" );
 
 #define read_lock_irq(lock)    do { __cli(); read_lock(lock); } while (0)
 #define read_unlock_irq(lock)  do { read_unlock(lock); __sti(); } while (0)
@@ -205,11 +212,3 @@ extern void _write_unlock(rwlock_t *rw);
 #endif /* SMP */
 #endif /* __ASM_SPINLOCK_H */
 
-
-
-
-
-
-
-
-
index 2e8081912169b4285ba469a9d6e7147e10449f98..89012a793b37404095fce42883cb5fa7cd4d5d05 100644 (file)
@@ -46,14 +46,15 @@ extern inline void * memchr(const void * cs,int c,size_t count)
     void *ptr;
 
     __asm__ __volatile__ ("   lr    0,%2\n"
+                          "   lr    1,%1\n"
                           "   la    %0,0(%3,%1)\n"
-                          "0: srst  %0,%1\n"
+                          "0: srst  %0,1\n"
                           "   jo    0b\n"
                           "   brc   13,1f\n"
                           "   slr   %0,%0\n"
                           "1:"
-                          : "=a" (ptr) : "a" (cs), "d" (c), "d" (count)
-                          : "cc", "0" );
+                          : "=&a" (ptr) : "a" (cs), "d" (c), "d" (count)
+                          : "cc", "0", "1" );
     return ptr;
 }
 
index dd837631d752815cb9d6e894dec5cae1f6bb6680..09ce0f321d650d3d5a68f95c3bf057878954bed7 100644 (file)
@@ -84,15 +84,14 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr)
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-                               "   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
                                "   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: st    %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
                                "1:\n"
                                ".section .fixup,\"ax\"\n"
-                               "2: sacf  0(1)\n"
+                               "2: sacf  0\n"
                                "   lhi   %1,%h3\n"
                                "   bras  4,3f\n"
                                "   .long 1b\n"
@@ -105,7 +104,7 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -113,15 +112,14 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr)
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-                               "   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
                                "   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: sth   %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
                                "1:\n"
                                ".section .fixup,\"ax\"\n"
-                               "2: sacf  0(1)\n"
+                               "2: sacf  0\n"
                                "   lhi   %1,%h3\n"
                                "   bras  4,3f\n"
                                "   .long 1b\n"
@@ -134,7 +132,7 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -142,15 +140,14 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
 {
         int err;
 
-        __asm__ __volatile__ (  "   iac   1\n"
-                               "   sr    %1,%1\n"
+        __asm__ __volatile__ (  "   sr    %1,%1\n"
                                "   la    4,%0\n"
                                 "   sacf  512\n"
                                 "0: stc   %2,0(4)\n"
-                                "   sacf  0(1)\n"
+                                "   sacf  0\n"
                                "1:\n"
                                ".section .fixup,\"ax\"\n"
-                               "2: sacf  0(1)\n"
+                               "2: sacf  0\n"
                                "   lhi   %1,%h3\n"
                                "   bras  4,3f\n"
                                "   .long 1b\n"
@@ -163,7 +160,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "4" );
         return err;
 }
 
@@ -208,15 +205,14 @@ extern int __put_user_bad(void);
 
 #define __get_user_asm_4(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sacf  512\n"                        \
                                 "0: l     %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -229,20 +225,19 @@ extern int __put_user_bad(void);
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u32*) ptr), "K" (-EFAULT)    \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sacf  512\n"                        \
                                 "0: lh    %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -255,21 +250,20 @@ extern int __put_user_bad(void);
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u16*) ptr), "K" (-EFAULT)    \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                   \
 ({                                                                      \
-        __asm__ __volatile__ (  "   iac   1\n"                          \
-                                "   sr    %1,%1\n"                      \
+        __asm__ __volatile__ (  "   sr    %1,%1\n"                      \
                                 "   la    4,%2\n"                       \
                                 "   sr    %0,%0\n"                      \
                                 "   sacf  512\n"                        \
                                 "0: ic    %0,0(4)\n"                    \
-                                "   sacf  0(1)\n"                       \
+                                "   sacf  0\n"                          \
                                 "1:\n"                                  \
                                 ".section .fixup,\"ax\"\n"              \
-                                "2: sacf  0(1)\n"                       \
+                                "2: sacf  0\n"                          \
                                 "   lhi   %1,%h3\n"                     \
                                 "   bras  4,3f\n"                       \
                                 "   .long 1b\n"                         \
@@ -282,7 +276,7 @@ extern int __put_user_bad(void);
                                 ".previous"                             \
                                 : "=d" (x) , "=&d" (err)                \
                                 : "m" (*(__u8*) ptr), "K" (-EFAULT)     \
-                                : "1", "4" );                           \
+                                : "4" );                                \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -345,22 +339,32 @@ extern inline unsigned long
 __copy_to_user_asm(void* to, const void* from,  long n)
 {
 
-        __asm__ __volatile__ (  "   iac   1\n"
-                                "   lr    2,%2\n"
+        __asm__ __volatile__ (  "   lr    2,%2\n"
                                 "   lr    4,%1\n"
                                 "   lr    3,%0\n"
                                 "   lr    5,3\n"
                                 "   sacf  512\n"
                                 "0: mvcle 4,2,0\n"
                                 "   jo    0b\n"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,3\n"
+                                "   sacf  0\n"
+                                "1: lr    %0,3\n"
+                                ".section .fixup,\"ax\"\n"
+                                "2: lhi   5,-4096\n"
+                                "   n     5,0x90\n"
+                                "   sr    5,4\n"
+                                "   mvcle 4,2,0\n"
+                                "   sacf  0\n"
+                                "   basr  4,0\n"
+                                "   l     4,3f-.(4)\n"
+                                "   br    4\n"
+                                "3: .long 1b\n"
+                                ".previous\n"
                                ".section __ex_table,\"a\"\n"
                                "   .align 4\n"
-                               "   .long  0b,1b\n"
+                               "   .long  0b,2b\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "2", "3", "4", "5" );
         return n;
 }
 
@@ -384,26 +388,35 @@ __copy_to_user_asm(void* to, const void* from,  long n)
 extern inline unsigned long
 __copy_from_user_asm(void* to, const void* from,  long n)
 {
-        __asm__ __volatile__ (  "   iac   1\n"
-                               "   lr    2,%1\n"
+        __asm__ __volatile__ (  "   lr    2,%1\n"
                                 "   lr    4,%2\n"
                                 "   lr    3,%0\n"
                                 "   lr    5,3\n"
                                 "   sacf  512\n"
                                 "0: mvcle 2,4,0\n"
                                 "   jo    0b\n"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,3\n"
+                                "   sacf  0\n"
+                                "1: lr    %0,5\n"
+                                ".section .fixup,\"ax\"\n"
+                                "2: lhi   3,-4096\n"
+                                "   n     3,0x90\n"
+                                "   sr    3,4\n"
+                                "   mvcle 2,4,0\n"
+                                "   sacf  0\n"
+                                "   basr  4,0\n"
+                                "   l     4,3f-.(4)\n"
+                                "   br    4\n"
+                                "3: .long 1b\n"
+                                ".previous\n"
                                ".section __ex_table,\"a\"\n"
                                "   .align 4\n"
-                               "   .long  0b,1b\n"
+                               "   .long  0b,2b\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "2", "3", "4", "5" );
         return n;
 }
 
-
 #define __copy_from_user(to, from, n)                           \
 ({                                                              \
         __copy_from_user_asm(to,from,n);                        \
@@ -433,8 +446,7 @@ static inline long
 strncpy_from_user(char *dst, const char *src, long count)
 {
         long len;
-        __asm__ __volatile__ (  "   iac   1\n"
-                               "   slr   %0,%0\n"
+        __asm__ __volatile__ (  "   slr   %0,%0\n"
                                "   lr    2,%1\n"
                                 "   lr    4,%2\n"
                                 "   slr   3,3\n"
@@ -446,7 +458,7 @@ strncpy_from_user(char *dst, const char *src, long count)
                                 "   ahi   %0,1\n"
                                 "   clr   %0,%3\n"
                                 "   jl    0b\n"
-                                "2: sacf  0(1)\n"
+                                "2: sacf  0\n"
                                ".section .fixup,\"ax\"\n"
                                 "3: lhi   %0,%h4\n"
                                "   basr  3,0\n"
@@ -462,7 +474,7 @@ strncpy_from_user(char *dst, const char *src, long count)
                                 : "=&a" (len)
                                 : "a"  (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "1", "2", "3", "4", "memory" );
+                                : "2", "3", "4", "memory" );
         return len;
 }
 
@@ -474,8 +486,7 @@ strncpy_from_user(char *dst, const char *src, long count)
 static inline unsigned long
 strnlen_user(const char * src, unsigned long n)
 {
-       __asm__ __volatile__ ("   iac   1\n"
-                              "   alr   %0,%1\n"
+       __asm__ __volatile__ ("   alr   %0,%1\n"
                              "   slr   0,0\n"
                              "   lr    4,%1\n"
                              "   sacf  512\n"
@@ -483,10 +494,10 @@ strnlen_user(const char * src, unsigned long n)
                              "   jo    0b\n"
                              "   slr   %0,%1\n"
                              "   ahi   %0,1\n"
-                             "   sacf  0(1)\n"
+                             "   sacf  0\n"
                               "1:\n"
                               ".section .fixup,\"ax\"\n"
-                              "2: sacf  0(1)\n"
+                              "2: sacf  0\n"
                               "   slr   %0,%0\n"
                               "   bras  4,3f\n"
                               "   .long 1b\n"
@@ -498,7 +509,7 @@ strnlen_user(const char * src, unsigned long n)
                              "   .long  0b,2b\n"
                              ".previous"
                              : "+&a" (n) : "d" (src)
-                             : "cc", "0", "1", "4" );
+                             : "cc", "0", "4" );
         return n;
 }
 #define strlen_user(str) strnlen_user(str, ~0UL)
@@ -510,23 +521,33 @@ strnlen_user(const char * src, unsigned long n)
 static inline unsigned long
 clear_user(void *to, unsigned long n)
 {
-        __asm__ __volatile__ (  "   iac   1\n"
-                                "   sacf  512\n"
+        __asm__ __volatile__ (  "   sacf  512\n"
                                 "   lr    4,%1\n"
                                 "   lr    5,%0\n"
                                 "   sr    2,2\n"
                                 "   sr    3,3\n"
                                 "0: mvcle 4,2,0\n"
                                 "   jo    0b\n"
-                                "1: sacf  0(1)\n"
-                                "   lr    %0,5\n"
+                                "   sacf  0\n"
+                                "1: lr    %0,3\n"
+                                ".section .fixup,\"ax\"\n"
+                                "2: lhi   5,-4096\n"
+                                "   n     5,0x90\n"
+                                "   sr    5,4\n"
+                                "   mvcle 4,2,0\n"
+                                "   sacf  0\n"
+                                "   basr  4,0\n"
+                                "   l     4,3f-.(4)\n"
+                                "   br    4\n"
+                                "3: .long 1b\n"
+                                ".previous\n"
                                ".section __ex_table,\"a\"\n"
                                "   .align 4\n"
-                               "   .long  0b,1b\n"
+                               "   .long  0b,2b\n"
                                ".previous"
                                 : "+&a" (n)
                                 : "a"   (to)
-                                : "cc", "1", "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
index b4323830af9fc7d461da4603be1ebf0c2ffb2c35..d4e39ae77de98c8830d4c10ad800605de76e6b1c 100644 (file)
@@ -14,6 +14,7 @@ struct ucontext {
        struct ucontext  *uc_link;
        stack_t           uc_stack;
        sigset_t          uc_sigmask;   /* mask last for extensibility */
+       struct sigcontext *sc; /* Added for pthread support */
 };
 
 
diff --git a/include/linux/dasd.h b/include/linux/dasd.h
deleted file mode 100644 (file)
index 5cdcf2e..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-
-#ifndef DASD_H
-#define DASD_H
-
-/* First of all the external stuff */
-#include <linux/ioctl.h>
-#include <linux/major.h>
-#include <linux/wait.h>
-
-#define IOCTL_LETTER 'D'
-/* Format the volume or an extent */
-#define BIODASDFORMAT  _IOW(IOCTL_LETTER,0,format_data_t) 
-/* Disable the volume (for Linux) */
-#define BIODASDDISABLE _IO(IOCTL_LETTER,1) 
-/* Enable the volume (for Linux) */
-#define BIODASDENABLE  _IO(IOCTL_LETTER,2) 
-/* Stuff for reading and writing the Label-Area to/from user space */
-#define BIODASDGTVLBL  _IOR(IOCTL_LETTER,3,dasd_volume_label_t)
-#define BIODASDSTVLBL  _IOW(IOCTL_LETTER,4,dasd_volume_label_t)
-#define BIODASDRWTB    _IOWR(IOCTL_LETTER,5,int)
-#define BIODASDRSID    _IOR(IOCTL_LETTER,6,senseid_t)
-#define BIODASDRLB     _IOR(IOCTL_LETTER,7,int)
-#define BLKGETBSZ      _IOR(IOCTL_LETTER,8,int)
-
-typedef struct {
-       int start_unit;
-       int stop_unit;
-       int blksize;
-} format_data_t;
-
-typedef
-union {
-       char bytes[512];
-       struct {
-               /* 80 Bytes of Label data */
-               char identifier[4];     /* e.g. "LNX1", "VOL1" or "CMS1" */
-               char label[6];  /* Given by user */
-               char security;
-               char vtoc[5];   /* Null in "LNX1"-labelled partitions */
-               char reserved0[5];
-               long ci_size;
-               long blk_per_ci;
-               long lab_per_ci;
-               char reserved1[4];
-               char owner[0xe];
-               char no_part;
-               char reserved2[0x1c];
-               /* 16 Byte of some information on the dasd */
-               short blocksize;
-               char nopart;
-               char unused;
-               long unused2[3];
-               /* 7*10 = 70 Bytes of partition data */
-               struct {
-                       char type;
-                       long start;
-                       long size;
-                       char unused;
-               } part[7];
-       } __attribute__ ((packed)) label;
-} dasd_volume_label_t;
-
-typedef union {
-       struct {
-               unsigned long no;
-               unsigned int ct;
-       } __attribute__ ((packed)) input;
-       struct {
-               unsigned long noct;
-       } __attribute__ ((packed)) output;
-} __attribute__ ((packed)) dasd_xlate_t;
-
-int dasd_init (void);
-#ifdef MODULE
-int init_module (void);
-void cleanup_module (void);
-#endif                         /* MODULE */
-
-/* Definitions for blk.h */
-/* #define DASD_MAGIC 0x44415344  is ascii-"DASD" */
-/* #define dasd_MAGIC 0x64617364;  is ascii-"dasd" */
-#define DASD_MAGIC 0xC4C1E2C4 /* is ebcdic-"DASD" */
-#define dasd_MAGIC 0x8481A284 /* is ebcdic-"dasd" */
-#define MDSK_MAGIC 0xD4C4E2D2 /* is ebcdic-"MDSK" */
-#define mdsk_MAGIC 0x9484A292 /* is ebcdic-"mdsk" */
-#define ERP_MAGIC  0xC5D9D740 /* is ebcdic-"ERP" */
-#define erp_MAGIC  0x45999740 /* is ebcdic-"erp" */
-
-#define DASD_NAME "dasd"
-#define DASD_PARTN_BITS 2
-#define DASD_MAX_DEVICES (256>>DASD_PARTN_BITS)
-
-#define MAJOR_NR DASD_MAJOR
-#define PARTN_BITS DASD_PARTN_BITS
-
-#ifdef __KERNEL__
-/* Now lets turn to the internal sbtuff */
-/*
-   define the debug levels:
-   - 0 No debugging output to console or syslog
-   - 1 Log internal errors to syslog, ignore check conditions 
-   - 2 Log internal errors and check conditions to syslog
-   - 3 Log internal errors to console, log check conditions to syslog
-   - 4 Log internal errors and check conditions to console
-   - 5 panic on internal errors, log check conditions to console
-   - 6 panic on both, internal errors and check conditions
- */
-#define DASD_DEBUG 4
-
-#define DASD_PROFILE
-/*
-   define the level of paranoia
-   - 0 quite sure, that things are going right
-   - 1 sanity checking, only to avoid panics
-   - 2 normal sanity checking
-   - 3 extensive sanity checks
-   - 4 exhaustive debug messages
- */
-#define DASD_PARANOIA 2
-
-/*
-   define the depth of flow control, which is logged as a check condition
-   - 0 No flow control messages
-   - 1 Entry of functions logged like check condition
-   - 2 Entry and exit of functions logged like check conditions
-   - 3 Internal structure broken down
-   - 4 unrolling of loops,...
- */
-#define DASD_FLOW_CONTROL 0
-
-#if DASD_DEBUG > 0
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x )
-#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x )
-#else
-#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x )
-#endif                         /* DASD_DEBUG */
-
-#define INTERNAL_ERRMSG(x,y...) \
-"Internal error: in file " __FILE__ " line: %d: " x, __LINE__, y
-#define INTERNAL_CHKMSG(x,y...) \
-"Inconsistency: in file " __FILE__ " line: %d: " x, __LINE__, y
-#define INTERNAL_FLWMSG(x,y...) \
-"Flow control: file " __FILE__ " line: %d: " x, __LINE__, y
-
-#if DASD_DEBUG > 4
-#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) )
-#elif DASD_DEBUG > 2
-#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) )
-#elif DASD_DEBUG > 0
-#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) )
-#else
-#define INTERNAL_ERROR(x...)
-#endif                         /* DASD_DEBUG */
-
-#if DASD_DEBUG > 5
-#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) )
-#elif DASD_DEBUG > 3
-#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) )
-#elif DASD_DEBUG > 1
-#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) )
-#else
-#define INTERNAL_CHECK(x...)
-#endif                         /* DASD_DEBUG */
-
-#if DASD_DEBUG > 3
-#define INTERNAL_FLOW(x...) PRINT_ERR ( INTERNAL_FLWMSG ( x ) )
-#elif DASD_DEBUG > 2
-#define INTERNAL_FLOW(x...) PRINT_WARN ( INTERNAL_FLWMSG ( x ) )
-#else
-#define INTERNAL_FLOW(x...)
-#endif                         /* DASD_DEBUG */
-
-#if DASD_FLOW_CONTROL > 0
-#define FUNCTION_ENTRY(x) INTERNAL_FLOW( x "entered %s\n","" );
-#else
-#define FUNCTION_ENTRY(x)
-#endif                         /* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 1
-#define FUNCTION_EXIT(x) INTERNAL_FLOW( x "exited %s\n","" );
-#else
-#define FUNCTION_EXIT(x)
-#endif                         /* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 2
-#define FUNCTION_CONTROL(x...) INTERNAL_FLOW( x );
-#else
-#define FUNCTION_CONTROL(x...)
-#endif                         /* DASD_FLOW_CONTROL */
-
-#if DASD_FLOW_CONTROL > 3
-#define LOOP_CONTROL(x...) INTERNAL_FLOW( x );
-#else
-#define LOOP_CONTROL(x...)
-#endif                         /* DASD_FLOW_CONTROL */
-
-#define DASD_DO_IO_SLEEP 0x01
-#define DASD_DO_IO_NOLOCK 0x02
-#define DASD_DO_IO_NODEC 0x04
-
-#define DASD_NOT_FORMATTED 0x01
-
-extern struct wait_queue *dasd_waitq;
-
-#undef DEBUG_DASD_MALLOC
-#ifdef DEBUG_DASD_MALLOC
-void *b;
-#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b)
-#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x)
-#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b)
-#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b)
-#endif                         /* DEBUG_DASD_MALLOC */
-
-#endif                         /* __KERNEL__ */
-#endif                         /* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
index 6e8646c8b60fd6aa6ad0534f83c34b9811430b97..a509979a1a033fd3d8ac2d838f2cf40379867221 100644 (file)
@@ -8,6 +8,8 @@
 extern int request_module(const char * name);
 extern int exec_usermodehelper(char *program_path, char *argv[], char *envp[]);
 #else
+#include <linux/errno.h>
+
 #define request_module(x) do {} while(0)
 static inline int exec_usermodehelper(char *program_path, char *argv[], char *envp[])
 {
index 6c5e2aede6324cb38926de4fa1d34d8afe8cae0e..c4a88b4819ac0e018e3c33dd1fd5ae310632f706 100644 (file)
@@ -47,7 +47,7 @@
 #endif
 
 #ifdef CONFIG_DASD
-#include <linux/dasd.h>
+#include <asm/dasd.h>
 #endif
 
 #ifdef CONFIG_BLK_DEV_XPRAM
@@ -199,9 +199,6 @@ extern void mdisk_setup(char *str, int *ints);
 #endif
 #ifdef CONFIG_DASD
 extern void dasd_setup(char *str, int *ints);
-#ifdef CONFIG_DASD_MDSK
-extern void dasd_mdsk_setup(char *str, int *ints);
-#endif
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
 extern void xpram_setup(char *str, int *ints);
@@ -1098,9 +1095,6 @@ static struct kernel_param raw_params[] __initdata = {
 #endif
 #ifdef CONFIG_DASD
         { "dasd=", dasd_setup },
-#ifdef CONFIG_DASD_MDSK
-        { "dasd_force_diag=", dasd_mdsk_setup },
-#endif
 #endif
 #ifdef CONFIG_BLK_DEV_XPRAM
         { "xpram_parts=", xpram_setup },
@@ -1414,6 +1408,9 @@ asmlinkage void __init start_kernel(void)
        vma_init();
        buffer_init(memory_end-memory_start);
        page_cache_init(memory_end-memory_start);
+#ifdef CONFIG_ARCH_S390
+       ccwcache_init();
+#endif
        signals_init();
        inode_init();
        file_table_init();
@@ -1552,9 +1549,7 @@ static void __init do_basic_setup(void)
 
        /* Set up devices .. */
        device_setup();
-#if  CONFIG_CHANDEV
-       chandev_init();
-#endif   
+
        /* .. executable formats .. */
        binfmt_setup();
 
index 58cece436d8adfc5d9a79c691435924ac4035d72..0ac760b1bfef3eab603579f39d73da051f494408 100644 (file)
@@ -774,6 +774,10 @@ void netif_rx(struct sk_buff *skb)
        if (backlog.qlen <= netdev_max_backlog) {
                if (backlog.qlen) {
                        if (netdev_dropping == 0) {
+                               if (skb->dev->flags & IFF_SLAVE  && 
+                                   skb->dev->slave) {
+                                       skb->dev = skb->dev->slave;
+                               }
                                skb_queue_tail(&backlog,skb);
                                mark_bh(NET_BH);
                                return;
diff --git a/scripts/makelst b/scripts/makelst
new file mode 100644 (file)
index 0000000..f341229
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+# A script to dump mixed source code & assembly
+# with correct relocations from System.map
+# Requires the following lines in Rules.make.
+#
+#%.lst: %.c
+#      $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+#      $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
+#
+#    Copyright (C) 2000 IBM Corporation
+#    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+#
+
+t1=`$3 --syms $2/$1.o | grep .text | grep " F " | head -n 1`
+t2=`echo $t1 | gawk '{ print $6 }'`
+t3=`grep $t2 $2/System.map`
+t4=`echo $t3 | gawk '{ print $1 }'`
+t5=`echo $t1 | gawk '{ print $1 }'`
+t6=`echo $t4 - $t5 | sed s/a/A/g | sed s/b/B/g | sed s/c/C/g | sed s/d/D/g | sed s/e/E/g | sed s/f/F/g`
+t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+$3 --source --adjust-vma=$t7 $2/$1.o > $2/$1.lst