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
=====
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
=========
}
+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.
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 ?
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.
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
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
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
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 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
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
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
--------------------------------------------------------------------------------
--- /dev/null
+ 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.
+
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
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/)
%.o: %.s
$(AS) $(ASFLAGS) $(EXTRA_CFLAGS) -o $@ $<
+%.lst: %.c
+ $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
+ $(TOPDIR)/scripts/makelst $* $(TOPDIR) $(OBJDUMP)
#
#
#
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" \
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
(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]);
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 {
#endif
}
}
+#endif
/*
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,
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
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,
/*
** 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
*/
* 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:
-# 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
#
-# 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
#
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
# 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
#
# 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
#include <linux/errno.h>
#include <linux/malloc.h>
#include <asm/ebcdic.h>
+#include <asm/debug.h>
#ifdef MODULE
#include <linux/module.h>
#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;
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);
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;
+++ /dev/null
-
-#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
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
mcck_return:
RESTORE_ALL
-#ifdef __SMP__
+#ifdef CONFIG_SMP
/*
* Restart interruption handler, kick starter for additional CPUs
*/
.Ltrace: .long syscall_trace
.Lvfork: .long sys_vfork
-#ifdef __SMP__
+#ifdef CONFIG_SMP
.Lschedtail: .long schedule_tail
#endif
* 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)
* 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
.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:
lctl %c6,%c6,.Lcr6
slr %r2,%r2
.Lldlp:
- lhi %r6,3 # 3 retries
+ la %r6,3 # 3 retries
.Lssch:
ssch 0(%r3) # load chunk of IPL_BS bytes
- jnz .Llderr
+ bnz .Llderr
.Lw4end:
- bras %r14,.Lwait4io
+ bas %r14,.Lwait4io
tm 8(%r5),0x82 # do we have a problem ?
- jnz .Lrecov
+ bnz .Lrecov
slr %r7,%r7
icm %r7,3,10(%r5) # get residual count
lcr %r7,%r7
- ahi %r7,IPL_BS # IPL_BS-residual=#bytes read
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
ar %r2,%r7 # add to total size
tm 8(%r5),0x01 # found a tape mark ?
- jnz .Ldone
+ bnz .Ldone
l %r0,.Lccwread+4 # update CCW data addresses
ar %r0,%r7
st %r0,.Lccwread+4
- j .Lldlp
+ b .Lldlp
.Ldone:
l %r14,.Lldret
br %r14 # r2 contains the total size
.Lrecov:
- bras %r14,.Lsense # do the sensing
- brct %r6,.Lssch # dec. retry count & branch
- j .Llderr
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
#
# Sense subroutine
#
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
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:
.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.
.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
#
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
ahi %r0,0x640
st %r0,4(%r6)
ahi %r6,8
- brct 7,.Lincr
+ bct 7,.Lincr
- j .Lldlp
+ b .Lldlp
.Llderr:
lpsw .Lcrash
.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
.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
.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:
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
#
.Lflt0: .double 0
.Lparm1:.long PARMAREA
.L4malign:.long 0xffc00000
+.Lbigmem:.long 0x04000000
+.Lrdstart:.long 0x02000000
+.Lmaxchunk:.long 0x00ffffff
#
# params at 10400 (setup.h)
.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
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++)
} /* 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
* 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);
#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);
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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) {
}
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");
}
static psw_t wait_psw;
-#ifndef __SMP__
+#ifndef CONFIG_SMP
static
#endif
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;
}
*/
#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
#include <net/arp.h>
#endif
-
/*
* I/O subsystem
*/
EXPORT_SYMBOL(get_devno_by_irq);
EXPORT_SYMBOL(get_irq_first);
EXPORT_SYMBOL(get_irq_next);
+EXPORT_SYMBOL(read_conf_data);
+EXPORT_SYMBOL(read_dev_chars);
+EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_device_register);
+EXPORT_SYMBOL(s390_device_unregister);
+
+EXPORT_SYMBOL(ccw_alloc_request);
+EXPORT_SYMBOL(ccw_free_request);
-/*
- * External interrupts
- */
EXPORT_SYMBOL(register_external_interrupt);
EXPORT_SYMBOL(unregister_external_interrupt);
+/*
+ * debug feature
+ */
+EXPORT_SYMBOL(debug_register);
+EXPORT_SYMBOL(debug_unregister);
+EXPORT_SYMBOL(debug_event);
+EXPORT_SYMBOL(debug_text_event);
+EXPORT_SYMBOL(debug_exception);
+EXPORT_SYMBOL(debug_text_exception);
+
/*
* memory management
*/
EXPORT_SYMBOL_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);
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
-
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;
{
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 */
{
s390irq_spin_unlock_irqrestore( irq, flags);
- printk("free_irq() : error, no action block ... !");
+ printk( "free_irq(%04X) : error, "
+ "no action block ... !\n", irq);
} /* endif */
if ( flag & DOIO_WAIT_FOR_INTERRUPT )
{
int io_sub = -1;
- __u32 io_parm;
psw_t io_new_psw;
int ccode;
uint64_t time_start;
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, ®s );
-
- } /* endif */
+ action->handler( irq, action->dev_id, ®s );
//
// reset intparm after final status or we will badly present unsolicited
*/
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, ®s );
-
- } /* endif */
+ action->handler( irq, action->dev_id, ®s );
} /* endif */
((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,
- ®s );
-
- } /* endif */
+ action->handler( irq, action->dev_id, ®s );
} /* endif */
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, ®s );
-
- } /* endif */
+ action->handler( irq, action->dev_id, ®s );
} /* endif */
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;
if ( ioinfo[irq]->ui.flags.ready )
pdi->status |= DEVSTAT_DEVICE_OWNED;
- return 0;
-
} /* endif */
+ return 0;
}
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 */
else
{
ioinfo[irq]->ui.flags.syncio = 1; // global
+ ioinfo[irq]->ui.flags.unknown = 0;
memset( &ioinfo[irq]->senseid, '\0', sizeof( senseid_t));
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 )
{
} /* endif */
- if ( ioinfo[irq]->ui.flags.oper )
+ if ( ioinfo[irq]->ui.flags.unknown )
irq_ret = 0;
else
irq_ret = -ENODEV;
/* added by Holger Smolinski for reipl support in reipl.S */
+extern void do_reipl (int);
void
reipl ( int sch )
{
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
__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
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);
* 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;
/*
* Reboot, halt and power_off routines for non SMP.
*/
-#ifndef __SMP__
+#ifndef CONFIG_SMP
void machine_restart(char * __unused)
{
reipl(S390_lowcore.ipl_device);
{
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
*/
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
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;
break;
*(to++) = c;
}
+ if (c == ' ' && to > command_line) to--;
*to = '\0';
*cmdline_p = command_line;
memory_end += PAGE_OFFSET;
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,
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:
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;
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.
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. */
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)
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)
void smp_send_stop(void)
{
- smp_signal_others(sigp_stop, 0, TRUE, NULL);
+ smp_signal_others(sigp_stop_and_store_status, 0, TRUE, NULL);
}
/*
{
int curr_cpu;
- __cpu_logical_map[0] = boot_cpu_addr;
current->processor = 0;
smp_num_cpus = 1;
for (curr_cpu = 0;
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);
}
* as well as call the "do_timer()" routine every clocktick
*/
-#ifdef __SMP__
+#ifdef CONFIG_SMP
extern __u16 boot_cpu_addr;
#endif
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;
* 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);
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
}
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 */
-}
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..
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);
all: dasdfmt
dasdfmt: dasdfmt.c
- $(CROSS_COMPILE)gcc -o $@ $^
- $(STRIP) $@
+ $(CROSS_COMPILE)gcc -I$(HPATH) -o $@ $^
+ $(CROSS_COMPILE)strip $@
clean:
rm -f dasdfmt
.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
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.
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
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 ;-)
* 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>
#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");
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) &&
char *str;
char output[60],o2[12];
+#ifdef RANGE_FORMATTING
i=params.start_unit;
do {
params.start_unit=i;
ASK_CHECK_PARAM(CHECK_END);
}
} while (rc!=1);
+#endif /* RANGE_FORMATTING */
i=params.blksize;
do {
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);
}
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,
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 : ");
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");
"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) {
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;
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;
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;
/* 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;
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++;
end_specified++;
break;
+ case 'r' :
+ range_param_str=optarg;
+ range_specified++;
+ break;
+#endif /* RANGE_FORMATTING */
+
case 'b' :
blksize_param_str=optarg;
blksize_specified++;
dev_filename=optarg;
devfile_specified++;
break;
- case 'r' :
- range_param_str=optarg;
- range_specified++;
- break;
}
}
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");
/******* 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) {
#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
#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); }
* 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
*
# 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
/*
* 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)
/*
* 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>
*
* ---------------------------------------------------------------------------
*
/*
* 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)
*
/*
* 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)
*
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
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;
}
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;
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) {
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)) {
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.**
/* 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 */
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
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
CFLAGS +=
O_TARGET := io.o
-O_OBJS :=
+O_OBJS := ccwcache.o
M_OBJS :=
SUBDIRS := $(SUBDIRS) arch/s390/drivers/block arch/s390/drivers/char \
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)
net/s390-net.o: dummy
$(MAKE) -C net
+
include $(TOPDIR)/Rules.make
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
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
* 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(®->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 (®ister_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 (®ister_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;
}
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;
}
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 =
{
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.
--- /dev/null
+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*);
+
+
+
--- /dev/null
+/*
+ * 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:
+ */
* (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
* 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;
--- /dev/null
+/*
+ * 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:
+ */
* (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))
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-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);
--- /dev/null
+/*
+ * 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:
+ */
--- /dev/null
+/*
+ * 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);
* 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 */ )
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)
{
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);
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;
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++;
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;
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)
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 ) {
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) {
}
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
--- /dev/null
+#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 */
* (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)"
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;
- }
}
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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 */
+/*
+ * 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)
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)
{
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)
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) {
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;
} 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;
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
-};
--- /dev/null
+#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 */
+++ /dev/null
-#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
-};
+++ /dev/null
-#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
+++ /dev/null
-/*
- 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)
-{
-}
+++ /dev/null
-
-#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;
-}
+++ /dev/null
-/*
- * 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
+++ /dev/null
-
-/*
- * 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 */
--- /dev/null
+/*
+ * 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 */
#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 */
*/
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 */
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 */
{
int vdev;
- vdev = simple_strtoul(str,&str,16);
+ vdev = simple_strtoul(str,&str,10);
if (vdev >= 0 && vdev < 65536)
raw3215_condevice = vdev;
return;
}
/*
- * 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)
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;
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;
}
/*
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);
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);
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 */
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);
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;
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;
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);
/* 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);
}
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;
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) {
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;
*/
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);
}
if (wait_cons_dev(raw->irq) != 0) {
/* that shouldn't happen */
raw->count = 0;
+ raw->written = 0;
}
raw->flags &= ~RAW3215_FLUSHING;
}
return 0;
}
-#if 0
-
static void
hwc_tty_close (struct tty_struct *tty,
struct file *filp)
"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)
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;
* 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>
kfree(p);
return -ENOMEM;
}
+ p->block->length = 0;
}
if (ctc->free_anchor == NULL)
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' */
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 );
} 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);
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 );
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);
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);
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 );
#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 );
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);
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]);
}
static int ctc_release(net_device *dev)
{
int rc;
- int x;
int i;
int j;
__u8 flags = 0x00;
* 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[];
/*
/* 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);
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 */
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
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;
}
(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;
#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 */
{
__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)
" 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)
" 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)
" 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)
" ahi %1,1\n"
" cs 0,%1,%0\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0" );
+ : "+m" (*v), "=&d" (i) : : "0", "cc" );
return i;
}
" 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)
" ahi %1,-1\n"
" cs 0,%1,%0\n"
" jl 0b"
- : "+m" (*v), "=&d" (i) : : "0" );
+ : "+m" (*v), "=&d" (i) : : "0", "cc" );
return i;
}
" 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;
}
" 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)
" or 1,%1\n"
" cs 0,1,%0\n"
" jl 0b"
- : "+m" (*v) : "d" (mask) : "0", "1" );
+ : "+m" (*v) : "d" (mask) : "0", "1", "cc" );
}
/*
"0:"
: "=&r" (retval), "+m" (*v)
: "d" (expected_oldval) , "d" (new_val)
- : "memory", "cc");
+ : "cc");
return retval;
}
" 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"
" 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 __ */
" 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 */
" 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"
" 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 */
" 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 */
#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)
" 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"
" 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;
}
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;
return size;
if (bit) {
- word = *p | orword[bit];
+ __asm__(" ic %0,0(%1)\n"
+ " icm %0,2,1(%1)\n"
+ " icm %0,4,2(%1)\n"
+ " icm %0,8,3(%1)"
+ : "=&a" (word) : "a" (p) );
+ word >>= bit;
+ res = bit;
/* Look for zero in first longword */
- __asm__(" lhi %0,24\n"
- " tmh %1,0xFFFF\n"
- " jo 0f\n"
- " ahi %0,-16\n"
+ __asm__(" lhi 0,0xff\n"
+ " tml %1,0xffff\n"
+ " jno 0f\n"
+ " ahi %0,16\n"
" srl %1,16\n"
- "0: tml %1,0xFF00\n"
- " jo 1f\n"
- " ahi %0,-8\n"
+ "0: tml %1,0x00ff\n"
+ " jno 1f\n"
+ " ahi %0,8\n"
" srl %1,8\n"
- "1: n %1,%2\n"
- " ic %1,0(%1,%3)\n"
+ "1: nr %1,0\n"
+ " ic %1,0(%1,%2)\n"
" alr %0,%1"
- : "=&d" (res), "+&d" (word)
- : "m" (mask), "a" (&_zb_findmap)
- : "cc" );
+ : "+&d" (res), "+&d" (word)
+ : "a" (&_zb_findmap)
+ : "cc", "0" );
if (res < 32)
return (p - addr)*32 + res;
p++;
--- /dev/null
+/*
+ * 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 */
+
+
+
--- /dev/null
+
+#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:
+ */
--- /dev/null
+#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 */
#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) */
#ifndef __irq_h
#define __irq_h
+#ifdef __KERNEL__
#include <asm/hardirq.h>
/*
#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);
/* ... in an operand exception. */
} __attribute__ ((packed)) pmcw_t;
+#endif /* __KERNEL__ */
+
/*
* subchannel status word
*/
#define SCHN_STAT_INTF_CTRL_CHK 0x02
#define SCHN_STAT_CHAIN_CHECK 0x01
+#ifdef __KERNEL__
+
/*
* subchannel information block
*/
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. */
#define CCW_CMD_SET_PGID 0xAF
#define CCW_CMD_SENSE_ID 0xE4
+#ifdef __KERNEL__
+
#define SENSE_MAX_COUNT 0x20
/*
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 */
char ecw[32]; /* extended control word */
} irb_t __attribute__ ((aligned(4)));
+#ifdef __KERNEL__
+
/*
* TPI info structure
*/
ciw_t ciw[16]; /* variable # of CIWs */
} __attribute__ ((packed,aligned(4))) senseid_t;
+#endif /* __KERNEL__ */
+
/*
* sense data
*/
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
#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 );
* 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) {
#define s390irq_spin_unlock_irqrestore(irq,flags) \
spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags)
+#endif /* __KERNEL__ */
#endif
__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,
__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,
#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 */
#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
* 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; }
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; }
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 */
*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;
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;
#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
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)
" 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;
}
{
__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) \
#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)
#endif /* SMP */
#endif /* __ASM_SPINLOCK_H */
-
-
-
-
-
-
-
-
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;
}
{
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"
".previous"
: "=m" (*((__u32*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "1", "4" );
+ : "4" );
return err;
}
{
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"
".previous"
: "=m" (*((__u16*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "1", "4" );
+ : "4" );
return err;
}
{
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"
".previous"
: "=m" (*((__u8*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "1", "4" );
+ : "4" );
return err;
}
#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" \
".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" \
".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" \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(__u8*) ptr), "K" (-EFAULT) \
- : "1", "4" ); \
+ : "4" ); \
})
#define __get_user(x, ptr) \
__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;
}
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); \
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"
" 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"
: "=&a" (len)
: "a" (dst), "d" (src), "d" (count),
"K" (-EFAULT)
- : "1", "2", "3", "4", "memory" );
+ : "2", "3", "4", "memory" );
return len;
}
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"
" 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"
" .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)
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;
}
struct ucontext *uc_link;
stack_t uc_stack;
sigset_t uc_sigmask; /* mask last for extensibility */
+ struct sigcontext *sc; /* Added for pthread support */
};
+++ /dev/null
-
-#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:
- */
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[])
{
#endif
#ifdef CONFIG_DASD
-#include <linux/dasd.h>
+#include <asm/dasd.h>
#endif
#ifdef CONFIG_BLK_DEV_XPRAM
#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);
#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 },
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();
/* Set up devices .. */
device_setup();
-#if CONFIG_CHANDEV
- chandev_init();
-#endif
+
/* .. executable formats .. */
binfmt_setup();
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;
--- /dev/null
+#!/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