]> git.hungrycats.org Git - linux/commitdiff
v2.4.7 -> v2.4.7.1
authorLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:14:54 +0000 (19:14 -0800)
committerLinus Torvalds <torvalds@athlon.transmeta.com>
Tue, 5 Feb 2002 03:14:54 +0000 (19:14 -0800)
  - Anton Altaparmakov: NTFS error checking
  - Johannes Erdfelt: USB updates
  - OGAWA Hirofumi: FAT update
  - Alan Cox: driver + s390 update merge
  - Richard Henderson: fix alpha sigsuspend error return value
  - Marcelo Tosatti: per-zone VM shortage
  - Daniel Phillips: generic use-once optimization instead of drop-behind
  - Bjorn Wesen: Cris architecture update
  - Anton Altaparmakov: support for Windows Dynamic Disks
  - James Washer: LDT loading SMP bug fix

324 files changed:
Documentation/Configure.help
Documentation/s390/CommonIO [new file with mode: 0644]
Documentation/s390/Debugging390.txt
Documentation/s390/TAPE
Documentation/s390/chandev.8
Makefile
arch/alpha/kernel/entry.S
arch/cris/Makefile
arch/cris/boot/compressed/decompress.ld
arch/cris/config.in
arch/cris/cris.ld
arch/cris/drivers/eeprom.c
arch/cris/drivers/lpslave/e100lpslave.S
arch/cris/drivers/lpslave/e100lpslavenet.c
arch/cris/drivers/parport.c
arch/cris/kernel/Makefile
arch/cris/kernel/entry.S
arch/cris/kernel/entryoffsets.c
arch/cris/kernel/head.S
arch/cris/kernel/irq.c
arch/cris/kernel/process.c
arch/cris/kernel/ptrace.c
arch/cris/kernel/setup.c
arch/cris/kernel/sys_cris.c
arch/cris/kernel/time.c
arch/cris/kernel/traps.c
arch/cris/lib/Makefile
arch/cris/lib/checksumcopy.S
arch/cris/lib/csumcpfruser.S [new file with mode: 0644]
arch/cris/mm/fault.c
arch/cris/mm/init.c
arch/cris/mm/tlb.c
arch/i386/kernel/cpuid.c
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/ldt.c
arch/i386/kernel/msr.c
arch/i386/kernel/process.c
arch/i386/math-emu/poly.h
arch/ppc/kernel/misc.S
arch/s390/Makefile
arch/s390/boot/Makefile
arch/s390/config.in
arch/s390/defconfig
arch/s390/kernel/debug.c
arch/s390/kernel/entry.S
arch/s390/kernel/head.S
arch/s390/kernel/irq.c
arch/s390/kernel/process.c
arch/s390/kernel/s390_ext.c
arch/s390/kernel/s390_ksyms.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kernel/traps.c
arch/s390/mm/Makefile
arch/s390/mm/fault.c
arch/s390/tools/dasdfmt/Makefile [deleted file]
arch/s390/tools/dasdfmt/dasdfmt.8 [deleted file]
arch/s390/tools/dasdfmt/dasdfmt.c [deleted file]
arch/s390/tools/silo/Makefile [deleted file]
arch/s390/tools/silo/cfg.c [deleted file]
arch/s390/tools/silo/cfg.h [deleted file]
arch/s390/tools/silo/silo.c [deleted file]
arch/s390/tools/silo/silo.conf [deleted file]
arch/s390x/Makefile
arch/s390x/config.in
arch/s390x/defconfig
arch/s390x/kernel/debug.c
arch/s390x/kernel/entry.S
arch/s390x/kernel/head.S
arch/s390x/kernel/irq.c
arch/s390x/kernel/linux32.c
arch/s390x/kernel/process.c
arch/s390x/kernel/s390_ext.c
arch/s390x/kernel/s390_ksyms.c
arch/s390x/kernel/setup.c
arch/s390x/kernel/signal.c
arch/s390x/kernel/smp.c
arch/s390x/kernel/time.c
arch/s390x/kernel/traps.c
arch/s390x/mm/fault.c
arch/s390x/tools/dasdfmt/Makefile [deleted file]
arch/s390x/tools/dasdfmt/dasdfmt.8 [deleted file]
arch/s390x/tools/dasdfmt/dasdfmt.c [deleted file]
arch/s390x/tools/silo/Makefile [deleted file]
arch/s390x/tools/silo/cfg.c [deleted file]
arch/s390x/tools/silo/cfg.h [deleted file]
arch/s390x/tools/silo/silo.c [deleted file]
arch/s390x/tools/silo/silo.conf [deleted file]
drivers/block/cpqarray.c
drivers/block/ida_cmd.h
drivers/block/ida_ioctl.h
drivers/char/moxa.c
drivers/char/riscom8.c
drivers/char/serial.c
drivers/char/synclink.c
drivers/media/video/zr36067.c
drivers/net/sk98lin/skge.c
drivers/net/sk98lin/skproc.c
drivers/net/wan/sbni.c
drivers/net/wan/sbni.h
drivers/pcmcia/i82365.c
drivers/pnp/Config.in
drivers/s390/Config.in
drivers/s390/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/xpram.c
drivers/s390/ccwcache.c
drivers/s390/char/Makefile
drivers/s390/char/con3215.c
drivers/s390/char/ctrlchar.c
drivers/s390/char/ctrlchar.h
drivers/s390/char/hwc.h
drivers/s390/char/hwc_con.c
drivers/s390/char/hwc_cpi.c [new file with mode: 0644]
drivers/s390/char/hwc_rw.c
drivers/s390/char/hwc_rw.h
drivers/s390/char/hwc_tty.c
drivers/s390/char/tape.c
drivers/s390/char/tape.h
drivers/s390/char/tape3480.c
drivers/s390/char/tape3480.h
drivers/s390/char/tape3490.c
drivers/s390/char/tape3490.h
drivers/s390/char/tape34xx.c
drivers/s390/char/tape34xx.h
drivers/s390/char/tape3590.c [new file with mode: 0644]
drivers/s390/char/tape3590.h [new file with mode: 0644]
drivers/s390/char/tapeblock.c
drivers/s390/char/tapeblock.h
drivers/s390/char/tapechar.c
drivers/s390/char/tapechar.h
drivers/s390/char/tapedefs.h
drivers/s390/char/tuball.c
drivers/s390/char/tubfs.c
drivers/s390/char/tubio.h
drivers/s390/char/tubtty.c
drivers/s390/char/tubttyscl.c
drivers/s390/char/tubttysiz.c
drivers/s390/idals.c
drivers/s390/misc/chandev.c
drivers/s390/net/Makefile
drivers/s390/net/ctcmain.c
drivers/s390/net/ctctty.c
drivers/s390/net/ctctty.h
drivers/s390/net/fsm.c
drivers/s390/net/fsm.h
drivers/s390/net/iucv.c
drivers/s390/net/iucv.h
drivers/s390/net/netiucv.c
drivers/s390/s390dyn.c
drivers/s390/s390io.c
drivers/s390/s390mach.c
drivers/scsi/atp870u.c
drivers/scsi/g_NCR5380.c
drivers/scsi/gdth_proc.c
drivers/scsi/megaraid.c
drivers/scsi/megaraid.h
drivers/scsi/ultrastor.c
drivers/sound/sb_card.c
drivers/sound/sb_mixer.c
drivers/sound/via82cxxx_audio.c
drivers/usb/ibmcam.c
drivers/usb/ov511.c
drivers/usb/rio500.c
drivers/usb/scanner.c
drivers/usb/scanner.h
drivers/usb/se401.c
drivers/usb/serial/empeg.c
drivers/usb/usb-ohci.c
drivers/usb/usb-ohci.h
drivers/usb/usb.c
fs/autofs/autofs_i.h
fs/fat/buffer.c
fs/fat/cvf.c
fs/fat/inode.c
fs/ntfs/dir.c
fs/ntfs/inode.c
fs/partitions/Config.in
fs/partitions/Makefile
fs/partitions/check.c
fs/partitions/ldm.c [new file with mode: 0644]
fs/partitions/ldm.h [new file with mode: 0644]
fs/proc/array.c
include/asm-cris/atomic.h
include/asm-cris/axisflashmap.h
include/asm-cris/checksum.h
include/asm-cris/delay.h
include/asm-cris/hardirq.h
include/asm-cris/io.h
include/asm-cris/irq.h
include/asm-cris/processor.h
include/asm-cris/ptrace.h
include/asm-cris/socket.h
include/asm-cris/softirq.h
include/asm-i386/apic.h
include/asm-i386/checksum.h
include/asm-i386/cobalt.h
include/asm-i386/desc.h
include/asm-i386/fixmap.h
include/asm-i386/io.h
include/asm-i386/lithium.h
include/asm-i386/locks.h
include/asm-i386/mmu.h
include/asm-i386/mmu_context.h
include/asm-i386/page.h
include/asm-i386/pci.h
include/asm-i386/pgalloc.h
include/asm-i386/pgtable-2level.h
include/asm-i386/pgtable-3level.h
include/asm-i386/processor.h
include/asm-i386/siginfo.h
include/asm-i386/signal.h
include/asm-i386/smp.h
include/asm-i386/smplock.h
include/asm-i386/string.h
include/asm-i386/system.h
include/asm-i386/uaccess.h
include/asm-s390/atomic.h
include/asm-s390/bitops.h
include/asm-s390/byteorder.h
include/asm-s390/cache.h
include/asm-s390/chandev.h
include/asm-s390/checksum.h
include/asm-s390/current.h
include/asm-s390/dasd.h
include/asm-s390/debug.h
include/asm-s390/div64.h
include/asm-s390/hardirq.h
include/asm-s390/idals.h
include/asm-s390/init.h
include/asm-s390/io.h
include/asm-s390/irq.h
include/asm-s390/lowcore.h
include/asm-s390/page.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/queue.h
include/asm-s390/s390dyn.h
include/asm-s390/setup.h
include/asm-s390/softirq.h
include/asm-s390/system.h
include/asm-s390/uaccess.h
include/asm-s390x/atomic.h
include/asm-s390x/cache.h
include/asm-s390x/chandev.h
include/asm-s390x/checksum.h
include/asm-s390x/current.h
include/asm-s390x/dasd.h
include/asm-s390x/debug.h
include/asm-s390x/hardirq.h
include/asm-s390x/idals.h
include/asm-s390x/init.h
include/asm-s390x/io.h
include/asm-s390x/irq.h
include/asm-s390x/lowcore.h
include/asm-s390x/page.h
include/asm-s390x/pci.h [new file with mode: 0644]
include/asm-s390x/pgalloc.h
include/asm-s390x/pgtable.h
include/asm-s390x/processor.h
include/asm-s390x/queue.h
include/asm-s390x/s390dyn.h
include/asm-s390x/setup.h
include/asm-s390x/signal.h
include/asm-s390x/softirq.h
include/asm-s390x/system.h
include/asm-s390x/termios.h
include/asm-s390x/uaccess.h
include/asm-s390x/unistd.h
include/linux/byteorder/swab.h
include/linux/byteorder/swabb.h
include/linux/fs.h
include/linux/hdlc.h
include/linux/i2c-dev.h
include/linux/i2o.h
include/linux/inetdevice.h
include/linux/init.h
include/linux/ipsec.h
include/linux/isapnp.h
include/linux/isicom.h
include/linux/kbd_kern.h
include/linux/kernel_stat.h
include/linux/lockd/lockd.h
include/linux/locks.h
include/linux/loop.h
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv4/listhelp.h
include/linux/netfilter_ipv6/ip6_tables.h
include/linux/netlink.h
include/linux/nfsd/nfsfh.h
include/linux/nubus.h
include/linux/pagemap.h
include/linux/parport.h
include/linux/parport_pc.h
include/linux/pm.h
include/linux/poll.h
include/linux/quotaops.h
include/linux/raid/md_compatible.h
include/linux/raid/md_k.h
include/linux/reiserfs_fs.h
include/linux/rtnetlink.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/stats.h
include/linux/sunrpc/types.h
include/linux/swap.h
include/linux/sysv_fs.h
include/linux/tty_flip.h
include/linux/videodev.h
kernel/softirq.c
kernel/sys.c
mm/filemap.c
mm/memory.c
mm/page_alloc.c
mm/swap.c
mm/vmscan.c
net/irda/ircomm/ircomm_tty.c
net/irda/ircomm/ircomm_tty_attach.c

index c20479af72390ed78b8799e76acffc2b5f5d4cbf..ce826df4e324d3a4ffc56c7212133741e7d16613 100644 (file)
@@ -12471,6 +12471,33 @@ CONFIG_MAC_PARTITION
   Say Y here if you would like to use hard disks under Linux which
   were partitioned on a Macintosh.
 
+Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
+CONFIG_LDM_PARTITION
+  Say Y here if you would like to use hard disks under Linux which
+  were partitioned using Windows 2000's or XP's Logical Disk Manager.
+  They are also known as "Dynamic Disks".
+
+  Windows 2000 introduced the concept of Dynamic Disks to get around
+  the limitations of the PC's partitioning scheme.  The Logical Disk
+  Manager allows the user to repartion a disk and create spanned,
+  mirrored, striped or RAID volumes, all without the need for
+  rebooting.
+
+  Normal partitions are now called Basic Disks under Windows 2000 and XP.
+
+  Technical documentation to accompany this driver is available from:
+  <http://linux-ntfs.sf.net/ldm>
+
+  If unsure, say N.
+
+Windows' LDM extra logging
+CONFIG_LDM_DEBUG
+  Say Y here if you would like LDM to log verbosely.  This could be
+  helpful if the driver doesn't work as expected and you'd like to
+  report a bug.
+
+  If unsure, say N.
+
 PC BIOS (MSDOS partition tables) support
 CONFIG_MSDOS_PARTITION
   Say Y here if you would like to use hard disks under Linux which
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
new file mode 100644 (file)
index 0000000..a11b29d
--- /dev/null
@@ -0,0 +1,124 @@
+S/390 common I/O-Layer - command line parameters and /proc entries
+==================================================================
+
+Command line parameters
+-----------------------
+
+* cio_msg = yes | no
+  
+  Determines whether information on found devices and sensed device 
+  characteristics should be shown during startup, i. e. messages of the types 
+  "Detected device 4711 on subchannel 42" and "SenseID: Device 4711 reports: ...".
+
+  Default is off.
+
+
+* cio_notoper_msg = yes | no
+
+  Determines whether messages of the type "Device 4711 became 'not operational'"
+  should be shown during startup; after startup, they will always be shown.
+  
+  Default is on.
+
+
+* cio_ignore = <range of device numbers>, <range of device numbers>, ...
+
+  The given device numbers will be ignored by the common I/O-layer; no detection
+  and device sensing will be done on any of those devices. The subchannel to 
+  which the device in question is attached will be treated as if no device was
+  attached.
+
+  An ignored device can be un-ignored later; see the "/proc entries"-section for
+  details.
+
+  The device numbers must be given hexadecimal.
+
+  For example, 
+       cio_ignore=0x23-0x42,0x4711
+  will ignore all devices with device numbers ranging from 23 to 42 and the 
+  device with device number 4711, if detected.
+
+  By default, no devices are ignored.
+
+
+* cio_proc_devinfo = yes | no
+
+  Determines whether the entries under /proc/deviceinfo/ (see below) should be
+  created. Since there are problems with systems with many devices attached, I
+  made it configurable.
+
+  Until the problems are dealt with, default is off.
+
+
+/proc entries
+-------------
+
+* /proc/subchannels
+
+  Shows for each subchannel
+  - device number
+  - device type/model and if applicable control unit type/model
+  - whether the device is in use
+  - path installed mask, path available mask, path operational mask and last 
+    path used mask
+  - the channel path IDs (chpids)
+
+
+* /proc/deviceinfo/
+
+  Shows in subdirectories for each device some characteristics:
+  - /proc/deviceinfo/<devno>/chpids: 
+       the channel path IDs
+  - /proc/deviceinfo/<devno>/in_use: 
+       whether the device is in use
+  - /proc/deviceinfo/<devno>/sensedata:
+       the device type/model and if applicable control unit type/model of the
+       device
+
+  NOTE: Since the number of inodes which can be dynamically allocated by procfs
+        is limited, device entries will only be created up to a magic number of
+        devices. The kernel will utter a warning that not all entries can be
+        created. In this case, you shouldn't use "cio_proc_devinfo=yes" (see
+        above).
+
+* /proc/cio_ignore
+
+  Lists the ranges of device numbers which are ignored by common I/O.
+
+  You can un-ignore certain or all devices by piping to /proc/cio_ignore. 
+  "free all" will un-ignore all ignored devices, 
+  "free <devnorange>, <devnorange>, ..." will un-ignore the specified devices.
+
+  For example, if devices 23 to 42 and 4711 are ignored,
+  - echo free 0x30-0x32 > /proc/cio_ignore
+    will un-ignore devices 30 to 32 and will leave devices 23 to 2F, 33 to 42
+    and 4711 ignored;
+  - echo free 0x41 > /proc/cio_ignore will furthermore un-ignore device 41;
+  - echo free all > /proc/cio_ignore will un-ignore all remaining ignored 
+    devices.
+
+  When a device is un-ignored, device recognition and sensing is performed and 
+  the device driver will be notified if possible, so the device will become
+  available to the system.
+
+
+* /proc/s390dbf/cio_*/ (S/390 debug feature)
+
+  Some views generated by the debug feature to hold various debug outputs.
+
+  - /proc/s390dbf/cio_crw/sprintf
+    Messages from the processing of pending channel report words (machine check
+    handling), which will also show when CONFIG_DEBUG_CRW is defined.
+
+  - /proc/s390dbf/cio_msg/sprintf
+    Various debug messages from the common I/O-layer; generally, messages which 
+    will also show when CONFIG_DEBUG_IO is defined.
+
+  - /proc/s390dbf/cio_trace/hex_ascii
+    Logs the calling of functions in the common I/O-layer and, if applicable, 
+    which subchannel they were called for.
+
+  The level of logging can be changed to be more or less verbose by piping to 
+  /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
+  the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
+
index 33cf0f544e4df373eb36d35e90db447d255bb5a3..32e668a6aa8efe3e7cb5e2880959054bf807401f 100644 (file)
@@ -1,5 +1,5 @@
               
-                          Debugging on Linux for s/390 & zSeries
+                          Debugging on Linux for s/390 & z/Architecture
                                       by
                Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
                Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -8,7 +8,7 @@
 Overview of Document:
 =====================
 This document is intended to give an good overview of how to debug 
-Linux for s/390 & zSeries it isn't intended as a complete reference & not a
+Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a
 tutorial on the fundamentals of C & assembly, it dosen't go into
 390 IO in any detail. It is intended to compliment the documents in the
 reference section below & any other worthwhile references you get.
@@ -21,46 +21,46 @@ Contents
 ========
 Register Set
 Address Spaces on Intel Linux
-Address Spaces on Linux for s/390 & zSeries
-The Linux for s/390 & zSeries Kernel Task Structure
-Register Usage & Stackframes on Linux for s/390 & zSeries
+Address Spaces on Linux for s/390 & z/Architecture
+The Linux for s/390 & z/Architecture Kernel Task Structure
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
 A sample program with comments
-Compiling programs for debugging on Linux for s/390 & zSeries
+Compiling programs for debugging on Linux for s/390 & z/Architecture
 Figuring out gcc compile errors
 Debugging Tools
 objdump
 strace
 Performance Debugging 
 Debugging under VM
-s/390 & zSeries IO Overview
-Debugging IO on s/390 & zSeries under VM
-GDB on s/390 & zSeries
+s/390 & z/Architecture IO Overview
+Debugging IO on s/390 & z/Architecture under VM
+GDB on s/390 & z/Architecture
 Stack chaining in gdb by hand
 Examining core dumps
 ldd
 Debugging modules
 The proc file system
 Starting points for debugging scripting languages etc.
-Tools soon to be available
 SysRq
 References
+Special Thanks
 
 Register Set
 ============
 The current architectures have the following registers.
  
-16  General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
+16  General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing. 
 
-16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment,
+16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory managment,
 interrupt control,debugging control etc.
 
-16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries
+16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture
 not used by normal programs but potentially could 
 be used as temporary storage. Their main purpose is their 1 to 1
 association with general purpose registers and are used in
 the kernel for copying data between kernel & user address spaces.
-Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) )
-is currently used by the pthread library as a pointer to
+Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit 
+pointer ) ) is currently used by the pthread library as a pointer to
 the current running threads private area.
 
 16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating 
@@ -72,7 +72,7 @@ Linux (currently) always uses IEEE & emulates G5 IEEE format on older machines,
 
 
 The PSW is the most important register on the machine it
-is 64 bit on s/390 & 128 bit on zSeries & serves the roles of 
+is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of 
 a program counter (pc), condition code register,memory space designator.
 In IBM standard notation I am counting bit 0 as the MSB.
 It has several advantages over a normal program counter
@@ -83,7 +83,7 @@ have a logical=physical mapping for the address you are
 currently running at.
 
       Bit           Value
-s/390 zSeries
+s/390 z/Architecture
 0       0     Reserved ( must be 0 ) otherwise specification exception occurs.
 
 1       1     Program Event Recording 1 PER enabled, 
@@ -100,7 +100,7 @@ s/390 zSeries
 
 8-11  8-11    PSW Key used for complex memory protection mechanism not used under linux
 
-12      12    1 on s/390 0 on zSeries
+12      12    1 on s/390 0 on z/Architecture
 
 13      13    Machine Check Mask 1=enable machine check interrupts
 
@@ -175,15 +175,19 @@ s/390 zSeries
                compatible.
          
          
-Prefix Page
------------      
+Prefix Page(s)
+--------------   
 This per cpu memory area is too intimately tied to the processor not to mention.
-It exists between the real addresses 0-4096 on the processor & is exchanged 
-with a page in absolute storage by the set prefix instruction in linux'es startup. 
-This page different on each processor.
-Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such
-information as exception indications & entry points for exceptions.
-Bytes after 0xc00 hex are used by linux for per processor globals.
+It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged 
+with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set 
+prefix instruction in linux'es startup. 
+This page is mapped to a different prefix for each processor in an SMP configuration
+( assuming the os designer is sane of course :-) ).
+Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture 
+are used by the processor itself for holding such information as exception indications & 
+entry points for exceptions.
+Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture 
+( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ).
 The closest thing to this on traditional architectures is the interrupt
 vector table. This is a good thing & does simplify some of the kernel coding
 however it means that we now cannot catch stray NULL pointers in the
@@ -219,9 +223,6 @@ processor ( if an smp box ).
 If using the virtual machine ( VM ) as a debugger it is quite difficult to
 know which user process is running as the address space you are looking at
 could be from any process in the run queue.
-Thankfully you normally get lucky as address spaces don't overlap that &
-you can recognise the code at by cross referencing with a dump made by objdump
-( more about that later ).
 
 The limitation of Intels addressing technique is that the linux
 kernel uses a very simple real address to virtual addressing technique
@@ -240,35 +241,77 @@ For backward compatibility we are only allowed use 31 bits (2GB)
 of our 32 bit addresses,however, we use entirely separate address 
 spaces for the user & kernel.
 
-This means we can support 2GB of non Extended RAM, & more
-with the Extended memory managment swap device & 64 Bit
-when it comes along.
+This means we can support 2GB of non Extended RAM on s/390, & more
+with the Extended memory managment swap device & 
+currently 4TB of physical memory currently on z/Architecture.
 
 
-Address Spaces on Linux for S390
-================================
+Address Spaces on Linux for s/390 & z/Architecture
+==================================================
 
 Our addressing scheme is as follows
 
 
-Himem 0x7fffffff 2GB on s/390   *****************          ****************
-2^64 bytes on zSeries           *  User Stack   *          *              *
-                               *****************          *              *
-                               *  Shared Libs  *          *              *          
-                                *****************          *              *  
-                               *               *          *    Kernel    *  
-                               *  User Program *          *              *
-                               *   Data BSS    *          *              *
-                                *    Text       *          *              *
-                               *   Sections    *          *              *
-0x00000000                      *****************          ****************
+Himem 0x7fffffff 2GB on s/390    *****************          ****************
+currently 0x3ffffffffff (2^42)-1 *  User Stack   *          *              *
+on z/Architecture.              *****************          *              *
+                                *  Shared Libs  *          *              *      
+                                 *****************          *              *  
+                                *               *          *    Kernel    *  
+                                *  User Program *          *              *
+                                *   Data BSS    *          *              *
+                                 *    Text       *          *              *
+                                *   Sections    *          *              *
+0x00000000                       *****************          ****************
 
 This also means that we need to look at the PSW problem state bit
 or the addressing mode to decide whether we are looking at
-user or kernel space. 
+user or kernel space.
+
+Virtual Addresses on s/390 & z/Architecture
+===========================================
+
+A virtual address on s/390 is made up of 3 parts
+The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology ) 
+being bits 1-11.
+The PX ( page index, corresponding to the page table entry (pte) in linux terminology )
+being bits 12-19. 
+The remaining bits BX (the byte index are the offset in the page )
+i.e. bits 20 to 31.
+
+On z/Architecture in linux we currently make up an address from 4 parts.
+The region index bits (RX) 0-32 we currently use bits 22-32
+The segment index (SX) being bits 33-43
+The page index (PX) being bits  44-51
+The byte index (BX) being bits  52-63
+
+Notes:
+1) s/390 has no PMD so the PMD is really the PGD also.
+A lot of this stuff is defined in pgtable.h.
+
+2) Also seeing as s/390's page indexes are only 1k  in size 
+(bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k )
+to make the best use of memory by updating 4 segment indices 
+entries each time we mess with a PMD & use offsets 
+0,1024,2048 & 3072 in this page as for our segment indexes.
+On z/Architecture our page indexes are now 2k in size
+( bits 12-19 x 8 bytes per pte ) we do a similar trick
+but only mess with 2 segment indices each time we mess with
+a PMD.
+
+3) As z/Architecture supports upto a massive 5-level page table lookup we 
+can only use 3 currently on Linux ( as this is all the generic kernel
+currently supports ) however this may change in future
+this allows us to access ( according to my sums )
+4TB of virtual storage per process i.e.
+4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes,
+enough for another 2 or 3 of years I think :-).
+to do this we use a region-third-table designation type in
+our address space control registers.
 
-The Linux for s/390 & zSeries Kernel Task Structure
-===================================================
+The Linux for s/390 & z/Architecture Kernel Task Structure
+==========================================================
 Each process/thread under Linux for S390 has its own kernel task_struct
 defined in linux/include/linux/sched.h
 The S390 on initialisation & resuming of a process on a cpu sets
@@ -287,7 +330,7 @@ each processor as follows.
             *        ( 4K )        *
 8K aligned  ************************ 
 
-                     zSeries
+                 z/Architecture
             ************************
             *  2 page kernel stack *
            *        ( 8K )        *
@@ -298,7 +341,7 @@ each processor as follows.
 
 What this means is that we don't need to dedicate any register or global variable
 to point to the current running process & can retrieve it with the following
-very simple construct for s/390 & one very similar for zSeries.
+very simple construct for s/390 & one very similar for z/Architecture.
 
 static inline struct task_struct * get_current(void)
 {
@@ -317,8 +360,8 @@ short amounts of time we don't need a separate stack for interrupts.
 
 
 
-Register Usage & Stackframes on Linux for s/390 & zSeries
-=========================================================
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
+=================================================================
 Overview:
 ---------
 This is the code that gcc produces at the top & the bottom of
@@ -331,7 +374,7 @@ Note: To follow stackframes requires a knowledge of C or Pascal &
 limited knowledge of one assembly language.
 
 It should be noted that there are some differences between the
-s/390 & zSeries stack layouts as the zSeries stack layout didn't have
+s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have
 to maintain compatibility with older linkage formats.
 
 Glossary:
@@ -367,8 +410,8 @@ epilogue:
 The code generated by the compiler to return to the caller.
 
 frameless-function
-A frameless function in Linux for s390 & zSeries is one which doesn't need 
-more than the register save area ( 96 bytes on s/390, 160 on zSeries )
+A frameless function in Linux for s390 & z/Architecture is one which doesn't 
+need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture )
 given to it by the caller.
 A frameless function never:
 1) Sets up a back chain.
@@ -428,8 +471,8 @@ int FunctionA(int a)
 }
 
 
-s/390 & zSeries Register usage
-==============================
+s/390 & z/Architecture Register usage
+=====================================
 r0       used by syscalls/assembly                  call-clobbered
 r1      used by syscalls/assembly                  call-clobbered
 r2       argument 0 / return value 0                call-clobbered
@@ -449,8 +492,8 @@ r15      stack-pointer                              saved
 
 f0       argument 0 / return value ( float/double ) call-clobbered
 f2       argument 1                                 call-clobbered
-f4       zSeries argument 2                           saved
-f6       zSeries argument 3                           saved
+f4       z/Architecture argument 2                  saved
+f6       z/Architecture argument 3                  saved
 The remaining floating points
 f1,f3,f5 f7-f15 are call-clobbered.
 
@@ -479,12 +522,13 @@ outgoing args area. It must be purely in the outgoing args
 area if crossing this boundary.
 6) Floating point parameters are mixed with outgoing args
 on the outgoing args area in the order the are passed in as parameters.
-7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries
+7) Floating point arguments 2 & 3 are saved in the outgoing args area for 
+z/Architecture
 
 
 Stack Frame Layout
 ------------------
-s/390     zSeries
+s/390     z/Architecture
 0         0             back chain ( a 0 here signifies end of back chain )
 4         8             eos ( end of stack, not used on Linux for S390 used in other linkage formats )
 8         16            glue used in other s/390 linkage formats for saved routine descriptors etc.
@@ -598,8 +642,8 @@ 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.
 
-64 bit zSeries code disassembly
--------------------------------
+64 bit z/Architecture code disassembly
+--------------------------------------
 
 If you understand the stuff above you'll understand the stuff
 below too so I'll avoid repeating myself & just say that 
@@ -637,12 +681,14 @@ main(int argc,char *argv[])
 
 
 
-Compiling programs for debugging on Linux for s/390 & zSeries
-=============================================================
--gdwarf2 now works & normal -g debugging works much better now
+Compiling programs for debugging on Linux for s/390 & z/Architecture
+====================================================================
+-gdwarf-2 now works it should be considered the default debugging
+format for s/390 & z/Architecture as it is more reliable for debugging
+shared libraries,  normal -g debugging works much better now
 Thanks to the IBM java compiler developers bug reports. 
 
-This is typically done adding/appending the flags -g to the 
+This is typically done adding/appending the flags -g or -gdwarf-2 to the 
 CFLAGS & LDFLAGS variables Makefile of the program concerned.
 
 If using gdb & you would like accurate displays of registers &
@@ -1148,7 +1194,7 @@ Displaying & modifying Registers
 --------------------------------
 D G will display all the gprs
 Adding a extra G to all the commands is neccessary to access the full 64 bit 
-content in VM on zSeries obviously this isn't required for access registers
+content in VM on z/Architecture obviously this isn't required for access registers
 as these are still 32 bit.
 e.g. DGG instead of DG 
 D X will display all the control registers
@@ -1251,7 +1297,7 @@ To get the address of main in the program.
 tr i pswa <address of main>
 Start the program, if VM drops to CP on what looks like the entry
 point of the main function this is most likely the process you wish to debug.
-Now do a D X13 or D XG13 on zSeries.
+Now do a D X13 or D XG13 on z/Architecture.
 On 31 bit the STD is bits 1-19 ( the STO segment table origin ) 
 & 25-31 ( the STL segment table length ) of CR13.
 now type
@@ -1260,7 +1306,48 @@ e.g.
 TR I R STD 8F32E1FF 0.7fffffff
 Another very useful variation is
 TR STORE INTO STD <CR13's value> <address range>
-
+for finding out when a particular variable changes.
+
+An alternative way of finding the STD of a currently running process 
+is to do the following, ( this method is more complex but
+could be quite convient if you aren't updating the kernel much &
+so your kernel structures will stay constant for a reasonable period of
+time ).
+
+grep task /proc/<pid>/status
+from this you should see something like
+task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68
+This now gives you a pointer to the task structure.
+Now make CC:="s390-gcc -g" kernel/sched.s
+To get the task_struct stabinfo.
+( task_struct is defined in include/linux/sched.h ).
+Now we want to look at
+task->active_mm->pgd
+on my machine the active_mm in the task structure stab is
+active_mm:(4,12),672,32
+its offset is 672/8=84=0x54
+the pgd member in the mm_struct stab is
+pgd:(4,6)=*(29,5),96,32
+so its offset is 96/8=12=0xc
+
+so we'll
+hexdump -s 0xf160054 /dev/mem | more
+i.e. task_struct+active_mm offset
+to look at the active_mm member
+f160054 0fee cc60 0019 e334 0000 0000 0000 0011
+hexdump -s 0x0feecc6c /dev/mem | more
+i.e. active_mm+pgd offset
+feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010
+we get something like
+now do 
+TR I R STD <pgd|0x7f> 0.7fffffff
+i.e. the 0x7f is added because the pgd only
+gives the page table origin & we need to set the low bits
+to the maximum possible segment table length.
+TR I R STD 0f2c007f 0.7fffffff
+on z/Architecture you'll probably need to do
+TR I R STD <pgd|0x7> 0.ffffffffffffffff
+to set the TableType to 0x1 & the Table length to 3.
 
 
 
@@ -1347,10 +1434,18 @@ will get your guests cpus back.
 
 Help for displaying ascii textstrings
 -------------------------------------
-As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have 
-written this little program which will convert a command line of hex digits to ascii text
-which can be compiled under linux & you can copy the hex digits from your x3270 terminal to
-your xterm if you are debugging from a linuxbox.
+On the very latest VM Nucleus'es VM can now display ascii
+( thanks Neale for the hint ) by doing
+D TX<lowaddr>.<len>
+e.g.
+D TX0.100
+
+Alternatively
+=============
+Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which
+will convert a command line of hex digits to ascii text which can be compiled under linux & 
+you can copy the hex digits from your x3270 terminal to your xterm if you are debugging
+from a linuxbox.
 
 This is quite useful when looking at a parameter passed in as a text string
 under VM ( unless you are good at decoding ASCII in your head ).
@@ -1532,8 +1627,8 @@ Congrats you've done your first backchain.
 
 
 
-s/390 & zSeries IO Overview
-===========================
+s/390 & z/Architecture IO Overview
+==================================
 
 I am not going to give a course in 390 IO architecture as this would take me quite a
 while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have 
@@ -1685,15 +1780,15 @@ ESCON or Paralell Cables used as a very high speed serial link
 between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
 
 
-Debugging IO on s/390 & zSeries under VM
-=========================================
+Debugging IO on s/390 & z/Architecture under VM
+===============================================
 
 Now we are ready to go on with IO tracing commands under VM
 
 A few self explanatory queries:
 Q OSA
 Q CTC
-Q DISK
+Q DISK ( This command is CMS specific )
 Q DASD
 
 
@@ -1998,9 +2093,14 @@ stack chaining in gdb by hand
 This is done using a the same trick described for VM 
 p/x (*($sp+56))&0x7fffffff get the first backchain.
 
-For zSeries do
-p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff
-in the macros below.
+For z/Architecture
+Replace 56 with 112 & ignore the &0x7fffffff
+in the macros below & do nasty casts to longs like the following
+as gdb unfortunately deals with printed arguments as ints which
+messes up everything.
+i.e. here is a 3rd backchain dereference
+p/x *(long *)(***(long ***)$sp+112)
+
 
 this outputs 
 $5 = 0x528f18 
@@ -2265,6 +2365,21 @@ in the kernel for some unknown reason.
 
 Some driver debugging techniques
 ================================
+debug feature
+-------------
+Some of our drivers now support a "debug feature" in
+/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
+for more info.
+e.g. 
+to switch on the lcs "debug feature"
+echo 5 > /proc/s390dbf/lcs/level
+& then after the error occured.
+cat /proc/s390dbf/lcs/sprintf >/logfile
+the logfile now contains some information which may help
+tech support resolve a problem in the field.
+
+
+
 high level debugging network drivers
 ------------------------------------
 ifconfig is a quite useful command
@@ -2339,65 +2454,10 @@ jdb <filename> another fully interactive gdb style debugger.
 & type ? in the debugger for help.
 
 
-Debugging Drivers
-=================
-Some of our drivers now support a debug logging feature in
-/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
-for more info.
-e.g. 
-to switch on lcs debugging
-echo 5 > /proc/s390dbf/lcs/level
-& then after the error occured.
-cat /proc/s390dbf/lcs/sprintf >/logfile
-the logfile now contains some information which may help
-tech support resolve a problem in the field.
-
-If you have VM look at the chapter Debugging IO on S390 under VM.
-
-
-
-
-Tools soon to be available
-==========================
-
-Dumptool & Lcrash
------------------
-Michael Holzheu & others here at IBM have a fairly mature port of 
-SGI's lcrash tool which allows one to look at kernel structures in a
-running kernel.
-
-It also complements a tool called dumptool which dumps all the kernels
-memory pages & registers to either a tape or a disk.
-This can be used by tech support or an ambitous end user do
-post mortem debugging of a machine like gdb core dumps.
-
-Going into how to use this tool in detail will be explained
-in other documentation supplied by IBM & the lcrash homepage
-http://oss.sgi.com/projects/lkcd/.
-
-How they work
--------------
-Lcrash is a perfectly normal application
-however it requires an additional file.
-It is built using a patch to the kernel source base.
-
-
-Debugging a live system it uses /dev/mem
-alternatively for post mortem debugging it uses the data 
-collected by dumptool.
-
-
-Ltrace
-------
-We also have a tool called ltrace in our CVS repository 
-no plans on a delivery date yet.
-ltrace is a superset of strace in that it also allows
-tracing of shared libraries calls as well as system calls,
-man ltrace for more info.
 
 SysRq
 =====
-This is now supported by linux for s/390 & zSeries.
+This is now supported by linux for s/390 & z/Architecture.
 To enable it do compile the kernel with 
 Kernel Hacking -> Magic SysRq Key Enabled
 echo "1" > /proc/sys/kernel/sysrq.
@@ -2426,14 +2486,14 @@ Linux & GDB source.
 Various info & man pages.
 CMS Help on tracing commands.
 Linux for s/390 Elf Application Binary Interface
-Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended )
+Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended )
 z/Architecture Principles of Operation SA22-7832-00
 Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the
 Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05
 
-
-
-
-
-
+Special Thanks
+==============
+Special thanks to Neale Ferguson who maintains a much
+prettier HTML version of this page at
+http://penguinvm.princeton.edu/notes.html#Debug390
 
index 5576f4923d7deb8466b074dfe8833535fa0b88d9..6329276b41bfe8a6f87d49b081c252f17b1a179f 100644 (file)
@@ -76,10 +76,9 @@ create an ISO9660 filesystem:
 - ensure the tape is at the beginning 
      mt -f /dev/ntibm0 rewind 
 
-- set the blocksize of the character driver. The blocksizes 512, 1024
-  and 2048 bytes are supported by ISO9660. 1024 is the default, u
-  which will be used here. 
-     mt -f /dev/ntibm0 setblk 1024 
+- set the blocksize of the character driver. The blocksize 2048 bytes
+  is commonly used on ISO9660 CD-Roms
+     mt -f /dev/ntibm0 setblk 2048 
 
 - write the filesystem to the character device driver 
      mkisofs -o /dev/ntibm0 somedir 
@@ -88,18 +87,16 @@ create an ISO9660 filesystem:
      mt -f /dev/ntibm0 rewind 
 
 - Now you can mount your new filesystem as a block device: 
-     mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt 
+     mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt 
 
 TODO List 
 
-- The backend code has to be enhanced to support error-recovery actions. 
-
-- The seeking algorithm of the block device has to be improved to speed 
-  things up 
+   - Driver has to be stabelized still
 
 BUGS 
 
-There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL.
+This driver is considered BETA, which means some weaknesses may still
+be in it.
 If an error occurs which cannot be handled by the code you will get a 
 sense-data dump.In that case please do the following: 
 
index 8b598b1ccb19182c45e0c3896a2222617d06bcab..6499cdf5d4e2931132700e3fb633f40053fef093 100644 (file)
@@ -7,29 +7,37 @@ channel device layer
 .SH SYNOPSIS
 The channel device layer is a layer to provide a consistent interface for
 configuration & default machine check (devices appearing & disappearing )
-handling Linux for zSeries channel devices.
+handling on Linux for s/390 & z/Series channel devices.
 
-These include among others
+
+s/390 & z/Series channel devices include among others
 
 .Bl -item
 .It
 lcs ( the most common ethernet/token ring/fddi standard on zSeries )
 .It
-ctc/escon hi speed like serial link standard on zSeries.
+ctc/escon hi speed like serial link standard on s/390 & z/Series.
 .It
 claw used to talk to cisco routers.
 .It
 qeth gigabit ethernet.
-.El
-
+.It
+osad used by osa/sf to configure osa devices, e.g. to share a osa card between 2 or more vm guests. osad is just added to the channel device layer for completeness, there are no plans at the current time to write a driver to exploit this under linux.
+.It
 These devices use two channels one read & one write for configuration &
-or communication.
-The motivation behind producing this layer was that there is a lot of
-duplicate code among the drivers for configuration so the lcs & ctc drivers
-tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172
-lcs compatible devices or escons/ctc's & to resolve this fight
-both device drivers had to be reconfigured rather than doing the
-configuration in a single place.
+or communication ( & a third channel the data channel in the case of gigabit ethernet ).
+The motivation behind developing this layer was that there was a lot of
+duplicate code among the channel device drivers for configuration. 
+Also the lcs & ctc drivers tended to fight over 3088/08's & 3088/1F's which could 
+be either 2216/3172 channel attached lcs compatible devices or escon/ctc pipes 
+between guests & to resolve this fight both device drivers had to be configured 
+separately,  this is now simplified by doing the configuration in a single place
+( the channel device layer ).
+
+This layer isn't invasive & it is quite okay to use channel drivers
+which don't use the channel device layer in conjunction with
+drivers which do.
+.El
 
 .SH DESCRIPTION
 The current setup can be read from /proc/chandev
@@ -37,30 +45,65 @@ arguments can be entered by...
 .Bl -enum
 .It
 Piping to /proc/chandev.
+e.g. echo reprobe >/proc/chandev
+will cause uninitialised channel devices to be probed.
 .It
-Entering them into /etc/chandev.conf comments are prefixed #.
+Entering them into /etc/chandev.conf comments are prefixed with #.
 .It
 Or from the boot command line using the 'chandev=' keyword
+e.g. chandev=noauto,0x0,0x480d;noauto,0x4810,0xffff
+will allow only devno's 0x480e & 0x480f to be autodetected.
 .El
 .Bl -item
 .It
-Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows.
-/bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>.
-The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script.
+Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows.
+/sbin/hotplug chandev <start starting_devnames> <machine_check (devname last/pre_recovery_status) (current/post_recovery_status)>.
+The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available.
 .It
 #!/bin/bash
 .It
 exec >/dev/console 2>&1 0>&1
+.It
+# Uncomment line below for debugging.
+.It
+# echo $*
+.It
+if [ "$1" = "chandev" ] && [ "$2" = "start" ]
+.It
+then
+.It
+    shift 2
+.It
+    while [ "$1" != "" ]  && [ "$1" != "machine_check" ]
+.It
+    do
+.It
+        isup=`ifconfig $1 2>/dev/null | grep UP`
+.It
+       if [ "$isup" = "" ]
+.It
+       then
+.It
+            ifup $1
+.It
+       fi
+.It
+       shift
+.It
+    done
+.It
+fi
+.It
+.It
+e.g. if tr0 & ctc0 were starting up & eth0 & eth1 devices disappeared & eth2 got a revalidate machine check ( which is normally fully recoverable ) nearly simultainously the parameters would be.
+.It
+/sbin/hotplug chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone eth2 revalidate good
+.It
+This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. Normally you wouldn't want to do anything like stop networking when a device disappears as this is hopefully temporary, I just added it to be complete. The chandev layer waits a few seconds for machine checks to settle before running /sbin/hotplug because several machine checks usually happen at once & the forked scripts would possibly race against each other to shutdown & start resources at the same time & behave rather stupidly.
 .El
 
-e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the  parameters would be.
-
-
-/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone
 
 
-This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone.
-
 valid chandev arguments are <> indicate optional parameters, | indicate a choice.
 
 .B glossary
@@ -77,21 +120,49 @@ force list: is a term specific to channel device layer describing a range of dev
 .It
 
 .Bl -item
-
 .It
-.B (ctc|escon|lcs|osad|qeth|claw)<devif_num>, 
-read_devno, write_devno, <port_no/protocol_no>, <checksum_received_ip_pkts>, <use_hw_stats>
+.B (ctc|escon|lcs|osad|qeth)<devif_num>, 
+read_devno,write_devno,<data_devno,memory_usage_in_k,port_no/protocol_no,checksum_received_ip_pkts,use_hw_stats>
+.It
+devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type.
+The data_devno field is only valid for qeth devices when not forcing a range of devices.
+all parameters after & including memory_usage_in_k can be set optionally if not set they
+go to default values. memory_usage_in_k ( 0 the default ) means let the driver choose,checksum_received_ip_pkts & use_hw_stats are set to false
+.It
+e.g. ctc0,0x7c00,0x7c01
 .It
-e.g. ctc0,0x7c00,0x7c01,0,0,0
+Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails.
 .It
-Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter.
+qeth,0x7c00,0x7d00,-1,4096
+All devices between 0x7c00 & 7d00 should be detected as gigabit ethernet, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
+.It
+qeth1,0x7c00,0x7c01,0x7c02
+.It
+devif_num=1,read=0x7c00,write=0x7c01,data=0x7c02, don't checksum received ip packets & use hw stats.
 .El
 .It
-
+.Bl -item
+.B claw devif_num, 
+read_devno,write_devno<,memory_usage_in_k,checksum_received_ip_pkts,use_hw_stats,>
+host_name,adapter_name,api_type
+.It
+CLAW currently is not autodetected as the host_name,adapter_name & api_type
+need to be set up, possibly some convention for setting these automatically
+may be contrived in the future & auto detection may be done but currently there isn't any.
+The names host_name,adapter_name,api_type may be 8 upto characters in length,
+host_name is the name of this host, adapter_name is the name of the adjacent host,
+api_type may be name 1 to 8 chars in length API & TCPIP are common values.
+The remainder of the parameters are the same as the description for other ctc escon etc. 
+.It
+A typical setup may be
+.It
+claw0,0xe00,0xe01,linuxa,rs6k,TCPIP
+.It
+.El
 .Bl -item
 .It
 .B add_parms
-,chan_type,<string>
+,chan_type,<lo_devno,hi_devno,>string
 .It
 chan_type bitfield 
 .It
@@ -99,22 +170,26 @@ ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20.
 .It
 This is for device driver specific options passed as a string to the driver
 not dealt with by the channel device layer it can't contain spaces.
+low_devno & hi_devno are optional parameters to specify a range.
+The channel device layer doesn't concatenate strings if device ranges overlap,
+before passing to a device driver.
 .El
 .It
 
 .Bl -item
 .It
 .B del_parms
-<,chan_type,exact_match>
+<,chan_type,exact_match,lo_devno>
 .It
 This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type.
+lo_devno is an optional parameter the delete to only happen if lo_devno matches a lo_devno in one of the ranges.
 .El
 .It
 
 .Bl -item
 .It
 .B noauto
-,<lo_devno>-<hi_devno>
+<,lo_devno,hi_devno>
 .It
 Don't probe a range of device numbers for channel devices.
 .El
@@ -128,7 +203,6 @@ Tells the channel layer to assign device names based on the read channel cuu num
 .It
 e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices.
 .El
-.El
 
 
 .B power user options
@@ -168,7 +242,6 @@ Opposite to use_devno_names described above.
 .It
 .B add_model
 ,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling
-
 .It
 Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard.
 Set max_port_no to 0 for non lcs devices.
@@ -180,18 +253,33 @@ not_operational=0x1, no_path=0x2, revalidate=0x4, gone=0x8
 chan_type bitfield
 .It
 ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20
-
-.It
+.El
 .Bl -item
 .It
 .B del_model
 ,cu_type,cu_model,dev_type,dev_model
 .It
--1 for any parameter is a wildcard,
+-1 for any parameter is a wildcard.
 .El
+
+.Bl -item
 .It
 .B del_all_models
+.It 
+should be obvious.
+.El
+.Bl -item
+.It
+.B  non_cautious_auto_detect
 .It
+Tells the channel device layer to attempt to auto detect devices even if their type/model pairs don't unambigously identify the device, e.g. 3088/1F's can either be escon CTC's or channel attached 3172 lcs compatible devices. If the wrong device driver attempts to probe these channels there may be big delays on startup or even a kernel lockup, use this option with caution.
+.El
+.Bl -item
+.It
+.B cautious_auto_detect
+.It
+ See non_cautious_auto_detect this is the default.
+.El
 .Bl -item
 .It
 .B auto_msck
@@ -248,6 +336,19 @@ Calls probe method for channels whose interrupts are not owned.
 .It
 .Bl -item
 .It
+.B unregister_probe <probefunc_addr>
+.It
+unregisters a single probe function or all of them.
+.El
+.Bl -item
+.It
+.B unregister_probe_by_chan_type
+.It
+unregisters all probe functions which match the chan_type bitfield exactly,
+useful if you want a configuration to survice a kernel upgrade.
+.El
+.Bl -item
+.It
 .B read_conf
 .It
 Read instructions from /etc/chandev.conf.
@@ -259,6 +360,16 @@ Read instructions from /etc/chandev.conf.
 .It
 Don't automatically read /etc/chandev.conf on boot.
 .El
+.Bl -item
+.It
+.B persist 
+,chan_type
+.It
+Force drivers modules to stay loaded even if no device is found,
+this is useful for debugging & one wishes to examine debug entries in 
+/proc/s390dbf/ to find out why a module failed to load.
+.El
+
 .It
 e.g the following sequence of commands should be roughly equivalent
 to rebooting for channel devices.
@@ -290,8 +401,8 @@ If you wish to write a driver channel device layer compatible
 .B /proc/chandev
 .It
 cat /proc/chandev to see current options chosen.
-.Iy
-echo <command> >proc/chandev to enter a new command
+.It
+echo <command> >/proc/chandev to enter a new command
 .It
 .B /etc/chandev.conf 
 .It
@@ -302,7 +413,7 @@ kernel parameters with the
 .B 'chandev=' 
 keyword.
 .It
-.B /bin/chandev
+.B /sbin/hotplug
 .It 
 A user script/executable which is run when devices come online "appear"
 or go offline "disappear".
index dcc1c365830bd4d937f1a194bae8de20a0d52c6d..e071618339aa59e300dd3c2443d26d9bba6ef1d3 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
-SUBLEVEL = 7
-EXTRAVERSION =
+SUBLEVEL = 8
+EXTRAVERSION =-pre1
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
index ac819f531c710995886fb5e8b053c71b15f2eaed..deb736f4fba6f48aed59ede2776359fa99da5673 100644 (file)
@@ -739,9 +739,12 @@ sys_sigsuspend:
        mov     $30,$17
        br      $1,do_switch_stack
        mov     $30,$18
+       subq    $30,16,$30
+       stq     $26,0($30)
        jsr     $26,do_sigsuspend
-       lda     $30,SWITCH_STACK_SIZE($30)
-       br      ret_from_sys_call
+       ldq     $26,0($30)
+       lda     $30,SWITCH_STACK_SIZE+16($30)
+       ret     $31,($26),1
 .end sys_sigsuspend
 
 .align 3
@@ -750,9 +753,12 @@ sys_rt_sigsuspend:
        mov     $30,$18
        br      $1,do_switch_stack
        mov     $30,$19
+       subq    $30,16,$30
+       stq     $26,0($30)
        jsr     $26,do_rt_sigsuspend
-       lda     $30,SWITCH_STACK_SIZE($30)
-       br      ret_from_sys_call
+       ldq     $26,0($30)
+       lda     $30,SWITCH_STACK_SIZE+16($30)
+       ret     $31,($26),1
 .end sys_rt_sigsuspend
 
        .data
index eeb45458d44e66912b198944ab16676860522a48..2c6d03f5ad345f4f97badb43384895d198ae2633 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $
+# $Id: Makefile,v 1.20 2001/07/05 10:07:58 jonashg Exp $
 # cris/Makefile
 #
 # This file is included by the global makefile so that you can add your own
@@ -55,7 +55,8 @@ ifdef CONFIG_ETRAX_AXISFLASHMAP
 # each others config options
 SUBDIRS += arch/cris/boot/rescue
 endif
-CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
+CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o
+DRIVERS += arch/cris/drivers/drivers.o
 LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
 LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
 
index 0b0a14fe61777c4352788ab2ae6b4db6e6f59ccb..24be54924970aca037fdf1e5b3534d208bab854c 100644 (file)
@@ -13,7 +13,6 @@ SECTIONS
                _stext = . ;
                *(.text)
                *(.rodata)
-               *(.rodata.*)
                _etext = . ;
        } > dram
        .data :
index 49c3188ed9f58bde595e35f6bc0731e301f0182f..77b5480c19e7b94583bd2dd51b42f5549d0c82db 100644 (file)
@@ -49,6 +49,10 @@ fi
 int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8
 
 int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2
+bool 'Use flash mirroring (for cramfs)' CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+if [ "$CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS" = "y" ]; then
+       int '  Individual flash chip size (in MB)' CONFIG_ETRAX_FLASH_SIZE 2
+fi
 
 choice 'Product LED port' \
        "Port-PA-LEDs   CONFIG_ETRAX_PA_LEDS    \
@@ -61,8 +65,8 @@ if [ "$CONFIG_ETRAX_NO_LEDS" != "y" ]; then
   int '  First red LED bit' CONFIG_ETRAX_LED1R 3
   int '  Second green LED bit' CONFIG_ETRAX_LED2G 4
   int '  Second red LED bit' CONFIG_ETRAX_LED2R 5
-  int '  Third green LED bit' CONFIG_ETRAX_LED3R 2
-  int '  Third red LED bit' CONFIG_ETRAX_LED3G 2
+  int '  Third green LED bit' CONFIG_ETRAX_LED3G 2
+  int '  Third red LED bit' CONFIG_ETRAX_LED3R 2
 fi
 
 if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then
@@ -169,7 +173,7 @@ endmenu
 
 source drivers/ieee1394/Config.in
 
-source drivers/message/i2o/Config.in
+source drivers/i2o/Config.in
 
 if [ "$CONFIG_NET" = "y" ]; then
   mainmenu_option next_comment
index 6d3187edcc05206a5ae893ed5029aefd6c04cac4..e0ffb51d9985369aa4c93285e3dc0ee4eb71de26 100644 (file)
@@ -24,7 +24,7 @@ SECTIONS
                *(.fixup)
                *(.text.__*)
                *(.rodata)
-               *(.rodata.*)
+               *(.rodata.__*)
        }
 
        . = ALIGN(4);                /* Exception table */
@@ -56,11 +56,18 @@ SECTIONS
        ___setup_start = .;
        .setup.init : { *(.setup.init) }
        ___setup_end = .;
-       ___initcall_start = .;
-       .initcall.init : { *(.initcall.init) }
-       ___initcall_end = .;
+       .initcall.init : {
+               ___initcall_start = .;
+               *(.initcall.init);
+               ___initcall_end = .;
+
+               /* We fill to the next page, so we can discard all init
+                  pages without needing to consider what payload might be
+                  appended to the kernel image.  */
+               FILL (0);
+               . = ALIGN (8192);
+       }
        __vmlinux_end = .;            /* last address of the physical file */
-       . = ALIGN(8192);
        ___init_end = .;
 
        __data_end = . ;              /* Move to _edata ? */
index 9a1388b2a10ca796fdf3f58ff6f245397b185671..ad3df73a28b163fa369d943aa3bcbd4203a17f88 100644 (file)
 *!                                  in the spin-lock.
 *!
 *!  $Log: eeprom.c,v $
+*!  Revision 1.8  2001/06/15 13:24:29  jonashg
+*!  * Added verification of pointers from userspace in read and write.
+*!  * Made busy counter volatile.
+*!  * Added define for inital write delay.
+*!  * Removed warnings by using loff_t instead of unsigned long.
+*!
+*!  Revision 1.7  2001/06/14 15:26:54  jonashg
+*!  Removed test because condition is always true.
+*!
+*!  Revision 1.6  2001/06/14 15:18:20  jonashg
+*!  Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).
+*!
 *!  Revision 1.5  2001/06/14 14:39:51  jonashg
 *!  Forgot to use name when registering the driver.
 *!
@@ -59,6 +71,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <asm/uaccess.h>
 #include "i2c.h"
 
 #define D(x) 
 #define EEPROM_MAJOR_NR 122  /* use a LOCAL/EXPERIMENTAL major for now */
 #define EEPROM_MINOR_NR 0
 
+/* Empirical sane initial value of the delay, the value will be adapted to
+ * what the chip needs when using EEPROM_ADAPTIVE_TIMING.
+ */
+#define INITIAL_WRITEDELAY_US 4000
 #define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
 
 /* This one defines how many times to try when eeprom fails. */
@@ -98,7 +115,7 @@ struct eeprom_type
   
   /* this one is to keep the read/write operations atomic */
   wait_queue_head_t wait_q;
-  int busy;
+  volatile int busy;
   int retry_cnt_addr; /* Used to keep track of number of retries for
                          adaptive timing adjustments */
   int retry_cnt_read;
@@ -114,9 +131,8 @@ static int eeprom_close(struct inode * inode, struct file * file);
 
 static int  eeprom_address(unsigned long addr);
 static int  read_from_eeprom(char * buf, int count);
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count);
-static int eeprom_read_buf(unsigned long addr,
-                           char * buf, int count);
+static int eeprom_write_buf(loff_t addr, const char * buf, int count);
+static int eeprom_read_buf(loff_t addr, char * buf, int count);
 
 static void eeprom_disable_write_protect(void);
 
@@ -159,7 +175,7 @@ int __init eeprom_init(void)
 
   /*
    *  Note: Most of this probing method was taken from the printserver (5470e)
-   *        codebase. It did not contain a way of finding the 16Kb chips
+   *        codebase. It did not contain a way of finding the 16kB chips
    *        (M24128 or variants). The method used here might not work
    *        for all models. If you encounter problems the easiest way
    *        is probably to define your model within #ifdef's, and hard-
@@ -167,7 +183,7 @@ int __init eeprom_init(void)
    */
 
   eeprom.size = 0;
-  eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/
+  eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;
   eeprom.usec_delay_step = 128;
   eeprom.adapt_state = 0;
   
@@ -181,7 +197,7 @@ int __init eeprom_init(void)
     unsigned char buf_2k_start[16];
     
     /* Im not sure this will work... :) */
-    /* assume 2Kb, if failure go for 16Kb */
+    /* assume 2kB, if failure go for 16kB */
     /* Test with 16kB settings.. */
     /* If it's a 2kB EEPROM and we address it outside it's range
      * it will mirror the address space:
@@ -373,17 +389,17 @@ int __init eeprom_init(void)
   switch(eeprom.size)
   {
    case (EEPROM_2KB):
-     printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0xA0;
      break;
    case (EEPROM_8KB):
-     printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 16;
      eeprom.select_cmd = 0x80;
      break;
    case (EEPROM_16KB):
-     printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name);
+     printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);
      eeprom.sequential_write_pagesize = 64;
      eeprom.select_cmd = 0xA0;     
      break;
@@ -463,8 +479,7 @@ static loff_t eeprom_lseek(struct file * file, loff_t offset, int orig)
 
 /* Reads data from eeprom. */
 
-static int eeprom_read_buf(unsigned long addr,
-                           char * buf, int count)
+static int eeprom_read_buf(loff_t addr, char * buf, int count)
 {
   struct file f;
 
@@ -543,7 +558,7 @@ static ssize_t eeprom_read(struct file * file, char * buf, size_t count, loff_t
 
 /* Writes data to eeprom. */
 
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count)
+static int eeprom_write_buf(loff_t addr, const char * buf, int count)
 {
   struct file f;
 
@@ -561,6 +576,11 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
   int i, written, restart=1;
   unsigned long p;
 
+  if (verify_area(VERIFY_READ, buf, count))
+  {
+    return -EFAULT;
+  }
+
   while(eeprom.busy)
   {
     interruptible_sleep_on(&eeprom.wait_q);
@@ -641,11 +661,8 @@ static ssize_t eeprom_write(struct file * file, const char * buf, size_t count,
           /* To High before */
           if (eeprom.usec_delay_step > 1)
           {
-            if (eeprom.usec_delay_step > 0)
-            {
-              eeprom.usec_delay_step *= 2;
-              eeprom.usec_delay_step--;
-            }
+            eeprom.usec_delay_step *= 2;
+            eeprom.usec_delay_step--;
             
             if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
             {
@@ -807,7 +824,12 @@ static int read_from_eeprom(char * buf, int count)
 
   while( (read < count))
   {    
-    buf[read++] = i2c_inbyte();      
+    if (put_user(i2c_inbyte(), &buf[read++]))
+    {
+      i2c_stop();
+
+      return -EFAULT;
+    }
 
     /*
      *  make sure we don't ack last byte or you will get very strange
index 35c8ad693acd702583d8609b5d203cd2a9258005..6e2991debdea683e53df7e64a3b81f83f4b626d3 100644 (file)
@@ -1,4 +1,4 @@
-       ;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $
+       ;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $
        ;;
        ;; Etrax100 slave network<->parport forwarder
        ;;
@@ -98,7 +98,7 @@ start:
 
        move.d  r0, [R_PAR1_CONFIG]
 
-       moveq   IO_FIELD(R_PAR1_DELAY, setup, 1), r0    ; setup time of value * 160 + 20
+       moveq   IO_FIELD(R_PAR1_DELAY, setup, 0), r0    ; setup time of value * 160 + 20 == 20 ns
        move.d  r0, [R_PAR1_DELAY]
 
        ;; we got four descriptors, that can be active at the same time:
index b90425be7e441804e755b58a33c340885c326fb1..f8ab69367ccf4a8a4427dc2639d18db478aabc9c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $
+/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $
  *
  * e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
  *
@@ -7,6 +7,12 @@
  * The outline of this driver comes from skeleton.c.
  *
  * $Log: e100lpslavenet.c,v $
+ * Revision 1.4  2001/06/21 16:55:26  olof
+ * Minimized par port setup time to gain bandwidth
+ *
+ * Revision 1.3  2001/06/21 15:49:02  olof
+ * Removed setting of default MAC address
+ *
  * Revision 1.2  2001/06/11 15:39:52  olof
  * Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave.
  *
@@ -198,10 +204,6 @@ etrax_ethernet_lpslave_init(struct net_device *dev)
        dev->get_stats          = e100_get_stats;
        dev->set_multicast_list = set_multicast_list;
        dev->set_mac_address    = e100_set_mac_address;
-        
-        /* set the default MAC address */
-
-       e100_set_mac_address(dev, &default_mac);
 
        /* Initialise the list of Etrax DMA-descriptors */
 
@@ -385,8 +387,8 @@ e100_open(struct net_device *dev)
           /* We want ECP forward mode since PAR1 is TX */
                IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd);        
 
-        /* Setup time of value * 160 + 20 ns == 180 ns below */
-        *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1);  
+        /* Setup time of value * 160 + 20 ns == 20 ns below */
+        *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0);  
 
         *R_PAR1_CTRL = 0;
 
@@ -944,7 +946,6 @@ boot_slave(unsigned char *code)
        TxDescList[1].ctrl = d_eol | d_int; 
                                                       
        TxDescList[1].buf = virt_to_phys(code);
-        /*TxDescList[1].buf = code;*/
        TxDescList[1].next = 0;
         
         /* setup the dma channel and start it */
index 3d62513d2f1e6da12456ed045425a5b7b8b5b81e..34b32f1c687b1ba3f657f2f6739affa8b33d3f6e 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $
+/* $Id: parport.c,v 1.7 2001/06/25 16:17:30 jonashg Exp $
  * 
  * Elinux parallel port driver
  * NOTE!
@@ -49,7 +49,7 @@ static inline int DPRINTK(void *nothing, ...) {return 0;}
  * Par0 in  : DMA3
  * Par1 out : DMA4
  * Par1 in  : DMA5
- * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding
+ * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding
  *       DMA and DMA irq
  */
 
@@ -80,8 +80,6 @@ struct etrax100par_struct {
        volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
        volatile u32 *ifirstadr;   /* adr to R_DMA_CHx_FIRST, input */
        volatile char *icmdadr;     /* adr to R_DMA_CHx_CMD, input */
-       const volatile u8 *istatusadr;  /* adr to R_DMA_CHx_STATUS, input */
-       volatile u32 *ihwswadr;    /* adr to R_DMA_CHx_HWSW, input */
 
        /* Non DMA interrupt stuff */
        unsigned long int_irq; /* R_VECT_MASK_RD */
@@ -97,15 +95,6 @@ struct etrax100par_struct {
   
        /* ----- end of fields initialised in port_table[] below ----- */
 
-       //  struct etrax_dma_descr tr_descr;
-       //  unsigned char tr_buf[LP_BUFFER_SIZE];
-       //  const unsigned char *tr_buf_curr; /* current char sent */
-       //  const unsigned char *tr_buf_last; /* last char in buf */
-  
-       //  int fifo_magic; /* fifo amount - bytes left in dma buffer */
-       //  unsigned char         fifo_didmagic; /* a fifo eop has been forced */
-       //  volatile int          tr_running; /* 1 if output is running */
-       
        struct parport *port;
   
        /* Shadow registers */
@@ -132,8 +121,6 @@ static struct etrax100par_struct port_table[] = {
                R_DMA_CH3_CLR_INTR,
                R_DMA_CH3_FIRST,
                R_DMA_CH3_CMD,
-               R_DMA_CH3_STATUS,
-               R_DMA_CH3_HWSW,
                /* Non DMA interrupt stuff */
                IO_BITNR(R_VECT_MASK_RD, par0),
                R_IRQ_MASK0_RD,
@@ -161,8 +148,6 @@ static struct etrax100par_struct port_table[] = {
                R_DMA_CH5_CLR_INTR,
                R_DMA_CH5_FIRST,
                R_DMA_CH5_CMD,
-               R_DMA_CH5_STATUS,
-               R_DMA_CH5_HWSW,
                /* Non DMA interrupt stuff */
                IO_BITNR(R_VECT_MASK_RD, par1),
                R_IRQ_MASK1_RD,
@@ -418,7 +403,7 @@ parport_etrax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 
 /* ----------- Initialisation code --------------------------------- */
 
-static void 
+static void __init
 parport_etrax_show_parallel_version(void)
 {
        printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n");
@@ -436,16 +421,12 @@ parport_etrax_show_parallel_version(void)
 #define PAR1_USE_DMA 0
 #endif
 
-static void 
+static void __init
 parport_etrax_init_registers(void)
 {
        struct etrax100par_struct *info;
        int i;
 
-       /* The different times below will be (value*160 + 20) ns,    */
-       /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6),    */
-       /* the setup time will be (6*160+20) = 980ns.                */
-
        for (i = 0, info = port_table; i < 2; i++, info++) {
 #ifndef CONFIG_ETRAX_PARALLEL_PORT0
                if (i == 0)
index 987267f9f9039a9267e13930490c6cfc18051c26..3c4dcc76507b081c69cea556df0f9693ab13deb2 100644 (file)
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $
+# $Id: Makefile,v 1.7 2001/07/05 01:11:48 hp Exp $
 #
 # Makefile for the linux kernel.
 #
@@ -8,8 +8,10 @@
 #
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
+# These assembly files can't be assembld with -traditional, so we
+# need another build rule than the one in the toplevel Makefile.
 .S.o:
-       $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+       $(CC) $(AFLAGS) -c $< -o $*.o
 
 all: kernel.o head.o
 
@@ -20,6 +22,7 @@ obj-y   := process.o signal.o entry.o traps.o irq.o \
 
 obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
 
+# This dependency isn't caught by mkdep.  See entry.S.
 entry.o: entryoffsets.s
 
 entryoffsets.s: entryoffsets.c
index 5287456b9ff18dadf52b507c658e483e4fd929a7..7237230c9cfe22dfd771801e4a2d19f3d524f9d2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $
+/* $Id: entry.S,v 1.31 2001/07/25 16:07:42 bjornw Exp $
  *
  *  linux/arch/cris/entry.S
  *
@@ -7,6 +7,36 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: entry.S,v $
+ *  Revision 1.31  2001/07/25 16:07:42  bjornw
+ *  softirq_active/mask -> softirq_pending only
+ *
+ *  Revision 1.30  2001/07/05 01:03:32  hp
+ *  - include asm/errno.h to get ENOSYS.
+ *  - Use ENOSYS, not local constant LENOSYS; tweak comments.
+ *  - Explain why .include, not #include is used.
+ *  - Make oops-register-dump if watchdog bits and it's not expected.
+ *  - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
+ *  - Use correct section attribute for section .rodata.
+ *  - Adjust sys_ni_syscall fill number.
+ *
+ *  Revision 1.29  2001/06/25 14:07:00  hp
+ *     Fix review comment.
+ *     * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ *     magic numbers.  Add comment that -traditional must not be used.
+ *     * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ *     Correct and update comment.
+ *     * Makefile (.S.o): Don't use -traditional.  Add comment why the
+ *     toplevel rule can't be used (now that there's a reason).
+ *
+ *  Revision 1.28  2001/06/21 02:00:40  hp
+ *     * entry.S: Include asm/unistd.h.
+ *     (_sys_call_table): Use section .rodata, not .data.
+ *     (_kernel_thread): Move from...
+ *     * process.c: ... here.
+ *     * entryoffsets.c (VAL): Break out from...
+ *     (OF): Use VAL.
+ *     (LCLONE_VM): New asmified value from CLONE_VM.
+ *
  *  Revision 1.27  2001/05/29 11:25:27  markusl
  *  In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
  *
 #include <linux/config.h>
 #include <linux/linkage.h>
 #include <linux/sys.h>
+#include <asm/unistd.h>
 #include <asm/sv_addr_ag.h>
+#include <asm/errno.h>
        
        ;; functions exported from this file
        
                        
        .globl _sys_call_table
        
-       ;; syscall error codes
-       
-LENOSYS = 38
-
-       ;; Get offsets into various structs.
+       ;; Get values and offsets into various structs.  The file isn't
+       ;; suitable for consumption by the preprocessor, so don't use
+       ;; #include.
        .include "entryoffsets.s"
 
        ;; process bits for ptrace.  FIXME: Should be in a header file.
@@ -227,7 +257,7 @@ _system_call:
        push    r10             ; push orig_r10
        clear.d [sp=sp-4]       ; frametype == 0, normal stackframe
        
-       movs.w  -LENOSYS,r0
+       movs.w  -ENOSYS,r0
        move.d  r0,[sp+LR10]    ; put the default return value in r10 in the frame
 
        ;; check if this process is syscall-traced
@@ -271,9 +301,7 @@ _ret_from_sys_call:
                
        ;; check if any bottom halves need service
        
-       move.d  _irq_stat,r10
-       move.d  [r10+],r0              ; softirq_active
-       and.d   [r10],r0               ; softirq_mask
+       test.d  [_irq_stat]            ; softirq_pending
        bne     handle_softirq
        nop
 
@@ -320,8 +348,8 @@ RBFexit:
 
 tracesys:
        ;; this first invocation of syscall_trace _requires_ that
-       ;; LR10 in the frame contains -LENOSYS (as is set in the beginning
-       ;; of system_call
+       ;; LR10 in the frame contains -ENOSYS (as is set in the beginning
+       ;; of system_call).
 
        jsr     _syscall_trace
 
@@ -333,7 +361,7 @@ tracesys:
        ;; check for sanity in the requested syscall number
 
        move.d  [sp+LR9], r9
-       movs.w  -LENOSYS, r10
+       movs.w  -ENOSYS, r10
        cmpu.w  NR_syscalls,r9  
        bcc     1f
        lslq    2,r9            ;  multiply by 4, in the delay slot
@@ -344,7 +372,7 @@ tracesys:
 
        ;; restore r10, r11, r12, r13, mof and srp into the needed registers
 
-       move.d  [sp+LORIG_R10], r10  ; LR10 is already filled with -LENOSYS
+       move.d  [sp+LORIG_R10], r10  ; LR10 is already filled with -ENOSYS.
        move.d  [sp+LR11],      r11
        move.d  [sp+LR12],      r12
        move.d  [sp+LR13],      r13
@@ -484,10 +512,72 @@ nobp:     pop     r11
 #endif
        
 _IRQ1_interrupt:
-_spurious_interrupt:   
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+       ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+       move    brp,[sp=sp-16]  ; instruction pointer and room for a fake SBFS frame
+       push    srp
+       push    dccr
+       push    mof
        di
-       jsr _hard_reset_now
+       subq    14*4,sp
+       movem   r13,[sp]
+       push    r10             ; push orig_r10
+       clear.d [sp=sp-4]       ; frametype == 0, normal frame
+
+;; We don't check that we actually were bit by the watchdog as opposed to
+;; an external NMI, since there is currently no handler for external NMI.
+
+;; We'll see this in ksymoops dumps.
+Watchdog_bite:
+
+;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
+;; time for an oops-dump over a 115k2 serial wire.  Another 100ms should do.
+
+;; Change the watchdog key to an arbitrary 3-bit value and restart the
+;; watchdog.
+#define WD_INIT 2
+       moveq     IO_FIELD (R_WATCHDOG, key, WD_INIT), r10
+       move.d  R_WATCHDOG, r11
+
+       move.d  r10,[r11]
+       moveq     IO_FIELD (R_WATCHDOG, key,                            \
+                           IO_EXTRACT (R_WATCHDOG, key,                \
+                                       IO_MASK (R_WATCHDOG, key))      \
+                           ^ WD_INIT)                                  \
+               | IO_STATE (R_WATCHDOG, enable, start),r10
+       move.d  r10,[r11]
+
+;; Note that we don't do "setf m" here (or after two necessary NOPs),
+;; since *not* doing that saves us from re-entrancy checks.  We don't want
+;; to get here again due to possible subsequent NMIs; we want the watchdog
+;; to reset us.
+
+       move.d  watchdogmsg,r10
+       jsr     _printk
+
+       move.d  sp,r10
+       jsr     _show_registers
+
+;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
+;; rather than "_spurious_interrupt".
        nop
+;; At this point we drop down into _spurious_interrupt, which will do a
+;; hard reset.
+
+       .section .rodata,"a"
+watchdogmsg:
+       .ascii  "Oops: bitten by watchdog\n\0"
+       .previous
+
+#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+
+_spurious_interrupt:   
+       di
+       jump _hard_reset_now
 
        ;; this handles the case when multiple interrupts arrive at the same time
        ;; we jump to the first set interrupt bit in a priority fashion
@@ -579,14 +669,80 @@ _hw_bp_trigs:
 _hw_bp_trig_ptr:
        .dword _hw_bp_trigs
 
-/* Because we compile this file with -traditional, we need to redefine
-   token-concatenation to the traditional trick, using an empty comment.
-   Normally (in other files, with ISO C as in gcc default) this is done
-   with the ## preprocessor operator.  */
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ *
+ * This *can* be done in C with an single-asm-wrapped-in-a-function, but you
+ * get more or less gross code.  The safer you make the asm-constraints,
+ * the grosser the code, at least with the gcc version in cris-dist-1.13.
+ */
+
+/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
+/*                   r10                r11         r12  */
+
+       .text
+       .global _kernel_thread
+_kernel_thread:
+
+       /* Save ARG for later.  */
+       move.d r11,r13
+
+       /* r11 is argument 2 to clone, the flags */
+       move.d r12,r11
+       or.w    LCLONE_VM,r11
+
+       /* Save FN for later.  */
+       move.d  r10,r12
+
+       /* r9 contains syscall number, to sys_clone */
+       movu.w  __NR_clone,r9
+
+       /* r10 is argument 1 to clone */
+       clear.d r10
+       
+       /* call sys_clone, this will fork */
+       break   13
+
+       /* parent or child? child returns 0 here. */
+       test.d  r10
+
+       /* jump if parent */
+       bne     1f
+       nop              /* delay slot */
+
+       /* set argument to function to call */
+       move.d  r13,r10
+
+       /* call specified function */
+       jsr     r12
+       /* If we ever return from the function, something bad has happened.  */
+
+       /* r9 is sys_exit syscall number */
+       movu.w  __NR_exit,r9
+
+       /* Give a really bad exit-value */
+       moveq   -1,r10
+
+       /* call sys_exit, killing the child */
+       break   13
+1:
+       ret
+       nop              /* delay slot */
+
+
+/* The file include/linux/linkage.h is wrong for compiling the
+   Linux/CRIS kernel.  We currently have C symbols in the kernel (only
+   the kernel) prefixed with _, hence, we need to redefine SYMBOL_NAME.  */
 
 #undef SYMBOL_NAME
-#define SYMBOL_NAME(X) _/**/X
-               
+#define SYMBOL_NAME(X) _##X
+
+       .section .rodata,"a"
 _sys_call_table:       
        .long SYMBOL_NAME(sys_ni_syscall)       /* 0  -  old "setup()" system call*/
        .long SYMBOL_NAME(sys_exit)
@@ -819,7 +975,7 @@ _sys_call_table:
          * been shrunk every time we add a new system call.
          */
 
-       .rept NR_syscalls-221
+       .rept NR_syscalls-222
                .long SYMBOL_NAME(sys_ni_syscall)
        .endr
        
index 421088e28eb5afc0774174e9cd2be6c49e446453..01b804699a5228302778fdf842f0f57b4754a339 100644 (file)
@@ -18,16 +18,20 @@ __asm__ (".if 0");
 #include <asm/processor.h>
 
 /* Exclude everything except the assembly by wrapping it in ".if 0".  */
-#undef OF
-#define OF(NAME, TYPE, MEMBER)                 \
+#undef VAL
+#define VAL(NAME, VALUE)                       \
 void NAME ## _fun (void)                       \
  {                                             \
   __asm__ (".endif \n"                         \
           #NAME " = %0 \n"                     \
           ".if 0\n"                            \
-          : : "i" (offsetof (TYPE, MEMBER)));  \
+          : : "i" (VALUE));                    \
  }
 
+#undef OF
+#define OF(NAME, TYPE, MEMBER)                 \
+  VAL (NAME, offsetof (TYPE, MEMBER))
+
 /* task_struct offsets.  */
 OF (LTASK_SIGPENDING, struct task_struct, sigpending)
 OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
@@ -51,4 +55,7 @@ OF (LTHREAD_KSP, struct thread_struct, ksp)
 OF (LTHREAD_USP, struct thread_struct, usp)
 OF (LTHREAD_DCCR, struct thread_struct, dccr)
 
+/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these.  */
+VAL (LCLONE_VM, CLONE_VM)
+
 __asm__ (".endif");
index 6a58d6c4db30aaaa2c970285668609e39957d9f8..39ae0bb8a2bbbccee18b543b5c9edc09027ba1f6 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $
+/* $Id: head.S,v 1.36 2001/06/29 12:39:31 pkj Exp $
  * 
  * Head of the kernel - alter with care
  *
@@ -7,6 +7,19 @@
  * Authors:    Bjorn Wesen (bjornw@axis.com)
  * 
  * $Log: head.S,v $
+ * Revision 1.36  2001/06/29 12:39:31  pkj
+ * Added support for mirroring the first flash to just below the
+ * second one, to make them look consecutive to cramfs.
+ *
+ * Revision 1.35  2001/06/25 14:07:00  hp
+ *     Fix review comment.
+ *     * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ *     magic numbers.  Add comment that -traditional must not be used.
+ *     * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ *     Correct and update comment.
+ *     * Makefile (.S.o): Don't use -traditional.  Add comment why the
+ *     toplevel rule can't be used (now that there's a reason).
+ *
  * Revision 1.34  2001/05/15 07:08:14  hp
  * Tweak "notice" to reflect that both r8 r9 are used
  *
        
 #include <linux/config.h>
 #define ASSEMBLER_MACROS_ONLY
+/* The IO_* macros use the ## token concatenation operator, so
+   -traditional must not be used when assembling this file.  */
 #include <asm/sv_addr_ag.h>
 
 #define CRAMFS_MAGIC 0x28cd3d45
        ;; 1G per process with CONFIG_CRIS_LOW_MAP.
 
 #ifdef CONFIG_CRIS_LOW_MAP
-       move.d  0x0004b098, r0  ; kseg mappings, temporary map of 0xc0->0x40
+       ; kseg mappings, temporary map of 0xc0->0x40
+       move.d    IO_FIELD (R_MMU_KBASE_HI, base_c, 4)          \
+               | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb)        \
+               | IO_FIELD (R_MMU_KBASE_HI, base_9, 9)          \
+               | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), r0
        move.d  r0, [R_MMU_KBASE_HI]
 
-       move.d  0x04040000, r0  ; temporary map of 0x40->0x40 and 0x00->0x00 
+       ; temporary map of 0x40->0x40 and 0x60->0x40 
+       move.d    IO_FIELD (R_MMU_KBASE_LO, base_6, 4)          \
+               | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
        move.d  r0, [R_MMU_KBASE_LO]
 
-       move.d  0x80075c71, r0  ; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped
+       ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
+       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
+               | IO_STATE (R_MMU_CONFIG, inv_excp, enable)     \
+               | IO_STATE (R_MMU_CONFIG, acc_excp, enable)     \
+               | IO_STATE (R_MMU_CONFIG, we_excp, enable)      \
+               | IO_STATE (R_MMU_CONFIG, seg_f, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_e, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_d, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_c, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_b, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_a, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_9, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_8, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_7, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_6, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_5, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_4, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_3, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_2, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_1, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
        move.d  r0, [R_MMU_CONFIG]
 #else
-       move.d  0x0804b000, r0  ; kseg mappings
+       ; kseg mappings
+       move.d    IO_FIELD (R_MMU_KBASE_HI, base_e, 8)          \
+               | IO_FIELD (R_MMU_KBASE_HI, base_c, 4)          \
+               | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), r0
        move.d  r0, [R_MMU_KBASE_HI]
 
-       move.d  0x00040000, r0  ; temporary map of 0x40->0x40 and 0x00->0x00 
+       ; temporary map of 0x40->0x40 and 0x00->0x00 
+       move.d    IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
        move.d  r0, [R_MMU_KBASE_LO]
 
-       move.d  0x8007d811, r0  ; mmu enable, segs f,e,c,b,4,0 segment mapped
+       ; mmu enable, segs f,e,c,b,4,0 segment mapped
+       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
+               | IO_STATE (R_MMU_CONFIG, inv_excp, enable)     \
+               | IO_STATE (R_MMU_CONFIG, acc_excp, enable)     \
+               | IO_STATE (R_MMU_CONFIG, we_excp, enable)      \
+               | IO_STATE (R_MMU_CONFIG, seg_f, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_e, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_d, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_c, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_b, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_a, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_9, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_8, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_7, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_6, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_5, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_4, seg)           \
+               | IO_STATE (R_MMU_CONFIG, seg_3, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_2, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_1, page)          \
+               | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
        move.d  r0, [R_MMU_CONFIG]
 #endif
 
@@ -308,6 +373,9 @@ inram:
        add.d   0x50000000, r9  ; add flash start in virtual memory (cached)
 #else
        add.d   0xf0000000, r9  ; add flash start in virtual memory (cached)
+#endif
+#ifdef CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+       add.d   MEM_CSE1_START-CONFIG_ETRAX_FLASH_SIZE*0x100000, r9   ; move flash start to upper mirror
 #endif
        move.d  r9, [_romfs_start]
 
@@ -406,26 +474,34 @@ start_it:
        
        moveq   0,r0
        move.d  r0,[R_EXT_DMA_0_ADDR]
-       move.d  0x860000,r0     ; cnt enable, word size, output, stop, size 0
+       ; cnt enable, word size, output, stop, size 0
+       move.d    IO_STATE (R_EXT_DMA_0_CMD, cnt, enable)       \
+               | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh)      \
+               | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh)       \
+               | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst)     \
+               | IO_STATE (R_EXT_DMA_0_CMD, wid, word)         \
+               | IO_STATE (R_EXT_DMA_0_CMD, dir, output)       \
+               | IO_STATE (R_EXT_DMA_0_CMD, run, stop)         \
+               | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),r0
        move.d  r0,[R_EXT_DMA_0_CMD]
 
        ;; reset dma4 and wait for completion
        
-       moveq   4,r0
+       moveq   IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
        move.b  r0,[R_DMA_CH4_CMD]
 w4u:   move.b  [R_DMA_CH4_CMD],r0
-       and.b   7,r0
-       cmp.b   4,r0
+       and.b   IO_MASK (R_DMA_CH4_CMD, cmd),r0
+       cmp.b   IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
        beq     w4u
        nop
 
        ;; reset dma5 and wait for completion
        
-       moveq   4,r0
+       moveq   IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
        move.b  r0,[R_DMA_CH5_CMD]
 w5u:   move.b  [R_DMA_CH5_CMD],r0
-       and.b   7,r0
-       cmp.b   4,r0
+       and.b   IO_MASK (R_DMA_CH5_CMD, cmd),r0
+       cmp.b   IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
        beq     w5u
        nop
 #endif 
@@ -434,42 +510,66 @@ w5u:      move.b  [R_DMA_CH5_CMD],r0
 
        moveq   0,r0
 #if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY)
-       or.d    0x140000,r0     ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+       ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+       or.d      IO_STATE (R_GEN_CONFIG, dma7, serial0)        \
+               | IO_STATE (R_GEN_CONFIG, dma6, serial0),r0
 #endif
 #if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)  
-       or.d    0xc00000,r0     ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+       or.d      IO_STATE (R_GEN_CONFIG, dma9, serial1)        \
+               | IO_STATE (R_GEN_CONFIG, dma8, serial1),r0
 #endif 
 #ifdef CONFIG_DMA_MEMCPY
-       or.d    0x003c0000,r0   ; 6/7 memory-memory DMA
+       ; 6/7 memory-memory DMA
+       or.d      IO_STATE (R_GEN_CONFIG, dma7, intdma6)        \
+               | IO_STATE (R_GEN_CONFIG, dma6, intdma7),r0
 #endif
 #ifdef CONFIG_ETRAX_SERIAL_PORT2
-       or.d    0x2808,r0       ; DMA channels 2 and 3 to serport 2, port 2 enabled
+       ; DMA channels 2 and 3 to serport 2, port 2 enabled
+       or.d      IO_STATE (R_GEN_CONFIG, dma3, serial2)        \
+               | IO_STATE (R_GEN_CONFIG, dma2, serial2)        \
+               | IO_STATE (R_GEN_CONFIG, ser2, select),r0
 #endif
 #if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
-       or.d    0x28100,r0      ; DMA channels 4 and 5 to serport 3, port 3 enabled
+       ; DMA channels 4 and 5 to serport 3, port 3 enabled
+       or.d      IO_STATE (R_GEN_CONFIG, dma5, serial3)        \
+               | IO_STATE (R_GEN_CONFIG, dma4, serial3)        \
+               | IO_STATE (R_GEN_CONFIG, ser3, select),r0
 #endif 
 #if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-       or.w    0x4,r0  ; parport 0 enabled using DMA 2/3
+       ; parport 0 enabled using DMA 2/3
+       or.w    IO_STATE (R_GEN_CONFIG, par0, select),r0
 #endif
 #if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
-       or.w    0x80,r0 ; parport 1 enabled using DMA 4/5
+       ; parport 1 enabled using DMA 4/5
+       or.w    IO_STATE (R_GEN_CONFIG, par1, select),r0
 #endif
 #ifdef CONFIG_ETRAX_IDE
-       or.d    0x3c02,r0       ; DMA channels 2 and 3 to ATA, ATA enabled
+       ; DMA channels 2 and 3 to ATA, ATA enabled
+       or.d      IO_STATE (R_GEN_CONFIG, dma3, ata)    \
+               | IO_STATE (R_GEN_CONFIG, dma2, ata)    \
+               | IO_STATE (R_GEN_CONFIG, ata, select),r0
 #endif
        
 #ifdef CONFIG_ETRAX_USB_HOST_PORT1
-       or.d    0x20000000,r0   ; Set the USB port 1 enable bit
+       ; Set the USB port 1 enable bit
+       or.d    IO_STATE (R_GEN_CONFIG, usb1, select),r0
 #endif
 #ifdef CONFIG_ETRAX_USB_HOST_PORT2
-       or.d    0x40000000,r0   ; Set the USB port 2 enable bit
+       ; Set the USB port 2 enable bit
+       or.d    IO_STATE (R_GEN_CONFIG, usb2, select),r0
 #endif
 #ifdef CONFIG_ETRAX_USB_HOST
-       and.d   0xff3fffff,r0   ; Connect DMA channels 8 and 9 to USB
+       ; Connect DMA channels 8 and 9 to USB
+       and.d   (~(IO_MASK (R_GEN_CONFIG, dma9)         \
+                  | IO_MASK (R_GEN_CONFIG, dma8)))     \
+               | IO_STATE (R_GEN_CONFIG, dma9, usb)    \
+               | IO_STATE (R_GEN_CONFIG, dma8, usb),r0
 #endif
        
 #ifdef CONFIG_JULIETTE
-       or.d    0x3c000,r0      ; DMA channels 4 and 5 to EXTDMA0, for Juliette
+       ; DMA channels 4 and 5 to EXTDMA0, for Juliette
+       or.d      IO_STATE (R_GEN_CONFIG, dma5, extdma0)        \
+               | IO_STATE (R_GEN_CONFIG, dma4, extdma0),r0
 #endif
        move.d  r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
 
@@ -492,17 +592,17 @@ w71:      move.b  [R_DMA_CH7_CMD],r0      ; wait for reset cycle to finish
        nop
 #endif
        
-       moveq   4,r0
+       moveq   IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
        move.b  r0,[R_DMA_CH8_CMD]      ; reset (ser1 dma out)
        move.b  r0,[R_DMA_CH9_CMD]      ; reset (ser1 dma in)
 w81:   move.b  [R_DMA_CH8_CMD],r0      ; wait for reset cycle to finish
-       and.b   7,r0
-       cmp.b   4,r0
+       and.b   IO_MASK (R_DMA_CH8_CMD, cmd),r0
+       cmp.b   IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
        beq     w81
        nop
 w91:   move.b  [R_DMA_CH9_CMD],r0      ; wait for reset cycle to finish
-       and.b   7,r0
-       cmp.b   4,r0
+       and.b   IO_MASK (R_DMA_CH9_CMD, cmd),r0
+       cmp.b   IO_STATE (R_DMA_CH9_CMD, cmd, reset),r0
        beq     w91
        nop
 
@@ -535,46 +635,106 @@ w91:     move.b  [R_DMA_CH9_CMD],r0      ; wait for reset cycle to finish
        
        ;; setup the serial port 0 at 115200 baud for debug purposes
        
-       moveq   0,r0
+       moveq     IO_STATE (R_SERIAL0_XOFF, tx_stop, enable)            \
+               | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable)         \
+               | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),r0
        move.d  r0,[R_SERIAL0_XOFF] 
 
-       move.b  0x99,r0
-       move.b  r0,[R_SERIAL0_BAUD]     ; 115.2kbaud for both transmit and receive
-
-       move.b  0x40,r0                 ; rec enable
+       ; 115.2kbaud for both transmit and receive
+       move.b    IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz)          \
+               | IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),r0
+       move.b  r0,[R_SERIAL0_BAUD]
+
+       ; Set up and enable the serial0 receiver.
+       move.b    IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop)          \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable)     \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rts_, active)           \
+               | IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle)       \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal)  \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even)          \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable)    \
+               | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),r0
        move.b  r0,[R_SERIAL0_REC_CTRL] 
        
-       move.b  0x40,r0                 ; tr enable
+       ; Set up and enable the serial0 transmitter.
+       move.b    IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0)                  \
+               | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable)       \
+               | IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled)      \
+               | IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit)      \
+               | IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal)    \
+               | IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even)            \
+               | IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable)      \
+               | IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),r0
        move.b  r0,[R_SERIAL0_TR_CTRL]
 
        ;; setup the serial port 1 at 115200 baud for debug purposes
        
-       moveq   0,r0
+       moveq     IO_STATE (R_SERIAL1_XOFF, tx_stop, enable)            \
+               | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable)         \
+               | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),r0
        move.d  r0,[R_SERIAL1_XOFF] 
 
-       move.b  0x99,r0
-       move.b  r0,[R_SERIAL1_BAUD]     ; 115.2kbaud for both transmit and receive
-
-       move.b  0x40,r0                 ; rec enable
+       ; 115.2kbaud for both transmit and receive
+       move.b    IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz)          \
+               | IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),r0
+       move.b  r0,[R_SERIAL1_BAUD]
+
+       ; Set up and enable the serial1 receiver.
+       move.b    IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop)          \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable)     \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rts_, active)           \
+               | IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle)       \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal)  \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even)          \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable)    \
+               | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),r0
        move.b  r0,[R_SERIAL1_REC_CTRL] 
        
-       move.b  0x40,r0                 ; tr enable
+       ; Set up and enable the serial1 transmitter.
+       move.b    IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0)                  \
+               | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable)       \
+               | IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled)      \
+               | IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit)      \
+               | IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal)    \
+               | IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even)            \
+               | IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable)      \
+               | IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),r0
        move.b  r0,[R_SERIAL1_TR_CTRL]
 
        
 #ifdef CONFIG_ETRAX_SERIAL_PORT3       
        ;; setup the serial port 3 at 115200 baud for debug purposes
        
-       moveq   0,r0
+       moveq     IO_STATE (R_SERIAL3_XOFF, tx_stop, enable)            \
+               | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable)         \
+               | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),r0
        move.d  r0,[R_SERIAL3_XOFF] 
 
-       move.b  0x99,r0
-       move.b  r0,[R_SERIAL3_BAUD]     ; 115.2kbaud for both transmit and receive
-
-       move.b  0x40,r0                 ; rec enable
+       ; 115.2kbaud for both transmit and receive
+       move.b    IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz)          \
+               | IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),r0
+       move.b  r0,[R_SERIAL3_BAUD]
+
+       ; Set up and enable the serial3 receiver.
+       move.b    IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop)          \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable)     \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rts_, active)           \
+               | IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle)       \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal)  \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even)          \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable)    \
+               | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),r0
        move.b  r0,[R_SERIAL3_REC_CTRL] 
        
-       move.b  0x40,r0                 ; tr enable
+       ; Set up and enable the serial3 transmitter.
+       move.b    IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0)                  \
+               | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable)       \
+               | IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled)      \
+               | IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit)      \
+               | IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal)    \
+               | IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even)            \
+               | IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable)      \
+               | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),r0
        move.b  r0,[R_SERIAL3_TR_CTRL]
 #endif
        
index 157be6a9cc99a0d3b93ec0bb4069e2bf79819bf6..a66a11510cd3e8dd45ff1148b80d838d86b4a8ec 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $
+/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $
  *
  *     linux/arch/cris/kernel/irq.c
  *
@@ -32,6 +32,7 @@
 #include <linux/timex.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -278,7 +279,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
         }
         irq_exit(cpu);
 
-       if (softirq_active(cpu) & softirq_mask(cpu))
+       if (softirq_pending(cpu))
                 do_softirq();
 
         /* unmasking and bottom half handling is done magically for us. */
@@ -422,7 +423,8 @@ void system_call(void);  /* from entry.S */
 void do_sigtrap(void); /* from entry.S */
 void gdb_handle_breakpoint(void); /* from entry.S */
 
-void init_IRQ(void)
+void __init
+init_IRQ(void)
 {
        int i;
 
@@ -488,7 +490,8 @@ void init_IRQ(void)
 
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
 /* Used by other archs to show/control IRQ steering during SMP */
-void init_irq_proc(void)
+void __init
+init_irq_proc(void)
 {
 }
 #endif
index 6a1ebfa2d1a2bb1922db60c6e4b29c7a401ed8f6..f0ab61b9cf17c028cb68faa70eb16edd9ea00c45 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $
+/* $Id: process.c,v 1.16 2001/06/21 02:00:40 hp Exp $
  * 
  *  linux/arch/cris/kernel/process.c
  *
@@ -8,6 +8,18 @@
  *  Authors:   Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: process.c,v $
+ *  Revision 1.16  2001/06/21 02:00:40  hp
+ *     * entry.S: Include asm/unistd.h.
+ *     (_sys_call_table): Use section .rodata, not .data.
+ *     (_kernel_thread): Move from...
+ *     * process.c: ... here.
+ *     * entryoffsets.c (VAL): Break out from...
+ *     (OF): Use VAL.
+ *     (LCLONE_VM): New asmified value from CLONE_VM.
+ *
+ *  Revision 1.15  2001/06/20 16:31:57  hp
+ *  Add comments to describe empty functions according to review.
+ *
  *  Revision 1.14  2001/05/29 11:27:59  markusl
  *  Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled
  *
@@ -71,6 +83,15 @@ union task_union init_task_union
       __attribute__((__section__(".data.init_task"))) =
              { INIT_TASK(init_task_union.task) };
 
+/*
+ * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if
+ * there would ever be a halt sequence (for power save when idle) with
+ * some largish delay when halting or resuming *and* a driver that can't
+ * afford that delay.  The hlt_counter would then be checked before
+ * executing the halt sequence, and the driver marks the unhaltable
+ * region by enable_hlt/disable_hlt.
+ */
+
 static int hlt_counter=0;
 
 void disable_hlt(void)
@@ -116,53 +137,28 @@ void machine_restart(void)
        hard_reset_now();
 }
 
-/* can't do much here... */
+/*
+ * Similar to machine_power_off, but don't shut off power.  Add code
+ * here to freeze the system for e.g. post-mortem debug purpose when
+ * possible.  This halt has nothing to do with the idle halt.
+ */
 
 void machine_halt(void)
 {
 }
 
+/* If or when software power-off is implemented, add code here.  */
+
 void machine_power_off(void)
 {
 }
 
 /*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
+ * When a process does an "exec", machine state like FPU and debug
+ * registers need to be reset.  This is a hook function for that.
+ * Currently we don't have any such state to reset, so this is empty.
  */
 
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
-       register long __a __asm__ ("r10");
-       
-       __asm__ __volatile__
-               ("movu.w %1,r9\n\t"     /* r9 contains syscall number, to sys_clone */
-                "clear.d r10\n\t"      /* r10 is argument 1 to clone */
-                "move.d %2,r11\n\t"    /* r11 is argument 2 to clone, the flags */
-                "break 13\n\t"         /* call sys_clone, this will fork */
-                "test.d r10\n\t"       /* parent or child? child returns 0 here. */
-                "bne 1f\n\t"           /* jump if parent */
-                "nop\n\t"              /* delay slot */
-                "move.d %4,r10\n\t"    /* set argument to function to call */
-                "jsr %5\n\t"           /* call specified function */
-                "movu.w %3,r9\n\t"     /* r9 is sys_exit syscall number */
-                "moveq -1,r10\n\t"     /* Give a really bad exit-value */
-                "break 13\n\t"         /* call sys_exit, killing the child */
-                "1:\n\t"
-                : "=r" (__a) 
-                : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit),
-                  "r" (arg), "r" (fn) 
-                : "r10", "r11", "r9");
-       
-       return __a;
-}
-
-
-
 void flush_thread(void)
 {
 }
index ea14381c090be3f3cdb3d8ef38a1e54a97dca8a4..37912fd9c1922048d05abf73069ca7fd2f9ca21b 100644 (file)
@@ -8,6 +8,9 @@
  * Authors:   Bjorn Wesen
  *
  * $Log: ptrace.c,v $
+ * Revision 1.6  2001/07/25 16:08:47  bjornw
+ * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7
+ *
  * Revision 1.5  2001/03/26 14:24:28  orjanf
  * * Changed loop condition.
  * * Added comment documenting non-standard ptrace behaviour.
index bc5eed86393a169cd0c4e60416764b2a4b6d1238..df9b93417b01114dc0b9377d809de9944bf0badc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $
+/* $Id: setup.c,v 1.18 2001/06/28 04:47:16 hp Exp $
  *
  *  linux/arch/cris/kernel/setup.c
  *
@@ -162,9 +162,9 @@ setup_arch(char **cmdline_p)
 
        paging_init();
 
-       /* we dont use a command line yet, so just let it be an empty string 
-          to start with */
-        
+       /* We dont use a command line yet, so just re-initialize it without
+          saving anything that might be there.  */
+
        *cmdline_p = command_line;
        strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */
 
@@ -249,7 +249,7 @@ int get_cpuinfo(char *buffer)
                       cpu_info[revision].flags & HAS_SCSI ? "yes" : "no",
                       cpu_info[revision].flags & HAS_ATA ? "yes" : "no",
                       cpu_info[revision].flags & HAS_USB ? "yes" : "no",
-                      (loops_per_jiffy * HZ + 500) / 100000,
-                      ((loops_per_jiffy * HZ + 500) / 1000) % 100);
+                      (loops_per_jiffy * HZ + 500) / 500000,
+                      ((loops_per_jiffy * HZ + 500) / 5000) % 100);
 }
 #endif /* CONFIG_PROC_FS */
index 4670283ed1167d97a11cafb9947d500019530a3a..7fbb2e8038871c5c279af6ac17be33e09415354c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $
+/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $
  *
  * linux/arch/cris/kernel/sys_cris.c
  *
@@ -44,34 +44,6 @@ asmlinkage int sys_pipe(unsigned long * fildes)
         return error;
 }
 
-/* sys_mmap used to take a ptr to a buffer instead containing the args
- * but we support syscalls with 6 arguments now 
- */
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
-                                 unsigned long prot, unsigned long flags,
-                                  unsigned long fd, off_t offset)
-{
-       struct file * file = NULL;
-        int ret = -EBADF;
-       
-        lock_kernel();
-        if (!(flags & MAP_ANONYMOUS)) {
-                if (!(file = fget(fd)))
-                        goto out;
-        }
-        
-        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-        down_write(&current->mm->mmap_sem);
-        ret = do_mmap(file, addr, len, prot, flags, offset);
-        up_write(&current->mm->mmap_sem);
-        if (file)
-                fput(file);
- out:
-        unlock_kernel();
-        return ret;
-}
-
 /* common code for old and new mmaps */
 static inline long
 do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
index b43911aadb90cf7ea47e88c88a9962112d11880f..7ad89928df5f2ee95dec75394130853f7796bc17 100644 (file)
@@ -1,9 +1,9 @@
-/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $
+/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $
  *
  *  linux/arch/cris/kernel/time.c
  *
  *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
- *  Copyright (C) 1999, 2000 Axis Communications AB
+ *  Copyright (C) 1999, 2000, 2001 Axis Communications AB
  *
  * 1994-07-02    Alan Modra
  *     fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
@@ -228,7 +228,7 @@ static int watchdog_key = 0;  /* arbitrary number */
 
 #define WATCHDOG_MIN_FREE_PAGES 8
 
-static inline void
+void
 reset_watchdog(void)
 {
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
@@ -242,6 +242,18 @@ reset_watchdog(void)
 #endif
 }
 
+/* stop the watchdog - we still need the correct key */
+
+void 
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+       watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+       *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+               IO_STATE(R_WATCHDOG, enable, stop);
+#endif 
+}
+
 /* last time the cmos clock got updated */
 static long last_rtc_update = 0;
 
@@ -443,6 +455,19 @@ time_init(void)
 #if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
        printk("Enabling watchdog...\n");
        start_watchdog();
-#endif
 
+       /* If we use the hardware watchdog, we want to trap it as an NMI
+          and dump registers before it resets us.  For this to happen, we
+          must set the "m" NMI enable flag (which once set, is unset only
+          when an NMI is taken).
+
+          The same goes for the external NMI, but that doesn't have any
+          driver or infrastructure support yet.  */
+       asm ("setf m");
+
+       *R_IRQ_MASK0_SET =
+               IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+       *R_VECT_MASK_SET =
+               IO_STATE(R_VECT_MASK_SET, nmi, set);
+#endif
 }
index d97e38fd7c36ae5381e341b6890e93606a56fb8a..9fcda3abd2b8d4d501d6ac38e6125d488df8c9af 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $
+/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $
  *
  *  linux/arch/cris/traps.c
  *
@@ -9,6 +9,7 @@
  *  Copyright (C) 2000,2001 Axis Communications AB
  *
  *  Authors:   Bjorn Wesen
+ *            Hans-Peter Nilsson
  *
  */
 
@@ -20,6 +21,7 @@
 #include <linux/ptrace.h>
 #include <linux/timer.h>
 #include <linux/mm.h>
+#include <asm/uaccess.h>
 
 #include <asm/system.h>
 #include <asm/segment.h>
@@ -36,6 +38,13 @@ int kstack_depth_to_print = 24;
 
 #define MODULE_RANGE (8*1024*1024)
 
+/*
+ * The output (format, strings and order) is adjusted to be usable with
+ * ksymoops-2.4.1 with some necessary CRIS-specific patches.  Please don't
+ * change it unless you're serious about adjusting ksymoops and syncing
+ * with the ksymoops maintainer.
+ */
+
 void 
 show_stack(unsigned long *sp)
 {
@@ -43,22 +52,31 @@ show_stack(unsigned long *sp)
         int i;
        extern char _stext, _etext;
 
-        /*
-         * debugging aid: "show_stack(NULL);" prints the
-         * back trace for this cpu.
-         */
+       /*
+        * debugging aid: "show_stack(NULL);" prints a
+        * back trace.
+        */
 
         if(sp == NULL)
                 sp = (unsigned long*)rdsp();
 
         stack = sp;
 
+       printk("\nStack from %08lx:\n       ", stack);
         for(i = 0; i < kstack_depth_to_print; i++) {
                 if (((long) stack & (THREAD_SIZE-1)) == 0)
                         break;
                 if (i && ((i % 8) == 0))
                         printk("\n       ");
-                printk("%08lx ", *stack++);
+               if (__get_user (addr, stack)) {
+                       /* This message matches "failing address" marked
+                          s390 in ksymoops, so lines containing it will
+                          not be filtered out by ksymoops.  */
+                       printk ("Failing address 0x%lx\n", stack);
+                       break;
+               }
+               stack++;
+               printk("%08lx ", addr);
         }
 
         printk("\nCall Trace: ");
@@ -67,7 +85,15 @@ show_stack(unsigned long *sp)
         module_start = VMALLOC_START;
         module_end = VMALLOC_END;
         while (((long) stack & (THREAD_SIZE-1)) != 0) {
-                addr = *stack++;
+               if (__get_user (addr, stack)) {
+                       /* This message matches "failing address" marked
+                          s390 in ksymoops, so lines containing it will
+                          not be filtered out by ksymoops.  */
+                       printk ("Failing address 0x%lx\n", stack);
+                       break;
+               }
+               stack++;
+
                 /*
                  * If the address is either in the text segment of the
                  * kernel, or in the region which contains vmalloc'ed
@@ -105,38 +131,53 @@ show_stack()
 void 
 show_registers(struct pt_regs * regs)
 {
+       /* We either use rdusp() - the USP register, which might not
+          correspond to the current process for all cases we're called,
+          or we use the current->thread.usp, which is not up to date for
+          the current process.  Experience shows we want the USP
+          register.  */
        unsigned long usp = rdusp();
 
-       printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n",
+       printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
               regs->irp, regs->srp, regs->dccr, usp, regs->mof );
-       printk(" r0: %08lx  r1: %08lx  r2: %08lx  r3: %08lx\n",
+       printk(" r0: %08lx  r1: %08lx   r2: %08lx  r3: %08lx\n",
               regs->r0, regs->r1, regs->r2, regs->r3);
-       printk(" r4: %08lx  r5: %08lx  r6: %08lx  r7: %08lx\n",
+       printk(" r4: %08lx  r5: %08lx   r6: %08lx  r7: %08lx\n",
               regs->r4, regs->r5, regs->r6, regs->r7);
-       printk(" r8: %08lx  r9: %08lx r10: %08lx r11: %08lx\n",
+       printk(" r8: %08lx  r9: %08lx  r10: %08lx r11: %08lx\n",
               regs->r8, regs->r9, regs->r10, regs->r11);
        printk("r12: %08lx r13: %08lx oR10: %08lx\n",
               regs->r12, regs->r13, regs->orig_r10);
+       printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE);
        printk("Process %s (pid: %d, stackpage=%08lx)\n",
               current->comm, current->pid, (unsigned long)current);
 
-       /* TODO, fix in_kernel detection */
-
-#if 0
        /*
          * When in-kernel, we also print out the stack and code at the
          * time of the fault..
          */
-        if (1) {
-               
-                printk("\nStack: ");
+        if (! user_mode(regs)) {
+               int i;
+
                 show_stack((unsigned long*)usp);
 
+               /* Dump kernel stack if the previous dump wasn't one.  */
+               if (usp != 0)
+                       show_stack (NULL);
+
                 printk("\nCode: ");
                 if(regs->irp < PAGE_OFFSET)
                         goto bad;
 
-                for(i = 0; i < 20; i++)
+               /* Often enough the value at regs->irp does not point to
+                  the interesting instruction, which is most often the
+                  _previous_ instruction.  So we dump at an offset large
+                  enough that instruction decoding should be in sync at
+                  the interesting point, but small enough to fit on a row
+                  (sort of).  We point out the regs->irp location in a
+                  ksymoops-friendly way by wrapping the byte for that
+                  address in parentheses.  */
+                for(i = -12; i < 12; i++)
                 {
                         unsigned char c;
                         if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
@@ -144,11 +185,14 @@ bad:
                                 printk(" Bad IP value.");
                                 break;
                         }
-                        printk("%02x ", c);
+
+                       if (i == 0)
+                         printk("(%02x) ", c);
+                       else
+                         printk("%02x ", c);
                 }
+               printk("\n");
         }
-        printk("\n");
-#endif
 }
 
 void 
@@ -157,10 +201,13 @@ die_if_kernel(const char * str, struct pt_regs * regs, long err)
        if(user_mode(regs))
                return;
 
+       stop_watchdog();
+
        printk("%s: %04lx\n", str, err & 0xffff);
 
        show_registers(regs);
-       show_stack(NULL);  /* print backtrace for kernel stack on this CPU */
+
+       reset_watchdog();
 
        do_exit(SIGSEGV);
 }
index 6ede712e346fdb16cf98187764fc921e56597190..da2b42434c62c10e83414c9cc15451a701fb59e2 100644 (file)
@@ -6,6 +6,6 @@
        $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
-obj-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o
+obj-y  = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o
 
 include $(TOPDIR)/Rules.make
index 57d4e6c3136c31aa00c9afdd867b83335b27c2f7..60d7f1a7edaabe32bf06e0a74db26b126c469308 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $
+/* $Id: checksumcopy.S,v 1.6 2001/06/28 03:57:16 hp Exp $
  * A fast checksum+copy routine using movem
  * Copyright (c) 1998, 2001 Axis Communications AB
  *
@@ -37,6 +37,7 @@ _csum_partial_copy_nocheck:
        subq    10*4,r12        ; update length for the first loop
        
 mloop: movem   [r10+],r9       ; read 10 longwords
+1:     ;; A failing userspace access will have this as PC.
        movem   r9,[r11+]       ; write 10 longwords
 
        ;; perform dword checksumming on the 10 longwords
@@ -105,6 +106,7 @@ no_fold:
        subq    2,r12
        
 wloop: move.w  [r10+],r9
+2:     ;; A failing userspace access will have this as PC.
        addu.w  r9,r13
        subq    2,r12
        bge     wloop
@@ -123,9 +125,8 @@ no_words:
 do_byte:       
        ;; copy and checksum the last byte
        move.b  [r10],r9
+3:     ;; A failing userspace access will have this as PC.
        addu.b  r9,r13
        move.b  r9,[r11]
        ret
        move.d  r13, r10
-               
-       
diff --git a/arch/cris/lib/csumcpfruser.S b/arch/cris/lib/csumcpfruser.S
new file mode 100644 (file)
index 0000000..d364e4d
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into
+ * csum_partial_copy_from_user by adding exception records.
+ *
+ * Copyright (C) 2001 Axis Communications AB.
+ *
+ * Author: Hans-Peter Nilsson.
+ */
+
+#include <asm/errno.h>
+
+/* Same function body, but a different name.  If we just added exception
+   records to _csum_partial_copy_nocheck and made it generic, we wouldn't
+   know a user fault from a kernel fault and we would have overhead in
+   each kernel caller for the error-pointer argument.
+
+   unsigned int csum_partial_copy_from_user
+     (const char *src, char *dst, int len, unsigned int sum, int *errptr);
+
+   Note that the errptr argument is only set if we encounter an error.
+   It is conveniently located on the stack, so the normal function body
+   does not have to handle it.  */
+
+#define _csum_partial_copy_nocheck _csum_partial_copy_from_user
+
+/* There are local labels numbered 1, 2 and 3 present to mark the
+   different from-user accesses.  */
+#include "checksumcopy.S"
+
+       .section .fixup,"ax"
+
+;; Here from the movem loop; restore stack.
+4:
+       movem   [sp+],r8
+;; r12 is already decremented.  Add back chunk_size-2.
+       addq    40-2,r12
+
+;; Here from the word loop; r12 is off by 2; add it back.
+5:
+       addq    2,r12
+
+;; Here from a failing single byte.
+6:
+
+;; Signal in *errptr that we had a failing access.
+       moveq   -EFAULT,r9
+       move.d  r9,[[sp]]
+
+;; Clear the rest of the destination area using memset.  Preserve the
+;; checksum for the readable bytes.
+       push    srp
+       push    r13
+       move.d  r11,r10
+       clear.d r11
+       jsr     _memset
+       pop     r10
+       jump    [sp+]
+
+       .previous
+       .section __ex_table,"a"
+       .dword 1b,4b
+       .dword 2b,5b
+       .dword 3b,6b
+       .previous
index b397f5df8323d6c2ac10a6cd5e3fad15aaabf66b..7e1f6d7c2e8657616705bec4f076c83f1cc8ebd9 100644 (file)
@@ -6,6 +6,16 @@
  *  Authors:  Bjorn Wesen 
  * 
  *  $Log: fault.c,v $
+ *  Revision 1.18  2001/07/18 22:14:32  bjornw
+ *  Enable interrupts in the bulk of do_page_fault
+ *
+ *  Revision 1.17  2001/07/18 13:07:23  bjornw
+ *  * Detect non-existant PTE's in vmalloc pmd synchronization
+ *  * Remove comment about fast-paths for VMALLOC_START etc, because all that
+ *    was totally bogus anyway it turned out :)
+ *  * Fix detection of vmalloc-area synchronization
+ *  * Add some comments
+ *
  *  Revision 1.16  2001/06/13 00:06:08  bjornw
  *  current_pgd should be volatile
  *
@@ -76,7 +86,9 @@ asmlinkage void do_page_fault(unsigned long address, struct pt_regs *regs,
 
 volatile pgd_t *current_pgd;
 
-/* fast TLB-fill fault handler */
+/* fast TLB-fill fault handler
+ * this is called from entry.S with interrupts disabled
+ */
 
 void
 handle_mmu_bus_fault(struct pt_regs *regs)
@@ -85,10 +97,9 @@ handle_mmu_bus_fault(struct pt_regs *regs)
        int index;
        int page_id;
        int miss, we, acc, inv;  
-       struct mm_struct *mm = current->active_mm;
        pmd_t *pmd;
        pte_t pte;
-       int errcode = 0;
+       int errcode;
        unsigned long address;
 
        cause = *R_MMU_CAUSE;
@@ -103,6 +114,20 @@ handle_mmu_bus_fault(struct pt_regs *regs)
        miss    = IO_EXTRACT(R_MMU_CAUSE,  miss_excp, cause);
        we      = IO_EXTRACT(R_MMU_CAUSE,  we_excp,   cause);
        
+       /* Note: the reason we don't set errcode's r/w flag here
+        * using the 'we' flag, is because the latter is only given
+        * if there is a write-protection exception, not given as a
+        * general r/w access mode flag. It is currently not possible
+        * to get this from the MMU (TODO: check if this is the case
+        * for LXv2).
+        * 
+        * The page-fault code won't care, but there will be two page-
+        * faults instead of one for the case of a write to a non-tabled
+        * page (miss, then write-protection).
+        */
+
+       errcode = 0;
+
        D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
                 "idx %d pid %d\n",
                 regs->irp, address, miss, inv, we, acc, index, page_id));
@@ -157,14 +182,14 @@ handle_mmu_bus_fault(struct pt_regs *regs)
                 * the write to R_TLB_LO also writes the vpn and page_id fields from
                 * R_MMU_CAUSE, which we in this case obviously want to keep
                 */
-               
+
                *R_TLB_LO = pte_val(pte);
 
                return;
        } 
 
-       errcode = 0x01 | (we << 1);
-
+       errcode = 1 | (we << 1);
+       
  dofault:
        /* leave it to the MM system fault handler below */
        D(printk("do_page_fault %p errcode %d\n", address, errcode));
@@ -214,25 +239,21 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
         * NOTE2: This is done so that, when updating the vmalloc
         * mappings we don't have to walk all processes pgdirs and
         * add the high mappings all at once. Instead we do it as they
-        * are used.
+        * are used. However vmalloc'ed page entries have the PAGE_GLOBAL
+        * bit set so sometimes the TLB can use a lingering entry.
         *
-        * TODO: On CRIS, we have a PTE Global bit which should be set in
-        * all the PTE's related to vmalloc in all processes - that means if
-        * we switch process and a vmalloc PTE is still in the TLB, it won't
-        * need to be reloaded. It's an optimization.
-        *
-        * Linux/CRIS's kernel is not page-mapped, so the comparision below
-        * should really be >= VMALLOC_START, however, kernel fixup errors
-        * will be handled more quickly by going through vmalloc_fault and then
-        * into bad_area_nosemaphore than falling through the find_vma user-mode
-        * tests.  As an aside can be mentioned that the difference in
-        * compiled code is neglibible; the instruction is the same, just a
-        * comparison with a different address of the same size.
+        * This verifies that the fault happens in kernel space
+         * and that the fault was not a protection error (error_code & 1).
          */
 
-        if (address >= TASK_SIZE)
+        if (address >= VMALLOC_START &&
+           !(error_code & 1) &&
+           !user_mode(regs))
                 goto vmalloc_fault;
 
+       /* we can and should enable interrupts at this point */
+       sti();
+
        mm = tsk->mm;
        writeaccess = error_code & 2;
        info.si_code = SEGV_MAPERR;
@@ -409,29 +430,48 @@ vmalloc_fault:
                 * Use current_pgd instead of tsk->active_mm->pgd
                 * since the latter might be unavailable if this
                 * code is executed in a misfortunately run irq
+                * (like inside schedule() between switch_mm and
+                *  switch_to...).
                  */
 
                 int offset = pgd_index(address);
                 pgd_t *pgd, *pgd_k;
                 pmd_t *pmd, *pmd_k;
+               pte_t *pte_k;
 
                 pgd = current_pgd + offset;
                 pgd_k = init_mm.pgd + offset;
 
-                if (!pgd_present(*pgd)) {
-                        if (!pgd_present(*pgd_k))
-                                goto bad_area_nosemaphore;
-                        set_pgd(pgd, *pgd_k);
-                        return;
-                }
+               /* Since we're two-level, we don't need to do both
+                * set_pgd and set_pmd (they do the same thing). If
+                * we go three-level at some point, do the right thing
+                * with pgd_present and set_pgd here. 
+                * 
+                * Also, since the vmalloc area is global, we don't
+                * need to copy individual PTE's, it is enough to
+                * copy the pgd pointer into the pte page of the
+                * root task. If that is there, we'll find our pte if
+                * it exists.
+                */
 
                 pmd = pmd_offset(pgd, address);
                 pmd_k = pmd_offset(pgd_k, address);
 
                 if (!pmd_present(*pmd_k))
                         goto bad_area_nosemaphore;
+
                 set_pmd(pmd, *pmd_k);
+
+               /* Make sure the actual PTE exists as well to
+                * catch kernel vmalloc-area accesses to non-mapped
+                * addresses. If we don't do this, this will just
+                * silently loop forever.
+                */
+
+                pte_k = pte_offset(pmd_k, address);
+                if (!pte_present(*pte_k))
+                        goto no_context;
+
                 return;
         }
-
 }
index 9630fe72110055122bed0dbf21650e862ac28d41..b9dd26a8c9293bb66f4091d4c0b50109a790a2a1 100644 (file)
@@ -7,6 +7,18 @@
  *  Authors:  Bjorn Wesen (bjornw@axis.com)
  *
  *  $Log: init.c,v $
+ *  Revision 1.29  2001/07/25 16:09:50  bjornw
+ *  val->sharedram will stay 0
+ *
+ *  Revision 1.28  2001/06/28 16:30:17  bjornw
+ *  Oops. This needs to wait until 2.4.6 is merged
+ *
+ *  Revision 1.27  2001/06/28 14:04:07  bjornw
+ *  Fill in sharedram
+ *
+ *  Revision 1.26  2001/06/18 06:36:02  hp
+ *  Enable free_initmem of __init-type pages
+ *
  *  Revision 1.25  2001/06/13 00:02:23  bjornw
  *  Use a separate variable to store the current pgd to avoid races in schedule
  *
@@ -438,11 +450,6 @@ init_ioremap(void)
 void 
 free_initmem(void)
 {
-#if 0
-       /* currently this is a bad idea since the cramfs image is catted onto
-        * the vmlinux image, and the end of that image is not page-padded so
-        * part of the cramfs image will be freed here
-        */
         unsigned long addr;
 
         addr = (unsigned long)(&__init_begin);
@@ -454,7 +461,6 @@ free_initmem(void)
         }
         printk ("Freeing unused kernel memory: %dk freed\n", 
                (&__init_end - &__init_begin) >> 10);
-#endif
 }
 
 void 
@@ -464,7 +470,7 @@ si_meminfo(struct sysinfo *val)
 
        i = max_mapnr;
        val->totalram = 0;
-       val->sharedram = atomic_read(&shmem_nrpages);
+       val->sharedram = 0;
        val->freeram = nr_free_pages();
        val->bufferram = atomic_read(&buffermem_pages);
        while (i-- > 0)  {
index 7e94f7da411391b47859b08178879a77df95c678..846b5571a2ed9b17cb0cad744355aaa91711fca0 100644 (file)
  *
  * The last page_id is never running - it is used as an invalid page_id
  * so we can make TLB entries that will never match.
+ *
+ * Notice that we need to make the flushes atomic, otherwise an interrupt
+ * handler that uses vmalloced memory might cause a TLB load in the middle
+ * of a flush causing.
  */
 
 struct mm_struct *page_id_map[NUM_PAGEID];
@@ -49,17 +53,18 @@ static int map_replace_ptr = 1;  /* which page_id_map entry to replace next */
 /* invalidate all TLB entries */
 
 void
-flush_tlb_all()
+flush_tlb_all(void)
 {
        int i;
+       unsigned long flags;
 
        /* the vpn of i & 0xf is so we dont write similar TLB entries
         * in the same 4-way entry group. details.. 
         */
 
+       save_and_cli(flags); /* flush needs to be atomic */
        for(i = 0; i < NUM_TLB_ENTRIES; i++) {
                *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
-
                *R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
                              IO_FIELD(R_TLB_HI, vpn,     i & 0xf ) );
                
@@ -69,6 +74,7 @@ flush_tlb_all()
                              IO_STATE(R_TLB_LO, we,    no       ) |
                              IO_FIELD(R_TLB_LO, pfn,   0        ) );
        }
+       restore_flags(flags);
        D(printk("tlb: flushed all\n"));
 }
 
@@ -79,6 +85,7 @@ flush_tlb_mm(struct mm_struct *mm)
 {
        int i;
        int page_id = mm->context;
+       unsigned long flags;
 
        D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
 
@@ -90,6 +97,7 @@ flush_tlb_mm(struct mm_struct *mm)
         * global pages. is it worth the extra I/O ? 
         */
 
+       save_and_cli(flags);  /* flush needs to be atomic */
        for(i = 0; i < NUM_TLB_ENTRIES; i++) {
                *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
                if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
@@ -103,6 +111,7 @@ flush_tlb_mm(struct mm_struct *mm)
                                      IO_FIELD(R_TLB_LO, pfn,   0   ) );
                }
        }
+       restore_flags(flags);
 }
 
 /* invalidate a single page */
@@ -114,6 +123,7 @@ flush_tlb_page(struct vm_area_struct *vma,
        struct mm_struct *mm = vma->vm_mm;
        int page_id = mm->context;
        int i;
+       unsigned long flags;
 
        D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
 
@@ -126,6 +136,7 @@ flush_tlb_page(struct vm_area_struct *vma,
         * and the virtual address requested 
         */
 
+       save_and_cli(flags);  /* flush needs to be atomic */
        for(i = 0; i < NUM_TLB_ENTRIES; i++) {
                unsigned long tlb_hi;
                *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -142,6 +153,7 @@ flush_tlb_page(struct vm_area_struct *vma,
                                      IO_FIELD(R_TLB_LO, pfn,   0   ) );
                }
        }
+       restore_flags(flags);
 }
 
 /* invalidate a page range */
@@ -153,6 +165,7 @@ flush_tlb_range(struct mm_struct *mm,
 {
        int page_id = mm->context;
        int i;
+       unsigned long flags;
 
        D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
                 start, end, page_id, mm));
@@ -167,6 +180,7 @@ flush_tlb_range(struct mm_struct *mm,
         * and the virtual address range
         */
 
+       save_and_cli(flags);  /* flush needs to be atomic */
        for(i = 0; i < NUM_TLB_ENTRIES; i++) {
                unsigned long tlb_hi, vpn;
                *R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
@@ -184,7 +198,29 @@ flush_tlb_range(struct mm_struct *mm,
                                      IO_FIELD(R_TLB_LO, pfn,   0   ) );
                }
        }
+       restore_flags(flags);
+}
+
+/* dump the entire TLB for debug purposes */
+
+#if 0
+void
+dump_tlb_all(void)
+{
+       int i;
+       unsigned long flags;
+       
+       printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we  |\n");
+
+       save_and_cli(flags);
+       for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+               *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+               printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
+                      i, *R_TLB_HI, *R_TLB_LO);
+       }
+       restore_flags(flags);
 }
+#endif
 
 /*
  * Initialize the context related info for a new mm_struct
@@ -228,8 +264,7 @@ alloc_context(struct mm_struct *mm)
        map_replace_ptr++;
 
        if(map_replace_ptr == INVALID_PAGEID)
-               map_replace_ptr = 0;         /* wrap around */
-       
+               map_replace_ptr = 0;         /* wrap around */  
 }
 
 /* 
index fe6528460f8411cabdf4ecd41cc58de282a944a9..7763dc8f23af35b8c97b7b75a954e167ea7cb5a2 100644 (file)
@@ -57,7 +57,7 @@ static void cpuid_smp_cpuid(void *cmd_block)
     cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
 }
 
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
 {
   struct cpuid_command cmd;
   
@@ -73,7 +73,7 @@ extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
 }
 #else /* ! CONFIG_SMP */
 
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
 {
   cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
 }
index 533c84f683092b9d5610919595913f9255740ae3..80dbe6e164eed5d9f1bcf38553a7c03d5608f28d 100644 (file)
@@ -15,12 +15,14 @@ struct dmi_header
 };
 
 #define dmi_printk(x)
-//#define dmi_printk(x) printk(x)
+//#define dmi_printk(x) printk x
 
 static char * __init dmi_string(struct dmi_header *dm, u8 s)
 {
        u8 *bp=(u8 *)dm;
        bp+=dm->length;
+       if(!s)
+               return "";
        s--;
        while(s>0)
        {
index e0ae4b4cd706c13f209499e4fd149cb16d5b9e1b..df70730d7a804439e2c5e22bf6365fa4dffcc2f4 100644 (file)
@@ -70,34 +70,19 @@ static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
        }
 
        /*
-        * Horrible dependencies! Try to get rid of this. This is wrong,
-        * as it only reloads the ldt for the first process with this
-        * mm. The implications are that you should really make sure that
-        * you have a ldt before you do the first clone(), otherwise
-        * you get strange behaviour (the kernel is safe, it's just user
-        * space strangeness).
-        *
-        * we have two choices: either we preallocate the LDT descriptor
-        * and can do a shared modify_ldt(), or we postallocate it and do
-        * an smp message pass to update it. Currently we are a bit
-        * un-nice to user-space and reload the LDT only on the next
-        * schedule. (only an issue on SMP)
-        *
         * the GDT index of the LDT is allocated dynamically, and is
         * limited by MAX_LDT_DESCRIPTORS.
         */
        down_write(&mm->mmap_sem);
        if (!mm->context.segments) {
+               void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
                error = -ENOMEM;
-               mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-               if (!mm->context.segments)
+               if (!segments)
                        goto out_unlock;
-               memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
-               
-               /*
-                * Possibly do an SMP cross-call to other CPUs to reload
-                * their LDTs?
-                */
+               memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+               wmb();
+               mm->context.segments = segments;
+               mm->context.cpuvalid = 1UL << smp_processor_id();
                load_LDT(mm);
        }
 
index fd8cf70883d50314619da0b4386386c804f93c0b..3bccd43a3d387373c914f43450b4fe2c8e607c8f 100644 (file)
@@ -43,7 +43,7 @@
 /* Note: "err" is handled in a funny way below.  Otherwise one version
    of gcc or another breaks. */
 
-extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
 {
   int err;
 
@@ -64,7 +64,7 @@ extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
   return err;
 }
 
-extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
 {
   int err;
 
@@ -110,7 +110,7 @@ static void msr_smp_rdmsr(void *cmd_block)
     cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
 }
 
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
 {
   struct msr_command cmd;
 
@@ -127,7 +127,7 @@ extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
   }
 }
 
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   struct msr_command cmd;
 
@@ -148,12 +148,12 @@ extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 
 #else /* ! CONFIG_SMP */
 
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
 {
   return wrmsr_eio(reg, eax, edx);
 }
 
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   return rdmsr_eio(reg, eax, edx);
 }
index c8458853e22aaf3e8cce54597df0a3fd1bce6b5a..d0ef4d2108ee7f0d01a011fcb49dea1442746307 100644 (file)
@@ -518,6 +518,7 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
                        memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
        }
        new_mm->context.segments = ldt;
+       new_mm->context.cpuvalid = ~0UL;        /* valid on all CPU's - they can't have stale data */
 }
 
 /*
index 026bb4cc543de78ec320b37b973bb2f25bb23d11..05b0f16443cd11755b512410dae62c636d0f0510 100644 (file)
@@ -60,7 +60,7 @@ asmlinkage void div_Xsig(Xsig *x1, const Xsig *x2, const Xsig *dest);
 /* Some versions of gcc make it difficult to stop eax from being clobbered.
    Merely specifying that it is used doesn't work...
  */
-extern inline unsigned long mul_32_32(const unsigned long arg1,
+static inline unsigned long mul_32_32(const unsigned long arg1,
                                      const unsigned long arg2)
 {
   int retval;
@@ -73,7 +73,7 @@ extern inline unsigned long mul_32_32(const unsigned long arg1,
 
 
 /* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
-extern inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
+static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
 {
   asm volatile ("movl %1,%%edi; movl %2,%%esi;
                  movl (%%esi),%%eax; addl %%eax,(%%edi);
@@ -88,7 +88,7 @@ extern inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
 /* Note: the constraints in the asm statement didn't always work properly
    with gcc 2.5.8.  Changing from using edi to using ecx got around the
    problem, but keep fingers crossed! */
-extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
+static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
 {
   asm volatile ("movl %2,%%ecx; movl %3,%%esi;
                  movl (%%esi),%%eax; addl %%eax,(%%ecx);
@@ -108,7 +108,7 @@ extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
 
 /* Negate (subtract from 1.0) the 12 byte Xsig */
 /* This is faster in a loop on my 386 than using the "neg" instruction. */
-extern inline void negate_Xsig(Xsig *x)
+static inline void negate_Xsig(Xsig *x)
 {
   asm volatile("movl %1,%%esi; "
                "xorl %%ecx,%%ecx; "
index c830d8cb7c12a8e85c23cdf2d5d640af35a07878..bf34878a32b22eae5fb2637361b0c97ab35b2139 100644 (file)
@@ -813,7 +813,7 @@ _GLOBAL(_get_HID0)
 _GLOBAL(_set_HID0)
        sync
        mtspr   HID0, r3
-       SYNC            /* Handle erratas in some cases */
+       SYNC            /* Handle errata in some cases */
        blr
 
 _GLOBAL(_get_ICTC)
index 396afde5370e1aa9b91adc349cf9bc31e3f6e6e6..b01587153c645ed8a54745acd9a80a40d0c6b4e9 100644 (file)
@@ -17,7 +17,11 @@ LD=$(CROSS_COMPILE)ld -m elf_s390
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux-shared.lds $(LDFLAGS)
+else
 LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
+endif
 
 CFLAGS_PIPE := -pipe
 CFLAGS_NSR  := -fno-strength-reduce
@@ -27,8 +31,8 @@ HEAD := arch/s390/kernel/head.o arch/s390/kernel/init_task.o
 
 SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
            drivers/s390 arch/s390/math-emu
-CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \
-           drivers/s390/io.o
+CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
 LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
 
 ifeq ($(CONFIG_MATHEMU),y)
index 16d607880f87cce1da29379a809cc61554c6f10e..99807ccfeb7d0b4416d6636da2ab01f66a61b3c0 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux s390-specific parts of the memory manager.
+# arch/s390/boot/Makefile
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
index 47a5c0f5d6bd9886b473669c27fb45b23cda9246..9ff9efb2cba44ef8cb32b3ff48089c28a755d6bc 100644 (file)
@@ -50,6 +50,8 @@ define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
 source drivers/s390/Config.in
index 8934dd690799dcb0c92105a7b549e34675b04d0d..14c29b19088c162c9495674da383a93b50319adc 100644 (file)
@@ -5,6 +5,8 @@
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
 CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARCH_S390=y
 
 #
@@ -40,6 +42,8 @@ CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
 
 #
 # Block device drivers
@@ -79,10 +83,13 @@ CONFIG_UNIX98_PTY_COUNT=256
 #
 # S/390 character device drivers
 #
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
 CONFIG_S390_TAPE=m
 
 #
@@ -102,6 +109,9 @@ CONFIG_S390_TAPE_3480=y
 #
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
@@ -109,7 +119,8 @@ CONFIG_TR=y
 #
 # S/390 network device drivers
 #
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -133,7 +144,8 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 
@@ -178,16 +190,18 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -195,7 +209,6 @@ CONFIG_PROC_FS=y
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -243,4 +256,4 @@ CONFIG_IBM_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
index 52524b757331a971d91b174ef2a7e471d2ecac39..4f0f67e351fa1bccd2c1710abbe6b3a82bccffc0 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
index 81e589b4fb0bbdb2b919f749d53333035eb8fa71..34d34bf4c1707dd36268c958f4ebddc5834bc774 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
+#include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
 #include <asm/smp.h>
@@ -200,8 +201,10 @@ sysc_return:
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+       l       %r1,processor(%r9)    # get cpu number from task struture
+       sll     %r1,L1_CACHE_SHIFT
+       al      %r1,BASED(.Lirq_stat) # get address of irq_stat
+       icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         bnz     BASED(sysc_handle_bottom_half)
 #
 # check, if reschedule is needed
@@ -657,10 +660,9 @@ pgm_sv:
         lh      %r7,__LC_PGM_ILC         # load instruction length
        GET_CURRENT
 pgm_no_sv:
+       la      %r3,0x7f
         lh      %r8,__LC_PGM_INT_CODE  # N.B. saved int code used later KEEP it
-        lr      %r3,%r8
-        la      %r0,0x7f
-        nr      %r3,%r0           # clear per-event-bit
+       nr      %r3,%r8           # reload & clear per-event-bit
         be      BASED(pgm_dn)     # none of Martins exceptions occurred bypass
         l       %r1,BASED(.Ljump_table)
         sll     %r3,2
@@ -676,8 +678,7 @@ pgm_per:cl      %r3,BASED(.Lc20)  # pseudo page fault ?
         be      BASED(pgm_go)     # if yes then don't reenable interrupts
         stosm   24(%r15),0x03     # reenable interrupts
 pgm_go: basr    %r14,%r1          # branch to interrupt-handler
-pgm_dn: la      %r0,0x80
-        nr      %r8,%r0           # check for per exception
+pgm_dn: n      %r8,BASED(.Lc128) # check for per excepton
         be      BASED(pgm_return)
         la      %r2,SP_PTREGS(15) # address of register-save area
         l       %r1,BASED(.Lhandle_per) # load adr. of per handler
@@ -713,8 +714,10 @@ io_return:
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+       l       %r1,processor(%r9)    # get cpu number from task struture
+       sll     %r1,L1_CACHE_SHIFT
+       al      %r1,BASED(.Lirq_stat) # get address of irq_stat
+       icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         bnz     BASED(io_handle_bottom_half)
 io_return_bh:  
 #
@@ -843,6 +846,7 @@ restart_go:
 .Lc0x2401:     .long  0x2401
 .Lc0x4000:     .long  0x4000
 .Lc0xff:       .long  0xff
+.Lc128:        .long  128
 
 /*
  * Symbol constants
@@ -854,6 +858,7 @@ restart_go:
 .Lentry_base:  .long  entry_base
 .Lext_hash:    .long  ext_int_hash
 .Lhandle_per:  .long  handle_per_exception
+.Lirq_stat:    .long  irq_stat
 .Ljump_table:  .long  pgm_check_table
 .Lschedule:    .long  schedule
 .Lclone:       .long  sys_clone
index fdbb3671c56388db1e8f4519f6747ec667e57f0b..746e4a0cefb661a53504cfdaa2c8dd15c85cffaf 100644 (file)
@@ -461,7 +461,7 @@ start:
         .org  0x10000
 startup:basr  %r13,0                     # get base
 .LPG1:  lctl  %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       l     %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+       la    %r12,parmarea-.LPG1(%r13)  # pointer to parameter area
                                         # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
        
@@ -502,9 +502,7 @@ startup:basr  %r13,0                     # get base
 # find out if we have an IEEE fpu
 #
         mvc    __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
-        ld     %f0,.Lflt0-.LPG1(%r13)   # load (float) 0.0
-        ldr    %f2,%f0
-        adbr   %f0,%f2                  # test IEEE add instruction
+       efpc   %r0,0                    # test IEEE extract fpc instruction
         oi     3(%r12),2                # set IEEE fpu flag
 .Lchkfpu:
 
@@ -514,7 +512,7 @@ startup:basr  %r13,0                     # get base
        mvc    __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
        la     %r0,0
        lr     %r1,%r0
-       la     %r2,.Lflt0-.LPG1(%r13)
+       la     %r2,4
        csp    %r0,%r2                   # Test CSP instruction
        oi     3(%r12),8                 # set CSP flag
 .Lchkcsp:
@@ -554,12 +552,7 @@ startup:basr  %r13,0                     # get base
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.long  PARMAREA
 .L4malign:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lmaxchunk:.long  0x00ffffff
 .Lmemsize:.long memory_size
 .Lmflags:.long machine_flags
 
@@ -567,6 +560,7 @@ startup:basr  %r13,0                     # get base
 # params at 10400 (setup.h)
 #
        .org   PARMAREA
+parmarea:      
         .long  0,0                      # IPL_DEVICE
         .long  0,RAMDISK_ORIGIN         # INITRD_START
         .long  0,0x800000               # INITRD_SIZE
@@ -578,7 +572,11 @@ startup:basr  %r13,0                     # get base
 #
 # startup-code, running in virtual mode
 #
+#ifdef CONFIG_SHARED_KERNEL
+       .org   0x100000
+#else
         .org   0x10800
+#endif
         .globl _stext
 _stext:        basr  %r13,0                    # get base
 .LPG2:
@@ -608,8 +606,8 @@ _stext:     basr  %r13,0                    # get base
         jo    .-4                       # branch back, if not finish
 # check control registers
         stctl  %c0,%c15,0(%r15)
-        oc     2(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
-        oc     0(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+       oi     2(%r15),0x20             # enable sigp external interrupts
+       oi     0(%r15),0x10             # switch on low address protection
         lctl   %c0,%c15,0(%r15)
 
 #
@@ -622,15 +620,12 @@ _stext:   basr  %r13,0                    # get base
         basr  %r13,0
        lpsw  .Ldw-.(%r13)           # load disabled wait psw
 #
-.Lstart:    .long  start_kernel
             .align 8
+.Ldw:      .long  0x000a0000,0x00000000
 .Lprefix:   .long  init_S390_lowcore   
 .Linittu:   .long  init_task_union
+.Lstart:    .long  start_kernel
 .Lbss_bgn:  .long  __bss_start
 .Lbss_end:  .long  _end
-.Locbits:   .long  0x01020408,0x10204080
-            .align 4
 .Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
-           .align 8
-.Ldw:      .long  0x000a0000,0x00000000
 
index 5f75276b16e9c3396537fbdae5c09c7211f9553f..ff02b77b68dabe32fcfd85c332578c33d5773d94 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -119,7 +119,7 @@ int get_irq_list(char *buf)
  */
 #ifdef CONFIG_SMP
 atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
-atomic_t global_irq_lock;
+atomic_t global_irq_lock = ATOMIC_INIT(0);
 atomic_t global_irq_count = ATOMIC_INIT(0);
 atomic_t global_bh_count;
 
@@ -188,7 +188,7 @@ static inline void wait_on_irq(int cpu)
                }
 
                /* Duh, we have to loop. Release the lock to avoid deadlocks */
-               clear_bit(0,&global_irq_lock);
+               atomic_set(&global_irq_lock, 0);
 
                for (;;) {
                        if (!--count) {
@@ -206,10 +206,8 @@ static inline void wait_on_irq(int cpu)
                        if (!local_bh_count(cpu)
                            && atomic_read(&global_bh_count))
                                continue;
-                       /* this works even though global_irq_lock not
-                           a long, but is arch-specific --RR */
-                       if (!test_and_set_bit(0,&global_irq_lock))
-                               break;
+                       if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
+                                break;
                }
        }
 }
@@ -246,18 +244,14 @@ void synchronize_irq(void)
 
 static inline void get_irqlock(int cpu)
 {
-       /* this works even though global_irq_lock not a long, but is
-          arch-specific --RR */
-       if (test_and_set_bit(0,&global_irq_lock)) {
+       if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
                /* do we already hold the lock? */
                if ( cpu == atomic_read(&global_irq_holder))
                        return;
                /* Uhhuh.. Somebody else got it. Wait.. */
                do {
-                       do {
-                               check_smp_invalidate(cpu);
-                       } while (test_bit(0,&global_irq_lock));
-               } while (test_and_set_bit(0,&global_irq_lock));
+                       check_smp_invalidate(cpu);
+               } while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
        }
        /*
         * We also to make sure that nobody else is running
@@ -391,6 +385,10 @@ EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
 #endif
 
 EXPORT_SYMBOL(global_bh_lock);
index 6fd1c642fc394bfb4b291cc4688c3ba10dd2eead..d7398d62c5c0701665d568af57a92fe2b80b0e11 100644 (file)
@@ -63,8 +63,7 @@ int cpu_idle(void *unused)
        wait_psw.mask = _WAIT_PSW_MASK;
        wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
        while(1) {
-                if (softirq_active(smp_processor_id()) &
-                   softirq_mask(smp_processor_id())) {
+                if (softirq_pending(smp_processor_id())) {
                         do_softirq();
                         __sti();
                         if (!current->need_resched)
@@ -307,11 +306,11 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
 
         frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
         frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
-        p->thread.regs = &frame->childregs;
+        p->thread.regs = (struct pt_regs *)&frame->childregs;
         p->thread.ksp = (unsigned long) frame;
-        frame->childregs = *regs;
+        memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
         frame->childregs.gprs[15] = new_stackp;
-        frame->eos = 0;
+        frame->back_chain = frame->eos = 0;
 
         /* new return point is ret_from_sys_call */
         frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
@@ -466,54 +465,3 @@ unsigned long get_wchan(struct task_struct *p)
 #undef last_sched
 #undef first_sched
 
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
-       struct fs_struct *fs;
-       extern struct task_struct *child_reaper;
-       struct task_struct *this_process=current;
-       
-       /*
-        * If we were started as result of loading a module, close all of the
-        * user space pages.  We don't need them, and if we didn't close them
-        * they would be locked into memory.
-        */
-       exit_mm(current);
-
-       this_process->session = 1;
-       this_process->pgrp = 1;
-       if(name)
-       {
-               strncpy(current->comm,name,15);
-               current->comm[15]=0;
-       }
-       else
-               current->comm[0]=0;
-       /* set signal mask to what we want to respond */
-        siginitsetinv(&current->blocked,mask);
-       /* exit_signal isn't set up */
-        /* if we inherit from cpu idle  */
-       this_process->exit_signal=SIGCHLD;
-       /* if priority=0 schedule can go into a tight loop */
-       this_process->policy= SCHED_OTHER;
-       /* nice goes priority=20-nice; */
-       this_process->nice=10;
-       if(use_init_fs)
-       {
-               exit_fs(this_process);  /* current->fs->count--; */
-               fs = init_task.fs;
-               current->fs = fs;
-               atomic_inc(&fs->count);
-               exit_files(current);
-       }
-       write_lock_irq(&tasklist_lock);
-       /* We want init as our parent */
-       REMOVE_LINKS(this_process);
-       this_process->p_opptr=this_process->p_pptr=child_reaper;
-       SET_LINKS(this_process);
-       write_unlock_irq(&tasklist_lock);
-}
index d8599bbf9ffd41f17fa05d8fdcf35ea707cab782..6e8eb54b6f46f1f659f3eef54509ffd0dc0da3f7 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
  * Simple hash strategy: index = code & 0xff;
  * ext_int_hash[index] is the start of the list for all external interrupts
  * that hash to this index. With the current set of external interrupts 
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element. 
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
 ext_int_info_t ext_int_info_timer;
 ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
@@ -39,7 +40,9 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
                 p = &ext_int_info_timer;
         else if (code == 0x2401) /* hwc_init is done too early too */
                 p = &ext_int_info_hwc;
-        else
+        else if (code == 0x2603) /* pfault_init is done too early too */
+               p = &ext_int_pfault;
+       else
                 p = (ext_int_info_t *)
                           kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
         if (p == NULL)
@@ -70,7 +73,7 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401)
+        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
                 kfree(p);
         return 0;
 }
index 1a4b18822d62fd303059f64a39f2285ab8fa266a..0cc338382e03797d6a2065eae4168ca3794b72b4 100644 (file)
@@ -43,6 +43,7 @@ EXPORT_SYMBOL_NOVERS(strncmp);
 EXPORT_SYMBOL_NOVERS(strncpy);
 EXPORT_SYMBOL_NOVERS(strnlen);
 EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strstr);
 EXPORT_SYMBOL_NOVERS(strtok);
 EXPORT_SYMBOL_NOVERS(strpbrk);
 
@@ -53,6 +54,8 @@ EXPORT_SYMBOL(machine_flags);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(kernel_thread);
 EXPORT_SYMBOL(csum_fold);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
 
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigabit ethernet multicast support */
index 5903db41addbc6989aa91acd4abeb2840c5850d1..82eacdd3911a887418ddb69a6c0fb7edbe40e8be 100644 (file)
@@ -43,6 +43,8 @@
 /*
  * Machine setup..
  */
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
@@ -140,6 +142,93 @@ static int __init vmpoff_setup(char *str)
 
 __setup("vmpoff=", vmpoff_setup);
 
+/*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+       int vdev;
+
+       vdev = simple_strtoul(str, &str, 0);
+       if (vdev >= 0 && vdev < 65536)
+               console_device = vdev;
+       return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+       if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+                SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+       if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+               SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+       if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+               SET_CONSOLE_3270;
+#endif
+        return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+       char query_buffer[1024];
+       char *ptr;
+
+        if (MACHINE_IS_VM) {
+               cpcmd("QUERY TERM", query_buffer, 1024);
+               ptr = strstr(query_buffer, "CONMODE");
+               /*
+                * Set the conmode to 3215 so that the device recognition 
+                * will set the cu_type of the console to 3215. If the
+                * conmode is 3270 and we don't set it back then both
+                * 3215 and the 3270 driver will try to access the console
+                * device (3215 as console and 3270 as normal tty).
+                */
+               cpcmd("TERM CONMODE 3215", NULL, 0);
+               if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+                       return;
+               }
+               if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+                       SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+                       SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+               } else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+                       SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+                       SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+               }
+        } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+               SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+               SET_CONSOLE_3270;
+#endif
+       } else {
+#if defined(CONFIG_HWC_CONSOLE)
+               SET_CONSOLE_HWC;
+#endif
+       }
+}
+
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
@@ -183,8 +272,6 @@ void __init setup_arch(char **cmdline_p)
                 return;
         smptrap=1;
 
-        printk("Command line is: %s\n", COMMAND_LINE);
-
         /*
          * Setup lowcore information for boot cpu
          */
@@ -244,7 +331,6 @@ void __init setup_arch(char **cmdline_p)
                  * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
                  */
                 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
-                       if (to != command_line) to--;
                         delay = simple_strtoul(from+9, &from, 0);
                        if (*from == 's' || *from == 'S') {
                                delay = delay*1000000;
@@ -253,7 +339,7 @@ void __init setup_arch(char **cmdline_p)
                                delay = delay*60*1000000;
                                from++;
                        }
-                       /* now wait for the requestedn amount of time */
+                       /* now wait for the requested amount of time */
                        udelay(delay);
                 }
                 cn = *(from++);
@@ -261,6 +347,8 @@ void __init setup_arch(char **cmdline_p)
                         break;
                 if (cn == '\n')
                         cn = ' ';  /* replace newlines with space */
+               if (cn == 0x0d)
+                       cn = ' ';  /* replace 0x0d with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
@@ -322,6 +410,9 @@ void __init setup_arch(char **cmdline_p)
        request_resource(&iomem_resource, res);
        request_resource(res, &code_resource);
        request_resource(res, &data_resource);
+
+        /* Setup default console */
+       conmode_default();
 }
 
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
index 33f43fee3e97b0e70d3156e62c29feb7acc6a143..e9068cb91ff475990bd116e71599f7aeee82b175 100644 (file)
@@ -332,6 +332,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
                /* Set up registers for signal handler */
                regs->gprs[15] = (addr_t)frame;
                regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+               regs->psw.mask = _USER_PSW_MASK;
        }
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
@@ -358,6 +359,11 @@ static void setup_frame(int sig, struct k_sigaction *ka,
 #endif
        /* Martin wants this for pthreads */
        regs->gprs[3] = (addr_t)&frame->sc;
+
+       /* We forgot to include these in the sigcontext.
+          To avoid breaking binary compatibility, they are passed as args. */
+       regs->gprs[4] = current->thread.trap_no;
+       regs->gprs[5] = current->thread.prot_addr;
        return;
 
 give_sigsegv:
@@ -414,7 +420,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
              siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
        /* Are we from a system call? */
-       if (regs->orig_gpr2 >= 0) {
+       if (regs->trap == __LC_SVC_OLD_PSW) {
                /* If so, check system call restarting.. */
                switch (regs->gprs[2]) {
                        case -ERESTARTNOHAND:
@@ -561,7 +567,6 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                                 /* FALLTHRU */
 
                        default:
-                               lock_kernel();
                                sigaddset(&current->pending.signal, signr);
                                recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
index 0f22a0fdc63edea2b49d68498679605956ecff2f..22aaeec63e532d43be64fba57c6341c2f3c880d0 100644 (file)
@@ -556,6 +556,7 @@ void smp_count_cpus(void)
  *      Activate a secondary processor.
  */
 extern void init_100hz_timer(void);
+extern int pfault_token(void);
 
 int __init start_secondary(void *cpuvoid)
 {
@@ -568,6 +569,10 @@ int __init start_secondary(void *cpuvoid)
                 /* nothing */ ;
         /* init per CPU 100 hz timer */
         init_100hz_timer();
+#ifdef CONFIG_PFAULT
+       /* Enable pfault pseudo page faults on this cpu. */
+       pfault_init();
+#endif
         /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
index f4bde27b381ab40966ff56bcaaf30777d62ec7a1..d3568efcf2657566bd80fd6b4c3c9691f7d5a639 100644 (file)
@@ -95,9 +95,10 @@ void do_gettimeofday(struct timeval *tv)
 {
        unsigned long flags;
        unsigned long usec, sec;
-       unsigned long lost_ticks = jiffies - wall_jiffies;
+       unsigned long lost_ticks;
 
        read_lock_irqsave(&xtime_lock, flags);
+       lost_ticks = jiffies - wall_jiffies;
        usec = do_gettimeoffset();
        if (lost_ticks)
                usec +=(USECS_PER_JIFFY*lost_ticks);
index cefc24013993a07a4f30e68c330946c3242fdf09..b73cb69f4a9a7ebc1439d66dea7c8fedf3d4ec82 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/gdb-stub.h>
 #endif
 #include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -53,6 +54,11 @@ int sysctl_userprocess_debug = 0;
 
 extern pgm_check_handler_t do_page_fault;
 extern pgm_check_handler_t do_pseudo_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
 
 spinlock_t die_lock;
 
@@ -142,7 +148,7 @@ DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
 DO_ERROR(SIGILL,  "privileged operation", privileged_op)
 DO_ERROR(SIGILL,  "execute exception", execute_exception)
 DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGILL,  "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGFPE,  "fixpoint divide exception", divide_exception)
 DO_ERROR(SIGILL,  "translation exception", translation_exception)
 DO_ERROR(SIGILL,  "special operand exception", special_op_exception)
 DO_ERROR(SIGILL,  "operand exception", operand_exception)
@@ -154,7 +160,6 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
        int signal = 0;
        int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE);
 
-        lock_kernel();
        location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
        if(problem_state)
                get_user(*((__u16 *) opcode), location);
@@ -197,7 +202,6 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
         } else if (signal)
                do_trap(interruption_code, signal,
                        "illegal operation", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -210,7 +214,6 @@ specification_exception(struct pt_regs * regs, long interruption_code)
        __u16 *location;
        int signal = 0;
 
-        lock_kernel();
         if (regs->psw.mask & PSW_PROBLEM_STATE) {
                location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
                get_user(*((__u16 *) opcode), location);
@@ -250,7 +253,6 @@ specification_exception(struct pt_regs * regs, long interruption_code)
         } else if (signal)
                 do_trap(interruption_code, signal,
                        "specification exception", regs, NULL);
-        unlock_kernel();
 }
 #else
 DO_ERROR(SIGILL, "specification exception", specification_exception)
@@ -262,7 +264,6 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
        __u16 *location;
        int signal = 0;
 
-        lock_kernel();
        location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
        if (MACHINE_HAS_IEEE)
                __asm__ volatile ("stfpc %0\n\t" 
@@ -333,7 +334,6 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
        } else if (signal) 
                 do_trap(interruption_code, signal,
                        "data exception", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -361,8 +361,26 @@ void __init trap_init(void)
        pgm_check_table[0x14] = &do_pseudo_page_fault;
         pgm_check_table[0x15] = &operand_exception;
         pgm_check_table[0x1C] = &privileged_op;
+#ifdef CONFIG_PFAULT
+       if (MACHINE_IS_VM) {
+               /* request the 0x2603 external interrupt */
+               if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+                       panic("Couldn't request external interrupt 0x2603");
+               /*
+                * First try to get pfault pseudo page faults going.
+                * If this isn't available turn on pagex page faults.
+                */
+               if (pfault_init() != 0) {
+                       /* Tough luck, no pfault. */
+                       unregister_external_interrupt(0x2603,
+                                                     pfault_interrupt);
+                       cpcmd("SET PAGEX ON", NULL, 0);
+               }
+       }
+#else
        if (MACHINE_IS_VM)
-               cpcmd("SET PAGEX ON", NULL, 0);
+               cpcmd("SET PAGEX ON", NULL, 0);
+#endif
 }
 
 
index 73e25bd3022a95b5270f868f47bdafd076233930..5f930b361d0a06befdb235259cc0918568e91a44 100644 (file)
@@ -1,5 +1,5 @@
 #
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the linux s390-specific parts of the memory manager.
 #
 # Note! Dependencies are done automagically by 'make dep', which also
 # removes any old dependencies. DON'T put your own dependencies here
index f1477a0d68edc02b96474954a024edfea4a9ce87..81daf0c1e3497b5bf5265d8a45f07537741ed588 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/compatmac.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -52,25 +53,14 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         unsigned long address;
         unsigned long fixup;
         int write;
-        unsigned long psw_mask;
-        unsigned long psw_addr;
        int si_code = SEGV_MAPERR;
        int kernel_address = 0;
 
-        /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-
-        psw_mask = S390_lowcore.program_old_psw.mask;
-        psw_addr = S390_lowcore.program_old_psw.addr;
-
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
          * the address 
          */
-
         address = S390_lowcore.trans_exc_code&0x7ffff000;
 
         tsk = current;
@@ -185,7 +175,7 @@ bad_area:
         up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
-        if (psw_mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_PROBLEM_STATE) {
                struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
@@ -243,7 +233,7 @@ no_context:
 out_of_memory:
        up_read(&mm->mmap_sem);
        printk("VM: killing process %s\n", tsk->comm);
-       if (psw_mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_PROBLEM_STATE)
                do_exit(SIGKILL);
        goto no_context;
 
@@ -259,7 +249,7 @@ do_sigbus:
        force_sig(SIGBUS, tsk);
 
        /* Kernel mode? Handle exceptions or die */
-       if (!(psw_mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
                goto no_context;
 }
 
@@ -275,24 +265,16 @@ static pseudo_wait_t *pseudo_lock_queue = NULL;
 static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
 
 /*
- * This routine handles pseudo page faults.
+ * This routine handles 'pagex' pseudo page faults.
  */
 asmlinkage void
 do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
-        DECLARE_WAITQUEUE(wait, current);
         pseudo_wait_t wait_struct;
         pseudo_wait_t *ptr, *last, *next;
-        unsigned long psw_mask;
         unsigned long address;
         int kernel_address;
 
-        /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-        psw_mask = S390_lowcore.program_old_psw.mask;
-
         /*
          * get the failing address
          * more specific the segment and page table portion of
@@ -332,7 +314,7 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
                 spin_unlock(&pseudo_wait_spinlock);
         } else {
                 /* Pseudo page faults in kernel mode is a bad idea */
-                if (!(psw_mask & PSW_PROBLEM_STATE)) {
+                if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
                         /*
                         * VM presents pseudo page faults if the interrupted
                         * state was not disabled for interrupts. So we can
@@ -383,4 +365,127 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
                 wait_event(wait_struct.queue, wait_struct.resolved);
         }
 }
-    
+
+#ifdef CONFIG_PFAULT 
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+       pfault_disable = 1;
+       return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+       __u16 refdiagc;
+       __u16 reffcode;
+       __u16 refdwlen;
+       __u16 refversn;
+       __u64 refgaddr;
+       __u64 refselmk;
+       __u64 refcmpmk;
+       __u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+int pfault_init(void)
+{
+       pfault_refbk_t refbk =
+       { 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+        int rc;
+
+       if (pfault_disable)
+               return -1;
+        __asm__ __volatile__(
+                "    diag  %1,%0,0x258\n"
+               "0:  j     2f\n"
+               "1:  la    %0,8\n"
+               "2:\n"
+               ".section __ex_table,\"a\"\n"
+               "   .align 4\n"
+               "   .long  0b,1b\n"
+               ".previous"
+                : "=d" (rc) : "a" (&refbk) : "cc" );
+        __ctl_set_bit(0, 9);
+        return rc;
+}
+
+void pfault_fini(void)
+{
+       pfault_refbk_t refbk =
+       { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+       if (pfault_disable)
+               return;
+       __ctl_clear_bit(0,9);
+        __asm__ __volatile__(
+                "    diag  %0,0,0x258\n"
+               "0:\n"
+               ".section __ex_table,\"a\"\n"
+               "   .align 4\n"
+               "   .long  0b,0b\n"
+               ".previous"
+               : : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+        DECLARE_WAITQUEUE(wait, current);
+       struct task_struct *tsk;
+       wait_queue_head_t queue;
+       wait_queue_head_t *qp;
+       __u16 subcode;
+
+       /*
+        * Get the external interruption subcode & pfault
+        * initial/completion signal bit. VM stores this 
+        * in the 'cpu address' field associated with the
+         * external interrupt. 
+        */
+       subcode = S390_lowcore.cpu_addr;
+       if ((subcode & 0xff00) != 0x06)
+               return;
+
+       /*
+        * Get the token (= address of kernel stack of affected task).
+        */
+       tsk = (struct task_struct *)
+               (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+       
+       if (subcode & 0x0080) {
+               /* signal bit is set -> a page has been swapped in by VM */
+               qp = (wait_queue_head_t *)
+                       xchg(&tsk->thread.pfault_wait, -1);
+               if (qp != NULL) {
+                       /* Initial interrupt was faster than the completion
+                        * interrupt. pfault_wait is valid. Set pfault_wait
+                        * back to zero and wake up the process. This can
+                        * safely be done because the task is still sleeping
+                        * and can't procude new pfaults. */
+                       tsk->thread.pfault_wait = 0ULL;
+                       wake_up(qp);
+               }
+       } else {
+               /* signal bit not set -> a real page is missing. */
+                init_waitqueue_head (&queue);
+               qp = (wait_queue_head_t *)
+                       xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+               if (qp != NULL) {
+                       /* Completion interrupt was faster than the initial
+                        * interrupt (swapped in a -1 for pfault_wait). Set
+                        * pfault_wait back to zero and exit. This can be
+                        * done safely because tsk is running in kernel 
+                        * mode and can't produce new pfaults. */
+                       tsk->thread.pfault_wait = 0ULL;
+               }
+
+                /* go to sleep */
+                wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+       }
+}
+#endif
+
diff --git a/arch/s390/tools/dasdfmt/Makefile b/arch/s390/tools/dasdfmt/Makefile
deleted file mode 100644 (file)
index b60641b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
-       $(CC) -o $@ $^
-       $(STRIP) $@
-
-clean:
-       rm -f dasdfmt
-
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.8 b/arch/s390/tools/dasdfmt/dasdfmt.8
deleted file mode 100644 (file)
index 9e6a4e8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR 
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR 
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR 
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
-       \fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
-       \fB-n\fR \fIdevnum\fR
-.sp
-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 device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c
deleted file mode 100644 (file)
index b04c9dd..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- *
- * dasdfmt.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Corporation
- *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- *   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>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _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
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
-       {if (i>1) \
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-                       "can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
-       {x=(int)strtol(param,&endptr,base); \
-       if (*endptr) \
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-                       "is in invalid format\n",prog_name);}
-
-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)
-{
-#ifdef RANGE_FORMATTING
-       printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
-               "<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
-       printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
-               "<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
-       printf("       -t means testmode\n");
-       printf("       -v means verbose mode\n");
-       printf("       -C means format compatible disk layout\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");
-       printf("           -n <s390-devnr>\n");
-       exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
-       FILE *file;
-       int d,rc;
-       kdev_t mi,ma;
-       int mi_i,ma_i; /* for scanf :-( */
-       char line[PROC_LINE_LENGTH];
-
-       file=fopen(PROC_DASD_DEVICES,"r");
-       if (file==NULL)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
-                       PROC_DASD_DEVICES ": %s (do you have the /proc " \
-                       "filesystem enabled?)\n",prog_name,strerror(errno));
-
-       /*      fgets(line,sizeof(line),file); omit first line */ 
-       while (fgets(line,sizeof(line),file)!=NULL) {
-                rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
-               ma=ma_i;
-               mi=mi_i;
-               if ( (rc==3) &&
-                       !((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
-                       !((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
-                       !((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
-                       *devno=d;
-                       *major_no=ma;
-                       *minor_no=mi;
-                       /* yes, this is a quick exit, but the easiest way */
-                       fclose(file);
-                       return;
-               }
-       }
-       fclose(file);
-
-       ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-                   "filesystem (are you sure to have the right parameter " \
-                   "dasd=xxx?)\n",
-               prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
-       kdev_t major_no,minor_no;
-       kdev_t file_major,file_minor;
-       struct stat stat_buf;
-       int rc;
-       int found;
-       char *devname;
-       char tmpname[MAX_FILELEN];
-
-       DIR *dp;
-       struct dirent *direntp;
-
-       /**** get minor number ****/
-       get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
-       /**** get device file ****/
-       if ((dp=opendir(SLASHDEV)) == NULL)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
-                       "\n",prog_name);
-       found=0;
-       while ((direntp=readdir(dp)) != NULL) {
-               strcpy(tmpname,SLASHDEV);
-               strcat(tmpname,direntp->d_name);
-               rc=stat(tmpname,&stat_buf);
-               if (!rc) {
-                       file_major=MAJOR(stat_buf.st_rdev);
-                       file_minor=MINOR(stat_buf.st_rdev);
-                       if ((file_major==major_no) && (file_minor==minor_no)) {
-                               found=1;
-                               break;
-                       }
-               }
-       }
-       if (found) {
-               devname=malloc(strlen(direntp->d_name));
-               strcpy(devname,tmpname);
-       }
-       rc=closedir(dp);
-       if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
-               "; continuing\n",prog_name);
-       if (found)
-               return devname;
-
-       if (verbosity>=1)
-               printf("I didn't find device node in " SLASHDEV \
-                       "; trying to create a temporary node\n");
-
-       /**** get temp file and create device node *****/
-       rc=mkstemp(tempfilename);
-       if (rc==-1)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
-                       "filename: %s\n",prog_name,strerror(errno));
-       close(rc);
-       rc=unlink(tempfilename);
-       
-       rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
-       if (rc)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
-                       "device node %s: %s\n",prog_name,tempfilename,
-                       strerror(errno));
-       return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
-       char *s;
-
-       if (NULL==(s=malloc(ERR_LENGTH)))
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
-       if ((mode&CHECK_START)&&(data.start_unit<0)) {
-               strcpy(s,"start track must be greater than zero");
-               goto exit;
-       }
-       if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
-               strcpy(s,"end track must be -1 or greater than zero");
-               goto exit;
-       }
-       if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
-               (data.stop_unit!=-1)) {
-               strcpy(s,"end track must be higher than start track");
-               goto exit;
-       }
-
-       if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
-               strcpy(s,"blocksize must be a positive integer");
-               goto exit;
-       }
-       if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
-               if ((data.blksize%2)&&(data.blksize!=1)) {
-                       strcpy(s,"blocksize must be a power of 2");
-                       goto exit;
-               }
-               data.blksize/=2;
-       }
-
-       free(s);
-       return NULL;
-exit:
-       return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
-       if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
-       if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
-               if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
-       char buffer[20]; /* should be enough for inputing track numbers */
-       char c;
-       int i,rc;
-       char *str;
-       char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
-       i=params.start_unit;
-       do {
-               params.start_unit=i;
-               sprintf(output,"the start track of the range to format " \
-                       "[%d]: ",i);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               ASK_SCANFORNUMBER(params.start_unit);
-               ASK_COMPLAIN_FORMAT;
-               ASK_CHECK_PARAM(CHECK_START);
-       } while (rc!=1);
-
-       i=params.stop_unit;
-       do {
-               params.stop_unit=i;
-               sprintf(output,"the end track of the range to format [");
-               if (i==-1) sprintf(o2,"END]: "); else
-                       sprintf(o2,"%d]: ",i);
-               strcat(output,o2);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               if ( (!strcasecmp(buffer,"end")) ||
-                       (!strcasecmp(buffer,"end\n")) ) {
-                       rc=1;
-                       params.stop_unit=-1;
-               } else {
-                       ASK_SCANFORNUMBER(params.stop_unit);
-                       ASK_COMPLAIN_FORMAT;
-                       ASK_CHECK_PARAM(CHECK_END);
-               }
-       } while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
-       i=params.blksize;
-       do {
-               params.blksize=i;
-               sprintf(output,"the blocksize of the formatting [%d]: ",i);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               ASK_SCANFORNUMBER(params.blksize);
-               ASK_COMPLAIN_FORMAT;
-               ASK_CHECK_PARAM(CHECK_BLKSIZE);
-       } while (rc!=1);
-
-       return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
-       FILE *f;
-       int ishift = 0;
-       struct mntent *ment;
-       struct stat stbuf;
-       char line[128];
-
-       /* If whole disk to be formatted ... */
-       if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
-               /* ... ignore partition-selector */
-               minor >>= DASD_PARTN_BITS;
-               ishift = DASD_PARTN_BITS;
-       }
-       /*
-        * first, check filesystems
-        */
-       if (!(f = fopen(PROC_MOUNTS, "r")))
-               ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
-                       strerror(errno));
-       while ((ment = getmntent(f))) {
-               if (stat(ment->mnt_fsname, &stbuf) == 0)
-                       if ((major == MAJOR(stbuf.st_rdev)) &&
-                               (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-                               ERRMSG("%s: device is mounted on %s!!\n",
-                                       prog_name,ment->mnt_dir);
-                               ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-                                       "format it, please unmount it.\n");
-                       }
-       }
-       fclose(f);
-       /*
-        * second, check active swap spaces
-        */
-       if (!(f = fopen(PROC_SWAPS, "r")))
-               ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
-       /*
-        * skip header line
-        */
-       fgets(line, sizeof(line), f);
-       while (fgets(line, sizeof(line), f)) {
-               char *p;
-               for (p = line; *p && (!isspace(*p)); p++) ;
-               *p = '\0';
-               if (stat(line, &stbuf) == 0)
-                       if ((major == MAJOR(stbuf.st_rdev)) &&
-                               (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-                               ERRMSG("%s: the device is in use for "
-                                       "swapping!!\n",prog_name);
-                               ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-                                       "format it, please use swapoff %s.\n",
-                                       line);
-                       }
-       }
-       fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-       int verbosity,int writenolabel,int labelspec,
-       char *label,int withoutprompt,int devno)
-{
-       int fd,rc;
-       struct stat stat_buf;
-       kdev_t minor_no,major_no;
-       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);
-       if (fd==-1)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
-                       "%s\n",prog_name,dev_name,strerror(errno));
-
-       if (verbosity>=1) {
-       }
-
-       rc=stat(dev_name,&stat_buf);
-       if (rc) {
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
-                       "%s\n",prog_name,strerror(errno));
-       } else {
-               if (!S_ISBLK(stat_buf.st_mode))
-                       ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
-                               "blockdevice.\n",prog_name);
-               major_no=MAJOR(stat_buf.st_rdev);
-               minor_no=MINOR(stat_buf.st_rdev);
-       }
-       check_mounted(major_no, minor_no);
-
-       get_xno_from_xno(&devno,&major_no,&minor_no,
-                       GIVEN_MAJOR|GIVEN_MINOR);
-       if ((!writenolabel) && (!labelspec)) {
-               sprintf(label,"LNX1 x%04x",devno);
-       }
-       
-       if ( ((withoutprompt)&&(verbosity>=1)) ||
-               (!withoutprompt) ) {
-               printf("\nI am going to format the device %s in the " \
-                       "following way:\n",dev_name);
-               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);
-               if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
-                       printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
-                              "yes":"no");
-#ifdef RANGE_FORMATTING
-               printf("   Start track             : %d\n" \
-                       ,format_params.start_unit);
-               printf("   End track               : ");
-               if (format_params.stop_unit==-1)
-                       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");
-       }
-
-       while (!testmode) {
-               if (!withoutprompt) {
-                       printf("\n--->> ATTENTION! <<---\n");
-                       printf("All data in the specified range of that " \
-                               "device will be lost.\nType \"yes\" to " \
-                               "continue, no will leave the disk untouched: ");
-                       fgets(inp_buffer,sizeof(inp_buffer),stdin);
-                       if (strcasecmp(inp_buffer,"yes") &&
-                               strcasecmp(inp_buffer,"yes\n")) {
-                               printf("Omitting ioctl call (disk will " \
-                                       "NOT be formatted).\n");
-                               break;
-                       }
-               }
-
-               if ( !(  (withoutprompt)&&(verbosity<1) ))
-                       printf("Formatting the device. This may take a " \
-                               "while (get yourself a coffee).\n");
-               rc=ioctl(fd,BIODASDFORMAT,format_params);
-               if (rc)
-                       ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
-                               "returned with the following error " \
-                               "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,BLKSSZGET,&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) {
-                       ERRMSG("%s: error during rereading the partition " \
-                              "table: %s.\n",prog_name,strerror(errno));
-               } else printf("done.\n");
-
-               break;
-       }
-
-       rc=close(fd);
-       if (rc)
-               ERRMSG("%s: error during close: " \
-                       "%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
-       int verbosity;
-       int testmode;
-       int withoutprompt;
-       int writenolabel,labelspec;
-
-       char *dev_name;
-       int devno;
-       char *dev_filename,*devno_param_str,*range_param_str;
-       char *start_param_str,*end_param_str,*blksize_param_str;
-       char label[LABEL_LENGTH+1];
-       
-       format_data_t format_params;
-
-       int rc;
-       int oc;
-       char *endptr;
-
-       char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-       int i,i1,i2;
-       char *str;
-
-       int start_specified,end_specified,blksize_specified;
-       int devfile_specified,devno_specified,range_specified;
-
-       /******************* initialization ********************/
-       prog_name=argv[0];
-
-       endptr=NULL;
-
-       /* set default values */
-       format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
-       format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
-       format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
-       format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
-       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;
-
-       /*************** parse parameters **********************/
-
-       /* avoid error message generated by getopt */
-       opterr=0;
-
-#ifdef RANGE_FORMATTING
-       while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
-       while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
-               switch (oc) {
-               case 'y':
-                       withoutprompt=1;
-                       break;
-
-               case 't':
-                       testmode=1;
-                       break;
-
-               case 'v':
-                       verbosity++;
-                       break;
-
-               case '?': /* fall-through */
-               case ':':
-                       exit_usage(EXIT_MISUSE);
-
-               case 'h':
-                       exit_usage(0);
-               case 'C':
-                       format_params.intensity&=0x08;
-                       break;
-
-               case 'V':
-                       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++;
-                       break;
-                       
-               case 'e' :
-                       end_param_str=optarg;
-                       end_specified++;
-                       break;
-
-               case 'r' :
-                       range_param_str=optarg;
-                       range_specified++;
-                       break;
-#endif /* RANGE_FORMATTING */
-
-               case 'b' :
-                       blksize_param_str=optarg;
-                       blksize_specified++;
-                       break;
-                       
-               case 'n' :
-                       devno_param_str=optarg;
-                       devno_specified++;
-                       break;
-               
-               case 'f' :
-                       dev_filename=optarg;
-                       devfile_specified++;
-                       break;
-               }
-       }
-
-       /******************** checking of parameters **************/
-
-       /* convert range into -s and -e */
-       CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
-       while (range_specified) {
-               start_specified++;
-               end_specified++;
-
-               /* scan for 1 or 2 integers, separated by a dash */
-               rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
-               if ((rc==3)&&(c1=='-')) {
-                       format_params.start_unit=i1;
-                       format_params.stop_unit=i2;
-                       break;
-               }
-               if (rc==1) {
-                       format_params.start_unit=i1;
-                       break;
-               }
-
-               /* scan for integer and -END */
-               rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
-               if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
-                       format_params.start_unit=i1;
-                       format_params.stop_unit=-1;
-                       break;
-               }
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
-                       "is in invalid format\n",prog_name);
-       }
-
-       if ((!devfile_specified)&&(!devno_specified))
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-                       "not specified\n",prog_name);
-
-       if ((devfile_specified+devno_specified)>1)
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-                       "can only be specified once\n",prog_name);
-
-       if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
-               (!blksize_specified)) {
-               format_params=ask_user_for_data(format_params);
-       }
-
-       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");
-       if (start_specified&&!range_specified)
-               PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
-                       "start track");
-       if (end_specified&&!range_specified)
-               PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
-                       "end track");
-       if (blksize_specified)
-               PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
-                       "blocksize");
-
-       /***********get dev_name *********************/
-       dev_name=(devno_specified)?
-               get_devname_from_devno(devno,verbosity):
-               dev_filename;
-
-       /*** range checking *********/
-       str=check_param(CHECK_ALL,format_params);
-       if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
-       /******* issue the real command and reread part table *******/
-       do_format_dasd(dev_name,format_params,testmode,verbosity,
-               writenolabel,labelspec,label,withoutprompt,devno);
-
-       /*************** cleanup ********************************/
-       if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
-               rc=unlink(dev_name);
-               if ((rc)&&(verbosity>=1))
-                       ERRMSG("%s: temporary device node %s could not be " \
-                               "removed: %s\n",prog_name,dev_name,
-                               strerror(errno));
-       } else {
-               if (devno_specified) {
-                       /* so we have allocated space for the filename */
-                       free(dev_name);
-               }
-       }
-
-       return 0;
-}
diff --git a/arch/s390/tools/silo/Makefile b/arch/s390/tools/silo/Makefile
deleted file mode 100644 (file)
index 62b11d7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-all: silo
-
-silo.o: silo.c
-       $(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
-       $(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
-       $(CC) -o $@ $^
-       $(STRIP) $@
-
-clean:
-       rm -f *.o silo
-
diff --git a/arch/s390/tools/silo/cfg.c b/arch/s390/tools/silo/cfg.c
deleted file mode 100644 (file)
index 2b11d93..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/* cfg.c  -  Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
-    fflush(stdout);
-    perror(msg);
-    exit(1);
-}
-
-
-void die(char *fmt,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,fmt);
-    vfprintf(stderr,fmt,ap);
-    va_end(ap);
-    fputc('\n',stderr);
-    exit(1);
-}
-
-char *pstrdup(const char *str)
-{
-    char *this;
-
-    if ((this = strdup(str)) == NULL) pdie("Out of memory");
-    return this;
-}
-
-int cfg_open(char *name)
-{
-    if (!strcmp(name,"-")) file = stdin;
-    else if (!(file = fopen(file_name = name,"r"))) pdie(name);
-    line_num = 1;
-    return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,msg);
-    vfprintf(stderr,msg,ap);
-    va_end(ap);
-    if (!file_name) fputc('\n',stderr);
-    else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
-    exit(1);
-}
-
-
-static int next_raw(void)
-{
-    int ch;
-
-    if (!back) return getc(file);
-    ch = back;
-    back = 0;
-    return ch;
-}
-
-
-static int next(void)
-{
-    static char *var;
-    char buffer[MAX_VAR_NAME+1];
-    int ch,braced;
-    char *put;
-
-    if (back) {
-       ch = back;
-       back = 0;
-       return ch;
-    }
-    if (var && *var) return *var++;
-    ch = getc(file);
-    if (ch == '\\') {
-       ch = getc(file);
-       if (ch == '$') return ch;
-       ungetc(ch,file);
-       return '\\';
-    }
-    if (ch != '$') return ch;
-    ch = getc(file);
-    braced = ch == '{';
-    put = buffer;
-    if (!braced) *put++ = ch;
-    while (1) {
-       ch = getc(file);
-#if 0
-       if (!braced && ch < ' ') {
-           ungetc(ch,file);
-           break;
-       }
-#endif
-       if (ch == EOF) cfg_error("EOF in variable name");
-       if (ch < ' ') cfg_error("control character in variable name");
-       if (braced && ch == '}') break;
-       if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
-           ungetc(ch,file);
-           break;
-       }
-       if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
-       *put++ = ch;
-    }
-    *put = 0;
-    if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
-    return next();
-}
-
-
-static void again(int ch)
-{
-    if (back) die("internal error: again invoked twice");
-    back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
-    char buf[MAX_TOKEN+1];
-    char *here;
-    int ch,escaped;
-
-    if (last_token) {
-       here = last_token;
-       last_token = NULL;
-       return here;
-    }
-    while (1) {
-       while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
-           if (ch == '\n') line_num++;
-       if (ch == EOF) return NULL;
-       if (ch != '#') break;
-       while ((ch = next_raw()), ch != '\n')
-           if (ch == EOF) return NULL;
-       line_num++;
-    }
-    if (ch == '=') return pstrdup("=");
-    if (ch == '"') {
-       here = buf;
-       while (here-buf < MAX_TOKEN) {
-           if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
-           if (ch == '"') {
-               *here = 0;
-               return pstrdup(buf);
-           }
-           if (ch == '\\') {
-               ch = next();
-               if (ch != '"' && ch != '\\' && ch != '\n')
-                   cfg_error("Bad use of \\ in quoted string");
-               if (ch == '\n') {
-                   while ((ch = next()), ch == ' ' || ch == '\t');
-                   if (!ch) continue;
-                   again(ch);
-                   ch = ' ';
-               }
-           }
-           if (ch == '\n' || ch == '\t')
-               cfg_error("\\n and \\t are not allowed in quoted strings");
-           *here++ = ch;
-       }
-       cfg_error("Quoted string is too long");
-       return 0; /* not reached */
-    }
-    here = buf;
-    escaped = 0;
-    while (here-buf < MAX_TOKEN) {
-       if (escaped) {
-           if (ch == EOF) cfg_error("\\ precedes EOF");
-           if (ch == '\n') line_num++;
-           else *here++ = ch == '\t' ? ' ' : ch;
-           escaped = 0;
-       }
-       else {
-           if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
-             ch == '=' || ch == EOF) {
-               again(ch);
-               *here = 0;
-               return pstrdup(buf);
-           }
-           if (!(escaped = (ch == '\\'))) *here++ = ch;
-       }
-       ch = next();
-    }
-    cfg_error("Token is too long");
-    return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
-    last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
-    char *this;
-
-    if (last_item) {
-       *item = last_item;
-       *value = last_value;
-       last_item = NULL;
-       return 1;
-    }
-    *value = NULL;
-    if (!(*item = cfg_get_token())) return 0;
-    if (!strcmp(*item,"=")) cfg_error("Syntax error");
-    if (!(this = cfg_get_token())) return 1;
-    if (strcmp(this,"=")) {
-       cfg_return_token(this);
-       return 1;
-    }
-    if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
-    if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
-    return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
-    last_item = item;
-    last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
-    while (table->type != cft_end) {
-       switch (table->type) {
-           case cft_strg:
-               if (table->data) free(table->data);
-           case cft_flag:
-               table->data = NULL;
-               break;
-           case cft_link:
-               table = ((CONFIG *) table->action)-1;
-               break;
-           default:
-               die("Unknown syntax code %d",table->type);
-       }
-       table++;
-    }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
-    void *context)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (value && walk->type != cft_strg)
-               cfg_error("'%s' doesn't have a value",walk->name);
-           if (!value && walk->type == cft_strg)
-               cfg_error("Value expected for '%s'",walk->name);
-           if (walk->data) {
-               if (walk->context == context)
-                   cfg_error("Duplicate entry '%s'",walk->name);
-               else {
-                   fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
-                   if (!copy) free(value);
-                   return 1;
-               }
-           }
-           if (walk->type == cft_flag) walk->data = &flag_set;
-           else if (walk->type == cft_strg) {
-                   if (copy) walk->data = pstrdup(value);
-                   else walk->data = value;
-           }
-           walk->context = context;
-           if (walk->action) ((void (*)(void)) walk->action)();
-           break;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    if (walk->type != cft_end) return 1;
-    cfg_return(item,value);
-    return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
-    if (!cfg_do_set(table,item,value,1,context))
-       cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++)
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
-           if (walk->type == cft_strg) free(walk->data);
-           walk->data = NULL;
-           return;
-       }
-    die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
-    char *item,*value;
-
-    while (1) {
-       if (!cfg_next(&item,&value)) return 0;
-       if (!cfg_do_set(table,item,value,0,table)) return 1;
-       free(item);
-    }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (walk->type != cft_flag)
-               die("cfg_get_flag: operating on non-flag %s",item);
-           return !!walk->data;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_flag: unknown item %s",item);
-    return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (walk->type != cft_strg)
-               die("cfg_get_strg: operating on non-string %s",item);
-           return walk->data;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_strg: unknown item %s",item);
-    return 0; /* not reached */
-}
diff --git a/arch/s390/tools/silo/cfg.h b/arch/s390/tools/silo/cfg.h
deleted file mode 100644 (file)
index 97d10bf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* cfg.h  -  Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
-    CFG_TYPE type;
-    char *name;
-    void *action;
-    void *data;
-    void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
-   file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
-   program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
-   since the last call to cfg_init, a warning message is issued if the context
-   keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
-   was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
-   value is returned if a variable not found in table has been met. Zero is
-   returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
diff --git a/arch/s390/tools/silo/silo.c b/arch/s390/tools/silo/silo.c
deleted file mode 100644 (file)
index 0236b2f..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- *  arch/s390/boot/silo.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *    Report bugs to: <linux390@de.ibm.com>
- *
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *               Fritz Elfert <felfert@to.com> contributed support for
- *                     /etc/silo.conf based on Intel's lilo
- *    Changes  :
- *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
-  { cft_strg, "append",                NULL,           NULL,NULL },
-  { cft_strg, "image",         NULL,           NULL,NULL },
-  { cft_strg, "ipldevice",     NULL,           NULL,NULL },
-  { cft_strg, "bootsect",      NULL,           NULL,NULL },
-  { cft_strg, "map",           NULL,           NULL,NULL },
-  { cft_strg, "parmfile",      NULL,           NULL,NULL },
-  { cft_strg, "ramdisk",       NULL,           NULL,NULL },
-  { cft_strg, "root",          NULL,           NULL,NULL },
-  { cft_flag, "readonly",      NULL,           NULL,NULL },
-  { cft_strg, "verbose",       NULL,           NULL,NULL },
-  { cft_strg, "testlevel",     NULL,           NULL,NULL },
-  { cft_end,  NULL,            NULL,           NULL,NULL }
-};
-  
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#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 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); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
-  {
-    short int verbosity;
-    short int testlevel;
-    char *image;
-    char *ipldevice;
-    char *parmfile;
-    char *ramdisk;
-    char *bootsect;
-    char *conffile;
-    char *bootmap;
-  }
-silo_options =
-{
-  1,                           /* verbosity */
-  2,                           /* testlevel */
-    SILO_IMAGE,                        /* image */
-    NULL,                      /* ipldevice */
-    SILO_PARMFILE,             /* parmfile */
-    NULL,                      /* initrd */
-    SILO_BOOTSECT,             /* bootsector */
-    SILO_CFG,                   /* silo.conf file */
-    SILO_BOOTMAP,               /* boot.map */
-};
-
-struct blockdesc
-  {
-    unsigned long off;
-    unsigned short ct;
-    unsigned long addr;
-  };
-
-struct blocklist
-  {
-    struct blockdesc blk[MAX_CLUSTERS];
-    unsigned short ix;
-  };
-
-void
-usage (void)
-{
-  printf ("Usage:\n");
-  printf ("silo -d ipldevice [additional options]\n");
-  printf ("-d /dev/node : set ipldevice to /dev/node\n");
-  printf ("-f image : set image to image\n");
-  printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
-  printf ("-p parmfile : set parameter file to parmfile\n");
-  printf ("-b bootsect : set bootsector to bootsect\n");
-  printf ("Additional options\n");
-  printf ("-B bootmap:\n");
-  printf ("-v: increase verbosity level\n");
-  printf ("-v#: set verbosity level to #\n");
-  printf ("-t: decrease testing level\n");
-  printf ("-h: print this message\n");
-  printf ("-?: print this message\n");
-  printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
-       char *tmp;
-       if (access(o->conffile, R_OK) && (errno == ENOENT))
-               return 0;
-       /* If errno != ENOENT, let cfg_open report an error */
-       cfg_open(o->conffile);
-       cfg_parse(cf_options);
-       tmp = cfg_get_strg(cf_options, "ipldevice");
-       if ( ! o->ipldevice  && tmp ) 
-               o->ipldevice = tmp;
-       tmp = cfg_get_strg(cf_options, "image");
-       if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp ) 
-               o->image = tmp;
-       tmp = cfg_get_strg(cf_options, "parmfile");
-       if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) 
-               o->parmfile = tmp;
-       if ( ! o -> ramdisk ) 
-               o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
-       tmp = cfg_get_strg(cf_options, "bootsect");
-       if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
-               o->bootsect = tmp;
-       tmp = cfg_get_strg(cf_options, "map") ;
-       if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp) 
-               o->bootmap = tmp; 
-       tmp = cfg_get_strg(cf_options, "verbose");
-       if ( tmp ) {
-               unsigned short v;
-               sscanf (tmp, "%hu", &v);
-               o->verbosity = v;
-       }
-       tmp = cfg_get_strg(cf_options, "testlevel");
-       if ( tmp ) {
-               unsigned short t;
-               sscanf (tmp, "%hu", &t);
-               o->testlevel += t;
-       }
-       return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
-       char *append = cfg_get_strg(cf_options, "append");
-       char *root = cfg_get_strg(cf_options, "root");
-       int ro = cfg_get_flag(cf_options, "readonly");
-       FILE *f,*of;
-       char *fn;
-       char c;
-       char *tmpdir=NULL,*save=NULL;
-
-       if (!append && !root && !ro)
-               return pfile;
-       of = fopen(pfile, "r");
-       if ( of ) {
-               NTRY( fn = tempnam(NULL,"parm."));
-       } else {
-               fn = pfile;
-       }
-       NTRY( f = fopen(fn, "a+"));
-       if ( of ) {
-               while ( ! feof (of) ) {
-                 c=fgetc(of);
-               fputc(c,f);
-               }
-       }
-       if (root)
-               fprintf(f, " root=%s", root);
-       if (ro)
-               fprintf(f, " ro");
-       if (append)
-               fprintf(f, " %s", append);
-       fprintf(f, "\n");
-       fclose(f);
-       fclose(of);
-       printf ("tempfile is %s\n",fn);
-       return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
-  int rc = 0;
-  int oc;
-
-  while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
-    {
-      switch (oc)
-       {
-       case 'V':
-         printf("silo version: %s\n",SILO_VERSION);
-         exit(0);
-       case 'v':
-         {
-           unsigned short v;
-           if (optarg && sscanf (optarg, "%hu", &v))
-             o->verbosity = v;
-           else
-             o->verbosity++;
-           PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
-           break;
-         }
-       case 't':
-         {
-           unsigned short t;
-           if (optarg && sscanf (optarg, "%hu", &t))
-             o->testlevel -= t;
-           else
-             o->testlevel--;
-            PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
-           break;
-         }
-       case 'h':
-       case '?':
-         usage ();
-         exit(0);
-       case 'd':
-         GETARG (o->ipldevice);
-         break;
-       case 'f':
-         GETARG (o->image);
-         break;
-        case 'F':                         
-          GETARG (o->conffile);              
-          break;                          
-       case 'p':
-         GETARG (o->parmfile);
-         break;
-       case 'r':
-         GETARG (o->ramdisk);
-         break;
-       case 'b':
-         GETARG (o->bootsect);
-         break;
-       case 'B':
-         GETARG (o->bootmap);
-       default:
-         rc = EINVAL;
-         break;
-       }
-    }
-  read_cfg(o);
-  return rc;
-}
-
-int
-verify_device (char *name)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  ITRY (stat (name, &dst));
-  if (S_ISBLK (dst.st_mode))
-    {
-      if (!(MINOR (dst.st_rdev) & PARTN_MASK))
-       {
-         rc = dst.st_rdev;
-       }
-      else
-       /* invalid MINOR & PARTN_MASK */
-       {
-         ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
-                      (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
-         rc = -1;
-         errno = EINVAL;
-       }
-    }
-  else
-    /* error S_ISBLK */
-    {
-      ERROR_LEVEL (1, "%s is no block device\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  int bs = 1024;
-  int l;
-
-  ITRY(stat ( name, &dst ));
-  if (S_ISREG (dst.st_mode))
-    {
-      if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
-       {
-         /* whatever to do if all is ok... */
-       }
-      else
-       /* devicenumber doesn't match */
-       {
-         ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
-         rc = -1;
-         errno = EINVAL;
-       }
-    }
-  else
-    /* error S_ISREG */
-    {
-      ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
-  int rc = 0;
-  int dev = 0;
-  int crc = 0;
-  if (!o->ipldevice || !o->image || !o->bootsect)
-    {
-     if (!o->ipldevice)
-       fprintf(stderr,"ipldevice\n");
-     if (!o->image)
-       fprintf(stderr,"image\n");
-     if (!o->bootsect)
-       fprintf(stderr,"bootsect\n");
-
-      usage ();
-      exit (1);
-    }
-  PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
-  PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
-  ITRY (dev = verify_device (o->ipldevice));
-  PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
-  PRINT_LEVEL (1, "\n");
-
-  PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
-  ITRY (verify_file (o->bootsect, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if ( o -> testlevel > 0  && 
-       ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
-     NTRY( o -> bootmap = tempnam(NULL,"boot."));
-  }
-  PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
-  if ( access ( o->bootmap, O_RDWR ) == -1 ) {
-    if ( errno == ENOENT ) {
-      ITRY (creat ( o-> bootmap, O_RDWR ));
-    } else {
-      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
-                 strerror(errno));
-    }
-  }
-  ITRY (verify_file (o->bootmap, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
-  ITRY (verify_file (o->image, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  o->parmfile = gen_tmpparm(o->parmfile);
-  PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if (o->ramdisk)
-    {
-      PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
-      ITRY (verify_file (o->ramdisk, dev));
-      PRINT_LEVEL (1, "...ok...");
-      PRINT_LEVEL (0, "\n");
-    }
-
-  return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
-  int fd;
-  int devfd;
-  struct stat fst;
-  int i;
-  int blk;
-  int bs;
-  int blocks;
-
-  int rc = 0;
-
-  ITRY (fd = open (name, O_RDONLY));
-  ITRY (fstat (fd, &fst));
-  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
-  ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
-  ITRY (ioctl (fd, FIGETBSZ, &bs));
-  blocks = (fst.st_size + bs - 1) / bs;
-  for (i = 0; i < blocks; i++)
-    {
-      blk = i;
-      ITRY (ioctl (fd, FIBMAP, &blk));
-      if (blk)
-       {
-         int oldblk = blk;
-         ITRY (ioctl (devfd, BIODASDRWTB, &blk));
-         if (blk <= 0)
-           {
-             ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
-             break;
-           }
-       }
-      else
-       {
-         PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
-       }
-      if (lst->ix == 0 || i == 0  || 
-         lst->blk[lst->ix - 1].ct >= 128 ||
-         (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
-          !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
-       {
-         if (lst->ix >= MAX_CLUSTERS)
-           {
-             rc = 1;
-             errno = ENOMEM;
-             break;
-           }
-         lst->blk[lst->ix].off = blk;
-         lst->blk[lst->ix].ct = 1;
-         lst->blk[lst->ix].addr = addr + i * bs;
-         lst->ix++;
-       }
-      else
-       {
-         lst->blk[lst->ix - 1].ct++;
-       }
-    }
-  ITRY(unlink("/tmp/silodev"));
-  return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
-  int i;
-  int s_fd, d_fd, b_fd, bd_fd;
-  struct stat s_st, d_st, b_st;
-  int rc=0;
-  int bs, boots;
-  char *tmpdev;
-  char buffer[4096]={0,};
-  int blocksize, sectsize;
-  ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
-  ITRY (fstat (d_fd, &d_st));
-  ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
-  ITRY (verify_file (o->bootsect, d_st.st_rdev));
-  for (i = 0; i < blklst->ix; i++)
-    {
-      int offset = blklst->blk[i].off;
-      int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
-      PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
-       if ( o->testlevel <= 1 ) {
-             NTRY (write (s_fd, &offset, sizeof (int)));
-             NTRY (write (s_fd, &addrct, sizeof (int)));
-       }
-    }
-  ITRY (ioctl (s_fd,FIGETBSZ, &bs));
-  ITRY (stat (o->bootmap, &s_st));
-  if (s_st.st_size > bs )
-    {
-      ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
-      rc = -1;
-      errno = EINVAL;
-    }
-  boots=0;
-  NTRY ( tmpdev = tmpnam(NULL) );
-  ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
-  ITRY (bd_fd = open (tmpdev, O_RDONLY));
-  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
-  ITRY (ioctl(s_fd,FIBMAP,&boots));
-  ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
-  PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
-  close (bd_fd);
-  close(s_fd);
-  ITRY (unlink(tmpdev));
-  /* Now patch the bootsector */
-  ITRY (stat (o->bootsect, &b_st));
-  if ((sectsize = b_st.st_size) > blocksize )
-    {
-      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
-      rc = -1;
-      errno = EINVAL;
-    }
-  ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  ITRY (read (b_fd, buffer, sectsize));
-  memset (buffer + 0xe0, 0, 8);
-  *(int *) (buffer + 0xe0) = boots;
-  if ( o -> testlevel <= 0 ) {
-    ITRY (write (d_fd, buffer, sectsize));
-    ITRY (lseek (d_fd, blocksize, SEEK_SET));
-    ITRY (write (d_fd, buffer, sectsize));
-  }
-  close (b_fd);
-  close (d_fd);
-  return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
-  int rc = 0;
-
-  int device_fd;
-  int image_fd;
-  struct blocklist blklist;
-  memset (&blklist, 0, sizeof (struct blocklist));
-  ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
-  if (o->parmfile)
-    {
-      ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
-    }
-  if (o->ramdisk)
-    {
-      ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
-    }
-  ITRY (write_bootsect (o, &blklist));
-  return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
-  int rc = 0;
-  char *save=NULL;
-  char *tmpdir=getenv("TMPDIR");
-  if (tmpdir) {
-    NTRY( save=(char*)malloc(strlen(tmpdir)));
-    NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
-  }
-  ITRY( setenv("TMPDIR",".",1));
-  ITRY (parse_options (&silo_options, argct, argv));
-  ITRY (verify_options (&silo_options));
-  if ( silo_options.testlevel > 0 ) {
-    printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
-  }
-  ITRY (do_silo (&silo_options));
-  if ( save )
-    ITRY( setenv("TMPDIR",save,1)); 
-  return rc;
-}
diff --git a/arch/s390/tools/silo/silo.conf b/arch/s390/tools/silo/silo.conf
deleted file mode 100644 (file)
index 47d8a45..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ipldevice = /dev/dasda 
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
index 7ea330273298a9345843d9c16af5a6db6a61876f..d68843b4ff68f1704e847dfab85354c4d2f6f654 100644 (file)
@@ -17,7 +17,11 @@ LD=$(CROSS_COMPILE)ld -m elf64_s390
 CPP=$(CC) -E
 OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
 LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux-shared.lds $(LDFLAGS)
+else
 LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux.lds $(LDFLAGS)
+endif
 MODFLAGS += -fpic
 
 CFLAGS_PIPE := -pipe
@@ -28,8 +32,8 @@ HEAD := arch/s390x/kernel/head.o arch/s390x/kernel/init_task.o
 
 SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
            drivers/s390
-CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES) \
-           drivers/s390/io.o
+CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
 LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
 
 all: image listing
index 8329a23fcae23b07dc4cbd86cb8894502e45c795..8228e9cb5dfb934fc25f8846aa58bedef2c99758 100644 (file)
@@ -53,6 +53,8 @@ define_bool CONFIG_KCORE_ELF y
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
 endmenu
 
 
index 9c5c32380b7a4b0d08109348feefcc268d448db7..a56d6f978f2a93af241538f62c7877ba2c25e5f3 100644 (file)
@@ -4,6 +4,8 @@
 # CONFIG_ISA is not set
 # CONFIG_EISA is not set
 # CONFIG_MCA is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 CONFIG_ARCH_S390=y
 CONFIG_ARCH_S390X=y
 
@@ -41,6 +43,8 @@ CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
 
 #
 # Block device drivers
@@ -58,7 +62,6 @@ CONFIG_BLK_DEV_XPRAM=m
 CONFIG_DASD=y
 CONFIG_DASD_ECKD=y
 CONFIG_DASD_FBA=y
-# CONFIG_DASD_DIAG is not set
 
 #
 # Multi-device support (RAID and LVM)
@@ -80,10 +83,13 @@ CONFIG_UNIX98_PTY_COUNT=256
 #
 # S/390 character device drivers
 #
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
 CONFIG_HWC=y
 CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
 CONFIG_S390_TAPE=m
 
 #
@@ -103,6 +109,9 @@ CONFIG_S390_TAPE_3480=y
 #
 CONFIG_NETDEVICES=y
 # CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_TR=y
 # CONFIG_FDDI is not set
@@ -110,7 +119,8 @@ CONFIG_TR=y
 #
 # S/390 network device drivers
 #
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
 CONFIG_CTC=m
 CONFIG_IUCV=m
 
@@ -134,7 +144,8 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_IP_MROUTE is not set
 # CONFIG_INET_ECN is not set
 # CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
 # CONFIG_KHTTPD is not set
 # CONFIG_ATM is not set
 
@@ -179,16 +190,18 @@ CONFIG_IP_MULTICAST=y
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
 # CONFIG_RAMFS is not set
 # CONFIG_ISO9660_FS is not set
 # CONFIG_JOLIET is not set
 # CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
 # CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
 # CONFIG_DEVFS_DEBUG is not set
 # CONFIG_DEVPTS_FS is not set
 # CONFIG_QNX4FS_FS is not set
@@ -196,7 +209,6 @@ CONFIG_PROC_FS=y
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
 # CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
 # CONFIG_UDF_FS is not set
 # CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
@@ -244,4 +256,4 @@ CONFIG_IBM_PARTITION=y
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
index 52524b757331a971d91b174ef2a7e471d2ecac39..4f0f67e351fa1bccd2c1710abbe6b3a82bccffc0 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ctype.h>
 #include <linux/version.h>
 #include <asm/uaccess.h>
index 0fec8eb3ead22117eb9e6808d31b508ee73eb32a..146d4cc189a82036192169770c73542fea88c25a 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sys.h>
 #include <linux/linkage.h>
 #include <linux/config.h>
+#include <asm/cache.h>
 #include <asm/lowcore.h>
 #include <asm/errno.h>
 #include <asm/smp.h>
@@ -80,7 +81,7 @@ flags        =  8
 sigpending   = 16
 need_resched = 32
 tsk_ptrace   = 40
-processor    = 100
+processor    = 92
 
 /*
  * Register usage in interrupt handlers:
@@ -194,8 +195,11 @@ sysc_return:
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+       lgf     %r1,processor(%r9)    # get cpu number from task struture
+       larl    %r2,irq_stat
+       sll     %r1,L1_CACHE_SHIFT
+       la      %r1,0(%r1,%r2)
+       icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         jnz     sysc_handle_bottom_half
 #
 # check, if reschedule is needed
@@ -607,7 +611,7 @@ sys_call_table:
         .long  SYSCALL(sys_pivot_root,sys32_pivot_root_wrapper)
         .long  SYSCALL(sys_mincore,sys32_mincore_wrapper)
         .long  SYSCALL(sys_madvise,sys32_madvise_wrapper)
-       .long  SYSCALL(sys_ni_syscall,sys32_getdents64_wrapper)/* 220 */
+       .long  SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
        .long  SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
         .rept  255-221
        .long  SYSCALL(sys_ni_syscall,sys_ni_syscall)
@@ -700,8 +704,11 @@ io_return:
 #
 # check, if bottom-half has to be done
 #
-        l       %r0,__LC_IRQ_STAT     # get softirq_active
-        n       %r0,__LC_IRQ_STAT+4   # and it with softirq_mask
+       lgf     %r1,processor(%r9)    # get cpu number from task struture
+       larl    %r2,irq_stat
+       sll     %r1,L1_CACHE_SHIFT
+       la      %r1,0(%r1,%r2)
+       icm     %r0,15,0(%r1)         # test irq_stat[#cpu].__softirq_pending
         jnz     io_handle_bottom_half
 io_return_bh:  
 #
index 4e23a71af29d5d45ce9a128569eba1de8b7a2347..e1dc4403e69f42684118527cf753ea6834a10796 100644 (file)
@@ -261,7 +261,7 @@ iplstart:
        l     %r1,0xb8                         # load ipl subchannel number
         la    %r2,IPL_BS                       # load start address
         bas   %r14,.Lloader                    # load rest of ipl image
-        l     %r12,.Lparm                      # pointer to parameter area
+        larl  %r12,parmarea                    # pointer to parameter area
         st    %r1,IPL_DEVICE+4-PARMAREA(%r12)  # store ipl device number
 
 #
@@ -303,7 +303,6 @@ iplstart:
         slr   %r0,%r0
         b     .Lcntlp
 .Ldelspc:
-        ic    %r0,0(%r3)
         ic    %r0,0(%r2,%r3)
         chi   %r0,0x20                         # is it a space ?
         be    .Lcntlp
@@ -353,7 +352,6 @@ iplstart:
         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
@@ -459,59 +457,81 @@ start:
 #
         .org  0x10000
 startup:basr  %r13,0                     # get base
-.LPG1:  n     %r13,.Lhighoff-.LPG1(%r13) # remove high order bit
+.LPG1:  sll   %r13,1                     # remove high order bit
+        srl   %r13,1
         lhi   %r1,1                      # mode 1 = esame
         slr   %r0,%r0                    # set cpuid to zero
         sigp  %r1,%r0,0x12               # switch to esame mode
        sam64                            # switch to 64 bit mode
        lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
-       lg    %r12,.Lparm1-.LPG1(%r13)   # pointer to parameter area
+       larl  %r12,parmarea              # pointer to parameter area
                                         # move IPL device to lowcore
         mvc   __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+                                        # set program check new psw mask
+       mvc   __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+
 
 #
 # find out memory size.
 #
-       mvc   0x1d0(16),.Lpcmem-.LPG1(%r13) # setup program check handler
+       la    %r1,1f-.LPG1(%r13)         # set program check address
+       stg   %r1,__LC_PGM_NEW_PSW+8
         lghi  %r2,1
         sllg  %r2,%r2,17                 # test in increments of 128KB
        lgr   %r1,%r2
        aghi  %r1,-8                     # test last word in the segment
-.Lloop:        
-       lg    %r0,0(%r1)                 # test 128KB segment
+0:     lg    %r0,0(%r1)                 # test 128KB segment
+        stg   %r0,0(%r1)
+       algr  %r1,%r2                    # add 128KB
+       bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
+1:     ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
+       larl  %r3,memory_size-.
+       stg   %r1,0(%r3)                 # store memory size
+#
+# find out memory size part 2. Running native the HSA is located at
+# 2GB and we will get an addressing exception trying to access it.
+# We have to restart the scan at 2GB to find out if the machine has
+# more than 2GB of storage.
+#
+       la    %r1,1f-.LPG1(%r13)         # set program check address
+       stg   %r1,__LC_PGM_NEW_PSW+8
+       lg    %r1,.Lscan2g-.LPG1(%r13)   # restart scanning @ 2GB + 128K - 8
+0:     lg    %r0,0(%r1)                 # test 128KB segment
        stg   %r0,0(%r1)
-       agr   %r1,%r2                    # add 128KB
-       bno   .Lloop-.LPG1(%r13)         # r1 < 0x80000000 -> loop
-.Lchkmem:
+       algr  %r1,%r2                    # add 128 KB
+       bc    12,0b-.LPG1(%r13)          # r1 < 2^64 -> loop
+1:     clg   %r1,.Lscan2g-.LPG1(%r13)   # program check @ 2GB + 128K - 8 ?
+       be    2f-.LPG1(%r13)
        ng    %r1,.L4malign-.LPG1(%r13)  # align to multiples of 4M
-       lg    %r2,.Lmemsize-.LPG1(%r13)  # address of variable memory_size
-       stg   %r1,0(%r2)                 # store memory size
+       larl  %r3,memory_size-.
+       stg   %r1,0(%r3)                 # store memory size
+2:
 
-       lg    %r12,.Lmflags-.LPG1(%r13)  # get address of machine_flags
+       larl  %r12,machine_flags-.
 #
 # find out if we are running under VM
 #
         stidp  __LC_CPUID               # store cpuid
        tm     __LC_CPUID,0xff          # running under VM ?
-       bno    .Lnovm-.LPG1(%r13)
+       bno    0f-.LPG1(%r13)
         oi     7(%r12),1                # set VM flag
-.Lnovm:
-        lh     %r0,__LC_CPUID+4         # get cpu version
+0:      lh     %r0,__LC_CPUID+4         # get cpu version
         chi    %r0,0x7490               # running on a P/390 ?
-        bne    .Lnop390-.LPG1(%r13)
+        bne    1f-.LPG1(%r13)
         oi     7(%r12),4                # set P/390 flag
-.Lnop390:
+1:
 
 #
 # find out if we have the MVPG instruction
 #
-       mvc    __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13)
-       sgr    %r0,%r0
-       lghi   %r1,0
-       lghi   %r2,0
-       mvpg   %r1,%r2                   # Test CSP instruction
-       oi     7(%r12),16                # set MVPG flag
-.Lchkmvpg:
+       la     %r1,0f-.LPG1(%r13)       # set program check address
+       stg    %r1,__LC_PGM_NEW_PSW+8
+       sgr    %r0,%r0
+       lghi   %r1,0
+       lghi   %r2,0
+       mvpg   %r1,%r2                  # test MVPG instruction
+       oi     7(%r12),16               # set MVPG flag
+0:
 
         lpswe .Lentry-.LPG1(13)         # jump to _stext in primary-space,
                                         # virtual and never return ...
@@ -533,21 +553,15 @@ startup:basr  %r13,0                     # get base
         .quad  0                        # cr13: home space segment table
         .quad  0xc0000000               # cr14: machine check handling off
         .quad  0                        # cr15: linkage stack operations
-.Lpcmem:.quad  0x0000000180000000,.Lchkmem
-.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.quad  PARMAREA
-.Lhighoff:.long 0x7fffffff
+.Lpcmsk:.quad  0x0000000180000000
 .L4malign:.quad 0xffffffffffc00000
-.Lbigmem:.quad 0x04000000
-.Lmaxchunk:.quad  0x00ffffff
-.Lmemsize:.quad memory_size
-.Lmflags:.quad machine_flags
+.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
 
 #
 # params at 10400 (setup.h)
 #
        .org   PARMAREA
+parmarea:
        .quad  0                        # IPL_DEVICE
         .quad  RAMDISK_ORIGIN           # INITRD_START
         .quad  RAMDISK_SIZE             # INITRD_SIZE
@@ -559,7 +573,11 @@ startup:basr  %r13,0                     # get base
 #
 # startup-code, running in virtual mode
 #
+#ifdef CONFIG_SHARED_KERNEL
+       .org   0x100000
+#else
         .org   0x10800
+#endif
         .globl _stext
 _stext:        basr  %r13,0                    # get base
 .LPG2:
@@ -569,7 +587,7 @@ _stext:     basr  %r13,0                    # get base
         l     %r1,__LC_IPLDEV           # load ipl device number
         spx   .Lprefix-.LPG2(%r13)      # set prefix to linux lowcore
         st    %r1,__LC_IPLDEV           # store ipl device number
-        lg    %r15,.Linittu-.LPG2(%r13)
+       larl  %r15,init_task_union
         aghi  %r15,16384                # init_task_union + 16384
         stg   %r15,__LC_KERNEL_STACK    # set end of kernel stack
         aghi  %r15,-160
@@ -579,8 +597,8 @@ _stext:     basr  %r13,0                    # get base
 #
 # clear bss memory
 #
-        lg    %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
-        lg    %r3,.Lbss_end-.LPG2(%r13) # end of bss
+       larl  %r2,__bss_start           # start of bss segment
+        larl  %r3,_end                  # end of bss segment
         sgr   %r3,%r2                   # length of bss
         sgr   %r4,%r4                   #
         sgr   %r5,%r5                   # set src,length and pad to zero
@@ -588,8 +606,8 @@ _stext:     basr  %r13,0                    # get base
         jo    .-4                       # branch back, if not finish
 # check control registers
         stctg  %c0,%c15,0(%r15)
-        oc     6(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
-        oc     4(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+       oi     6(%r15),0x20             # enable sigp external interrupts
+       oi     4(%r15),0x10             # switch on low address proctection
         lctlg  %c0,%c15,0(%r15)
 
 #
@@ -601,15 +619,8 @@ _stext:    basr  %r13,0                    # get base
         basr  %r13,0
        lpswe .Ldw-.(%r13)           # load disabled wait psw
 #
-.Lstart:    .quad  start_kernel
             .align 8
+.Ldw:       .quad  0x0002000180000000,0x0000000000000000
 .Lprefix:   .long  init_S390_lowcore   
-.Linittu:   .quad  init_task_union
-.Lbss_bgn:  .quad  __bss_start
-.Lbss_end:  .quad  _end
-.Locbits:   .quad  0x0102040810204080
-            .align 4
 .Laregs:    .long  0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
-           .align 8
-.Ldw:      .quad  0x0002000180000000,0x0000000000000000
 
index f9b5a8db6c925055a041118e37e394eb770ba5d7..92023c04b63665f0d9b79ee953e2f6d4dc483578 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/random.h>
 #include <linux/smp.h>
@@ -385,6 +385,10 @@ EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
 #endif
 
 EXPORT_SYMBOL(global_bh_lock);
index a6f5ba56d3b9d4e34ee74e8ddad10a4b1ce024b2..db8fc1d535359b07a241d79fb0e9143f0b48f250 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/sem.h>
 #include <linux/msg.h>
 #include <linux/shm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/uio.h>
 #include <linux/nfs_fs.h>
 #include <linux/smb_fs.h>
@@ -4176,8 +4176,8 @@ static inline long do_mmap2(
        unsigned long prot, unsigned long flags,
        unsigned long fd, unsigned long pgoff)
 {
-       int error = -EBADF;
        struct file * file = NULL;
+       unsigned long error = -EBADF;
 
        flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
        if (!(flags & MAP_ANONYMOUS)) {
@@ -4188,6 +4188,11 @@ static inline long do_mmap2(
 
        down_write(&current->mm->mmap_sem);
        error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+       if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
+               /* Result is out of bounds.  */
+               do_munmap(current->mm, addr, len);
+               error = -ENOMEM;
+       }
        up_write(&current->mm->mmap_sem);
 
        if (file)
index 87dd4a312148b2beb793264f7f9734ee13da0348..c339e730b18f8ea09ce23eadb89ed63d522d4ae1 100644 (file)
@@ -63,8 +63,7 @@ int cpu_idle(void *unused)
        wait_psw.mask = _WAIT_PSW_MASK;
        wait_psw.addr = (unsigned long) &&idle_wakeup;
        while(1) {
-                if (softirq_active(smp_processor_id()) &
-                   softirq_mask(smp_processor_id())) {
+                if (softirq_pending(smp_processor_id())) {
                         do_softirq();
                         __sti();
                         if (!current->need_resched)
@@ -311,7 +310,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
         p->thread.ksp = (unsigned long) frame;
         frame->childregs = *regs;
         frame->childregs.gprs[15] = new_stackp;
-        frame->eos = 0;
+        frame->back_chain = frame->eos = 0;
 
         /* new return point is ret_from_sys_call */
         frame->gprs[8] = (unsigned long) &ret_from_fork;
@@ -460,54 +459,3 @@ unsigned long get_wchan(struct task_struct *p)
 #undef last_sched
 #undef first_sched
 
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
-       struct fs_struct *fs;
-       extern struct task_struct *child_reaper;
-       struct task_struct *this_process=current;
-       
-       /*
-        * If we were started as result of loading a module, close all of the
-        * user space pages.  We don't need them, and if we didn't close them
-        * they would be locked into memory.
-        */
-       exit_mm(current);
-
-       this_process->session = 1;
-       this_process->pgrp = 1;
-       if(name)
-       {
-               strncpy(current->comm,name,15);
-               current->comm[15]=0;
-       }
-       else
-               current->comm[0]=0;
-       /* set signal mask to what we want to respond */
-        siginitsetinv(&current->blocked,mask);
-       /* exit_signal isn't set up */
-        /* if we inherit from cpu idle  */
-       this_process->exit_signal=SIGCHLD;
-       /* if priority=0 schedule can go into a tight loop */
-       this_process->policy= SCHED_OTHER;
-       /* nice goes priority=20-nice; */
-       this_process->nice=10;
-       if(use_init_fs)
-       {
-               exit_fs(this_process);  /* current->fs->count--; */
-               fs = init_task.fs;
-               current->fs = fs;
-               atomic_inc(&fs->count);
-               exit_files(current);
-       }
-       write_lock_irq(&tasklist_lock);
-       /* We want init as our parent */
-       REMOVE_LINKS(this_process);
-       this_process->p_opptr=this_process->p_pptr=child_reaper;
-       SET_LINKS(this_process);
-       write_unlock_irq(&tasklist_lock);
-}
index d8599bbf9ffd41f17fa05d8fdcf35ea707cab782..949dd78c6192562493c266a00a2a84b93f42027b 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/lowcore.h>
 #include <asm/s390_ext.h>
 
  * Simple hash strategy: index = code & 0xff;
  * ext_int_hash[index] is the start of the list for all external interrupts
  * that hash to this index. With the current set of external interrupts 
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element. 
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element. 
  */
 ext_int_info_t *ext_int_hash[256] = { 0, };
 ext_int_info_t ext_int_info_timer;
 ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
 
 int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
         ext_int_info_t *p;
@@ -39,6 +40,8 @@ int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
                 p = &ext_int_info_timer;
         else if (code == 0x2401) /* hwc_init is done too early too */
                 p = &ext_int_info_hwc;
+        else if (code == 0x2603) /* pfault_init is done too early too */
+                p = &ext_int_pfault;
         else
                 p = (ext_int_info_t *)
                           kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
@@ -70,7 +73,7 @@ int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) {
                 q->next = p->next;
         else
                 ext_int_hash[index] = p->next;
-        if (code != 0x1004 && code != 0x2401)
+        if (code != 0x1004 && code != 0x2401 && code != 0x2603)
                 kfree(p);
         return 0;
 }
index a22307ebf555df804556ec3275759ae866f45b4b..e1f64338c108485eaa97eef263e7ca0fbbd0bc66 100644 (file)
@@ -64,6 +64,8 @@ EXPORT_SYMBOL(overflowgid);
 EXPORT_SYMBOL(machine_flags);
 EXPORT_SYMBOL(__udelay);
 EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
 
 #if CONFIG_IP_MULTICAST
 /* Required for lcs gigibit ethernet multicast support */
index e7e7e2d17f668838d295aae0c0e8b1e185437f97..397f8d358eea810a80a2d008f22949751176c69d 100644 (file)
@@ -43,6 +43,8 @@
 /*
  * Machine setup..
  */
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
 unsigned long memory_size = 0;
 unsigned long machine_flags = 0;
 __u16 boot_cpu_addr;
@@ -140,6 +142,93 @@ static int __init vmpoff_setup(char *str)
 
 __setup("vmpoff=", vmpoff_setup);
 
+/*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+       int vdev;
+
+       vdev = simple_strtoul(str, &str, 0);
+       if (vdev >= 0 && vdev < 65536)
+               console_device = vdev;
+       return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+       if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+                SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+       if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+               SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+       if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+               SET_CONSOLE_3270;
+#endif
+        return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+       char query_buffer[1024];
+       char *ptr;
+
+        if (MACHINE_IS_VM) {
+               cpcmd("QUERY TERM", query_buffer, 1024);
+               ptr = strstr(query_buffer, "CONMODE");
+               /*
+                * Set the conmode to 3215 so that the device recognition 
+                * will set the cu_type of the console to 3215. If the
+                * conmode is 3270 and we don't set it back then both
+                * 3215 and the 3270 driver will try to access the console
+                * device (3215 as console and 3270 as normal tty).
+                */
+               cpcmd("TERM CONMODE 3215", NULL, 0);
+               if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+                       return;
+               }
+               if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+                       SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+                       SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+               } else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+                       SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+                       SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+                       SET_CONSOLE_HWC;
+#endif
+               }
+        } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+               SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+               SET_CONSOLE_3270;
+#endif
+       } else {
+#if defined(CONFIG_HWC_CONSOLE)
+               SET_CONSOLE_HWC;
+#endif
+       }
+}
+
 /*
  * Reboot, halt and power_off routines for non SMP.
  */
@@ -177,14 +266,11 @@ void __init setup_arch(char **cmdline_p)
        unsigned long start_pfn, end_pfn;
         static unsigned int smptrap=0;
         unsigned long delay = 0;
-        int len = 0;
 
         if (smptrap)
                 return;
         smptrap=1;
 
-        printk("Command line is: %s\n", COMMAND_LINE);
-
         /*
          * Setup lowcore information for boot cpu
          */
@@ -221,7 +307,6 @@ void __init setup_arch(char **cmdline_p)
                  * "mem=XXX[kKmM]" sets memsize 
                  */
                 if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
-                        if (to != command_line) to--;
                         memory_end = simple_strtoul(from+4, &from, 0);
                         if ( *from == 'K' || *from == 'k' ) {
                                 memory_end = memory_end << 10;
@@ -235,7 +320,6 @@ void __init setup_arch(char **cmdline_p)
                  * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
                  */
                 if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
-                       if (to != command_line) to--;
                         delay = simple_strtoul(from+9, &from, 0);
                        if (*from == 's' || *from == 'S') {
                                delay = delay*1000000;
@@ -244,7 +328,7 @@ void __init setup_arch(char **cmdline_p)
                                delay = delay*60*1000000;
                                from++;
                        }
-                       /* now wait for the requestion amount of time */
+                       /* now wait for the requested amount of time */
                        udelay(delay);
                 }
                 cn = *(from++);
@@ -252,10 +336,12 @@ void __init setup_arch(char **cmdline_p)
                         break;
                 if (cn == '\n')
                         cn = ' ';  /* replace newlines with space */
+               if (cn == 0x0d)
+                       cn = ' ';  /* replace 0x0d with space */
                 if (cn == ' ' && c == ' ')
                         continue;  /* remove additional spaces */
                 c = cn;
-                if (COMMAND_LINE_SIZE <= ++len)
+                if (to - command_line >= COMMAND_LINE_SIZE)
                         break;
                 *(to++) = c;
         }
@@ -313,6 +399,9 @@ void __init setup_arch(char **cmdline_p)
        request_resource(&iomem_resource, res);
        request_resource(res, &code_resource);
        request_resource(res, &data_resource);
+
+        /* Setup default console */
+       conmode_default();
 }
 
 void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
index ebce09f31e860b1e8005b8e5153f96ca8b38e461..8f04e9e956bd9d9242348758844653dbf0c85e27 100644 (file)
@@ -333,6 +333,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka,
                /* Set up registers for signal handler */
                regs->gprs[15] = (addr_t)frame;
                regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+               regs->psw.mask = _USER_PSW_MASK;
        }
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
@@ -359,6 +360,11 @@ static void setup_frame(int sig, struct k_sigaction *ka,
 #endif
        /* Martin wants this for pthreads */
        regs->gprs[3] = (addr_t)&frame->sc;
+
+       /* We forgot to include these in the sigcontext.
+          To avoid breaking binary compatibility, they are passed as args. */
+       regs->gprs[4] = current->thread.trap_no;
+       regs->gprs[5] = current->thread.prot_addr;
        return;
 
 give_sigsegv:
@@ -415,7 +421,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka,
              siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
 {
        /* Are we from a system call? */
-       if (regs->orig_gpr2 >= 0) {
+       if (regs->trap == __LC_SVC_OLD_PSW) {
                /* If so, check system call restarting.. */
                switch (regs->gprs[2]) {
                        case -ERESTARTNOHAND:
@@ -568,7 +574,6 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
                                 /* FALLTHRU */
 
                        default:
-                               lock_kernel();
                                sigaddset(&current->pending.signal, signr);
                                recalc_sigpending(current);
                                current->flags |= PF_SIGNALED;
index 43132c6ab20a5cea2ac62e6ce55100db6c9c320b..0cc7a4395200387961df391e95e3f64c8fbd9ff7 100644 (file)
@@ -543,6 +543,7 @@ void smp_count_cpus(void)
  *      Activate a secondary processor.
  */
 extern void init_100hz_timer(void);
+extern int pfault_init(void);
 
 int __init start_secondary(void *cpuvoid)
 {
@@ -555,6 +556,10 @@ int __init start_secondary(void *cpuvoid)
                 /* nothing */ ;
         /* init per CPU 100 hz timer */
         init_100hz_timer();
+#ifdef CONFIG_PFAULT
+       /* Enable pfault pseudo page faults on this cpu. */
+       pfault_init();
+#endif
         /* cpu_idle will call schedule for us */
         return cpu_idle(NULL);
 }
index d4e91842e6cd252c94c63c45ce48a50e5b67bcf1..bc5f24bd80e9ef64e5e8b3786ea828923b9a164b 100644 (file)
@@ -101,9 +101,10 @@ void do_gettimeofday(struct timeval *tv)
 {
        unsigned long flags;
        unsigned long usec, sec;
-       unsigned long lost_ticks = jiffies - wall_jiffies;
+       unsigned long lost_ticks;
 
        read_lock_irqsave(&xtime_lock, flags);
+       lost_ticks = jiffies - wall_jiffies;
        usec = do_gettimeoffset();
        if (lost_ticks)
                usec +=(USECS_PER_JIFFY*lost_ticks);
index 3301ddc18001d5d8c071a9efdc952c513ae1dd1b..0d3b2c4ab1014ccbfbf62b236400711bff56089e 100644 (file)
@@ -35,6 +35,8 @@
 #if CONFIG_REMOTE_DEBUG
 #include <asm/gdb-stub.h>
 #endif
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
 
 /* Called from entry.S only */
 extern void handle_per_exception(struct pt_regs *regs);
@@ -51,6 +53,11 @@ int sysctl_userprocess_debug = 0;
 #endif
 
 extern pgm_check_handler_t do_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
 
 spinlock_t die_lock;
 
@@ -152,7 +159,6 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
        __u16 *location;
        int do_sig = 0;
 
-        lock_kernel();
        location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
        /* WARNING don't change this check back to */
        /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */
@@ -171,7 +177,6 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
                do_sig = 1;
        if (do_sig)
                do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
-        unlock_kernel();
 }
 
 asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
@@ -179,7 +184,6 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
        __u16 *location;
        int do_sig = 0;
 
-        lock_kernel();
        location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
        __asm__ volatile ("stfpc %0\n\t" 
                          : "=m" (current->thread.fp_regs.fpc));
@@ -194,7 +198,6 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
                do_sig = 1;
         if (do_sig)
                 do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
-        unlock_kernel();
 }
 
 
@@ -223,6 +226,21 @@ void __init trap_init(void)
         pgm_check_table[0x1C] = &privileged_op;
         pgm_check_table[0x38] = &addressing_exception;
         pgm_check_table[0x3B] = &do_page_fault;
+#ifdef CONFIG_PFAULT
+       if (MACHINE_IS_VM) {
+               /* request the 0x2603 external interrupt */
+               if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+                       panic("Couldn't request external interrupt 0x2603");
+               /*
+                * Try to get pfault pseudo page faults going.
+                */
+               if (pfault_init() != 0) {
+                       /* Tough luck, no pfault. */
+                       unregister_external_interrupt(0x2603,
+                                                     pfault_interrupt);
+               }
+       }
+#endif
 }
 
 
index 82136dcf2907e79461cf5fef6e042051132a3cb6..68bd74eb6101b2a915d0b492180638d9e8c31754 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/init.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -80,19 +81,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
         unsigned long address;
         unsigned long fixup;
         int write;
-        unsigned long psw_mask;
-        unsigned long psw_addr;
        int si_code = SEGV_MAPERR;
        int kernel_address = 0;
 
-        /*
-         *  get psw mask of Program old psw to find out,
-         *  if user or kernel mode
-         */
-
-        psw_mask = S390_lowcore.program_old_psw.mask;
-        psw_addr = S390_lowcore.program_old_psw.addr;
-
         /* 
          * get the failing address 
          * more specific the segment and page table portion of 
@@ -215,7 +206,7 @@ bad_area:
         up_read(&mm->mmap_sem);
 
         /* User mode accesses just cause a SIGSEGV */
-        if (psw_mask & PSW_PROBLEM_STATE) {
+        if (regs->psw.mask & PSW_PROBLEM_STATE) {
                struct siginfo si;
                 tsk->thread.prot_addr = address;
                 tsk->thread.trap_no = error_code;
@@ -273,7 +264,7 @@ no_context:
 out_of_memory:
        up_read(&mm->mmap_sem);
        printk("VM: killing process %s\n", tsk->comm);
-       if (psw_mask & PSW_PROBLEM_STATE)
+       if (regs->psw.mask & PSW_PROBLEM_STATE)
                do_exit(SIGKILL);
        goto no_context;
 
@@ -289,6 +280,140 @@ do_sigbus:
        force_sig(SIGBUS, tsk);
 
        /* Kernel mode? Handle exceptions or die */
-       if (!(psw_mask & PSW_PROBLEM_STATE))
+       if (!(regs->psw.mask & PSW_PROBLEM_STATE))
                goto no_context;
 }
+
+#ifdef CONFIG_PFAULT
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+       pfault_disable = 1;
+       return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+       __u16 refdiagc;
+       __u16 reffcode;
+       __u16 refdwlen;
+       __u16 refversn;
+       __u64 refgaddr;
+       __u64 refselmk;
+       __u64 refcmpmk;
+       __u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+typedef struct _pseudo_wait_t {
+       struct _pseudo_wait_t *next;
+       wait_queue_head_t queue;
+       unsigned long address;
+       int resolved;
+} pseudo_wait_t;
+
+static pseudo_wait_t *pseudo_lock_queue = NULL;
+static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
+
+int pfault_init(void)
+{
+       pfault_refbk_t refbk =
+       { 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+        int rc;
+
+       if (pfault_disable)
+               return -1;
+        __asm__ __volatile__(
+                "    diag  %1,%0,0x258\n"
+               "0:  j     2f\n"
+               "1:  la    %0,8\n"
+               "2:\n"
+               ".section __ex_table,\"a\"\n"
+               "   .align 4\n"
+               "   .quad  0b,1b\n"
+               ".previous"
+                : "=d" (rc) : "a" (&refbk) : "cc" );
+       __ctl_set_bit(0, 9);
+        return rc;
+}
+
+void pfault_fini(void)
+{
+       pfault_refbk_t refbk =
+       { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+       if (pfault_disable)
+               return;
+       __ctl_clear_bit(0, 9);
+        __asm__ __volatile__(
+                "    diag  %0,0,0x258\n"
+               "0:\n"
+               ".section __ex_table,\"a\"\n"
+               "   .align 4\n"
+               "   .quad  0b,0b\n"
+               ".previous"
+               : : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+        DECLARE_WAITQUEUE(wait, current);
+       struct task_struct *tsk;
+       wait_queue_head_t queue;
+       wait_queue_head_t *qp;
+       __u16 subcode;
+
+       /*
+        * Get the external interruption subcode & pfault
+        * initial/completion signal bit. VM stores this 
+        * in the 'cpu address' field associated with the
+         * external interrupt. 
+        */
+       subcode = S390_lowcore.cpu_addr;
+       if ((subcode & 0xff00) != 0x06)
+               return;
+
+       /*
+        * Get the token (= address of kernel stack of affected task).
+        */
+       tsk = (struct task_struct *)
+               (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+
+       if (subcode & 0x0080) {
+               /* signal bit is set -> a page has been swapped in by VM */
+               qp = (wait_queue_head_t *)
+                       xchg(&tsk->thread.pfault_wait, -1);
+               if (qp != NULL) {
+                       /* Initial interrupt was faster than the completion
+                        * interrupt. pfault_wait is valid. Set pfault_wait
+                        * back to zero and wake up the process. This can
+                        * safely be done because the task is still sleeping
+                        * and can't procude new pfaults. */
+                       tsk->thread.pfault_wait = 0ULL;
+                       wake_up(qp);
+               }
+       } else {
+               /* signal bit not set -> a real page is missing. */
+                init_waitqueue_head (&queue);
+               qp = (wait_queue_head_t *)
+                       xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+               if (qp != NULL) {
+                       /* Completion interrupt was faster than the initial
+                        * interrupt (swapped in a -1 for pfault_wait). Set
+                        * pfault_wait back to zero and exit. This can be
+                        * done safely because tsk is running in kernel 
+                        * mode and can't produce new pfaults. */
+                       tsk->thread.pfault_wait = 0ULL;
+               }
+
+                /* go to sleep */
+                wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+       }
+}
+#endif
+
diff --git a/arch/s390x/tools/dasdfmt/Makefile b/arch/s390x/tools/dasdfmt/Makefile
deleted file mode 100644 (file)
index b60641b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
-       $(CC) -o $@ $^
-       $(STRIP) $@
-
-clean:
-       rm -f dasdfmt
-
diff --git a/arch/s390x/tools/dasdfmt/dasdfmt.8 b/arch/s390x/tools/dasdfmt/dasdfmt.8
deleted file mode 100644 (file)
index 9e6a4e8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR 
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR 
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR 
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
-       \fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
-       \fB-n\fR \fIdevnum\fR
-.sp
-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 device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
diff --git a/arch/s390x/tools/dasdfmt/dasdfmt.c b/arch/s390x/tools/dasdfmt/dasdfmt.c
deleted file mode 100644 (file)
index b04c9dd..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- *
- * dasdfmt.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Corporation
- *    Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- *  Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- *  Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- *   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>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8  /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _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
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
-       {if (i>1) \
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-                       "can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
-       {x=(int)strtol(param,&endptr,base); \
-       if (*endptr) \
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
-                       "is in invalid format\n",prog_name);}
-
-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)
-{
-#ifdef RANGE_FORMATTING
-       printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
-               "<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
-       printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
-               "<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
-       printf("       -t means testmode\n");
-       printf("       -v means verbose mode\n");
-       printf("       -C means format compatible disk layout\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");
-       printf("           -n <s390-devnr>\n");
-       exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
-       FILE *file;
-       int d,rc;
-       kdev_t mi,ma;
-       int mi_i,ma_i; /* for scanf :-( */
-       char line[PROC_LINE_LENGTH];
-
-       file=fopen(PROC_DASD_DEVICES,"r");
-       if (file==NULL)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
-                       PROC_DASD_DEVICES ": %s (do you have the /proc " \
-                       "filesystem enabled?)\n",prog_name,strerror(errno));
-
-       /*      fgets(line,sizeof(line),file); omit first line */ 
-       while (fgets(line,sizeof(line),file)!=NULL) {
-                rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
-               ma=ma_i;
-               mi=mi_i;
-               if ( (rc==3) &&
-                       !((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
-                       !((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
-                       !((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
-                       *devno=d;
-                       *major_no=ma;
-                       *minor_no=mi;
-                       /* yes, this is a quick exit, but the easiest way */
-                       fclose(file);
-                       return;
-               }
-       }
-       fclose(file);
-
-       ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
-                   "filesystem (are you sure to have the right parameter " \
-                   "dasd=xxx?)\n",
-               prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
-       kdev_t major_no,minor_no;
-       kdev_t file_major,file_minor;
-       struct stat stat_buf;
-       int rc;
-       int found;
-       char *devname;
-       char tmpname[MAX_FILELEN];
-
-       DIR *dp;
-       struct dirent *direntp;
-
-       /**** get minor number ****/
-       get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
-       /**** get device file ****/
-       if ((dp=opendir(SLASHDEV)) == NULL)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
-                       "\n",prog_name);
-       found=0;
-       while ((direntp=readdir(dp)) != NULL) {
-               strcpy(tmpname,SLASHDEV);
-               strcat(tmpname,direntp->d_name);
-               rc=stat(tmpname,&stat_buf);
-               if (!rc) {
-                       file_major=MAJOR(stat_buf.st_rdev);
-                       file_minor=MINOR(stat_buf.st_rdev);
-                       if ((file_major==major_no) && (file_minor==minor_no)) {
-                               found=1;
-                               break;
-                       }
-               }
-       }
-       if (found) {
-               devname=malloc(strlen(direntp->d_name));
-               strcpy(devname,tmpname);
-       }
-       rc=closedir(dp);
-       if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
-               "; continuing\n",prog_name);
-       if (found)
-               return devname;
-
-       if (verbosity>=1)
-               printf("I didn't find device node in " SLASHDEV \
-                       "; trying to create a temporary node\n");
-
-       /**** get temp file and create device node *****/
-       rc=mkstemp(tempfilename);
-       if (rc==-1)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
-                       "filename: %s\n",prog_name,strerror(errno));
-       close(rc);
-       rc=unlink(tempfilename);
-       
-       rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
-       if (rc)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
-                       "device node %s: %s\n",prog_name,tempfilename,
-                       strerror(errno));
-       return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
-       char *s;
-
-       if (NULL==(s=malloc(ERR_LENGTH)))
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
-       if ((mode&CHECK_START)&&(data.start_unit<0)) {
-               strcpy(s,"start track must be greater than zero");
-               goto exit;
-       }
-       if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
-               strcpy(s,"end track must be -1 or greater than zero");
-               goto exit;
-       }
-       if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
-               (data.stop_unit!=-1)) {
-               strcpy(s,"end track must be higher than start track");
-               goto exit;
-       }
-
-       if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
-               strcpy(s,"blocksize must be a positive integer");
-               goto exit;
-       }
-       if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
-               if ((data.blksize%2)&&(data.blksize!=1)) {
-                       strcpy(s,"blocksize must be a power of 2");
-                       goto exit;
-               }
-               data.blksize/=2;
-       }
-
-       free(s);
-       return NULL;
-exit:
-       return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
-       if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
-       if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
-               if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
-       char buffer[20]; /* should be enough for inputing track numbers */
-       char c;
-       int i,rc;
-       char *str;
-       char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
-       i=params.start_unit;
-       do {
-               params.start_unit=i;
-               sprintf(output,"the start track of the range to format " \
-                       "[%d]: ",i);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               ASK_SCANFORNUMBER(params.start_unit);
-               ASK_COMPLAIN_FORMAT;
-               ASK_CHECK_PARAM(CHECK_START);
-       } while (rc!=1);
-
-       i=params.stop_unit;
-       do {
-               params.stop_unit=i;
-               sprintf(output,"the end track of the range to format [");
-               if (i==-1) sprintf(o2,"END]: "); else
-                       sprintf(o2,"%d]: ",i);
-               strcat(output,o2);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               if ( (!strcasecmp(buffer,"end")) ||
-                       (!strcasecmp(buffer,"end\n")) ) {
-                       rc=1;
-                       params.stop_unit=-1;
-               } else {
-                       ASK_SCANFORNUMBER(params.stop_unit);
-                       ASK_COMPLAIN_FORMAT;
-                       ASK_CHECK_PARAM(CHECK_END);
-               }
-       } while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
-       i=params.blksize;
-       do {
-               params.blksize=i;
-               sprintf(output,"the blocksize of the formatting [%d]: ",i);
-               ASK_PRINTOUT;
-               ASK_GETBUFFER;
-               ASK_SCANFORNUMBER(params.blksize);
-               ASK_COMPLAIN_FORMAT;
-               ASK_CHECK_PARAM(CHECK_BLKSIZE);
-       } while (rc!=1);
-
-       return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
-       FILE *f;
-       int ishift = 0;
-       struct mntent *ment;
-       struct stat stbuf;
-       char line[128];
-
-       /* If whole disk to be formatted ... */
-       if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
-               /* ... ignore partition-selector */
-               minor >>= DASD_PARTN_BITS;
-               ishift = DASD_PARTN_BITS;
-       }
-       /*
-        * first, check filesystems
-        */
-       if (!(f = fopen(PROC_MOUNTS, "r")))
-               ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
-                       strerror(errno));
-       while ((ment = getmntent(f))) {
-               if (stat(ment->mnt_fsname, &stbuf) == 0)
-                       if ((major == MAJOR(stbuf.st_rdev)) &&
-                               (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-                               ERRMSG("%s: device is mounted on %s!!\n",
-                                       prog_name,ment->mnt_dir);
-                               ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-                                       "format it, please unmount it.\n");
-                       }
-       }
-       fclose(f);
-       /*
-        * second, check active swap spaces
-        */
-       if (!(f = fopen(PROC_SWAPS, "r")))
-               ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
-       /*
-        * skip header line
-        */
-       fgets(line, sizeof(line), f);
-       while (fgets(line, sizeof(line), f)) {
-               char *p;
-               for (p = line; *p && (!isspace(*p)); p++) ;
-               *p = '\0';
-               if (stat(line, &stbuf) == 0)
-                       if ((major == MAJOR(stbuf.st_rdev)) &&
-                               (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
-                               ERRMSG("%s: the device is in use for "
-                                       "swapping!!\n",prog_name);
-                               ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
-                                       "format it, please use swapoff %s.\n",
-                                       line);
-                       }
-       }
-       fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
-       int verbosity,int writenolabel,int labelspec,
-       char *label,int withoutprompt,int devno)
-{
-       int fd,rc;
-       struct stat stat_buf;
-       kdev_t minor_no,major_no;
-       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);
-       if (fd==-1)
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
-                       "%s\n",prog_name,dev_name,strerror(errno));
-
-       if (verbosity>=1) {
-       }
-
-       rc=stat(dev_name,&stat_buf);
-       if (rc) {
-               ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
-                       "%s\n",prog_name,strerror(errno));
-       } else {
-               if (!S_ISBLK(stat_buf.st_mode))
-                       ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
-                               "blockdevice.\n",prog_name);
-               major_no=MAJOR(stat_buf.st_rdev);
-               minor_no=MINOR(stat_buf.st_rdev);
-       }
-       check_mounted(major_no, minor_no);
-
-       get_xno_from_xno(&devno,&major_no,&minor_no,
-                       GIVEN_MAJOR|GIVEN_MINOR);
-       if ((!writenolabel) && (!labelspec)) {
-               sprintf(label,"LNX1 x%04x",devno);
-       }
-       
-       if ( ((withoutprompt)&&(verbosity>=1)) ||
-               (!withoutprompt) ) {
-               printf("\nI am going to format the device %s in the " \
-                       "following way:\n",dev_name);
-               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);
-               if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
-                       printf("   Compatible Disk Layout  : %s\n",(format_params.intensity&0x08)?
-                              "yes":"no");
-#ifdef RANGE_FORMATTING
-               printf("   Start track             : %d\n" \
-                       ,format_params.start_unit);
-               printf("   End track               : ");
-               if (format_params.stop_unit==-1)
-                       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");
-       }
-
-       while (!testmode) {
-               if (!withoutprompt) {
-                       printf("\n--->> ATTENTION! <<---\n");
-                       printf("All data in the specified range of that " \
-                               "device will be lost.\nType \"yes\" to " \
-                               "continue, no will leave the disk untouched: ");
-                       fgets(inp_buffer,sizeof(inp_buffer),stdin);
-                       if (strcasecmp(inp_buffer,"yes") &&
-                               strcasecmp(inp_buffer,"yes\n")) {
-                               printf("Omitting ioctl call (disk will " \
-                                       "NOT be formatted).\n");
-                               break;
-                       }
-               }
-
-               if ( !(  (withoutprompt)&&(verbosity<1) ))
-                       printf("Formatting the device. This may take a " \
-                               "while (get yourself a coffee).\n");
-               rc=ioctl(fd,BIODASDFORMAT,format_params);
-               if (rc)
-                       ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
-                               "returned with the following error " \
-                               "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,BLKSSZGET,&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) {
-                       ERRMSG("%s: error during rereading the partition " \
-                              "table: %s.\n",prog_name,strerror(errno));
-               } else printf("done.\n");
-
-               break;
-       }
-
-       rc=close(fd);
-       if (rc)
-               ERRMSG("%s: error during close: " \
-                       "%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
-       int verbosity;
-       int testmode;
-       int withoutprompt;
-       int writenolabel,labelspec;
-
-       char *dev_name;
-       int devno;
-       char *dev_filename,*devno_param_str,*range_param_str;
-       char *start_param_str,*end_param_str,*blksize_param_str;
-       char label[LABEL_LENGTH+1];
-       
-       format_data_t format_params;
-
-       int rc;
-       int oc;
-       char *endptr;
-
-       char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
-       int i,i1,i2;
-       char *str;
-
-       int start_specified,end_specified,blksize_specified;
-       int devfile_specified,devno_specified,range_specified;
-
-       /******************* initialization ********************/
-       prog_name=argv[0];
-
-       endptr=NULL;
-
-       /* set default values */
-       format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
-       format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
-       format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
-       format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
-       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;
-
-       /*************** parse parameters **********************/
-
-       /* avoid error message generated by getopt */
-       opterr=0;
-
-#ifdef RANGE_FORMATTING
-       while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
-       while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
-               switch (oc) {
-               case 'y':
-                       withoutprompt=1;
-                       break;
-
-               case 't':
-                       testmode=1;
-                       break;
-
-               case 'v':
-                       verbosity++;
-                       break;
-
-               case '?': /* fall-through */
-               case ':':
-                       exit_usage(EXIT_MISUSE);
-
-               case 'h':
-                       exit_usage(0);
-               case 'C':
-                       format_params.intensity&=0x08;
-                       break;
-
-               case 'V':
-                       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++;
-                       break;
-                       
-               case 'e' :
-                       end_param_str=optarg;
-                       end_specified++;
-                       break;
-
-               case 'r' :
-                       range_param_str=optarg;
-                       range_specified++;
-                       break;
-#endif /* RANGE_FORMATTING */
-
-               case 'b' :
-                       blksize_param_str=optarg;
-                       blksize_specified++;
-                       break;
-                       
-               case 'n' :
-                       devno_param_str=optarg;
-                       devno_specified++;
-                       break;
-               
-               case 'f' :
-                       dev_filename=optarg;
-                       devfile_specified++;
-                       break;
-               }
-       }
-
-       /******************** checking of parameters **************/
-
-       /* convert range into -s and -e */
-       CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
-       while (range_specified) {
-               start_specified++;
-               end_specified++;
-
-               /* scan for 1 or 2 integers, separated by a dash */
-               rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
-               if ((rc==3)&&(c1=='-')) {
-                       format_params.start_unit=i1;
-                       format_params.stop_unit=i2;
-                       break;
-               }
-               if (rc==1) {
-                       format_params.start_unit=i1;
-                       break;
-               }
-
-               /* scan for integer and -END */
-               rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
-               if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
-                       format_params.start_unit=i1;
-                       format_params.stop_unit=-1;
-                       break;
-               }
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
-                       "is in invalid format\n",prog_name);
-       }
-
-       if ((!devfile_specified)&&(!devno_specified))
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-                       "not specified\n",prog_name);
-
-       if ((devfile_specified+devno_specified)>1)
-               ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
-                       "can only be specified once\n",prog_name);
-
-       if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
-               (!blksize_specified)) {
-               format_params=ask_user_for_data(format_params);
-       }
-
-       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");
-       if (start_specified&&!range_specified)
-               PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
-                       "start track");
-       if (end_specified&&!range_specified)
-               PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
-                       "end track");
-       if (blksize_specified)
-               PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
-                       "blocksize");
-
-       /***********get dev_name *********************/
-       dev_name=(devno_specified)?
-               get_devname_from_devno(devno,verbosity):
-               dev_filename;
-
-       /*** range checking *********/
-       str=check_param(CHECK_ALL,format_params);
-       if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
-       /******* issue the real command and reread part table *******/
-       do_format_dasd(dev_name,format_params,testmode,verbosity,
-               writenolabel,labelspec,label,withoutprompt,devno);
-
-       /*************** cleanup ********************************/
-       if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
-               rc=unlink(dev_name);
-               if ((rc)&&(verbosity>=1))
-                       ERRMSG("%s: temporary device node %s could not be " \
-                               "removed: %s\n",prog_name,dev_name,
-                               strerror(errno));
-       } else {
-               if (devno_specified) {
-                       /* so we have allocated space for the filename */
-                       free(dev_name);
-               }
-       }
-
-       return 0;
-}
diff --git a/arch/s390x/tools/silo/Makefile b/arch/s390x/tools/silo/Makefile
deleted file mode 100644 (file)
index 62b11d7..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-all: silo
-
-silo.o: silo.c
-       $(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
-       $(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
-       $(CC) -o $@ $^
-       $(STRIP) $@
-
-clean:
-       rm -f *.o silo
-
diff --git a/arch/s390x/tools/silo/cfg.c b/arch/s390x/tools/silo/cfg.c
deleted file mode 100644 (file)
index 2b11d93..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-/* cfg.c  -  Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
-    fflush(stdout);
-    perror(msg);
-    exit(1);
-}
-
-
-void die(char *fmt,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,fmt);
-    vfprintf(stderr,fmt,ap);
-    va_end(ap);
-    fputc('\n',stderr);
-    exit(1);
-}
-
-char *pstrdup(const char *str)
-{
-    char *this;
-
-    if ((this = strdup(str)) == NULL) pdie("Out of memory");
-    return this;
-}
-
-int cfg_open(char *name)
-{
-    if (!strcmp(name,"-")) file = stdin;
-    else if (!(file = fopen(file_name = name,"r"))) pdie(name);
-    line_num = 1;
-    return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
-    va_list ap;
-
-    fflush(stdout);
-    va_start(ap,msg);
-    vfprintf(stderr,msg,ap);
-    va_end(ap);
-    if (!file_name) fputc('\n',stderr);
-    else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
-    exit(1);
-}
-
-
-static int next_raw(void)
-{
-    int ch;
-
-    if (!back) return getc(file);
-    ch = back;
-    back = 0;
-    return ch;
-}
-
-
-static int next(void)
-{
-    static char *var;
-    char buffer[MAX_VAR_NAME+1];
-    int ch,braced;
-    char *put;
-
-    if (back) {
-       ch = back;
-       back = 0;
-       return ch;
-    }
-    if (var && *var) return *var++;
-    ch = getc(file);
-    if (ch == '\\') {
-       ch = getc(file);
-       if (ch == '$') return ch;
-       ungetc(ch,file);
-       return '\\';
-    }
-    if (ch != '$') return ch;
-    ch = getc(file);
-    braced = ch == '{';
-    put = buffer;
-    if (!braced) *put++ = ch;
-    while (1) {
-       ch = getc(file);
-#if 0
-       if (!braced && ch < ' ') {
-           ungetc(ch,file);
-           break;
-       }
-#endif
-       if (ch == EOF) cfg_error("EOF in variable name");
-       if (ch < ' ') cfg_error("control character in variable name");
-       if (braced && ch == '}') break;
-       if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
-           ungetc(ch,file);
-           break;
-       }
-       if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
-       *put++ = ch;
-    }
-    *put = 0;
-    if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
-    return next();
-}
-
-
-static void again(int ch)
-{
-    if (back) die("internal error: again invoked twice");
-    back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
-    char buf[MAX_TOKEN+1];
-    char *here;
-    int ch,escaped;
-
-    if (last_token) {
-       here = last_token;
-       last_token = NULL;
-       return here;
-    }
-    while (1) {
-       while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
-           if (ch == '\n') line_num++;
-       if (ch == EOF) return NULL;
-       if (ch != '#') break;
-       while ((ch = next_raw()), ch != '\n')
-           if (ch == EOF) return NULL;
-       line_num++;
-    }
-    if (ch == '=') return pstrdup("=");
-    if (ch == '"') {
-       here = buf;
-       while (here-buf < MAX_TOKEN) {
-           if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
-           if (ch == '"') {
-               *here = 0;
-               return pstrdup(buf);
-           }
-           if (ch == '\\') {
-               ch = next();
-               if (ch != '"' && ch != '\\' && ch != '\n')
-                   cfg_error("Bad use of \\ in quoted string");
-               if (ch == '\n') {
-                   while ((ch = next()), ch == ' ' || ch == '\t');
-                   if (!ch) continue;
-                   again(ch);
-                   ch = ' ';
-               }
-           }
-           if (ch == '\n' || ch == '\t')
-               cfg_error("\\n and \\t are not allowed in quoted strings");
-           *here++ = ch;
-       }
-       cfg_error("Quoted string is too long");
-       return 0; /* not reached */
-    }
-    here = buf;
-    escaped = 0;
-    while (here-buf < MAX_TOKEN) {
-       if (escaped) {
-           if (ch == EOF) cfg_error("\\ precedes EOF");
-           if (ch == '\n') line_num++;
-           else *here++ = ch == '\t' ? ' ' : ch;
-           escaped = 0;
-       }
-       else {
-           if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
-             ch == '=' || ch == EOF) {
-               again(ch);
-               *here = 0;
-               return pstrdup(buf);
-           }
-           if (!(escaped = (ch == '\\'))) *here++ = ch;
-       }
-       ch = next();
-    }
-    cfg_error("Token is too long");
-    return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
-    last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
-    char *this;
-
-    if (last_item) {
-       *item = last_item;
-       *value = last_value;
-       last_item = NULL;
-       return 1;
-    }
-    *value = NULL;
-    if (!(*item = cfg_get_token())) return 0;
-    if (!strcmp(*item,"=")) cfg_error("Syntax error");
-    if (!(this = cfg_get_token())) return 1;
-    if (strcmp(this,"=")) {
-       cfg_return_token(this);
-       return 1;
-    }
-    if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
-    if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
-    return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
-    last_item = item;
-    last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
-    while (table->type != cft_end) {
-       switch (table->type) {
-           case cft_strg:
-               if (table->data) free(table->data);
-           case cft_flag:
-               table->data = NULL;
-               break;
-           case cft_link:
-               table = ((CONFIG *) table->action)-1;
-               break;
-           default:
-               die("Unknown syntax code %d",table->type);
-       }
-       table++;
-    }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
-    void *context)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (value && walk->type != cft_strg)
-               cfg_error("'%s' doesn't have a value",walk->name);
-           if (!value && walk->type == cft_strg)
-               cfg_error("Value expected for '%s'",walk->name);
-           if (walk->data) {
-               if (walk->context == context)
-                   cfg_error("Duplicate entry '%s'",walk->name);
-               else {
-                   fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
-                   if (!copy) free(value);
-                   return 1;
-               }
-           }
-           if (walk->type == cft_flag) walk->data = &flag_set;
-           else if (walk->type == cft_strg) {
-                   if (copy) walk->data = pstrdup(value);
-                   else walk->data = value;
-           }
-           walk->context = context;
-           if (walk->action) ((void (*)(void)) walk->action)();
-           break;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    if (walk->type != cft_end) return 1;
-    cfg_return(item,value);
-    return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
-    if (!cfg_do_set(table,item,value,1,context))
-       cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++)
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
-           if (walk->type == cft_strg) free(walk->data);
-           walk->data = NULL;
-           return;
-       }
-    die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
-    char *item,*value;
-
-    while (1) {
-       if (!cfg_next(&item,&value)) return 0;
-       if (!cfg_do_set(table,item,value,0,table)) return 1;
-       free(item);
-    }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (walk->type != cft_flag)
-               die("cfg_get_flag: operating on non-flag %s",item);
-           return !!walk->data;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_flag: unknown item %s",item);
-    return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
-    CONFIG *walk;
-
-    for (walk = table; walk->type != cft_end; walk++) {
-       if (walk->name && !strcasecmp(walk->name,item)) {
-           if (walk->type != cft_strg)
-               die("cfg_get_strg: operating on non-string %s",item);
-           return walk->data;
-       }
-       if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
-    }
-    die("cfg_get_strg: unknown item %s",item);
-    return 0; /* not reached */
-}
diff --git a/arch/s390x/tools/silo/cfg.h b/arch/s390x/tools/silo/cfg.h
deleted file mode 100644 (file)
index 97d10bf..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/* cfg.h  -  Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
-    CFG_TYPE type;
-    char *name;
-    void *action;
-    void *data;
-    void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
-   file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
-   program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
-   since the last call to cfg_init, a warning message is issued if the context
-   keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
-   was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
-   value is returned if a variable not found in table has been met. Zero is
-   returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
diff --git a/arch/s390x/tools/silo/silo.c b/arch/s390x/tools/silo/silo.c
deleted file mode 100644 (file)
index 0236b2f..0000000
+++ /dev/null
@@ -1,586 +0,0 @@
-/*
- *  arch/s390/boot/silo.c
- *
- *  S390 version
- *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- *    Report bugs to: <linux390@de.ibm.com>
- *
- *    Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *               Fritz Elfert <felfert@to.com> contributed support for
- *                     /etc/silo.conf based on Intel's lilo
- *    Changes  :
- *               01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- *                 adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
-  { cft_strg, "append",                NULL,           NULL,NULL },
-  { cft_strg, "image",         NULL,           NULL,NULL },
-  { cft_strg, "ipldevice",     NULL,           NULL,NULL },
-  { cft_strg, "bootsect",      NULL,           NULL,NULL },
-  { cft_strg, "map",           NULL,           NULL,NULL },
-  { cft_strg, "parmfile",      NULL,           NULL,NULL },
-  { cft_strg, "ramdisk",       NULL,           NULL,NULL },
-  { cft_strg, "root",          NULL,           NULL,NULL },
-  { cft_flag, "readonly",      NULL,           NULL,NULL },
-  { cft_strg, "verbose",       NULL,           NULL,NULL },
-  { cft_strg, "testlevel",     NULL,           NULL,NULL },
-  { cft_end,  NULL,            NULL,           NULL,NULL }
-};
-  
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#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 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); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
-  {
-    short int verbosity;
-    short int testlevel;
-    char *image;
-    char *ipldevice;
-    char *parmfile;
-    char *ramdisk;
-    char *bootsect;
-    char *conffile;
-    char *bootmap;
-  }
-silo_options =
-{
-  1,                           /* verbosity */
-  2,                           /* testlevel */
-    SILO_IMAGE,                        /* image */
-    NULL,                      /* ipldevice */
-    SILO_PARMFILE,             /* parmfile */
-    NULL,                      /* initrd */
-    SILO_BOOTSECT,             /* bootsector */
-    SILO_CFG,                   /* silo.conf file */
-    SILO_BOOTMAP,               /* boot.map */
-};
-
-struct blockdesc
-  {
-    unsigned long off;
-    unsigned short ct;
-    unsigned long addr;
-  };
-
-struct blocklist
-  {
-    struct blockdesc blk[MAX_CLUSTERS];
-    unsigned short ix;
-  };
-
-void
-usage (void)
-{
-  printf ("Usage:\n");
-  printf ("silo -d ipldevice [additional options]\n");
-  printf ("-d /dev/node : set ipldevice to /dev/node\n");
-  printf ("-f image : set image to image\n");
-  printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
-  printf ("-p parmfile : set parameter file to parmfile\n");
-  printf ("-b bootsect : set bootsector to bootsect\n");
-  printf ("Additional options\n");
-  printf ("-B bootmap:\n");
-  printf ("-v: increase verbosity level\n");
-  printf ("-v#: set verbosity level to #\n");
-  printf ("-t: decrease testing level\n");
-  printf ("-h: print this message\n");
-  printf ("-?: print this message\n");
-  printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
-       char *tmp;
-       if (access(o->conffile, R_OK) && (errno == ENOENT))
-               return 0;
-       /* If errno != ENOENT, let cfg_open report an error */
-       cfg_open(o->conffile);
-       cfg_parse(cf_options);
-       tmp = cfg_get_strg(cf_options, "ipldevice");
-       if ( ! o->ipldevice  && tmp ) 
-               o->ipldevice = tmp;
-       tmp = cfg_get_strg(cf_options, "image");
-       if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp ) 
-               o->image = tmp;
-       tmp = cfg_get_strg(cf_options, "parmfile");
-       if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp) 
-               o->parmfile = tmp;
-       if ( ! o -> ramdisk ) 
-               o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
-       tmp = cfg_get_strg(cf_options, "bootsect");
-       if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
-               o->bootsect = tmp;
-       tmp = cfg_get_strg(cf_options, "map") ;
-       if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp) 
-               o->bootmap = tmp; 
-       tmp = cfg_get_strg(cf_options, "verbose");
-       if ( tmp ) {
-               unsigned short v;
-               sscanf (tmp, "%hu", &v);
-               o->verbosity = v;
-       }
-       tmp = cfg_get_strg(cf_options, "testlevel");
-       if ( tmp ) {
-               unsigned short t;
-               sscanf (tmp, "%hu", &t);
-               o->testlevel += t;
-       }
-       return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
-       char *append = cfg_get_strg(cf_options, "append");
-       char *root = cfg_get_strg(cf_options, "root");
-       int ro = cfg_get_flag(cf_options, "readonly");
-       FILE *f,*of;
-       char *fn;
-       char c;
-       char *tmpdir=NULL,*save=NULL;
-
-       if (!append && !root && !ro)
-               return pfile;
-       of = fopen(pfile, "r");
-       if ( of ) {
-               NTRY( fn = tempnam(NULL,"parm."));
-       } else {
-               fn = pfile;
-       }
-       NTRY( f = fopen(fn, "a+"));
-       if ( of ) {
-               while ( ! feof (of) ) {
-                 c=fgetc(of);
-               fputc(c,f);
-               }
-       }
-       if (root)
-               fprintf(f, " root=%s", root);
-       if (ro)
-               fprintf(f, " ro");
-       if (append)
-               fprintf(f, " %s", append);
-       fprintf(f, "\n");
-       fclose(f);
-       fclose(of);
-       printf ("tempfile is %s\n",fn);
-       return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
-  int rc = 0;
-  int oc;
-
-  while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
-    {
-      switch (oc)
-       {
-       case 'V':
-         printf("silo version: %s\n",SILO_VERSION);
-         exit(0);
-       case 'v':
-         {
-           unsigned short v;
-           if (optarg && sscanf (optarg, "%hu", &v))
-             o->verbosity = v;
-           else
-             o->verbosity++;
-           PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
-           break;
-         }
-       case 't':
-         {
-           unsigned short t;
-           if (optarg && sscanf (optarg, "%hu", &t))
-             o->testlevel -= t;
-           else
-             o->testlevel--;
-            PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
-           break;
-         }
-       case 'h':
-       case '?':
-         usage ();
-         exit(0);
-       case 'd':
-         GETARG (o->ipldevice);
-         break;
-       case 'f':
-         GETARG (o->image);
-         break;
-        case 'F':                         
-          GETARG (o->conffile);              
-          break;                          
-       case 'p':
-         GETARG (o->parmfile);
-         break;
-       case 'r':
-         GETARG (o->ramdisk);
-         break;
-       case 'b':
-         GETARG (o->bootsect);
-         break;
-       case 'B':
-         GETARG (o->bootmap);
-       default:
-         rc = EINVAL;
-         break;
-       }
-    }
-  read_cfg(o);
-  return rc;
-}
-
-int
-verify_device (char *name)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  ITRY (stat (name, &dst));
-  if (S_ISBLK (dst.st_mode))
-    {
-      if (!(MINOR (dst.st_rdev) & PARTN_MASK))
-       {
-         rc = dst.st_rdev;
-       }
-      else
-       /* invalid MINOR & PARTN_MASK */
-       {
-         ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
-                      (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
-         rc = -1;
-         errno = EINVAL;
-       }
-    }
-  else
-    /* error S_ISBLK */
-    {
-      ERROR_LEVEL (1, "%s is no block device\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
-  int rc = 0;
-  struct stat dst;
-  struct stat st;
-  int bs = 1024;
-  int l;
-
-  ITRY(stat ( name, &dst ));
-  if (S_ISREG (dst.st_mode))
-    {
-      if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
-       {
-         /* whatever to do if all is ok... */
-       }
-      else
-       /* devicenumber doesn't match */
-       {
-         ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
-         rc = -1;
-         errno = EINVAL;
-       }
-    }
-  else
-    /* error S_ISREG */
-    {
-      ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
-      rc = -1;
-      errno = EINVAL;
-    }
-  return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
-  int rc = 0;
-  int dev = 0;
-  int crc = 0;
-  if (!o->ipldevice || !o->image || !o->bootsect)
-    {
-     if (!o->ipldevice)
-       fprintf(stderr,"ipldevice\n");
-     if (!o->image)
-       fprintf(stderr,"image\n");
-     if (!o->bootsect)
-       fprintf(stderr,"bootsect\n");
-
-      usage ();
-      exit (1);
-    }
-  PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
-  PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
-  ITRY (dev = verify_device (o->ipldevice));
-  PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
-  PRINT_LEVEL (1, "\n");
-
-  PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
-  ITRY (verify_file (o->bootsect, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if ( o -> testlevel > 0  && 
-       ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
-     NTRY( o -> bootmap = tempnam(NULL,"boot."));
-  }
-  PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
-  if ( access ( o->bootmap, O_RDWR ) == -1 ) {
-    if ( errno == ENOENT ) {
-      ITRY (creat ( o-> bootmap, O_RDWR ));
-    } else {
-      PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
-                 strerror(errno));
-    }
-  }
-  ITRY (verify_file (o->bootmap, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
-  ITRY (verify_file (o->image, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  o->parmfile = gen_tmpparm(o->parmfile);
-  PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
-  ITRY (verify_file (o->parmfile, dev));
-  PRINT_LEVEL (1, "...ok...");
-  PRINT_LEVEL (0, "\n");
-
-  if (o->ramdisk)
-    {
-      PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
-      ITRY (verify_file (o->ramdisk, dev));
-      PRINT_LEVEL (1, "...ok...");
-      PRINT_LEVEL (0, "\n");
-    }
-
-  return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
-  int fd;
-  int devfd;
-  struct stat fst;
-  int i;
-  int blk;
-  int bs;
-  int blocks;
-
-  int rc = 0;
-
-  ITRY (fd = open (name, O_RDONLY));
-  ITRY (fstat (fd, &fst));
-  ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
-  ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
-  ITRY (ioctl (fd, FIGETBSZ, &bs));
-  blocks = (fst.st_size + bs - 1) / bs;
-  for (i = 0; i < blocks; i++)
-    {
-      blk = i;
-      ITRY (ioctl (fd, FIBMAP, &blk));
-      if (blk)
-       {
-         int oldblk = blk;
-         ITRY (ioctl (devfd, BIODASDRWTB, &blk));
-         if (blk <= 0)
-           {
-             ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
-             break;
-           }
-       }
-      else
-       {
-         PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
-       }
-      if (lst->ix == 0 || i == 0  || 
-         lst->blk[lst->ix - 1].ct >= 128 ||
-         (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
-          !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
-       {
-         if (lst->ix >= MAX_CLUSTERS)
-           {
-             rc = 1;
-             errno = ENOMEM;
-             break;
-           }
-         lst->blk[lst->ix].off = blk;
-         lst->blk[lst->ix].ct = 1;
-         lst->blk[lst->ix].addr = addr + i * bs;
-         lst->ix++;
-       }
-      else
-       {
-         lst->blk[lst->ix - 1].ct++;
-       }
-    }
-  ITRY(unlink("/tmp/silodev"));
-  return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
-  int i;
-  int s_fd, d_fd, b_fd, bd_fd;
-  struct stat s_st, d_st, b_st;
-  int rc=0;
-  int bs, boots;
-  char *tmpdev;
-  char buffer[4096]={0,};
-  int blocksize, sectsize;
-  ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
-  ITRY (fstat (d_fd, &d_st));
-  ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
-  ITRY (verify_file (o->bootsect, d_st.st_rdev));
-  for (i = 0; i < blklst->ix; i++)
-    {
-      int offset = blklst->blk[i].off;
-      int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
-      PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
-       if ( o->testlevel <= 1 ) {
-             NTRY (write (s_fd, &offset, sizeof (int)));
-             NTRY (write (s_fd, &addrct, sizeof (int)));
-       }
-    }
-  ITRY (ioctl (s_fd,FIGETBSZ, &bs));
-  ITRY (stat (o->bootmap, &s_st));
-  if (s_st.st_size > bs )
-    {
-      ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
-      rc = -1;
-      errno = EINVAL;
-    }
-  boots=0;
-  NTRY ( tmpdev = tmpnam(NULL) );
-  ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
-  ITRY (bd_fd = open (tmpdev, O_RDONLY));
-  ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
-  ITRY (ioctl(s_fd,FIBMAP,&boots));
-  ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
-  PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
-  close (bd_fd);
-  close(s_fd);
-  ITRY (unlink(tmpdev));
-  /* Now patch the bootsector */
-  ITRY (stat (o->bootsect, &b_st));
-  if ((sectsize = b_st.st_size) > blocksize )
-    {
-      ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
-      rc = -1;
-      errno = EINVAL;
-    }
-  ITRY (b_fd = open (o->bootsect, O_RDONLY));
-  ITRY (read (b_fd, buffer, sectsize));
-  memset (buffer + 0xe0, 0, 8);
-  *(int *) (buffer + 0xe0) = boots;
-  if ( o -> testlevel <= 0 ) {
-    ITRY (write (d_fd, buffer, sectsize));
-    ITRY (lseek (d_fd, blocksize, SEEK_SET));
-    ITRY (write (d_fd, buffer, sectsize));
-  }
-  close (b_fd);
-  close (d_fd);
-  return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
-  int rc = 0;
-
-  int device_fd;
-  int image_fd;
-  struct blocklist blklist;
-  memset (&blklist, 0, sizeof (struct blocklist));
-  ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
-  if (o->parmfile)
-    {
-      ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
-    }
-  if (o->ramdisk)
-    {
-      ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
-    }
-  ITRY (write_bootsect (o, &blklist));
-  return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
-  int rc = 0;
-  char *save=NULL;
-  char *tmpdir=getenv("TMPDIR");
-  if (tmpdir) {
-    NTRY( save=(char*)malloc(strlen(tmpdir)));
-    NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
-  }
-  ITRY( setenv("TMPDIR",".",1));
-  ITRY (parse_options (&silo_options, argct, argv));
-  ITRY (verify_options (&silo_options));
-  if ( silo_options.testlevel > 0 ) {
-    printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
-  }
-  ITRY (do_silo (&silo_options));
-  if ( save )
-    ITRY( setenv("TMPDIR",save,1)); 
-  return rc;
-}
diff --git a/arch/s390x/tools/silo/silo.conf b/arch/s390x/tools/silo/silo.conf
deleted file mode 100644 (file)
index 47d8a45..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-ipldevice = /dev/dasda 
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
index 8b2ebafa634e29212f78b27fe0d07d3fdd4be7b4..340dc7e65ee6e458b839d9c72d58d9993d071eb7 100644 (file)
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #include <linux/config.h>      /* CONFIG_PROC_FS */
 #include <linux/module.h>
@@ -44,8 +41,8 @@
 
 #define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
 
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.4)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,4)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.5)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,5)
 
 /* Embedded module documentation macros - see modules.h */
 /* Original author Chris Frantz - Compaq Computer Corporation */
@@ -206,7 +203,7 @@ static struct block_device_operations ida_fops  = {
 static void __init ida_procinit(int i)
 {
        if (proc_array == NULL) {
-               proc_array = proc_mkdir("array", proc_root_driver);
+               proc_array = proc_mkdir("cpqarray", proc_root_driver);
                if (!proc_array) return;
        }
 
@@ -315,11 +312,18 @@ void cleanup_module(void)
 {
        int i;
        struct gendisk *g;
-
-       remove_proc_entry("array", proc_root_driver);
+       char buff[4]; 
 
        for(i=0; i<nr_ctlr; i++) {
-               hba[i]->access.set_intr_mask(hba[i], 0);
+
+               /* sendcmd will turn off interrupt, and send the flush... 
+                * To write all data in the battery backed cache to disks    
+                * no data returned, but don't want to send NULL to sendcmd */  
+               if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
+               {
+                       printk(KERN_WARNING "Unable to flush cache on "
+                               "controller %d\n", i);  
+               }
                free_irq(hba[i]->intr, hba[i]);
                iounmap(hba[i]->vaddr);
                unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
@@ -342,7 +346,7 @@ void cleanup_module(void)
                        }
                }
        }
-
+       remove_proc_entry("cpqarray", proc_root_driver);
        kfree(ida);
        kfree(ida_sizes);
        kfree(ida_hardsizes);
@@ -1079,7 +1083,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
 
        if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
           (hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
-               printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n",
+               printk(KERN_NOTICE "Non Fatal error on ida/c%dd%d\n",
                                cmd->ctlr, cmd->hdr.unit);
                hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
        }
@@ -1148,6 +1152,15 @@ static void do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
                         */
                        if (c->busaddr == a) {
                                removeQ(&h->cmpQ, c);
+                               /*  Check for invalid command.
+                                 *  Controller returns command error,
+                                 *  But rcode = 0.
+                                 */
+
+                               if((a1 & 0x03) && (c->req.hdr.rcode == 0))
+                                {
+                                       c->req.hdr.rcode = RCODE_INVREQ;
+                                }
                                if (c->type == CMD_RWREQ) {
                                        complete_command(c, 0);
                                        cmd_free(h, c, 1);
@@ -1315,6 +1328,8 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
                c->req.hdr.sg_cnt = 1;
                break;
        case IDA_READ:
+       case READ_FLASH_ROM:
+       case SENSE_CONTROLLER_PERFORMANCE:
                p = kmalloc(io->sg[0].size, GFP_KERNEL);
                if (!p) 
                { 
@@ -1331,6 +1346,8 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
        case IDA_WRITE:
        case IDA_WRITE_MEDIA:
        case DIAG_PASS_THRU:
+       case COLLECT_BUFFER:
+       case WRITE_FLASH_ROM:
                p = kmalloc(io->sg[0].size, GFP_KERNEL);
                if (!p) 
                { 
@@ -1373,10 +1390,14 @@ static int ida_ctlr_ioctl(int ctlr, int dsk, ida_ioctl_t *io)
                                 PCI_DMA_BIDIRECTIONAL);
        case IDA_READ:
        case DIAG_PASS_THRU:
+       case SENSE_CONTROLLER_PERFORMANCE:
+       case READ_FLASH_ROM:
                copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
                /* fall through and free p */
        case IDA_WRITE:
        case IDA_WRITE_MEDIA:
+       case COLLECT_BUFFER:
+       case WRITE_FLASH_ROM:
                kfree(p);
                break;
        default:;
index 6d57a85ee5b6cc435a350e8c416702f6c5d6712f..b3d91ba437265ede0200ecbe4e452b9c3a5fe673 100644 (file)
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #ifndef ARRAYCMD_H
 #define ARRAYCMD_H
@@ -342,6 +339,11 @@ typedef struct {
 } scsi_param_t;
 
 #define RESUME_BACKGROUND_ACTIVITY     0x99
+#define SENSE_CONTROLLER_PERFORMANCE   0xa8
+#define FLUSH_CACHE                    0xc2
+#define COLLECT_BUFFER                 0xd2
+#define READ_FLASH_ROM                 0xf6
+#define WRITE_FLASH_ROM                        0xf7
 #pragma pack() 
 
 #endif /* ARRAYCMD_H */
index 5cc212431689086dd8758511daf0cc4330c11d5b..e90825be74041c219052102852a480ead916c1b1 100644 (file)
@@ -18,9 +18,6 @@
  *
  *    Questions/Comments/Bugfixes to arrays@compaq.com
  *
- *    If you want to make changes, improve or add functionality to this
- *    driver, you'll probably need the Compaq Array Controller Interface
- *    Specificiation (Document number ECG086/1198)
  */
 #ifndef IDA_IOCTL_H
 #define IDA_IOCTL_H
index 49b220a9ed07652a477784dbd4fc0136559e876d..0f885ca302daa1e73e8213ff1f0bde222114e485 100644 (file)
@@ -573,6 +573,8 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
                        up(&moxaBuffSem);
                        return (-ENOMEM);
                }
+               /* This test is guarded by the BuffSem so no longer needed
+                  delete me in 2.5 */
                if (moxaXmitBuff)
                        free_page(page);
                else
index f2b15ce66cc44d04bec7cc7a820edccef41f8435..515bf9dc253571d8cc353aa32a2fe4b6c123b5cb 100644 (file)
  *      along with this program; if not, write to the Free Software
  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- *     Revision 1.0 
+ *     Revision 1.1
+ *
+ *     ChangeLog:
+ *     Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 27-Jun-2001
+ *     - get rid of check_region and several cleanups
  */
 
 #include <linux/module.h>
@@ -97,10 +101,18 @@ static unsigned long baud_table[] =  {
 };
 
 static struct riscom_board rc_board[RC_NBOARD] =  {
-       { 0, RC_IOBASE1, 0, },
-       { 0, RC_IOBASE2, 0, },
-       { 0, RC_IOBASE3, 0, },
-       { 0, RC_IOBASE4, 0, },
+       {
+               base:   RC_IOBASE1,
+       },
+       {
+               base:   RC_IOBASE2,
+       },
+       {
+               base:   RC_IOBASE3,
+       },
+       {
+               base:   RC_IOBASE4,
+       },
 };
 
 static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
@@ -122,9 +134,9 @@ static inline int rc_paranoia_check(struct riscom_port const * port,
                                    kdev_t device, const char *routine)
 {
 #ifdef RISCOM_PARANOIA_CHECK
-       static const char *badmagic =
+       static const char badmagic[] = KERN_INFO
                "rc: Warning: bad riscom port magic number for device %s in %s\n";
-       static const char *badinfo =
+       static const char badinfo[] = KERN_INFO
                "rc: Warning: null riscom port for device %s in %s\n";
 
        if (!port) {
@@ -186,32 +198,29 @@ static inline void rc_wait_CCR(struct riscom_board const * bp)
                if (!rc_in(bp, CD180_CCR))
                        return;
        
-       printk("rc%d: Timeout waiting for CCR.\n", board_No(bp));
+       printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
 }
 
 /*
  *  RISCom/8 probe functions.
  */
 
-static inline int rc_check_io_range(struct riscom_board * const bp)
+static inline int rc_request_io_range(struct riscom_board * const bp)
 {
        int i;
        
        for (i = 0; i < RC_NIOPORT; i++)  
-               if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1))  {
-                       printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n",
-                              board_No(bp), bp->base);
-                       return 1;
+               if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
+                                  "RISCom/8"))  {
+                       goto out_release;
                }
        return 0;
-}
-
-static inline void rc_request_io_range(struct riscom_board * const bp)
-{
-       int i;
-       
-       for (i = 0; i < RC_NIOPORT; i++) 
-               request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" );
+out_release:
+       printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
+                        board_No(bp), bp->base);
+       while(--i >= 0)
+               release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
+       return 1;
 }
 
 static inline void rc_release_io_range(struct riscom_board * const bp)
@@ -221,7 +230,6 @@ static inline void rc_release_io_range(struct riscom_board * const bp)
        for (i = 0; i < RC_NIOPORT; i++)  
                release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
 }
-
        
 /* Must be called with enabled interrupts */
 static inline void rc_long_delay(unsigned long delay)
@@ -265,7 +273,7 @@ static int __init rc_probe(struct riscom_board *bp)
        
        bp->irq = 0;
 
-       if (rc_check_io_range(bp))
+       if (rc_request_io_range(bp))
                return 1;
        
        /* Are the I/O ports here ? */
@@ -277,9 +285,9 @@ static int __init rc_probe(struct riscom_board *bp)
        val2 = rc_in(bp, CD180_PPRL);
        
        if ((val1 != 0x5a) || (val2 != 0xa5))  {
-               printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
+               printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
                       board_No(bp), bp->base);
-               return 1;
+               goto out_release;
        }
        
        /* It's time to find IRQ for this board */
@@ -297,27 +305,30 @@ static int __init rc_probe(struct riscom_board *bp)
                rc_init_CD180(bp);                      /* Reset CD180 again      */
        
                if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX)))  {
-                       printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
-                              board_No(bp), bp->base);
-                       return 1;
+                       printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
+                                       "found.\n", board_No(bp), bp->base);
+                       goto out_release;
                }
        }
        
        if (irqs <= 0)  {
-               printk("rc%d: Can't find IRQ for RISCom/8 board at 0x%03x.\n",
-                      board_No(bp), bp->base);
-               return 1;
+               printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
+                               "at 0x%03x.\n", board_No(bp), bp->base);
+               goto out_release;
        }
-       rc_request_io_range(bp);
        bp->irq = irqs;
        bp->flags |= RC_BOARD_PRESENT;
        
-       printk("rc%d: RISCom/8 Rev. %c board detected at 0x%03x, IRQ %d.\n",
+       printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
+                        "0x%03x, IRQ %d.\n",
               board_No(bp),
               (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A',   /* Board revision */
               bp->base, bp->irq);
        
        return 0;
+out_release:
+       rc_release_io_range(bp);
+       return 1;
 }
 
 /* 
@@ -354,7 +365,7 @@ static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
                        return port;
                }
        }
-       printk("rc%d: %s interrupt from invalid port %d\n", 
+       printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n", 
               board_No(bp), what, channel);
        return NULL;
 }
@@ -371,7 +382,8 @@ static inline void rc_receive_exc(struct riscom_board const * bp)
 
        tty = port->tty;
        if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-               printk("rc%d: port %d: Working around flip buffer overflow.\n",
+               printk(KERN_WARNING "rc%d: port %d: Working around flip "
+                                   "buffer overflow.\n",
                       board_No(bp), port_No(port));
                return;
        }
@@ -381,7 +393,7 @@ static inline void rc_receive_exc(struct riscom_board const * bp)
        if (status & RCSR_OE)  {
                port->overrun++;
 #if 0          
-               printk("rc%d: port %d: Overrun. Total %ld overruns.\n", 
+               printk(KERN_ERR "rc%d: port %d: Overrun. Total %ld overruns\n", 
                       board_No(bp), port_No(port), port->overrun);
 #endif         
        }
@@ -394,12 +406,13 @@ static inline void rc_receive_exc(struct riscom_board const * bp)
                return;
        }
        if (status & RCSR_TOUT)  {
-               printk("rc%d: port %d: Receiver timeout. Hardware problems ?\n", 
+               printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
+                                   "Hardware problems ?\n", 
                       board_No(bp), port_No(port));
                return;
                
        } else if (status & RCSR_BREAK)  {
-               printk("rc%d: port %d: Handling break...\n",
+               printk(KERN_INFO "rc%d: port %d: Handling break...\n",
                       board_No(bp), port_No(port));
                *tty->flip.flag_buf_ptr++ = TTY_BREAK;
                if (port->flags & ASYNC_SAK)
@@ -441,7 +454,8 @@ static inline void rc_receive(struct riscom_board const * bp)
        
        while (count--)  {
                if (tty->flip.count >= TTY_FLIPBUF_SIZE)  {
-                       printk("rc%d: port %d: Working around flip buffer overflow.\n",
+                       printk(KERN_WARNING "rc%d: port %d: Working around "
+                                           "flip buffer overflow.\n",
                               board_No(bp), port_No(port));
                        break;
                }
@@ -594,7 +608,8 @@ static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                                  RC_BSR_MINT | RC_BSR_RINT))) {
        
                if (status & RC_BSR_TOUT) 
-                       printk("rc%d: Got timeout. Hardware error ?\n", board_No(bp));
+                       printk(KERN_WARNING "rc%d: Got timeout. Hardware "
+                                           "error?\n", board_No(bp));
                
                else if (status & RC_BSR_RINT) {
                        ack = rc_in(bp, RC_ACK_RINT);
@@ -604,7 +619,8 @@ static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                        else if (ack == (RC_ID | GIVR_IT_REXC))
                                rc_receive_exc(bp);
                        else
-                               printk("rc%d: Bad receive ack 0x%02x.\n",
+                               printk(KERN_WARNING "rc%d: Bad receive ack "
+                                                   "0x%02x.\n",
                                       board_No(bp), ack);
                
                } else if (status & RC_BSR_TINT) {
@@ -613,7 +629,8 @@ static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                        if (ack == (RC_ID | GIVR_IT_TX))
                                rc_transmit(bp);
                        else
-                               printk("rc%d: Bad transmit ack 0x%02x.\n",
+                               printk(KERN_WARNING "rc%d: Bad transmit ack "
+                                                   "0x%02x.\n",
                                       board_No(bp), ack);
                
                } else /* if (status & RC_BSR_MINT) */ {
@@ -622,7 +639,8 @@ static void rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                        if (ack == (RC_ID | GIVR_IT_MODEM)) 
                                rc_check_modem(bp);
                        else
-                               printk("rc%d: Bad modem ack 0x%02x.\n",
+                               printk(KERN_WARNING "rc%d: Bad modem ack "
+                                                   "0x%02x.\n",
                                       board_No(bp), ack);
                
                } 
@@ -644,7 +662,8 @@ static inline int rc_setup_board(struct riscom_board * bp)
        if (bp->flags & RC_BOARD_ACTIVE) 
                return 0;
        
-       error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT, "RISCom/8", NULL);
+       error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT,
+                           "RISCom/8", NULL);
        if (error) 
                return error;
        
@@ -892,14 +911,14 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
                return;
        
 #ifdef RC_REPORT_OVERRUN
-       printk("rc%d: port %d: Total %ld overruns were detected.\n",
+       printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
               board_No(bp), port_No(port), port->overrun);
 #endif 
 #ifdef RC_REPORT_FIFO
        {
                int i;
                
-               printk("rc%d: port %d: FIFO hits [ ",
+               printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
                       board_No(bp), port_No(port));
                for (i = 0; i < 10; i++)  {
                        printk("%ld ", port->hits[i]);
@@ -932,7 +951,8 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
        port->flags &= ~ASYNC_INITIALIZED;
        
        if (--bp->count < 0)  {
-               printk("rc%d: rc_shutdown_port: bad board count: %d\n",
+               printk(KERN_INFO "rc%d: rc_shutdown_port: "
+                                "bad board count: %d\n",
                       board_No(bp), bp->count);
                bp->count = 0;
        }
@@ -1118,27 +1138,24 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
                return;
        
        save_flags(flags); cli();
-       if (tty_hung_up_p(filp))  {
-               restore_flags(flags);
-               return;
-       }
+       if (tty_hung_up_p(filp))
+               goto out;
        
        bp = port_Board(port);
        if ((tty->count == 1) && (port->count != 1))  {
-               printk("rc%d: rc_close: bad port count;"
+               printk(KERN_INFO "rc%d: rc_close: bad port count;"
                       " tty->count is 1, port count is %d\n",
                       board_No(bp), port->count);
                port->count = 1;
        }
        if (--port->count < 0)  {
-               printk("rc%d: rc_close: bad port count for tty%d: %d\n",
+               printk(KERN_INFO "rc%d: rc_close: bad port count "
+                                "for tty%d: %d\n",
                       board_No(bp), port_No(port), port->count);
                port->count = 0;
        }
-       if (port->count)  {
-               restore_flags(flags);
-               return;
-       }
+       if (port->count)
+               goto out;
        port->flags |= ASYNC_CLOSING;
        /*
         * Save the termios structure, since this port may have
@@ -1198,7 +1215,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp)
        port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
                         ASYNC_CLOSING);
        wake_up_interruptible(&port->close_wait);
-       restore_flags(flags);
+out:   restore_flags(flags);
 }
 
 static int rc_write(struct tty_struct * tty, int from_user, 
@@ -1293,15 +1310,13 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch)
 
        save_flags(flags); cli();
        
-       if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
-               restore_flags(flags);
-               return;
-       }
+       if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+               goto out;
 
        port->xmit_buf[port->xmit_head++] = ch;
        port->xmit_head &= SERIAL_XMIT_SIZE - 1;
        port->xmit_cnt++;
-       restore_flags(flags);
+out:   restore_flags(flags);
 }
 
 static void rc_flush_chars(struct tty_struct * tty)
@@ -1383,21 +1398,18 @@ static int rc_get_modem_info(struct riscom_port * port, unsigned int *value)
                | ((status & MSVR_CD)  ? TIOCM_CAR : 0)
                | ((status & MSVR_DSR) ? TIOCM_DSR : 0)
                | ((status & MSVR_CTS) ? TIOCM_CTS : 0);
-       put_user(result, value);
-       return 0;
+       return put_user(result, value);
 }
 
 static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
                             unsigned int *value)
 {
-       int error;
        unsigned int arg;
        unsigned long flags;
        struct riscom_board *bp = port_Board(port);
 
-       error = get_user(arg, value);
-       if (error) 
-               return error;
+       if (get_user(arg, value))
+               return -EFAULT;
        switch (cmd) {
         case TIOCMBIS: 
                if (arg & TIOCM_RTS) 
@@ -1453,12 +1465,9 @@ static inline int rc_set_serial_info(struct riscom_port * port,
        struct riscom_board *bp = port_Board(port);
        int change_speed;
        unsigned long flags;
-       int error;
        
-       error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
-       if (error)
-               return error;
-       copy_from_user(&tmp, newinfo, sizeof(tmp));
+       if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+               return -EFAULT;
        
 #if 0  
        if ((tmp.irq != bp->irq) ||
@@ -1501,11 +1510,6 @@ static inline int rc_get_serial_info(struct riscom_port * port,
 {
        struct serial_struct tmp;
        struct riscom_board *bp = port_Board(port);
-       int error;
-       
-       error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
-       if (error)
-               return error;
        
        memset(&tmp, 0, sizeof(tmp));
        tmp.type = PORT_CIRRUS;
@@ -1517,8 +1521,7 @@ static inline int rc_get_serial_info(struct riscom_port * port,
        tmp.close_delay = port->close_delay * HZ/100;
        tmp.closing_wait = port->closing_wait * HZ/100;
        tmp.xmit_fifo_size = CD180_NFIFO;
-       copy_to_user(retinfo, &tmp, sizeof(tmp));
-       return 0;
+       return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
 
 static int rc_ioctl(struct tty_struct * tty, struct file * filp, 
@@ -1526,7 +1529,6 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp,
                    
 {
        struct riscom_port *port = (struct riscom_port *)tty->driver_data;
-       int error;
        int retval;
                                
        if (rc_paranoia_check(port, tty->device, "rc_ioctl"))
@@ -1540,29 +1542,24 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp,
                tty_wait_until_sent(tty, 0);
                if (!arg)
                        rc_send_break(port, HZ/4);      /* 1/4 second */
-               return 0;
+               break;
         case TCSBRKP:  /* support for POSIX tcsendbreak() */
                retval = tty_check_change(tty);
                if (retval)
                        return retval;
                tty_wait_until_sent(tty, 0);
                rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
-               return 0;
+               break;
         case TIOCGSOFTCAR:
                return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
         case TIOCSSOFTCAR:
-               retval = get_user(arg,(unsigned int *) arg);
-               if (retval)
-                       return retval;
+               if (get_user(arg,(unsigned int *) arg))
+                       return -EFAULT;
                tty->termios->c_cflag =
                        ((tty->termios->c_cflag & ~CLOCAL) |
                        (arg ? CLOCAL : 0));
-               return 0;
+               break;
         case TIOCMGET:
-               error = verify_area(VERIFY_WRITE, (void *) arg,
-                                   sizeof(unsigned int));
-               if (error)
-                       return error;
                return rc_get_modem_info(port, (unsigned int *) arg);
         case TIOCMBIS:
         case TIOCMBIC:
@@ -1751,7 +1748,7 @@ static inline int rc_init_drivers(void)
 
        
        if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
-               printk("rc: Couldn't get free page.\n");
+               printk(KERN_ERR "rc: Couldn't get free page.\n");
                return 1;
        }
        init_bh(RISCOM8_BH, do_riscom_bh);
@@ -1795,14 +1792,16 @@ static inline int rc_init_drivers(void)
        
        if ((error = tty_register_driver(&riscom_driver)))  {
                free_page((unsigned long)tmp_buf);
-               printk("rc: Couldn't register RISCom/8 driver, error = %d\n",
+               printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
+                               "error = %d\n",
                       error);
                return 1;
        }
        if ((error = tty_register_driver(&riscom_callout_driver)))  {
                free_page((unsigned long)tmp_buf);
                tty_unregister_driver(&riscom_driver);
-               printk("rc: Couldn't register RISCom/8 callout driver, error = %d\n",
+               printk(KERN_ERR "rc: Couldn't register RISCom/8 callout "
+                               "driver, error = %d\n",
                       error);
                return 1;
        }
@@ -1867,6 +1866,12 @@ static int __init riscom8_setup(char *str)
 __setup("riscom8=", riscom8_setup);
 #endif
 
+static const char banner[] __initdata =
+       KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
+                 "1994-1996.\n";
+static const char no_boards_msg[] __initdata =
+       KERN_INFO "rc: No RISCom/8 boards detected.\n";
+
 /* 
  * This routine must be called by kernel at boot time 
  */
@@ -1875,7 +1880,7 @@ static int __init riscom8_init(void)
        int i;
        int found = 0;
 
-       printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n");
+       printk(banner);
 
        if (rc_init_drivers()) 
                return -EIO;
@@ -1886,7 +1891,7 @@ static int __init riscom8_init(void)
        
        if (!found)  {
                rc_release_drivers();
-               printk("rc: No RISCom/8 boards detected.\n");
+               printk(no_boards_msg);
                return -EIO;
        }
        return 0;
index f36e7334cc63ef5ac66b4ae61178750a286836aa..47cffac538ff431133f40077396beddd4cfb37f9 100644 (file)
@@ -3157,6 +3157,9 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
        info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 #endif
 
+       /*
+        *      This relies on lock_kernel() stuff so wants tidying for 2.5
+        */
        if (!tmp_buf) {
                page = get_zeroed_page(GFP_KERNEL);
                if (!page) {
index 0653ab0942df335384d624cf9730af14ef40ad70..5487987ed947b878c08ff77453026ad0e533e905 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $
+ * $Id: synclink.c,v 3.12 2001/07/18 19:14:21 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -879,35 +879,35 @@ static int mgsl_loopmode_send_done( struct mgsl_struct * info );
 /*
  * Global linked list of SyncLink devices
  */
-struct mgsl_struct *mgsl_device_list = NULL;
-int mgsl_device_count = 0;
+struct mgsl_struct *mgsl_device_list;
+int mgsl_device_count;
 
 /*
  * Set this param to non-zero to load eax with the
  * .text section address and breakpoint on module load.
  * This is useful for use with gdb and add-symbol-file command.
  */
-int break_on_load=0;
+int break_on_load;
 
 /*
  * Driver major number, defaults to zero to get auto
  * assigned major number. May be forced as module parameter.
  */
-int ttymajor=0;
+int ttymajor;
 
-int cuamajor=0;
+int cuamajor;
 
 /*
  * Array of user specified options for ISA adapters.
  */
-static int io[MAX_ISA_DEVICES] = {0,};
-static int irq[MAX_ISA_DEVICES] = {0,};
-static int dma[MAX_ISA_DEVICES] = {0,};
-static int debug_level = 0;
-static int maxframe[MAX_TOTAL_DEVICES] = {0,};
-static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
-static int txdmabufs[MAX_TOTAL_DEVICES] = {0,};
-static int txholdbufs[MAX_TOTAL_DEVICES] = {0,};
+static int io[MAX_ISA_DEVICES];
+static int irq[MAX_ISA_DEVICES];
+static int dma[MAX_ISA_DEVICES];
+static int debug_level;
+static int maxframe[MAX_TOTAL_DEVICES];
+static int dosyncppp[MAX_TOTAL_DEVICES];
+static int txdmabufs[MAX_TOTAL_DEVICES];
+static int txholdbufs[MAX_TOTAL_DEVICES];
        
 MODULE_PARM(break_on_load,"i");
 MODULE_PARM(ttymajor,"i");
@@ -922,7 +922,7 @@ MODULE_PARM(txdmabufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "3.8";
+static char *driver_version = "$Revision: 3.12 $";
 
 static int __init synclink_init_one (struct pci_dev *dev,
                                     const struct pci_device_id *ent);
@@ -4356,9 +4356,9 @@ int mgsl_claim_resources(struct mgsl_struct *info)
                        goto errout;
                }
                info->shared_mem_requested = 1;
-               if (request_mem_region(info->phys_lcr_base,128,"synclink") == NULL) {
+               if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
                        printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
-                               __FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+                               __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
                        goto errout;
                }
                info->lcr_mem_requested = 1;
@@ -4440,7 +4440,7 @@ void mgsl_release_resources(struct mgsl_struct *info)
                info->shared_mem_requested = 0;
        }
        if ( info->lcr_mem_requested ) {
-               release_mem_region(info->phys_lcr_base,128);
+               release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
                info->lcr_mem_requested = 0;
        }
        if (info->memory_base){
@@ -4520,7 +4520,9 @@ void mgsl_add_device( struct mgsl_struct *info )
        }
 
 #ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef MODULE
        if (info->dosyncppp)
+#endif
                mgsl_sppp_init(info);
 #endif
 }      /* end of mgsl_add_device() */
@@ -4637,7 +4639,7 @@ int mgsl_init_tty()
                printk("%s(%d):Couldn't register callout driver\n",
                        __FILE__,__LINE__);
 
-       printk("%s version %s, tty major#%d callout major#%d\n",
+       printk("%s %s, tty major#%d callout major#%d\n",
                driver_name, driver_version,
                serial_driver.major, callout_driver.major);
                
@@ -4703,7 +4705,7 @@ int __init mgsl_init(void)
 
        EXPORT_NO_SYMBOLS;
        
-       printk("%s version %s\n", driver_name, driver_version);
+       printk("%s %s\n", driver_name, driver_version);
        
        mgsl_enum_isa_devices();
        pci_register_driver(&synclink_pci_driver);
@@ -4739,7 +4741,7 @@ static void __exit synclink_exit(void)
        struct mgsl_struct *info;
        struct mgsl_struct *tmp;
 
-       printk("Unloading %s: version %s\n", driver_name, driver_version);
+       printk("Unloading %s: %s\n", driver_name, driver_version);
        save_flags(flags);
        cli();
        if ((rc = tty_unregister_driver(&serial_driver)))
@@ -7986,6 +7988,10 @@ void mgsl_sppp_init(struct mgsl_struct *info)
        d->tx_timeout = mgsl_sppp_tx_timeout;
        d->watchdog_timeo = 10*HZ;
 
+#if LINUX_VERSION_CODE < VERSION(2,4,4) 
+       dev_init_buffers(d);
+#endif
+
        if (register_netdev(d) == -1) {
                printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
                sppp_detach(info->netdev);
index ab74223056b2baabbe0f950418edae635cdc383a..c8724990abcee22034990affb8b466496f521865 100644 (file)
@@ -50,7 +50,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
@@ -3752,6 +3752,9 @@ static int do_zoran_ioctl(struct zoran *zr, unsigned int cmd,
                        /*
                         *   Write the overlay mask if clips are wanted.
                         */
+                        
+                       if (vw.clipcount > 2048)
+                               return -EINVAL;
                        if (vw.clipcount) {
                                vcp =
                                    vmalloc(sizeof(struct video_clip) *
index e337ff64b54d5a5856f8f15a722b9a7e6816f5d5..f955b003a1ddaab3627d78a6dc17b36877362353 100644 (file)
@@ -1473,7 +1473,7 @@ struct net_device *dev)
 {
 DEV_NET                        *pNet;
 SK_AC                  *pAC;
-unsigned int   Flags;          /* for spin lock */
+unsigned long  Flags;          /* for spin lock */
 int            i;
 SK_EVPARA              EvPara;         /* an event parameter union */
 
@@ -1580,7 +1580,7 @@ struct net_device *dev)
 DEV_NET                *pNet;
 SK_AC          *pAC;
 
-unsigned int   Flags;          /* for spin lock */
+unsigned long  Flags;          /* for spin lock */
 int                            i;
 int                            PortIdx;
 SK_EVPARA              EvPara;
@@ -1732,7 +1732,7 @@ TX_PORT           *pTxPort,       /* pointer to struct of port to send to */
 struct sk_buff *pMessage)      /* pointer to send-message */
 {
 TXD            *pTxd;          /* the rxd to fill */
-unsigned int   Flags;
+unsigned long  Flags;
 SK_U64         PhysAddr;
 int            BytesSend;
 
@@ -1898,7 +1898,7 @@ SK_AC             *pAC,           /* pointer to the adapter context */
 RX_PORT                *pRxPort)       /* ptr to port struct for which the ring
                                   should be filled */
 {
-unsigned int   Flags;
+unsigned long  Flags;
 
        spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
        while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
@@ -2329,7 +2329,7 @@ SK_AC     *pAC,           /* pointer to adapter context */
 RX_PORT        *pRxPort)       /* pointer to rx port struct */
 {
 RXD            *pRxd;  /* pointer to the current descriptor */
-unsigned int   Flags;
+unsigned long  Flags;
  SK_U64                PhysAddr;
 
        if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
@@ -2376,7 +2376,7 @@ TX_PORT   *pTxPort)       /* pointer to tx prt struct */
 {
 TXD            *pTxd;          /* pointer to the current descriptor */
 int            i;
-unsigned int   Flags;
+unsigned long  Flags;
 
        spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
        pTxd = pTxPort->pTxdRingHead;
@@ -2500,8 +2500,8 @@ DEV_NET *pNet = (DEV_NET*) dev->priv;
 SK_AC  *pAC = pNet->pAC;
 
 struct sockaddr        *addr = p;
-unsigned int   Flags;
-       
+unsigned long  Flags;
+
        SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
                ("SkGeSetMacAddr starts now...\n"));
        if(netif_running(dev)) {
@@ -2548,7 +2548,7 @@ SK_AC             *pAC;
 struct dev_mc_list     *pMcList;
 int                    i;
 int                    PortIdx;
-unsigned int           Flags;
+unsigned long          Flags;
 
        SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
                ("SkGeSetRxMode starts now... "));
@@ -2619,7 +2619,7 @@ static int SkGeChangeMtu(struct net_device *dev, int NewMtu)
 DEV_NET                *pNet;
 DEV_NET                *pOtherNet;
 SK_AC          *pAC;
-unsigned int   Flags;
+unsigned long  Flags;
 int            i;
 SK_EVPARA      EvPara;
 
@@ -2842,7 +2842,7 @@ SK_AC     *pAC = pNet->pAC;
 SK_PNMI_STRUCT_DATA *pPnmiStruct;       /* structure for all Pnmi-Data */
 SK_PNMI_STAT    *pPnmiStat;             /* pointer to virtual XMAC stat. data */SK_PNMI_CONF    *pPnmiConf;             /* pointer to virtual link config. */
 unsigned int    Size;                   /* size of pnmi struct */
-unsigned int   Flags;                  /* for spin lock */
+unsigned long  Flags;                  /* for spin lock */
 
        SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
                ("SkGeStats starts now...\n"));
@@ -2966,7 +2966,7 @@ DEV_NET           *pNet,  /* pointer to the adapter context */
 unsigned int   Size,   /* length of ioctl data */
 int            mode)   /* flag for set/preset */
 {
-unsigned int   Flags;  /* for spin lock */
+unsigned long  Flags;  /* for spin lock */
 SK_AC          *pAC;
 
        SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
@@ -3370,7 +3370,7 @@ SK_AC     *pAC            /* pointer to adapter context */
 int    StrLen = 80;            /* length of the string, defined in SK_AC */
 char   Keyword[] = VPD_NAME;   /* vpd productname identifier */
 int    ReturnCode;             /* return code from vpd_read */
-unsigned int Flags;
+unsigned long Flags;
 
        spin_lock_irqsave(&pAC->SlowPathLock, Flags);
        ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
@@ -3639,7 +3639,7 @@ int               FromPort;       /* the port from which we switch away */
 int            ToPort;         /* the port we switch to */
 SK_EVPARA      NewPara;        /* parameter for further events */
 int            Stat;
-unsigned int   Flags;
+unsigned long  Flags;
 
        switch (Event) {
        case SK_DRV_ADAP_FAIL:
index fd4ec0353c57b4a4e4c7db1d48e1a0a139977064..3771db393875924c2ba5665c51ef3ffcfef7cdb7 100644 (file)
@@ -103,7 +103,7 @@ void *data)
        DEV_NET                         *pNet;
        SK_AC                           *pAC;
        char                            test_buf[100];
-       unsigned int                    Flags;          
+       unsigned long                   Flags;          
        unsigned int                    Size;
        struct net_device               *next;
        struct net_device               *SkgeProcDev = root_dev;
index d2676187ba27fa89439a2af4f5b2ad9e67cddd3f..9f430e6f93e3aae92ad698baf744514af7732452 100644 (file)
@@ -1,64 +1,42 @@
-/*
- * Driver for Granch SBNI-12 leased line network adapters.
- * 
- * Copyright 1997 - 1999, Granch ltd.
- * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+/* sbni.c:  Granch SBNI12 leased line adapters driver for linux
+ *
+ *     Written 2001 by Denis I.Timofeev (timofeev@granch.ru)
+ *
+ *     Previous versions were written by Yaroslav Polyakov,
+ *     Alexey Zverev and Max Khon.
+ *
+ *     Driver supports SBNI12-02,-04,-05,-10,-11 cards, single and
+ *     double-channel, PCI and ISA modifications.
+ *     More info and useful utilities to work with SBNI12 cards you can find
+ *     at http://www.granch.com (English) or http://www.granch.ru (Russian)
+ *
+ *     This software may be used and distributed according to the terms
+ *     of the GNU Public License.
  *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- * 
- *   // Whole developers team:
- *   //   Yaroslav Polyakov (xenon@granch.ru)
- *   //      - main developer of this version
- *   //   Alexey Zverev (zverev@granch.ru)
- *   //      - previous SBNI driver for linux
- *   //   Alexey Chirkov (chirkov@granch.ru)
- *   //      - all the hardware work and consulting
- *   //   Max Khon (max@iclub.nsu.ru)
- *   //      - first SBNI driver for linux
- *   // --------------------------------------------
- *   // also I thank: 
- *   //   Max Krasnyansky (max@uznet.net)
- *   //      - for bug hunting and many ideas
- *   //   Alan Cox (Alan.Cox@linux.org)
- *   //             - for consulting in some hardcore questions
- *   //   Donald Becker (becker@scyld.com)
- *   //      - for pretty nice skeleton 
- * 
- *   More info and useful utilities to work w/ SBNI you can find at 
- *   http://www.granch.ru.
  *
- *  3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ *  5.0.1      Jun 22 2001
+ *       - Fixed bug in probe
+ *  5.0.0      Jun 06 2001
+ *       - Driver was completely redesigned by Denis I.Timofeev,
+ *       - now PCI/Dual, ISA/Dual (with single interrupt line) models are
+ *       - supported
+ *  3.3.0      Thu Feb 24 21:30:28 NOVT 2000 
+ *        - PCI cards support
+ *  3.2.0      Mon Dec 13 22:26:53 NOVT 1999
+ *       - Completely rebuilt all the packet storage system
+ *       -    to work in Ethernet-like style.
+ *  3.1.1      just fixed some bugs (5 aug 1999)
+ *  3.1.0      added balancing feature (26 apr 1999)
+ *  3.0.1      just fixed some bugs (14 apr 1999).
+ *  3.0.0      Initial Revision, Yaroslav Polyakov (24 Feb 1999)
  *        - added pre-calculation for CRC, fixed bug with "len-2" frames, 
  *        - removed outbound fragmentation (MTU=1000), written CRC-calculation 
  *        - on asm, added work with hard_headers and now we have our own cache 
  *        - for them, optionally supported word-interchange on some chipsets,
- *        - something else I cant remember ;) 
  * 
- *  3.0.1 = just fixed some bugs (14 apr 1999).
- *       - fixed statistical tx bug 
- *        - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
- *       - fixed source address bug.
- *        - fixed permanent nirvana bug 
- * 
- *  3.1.0 = (Katyusha) (26 apr 1999)
- *        - Added balancing feature
- * 
- *  3.1.1 = (Medea) (5 aug 1999)
- *        - Fixed mac.raw bug
- *       - Thanks to tolix@olviko.ru and 
- *        - to Barnaul Brewery, producers of my favorite beer "Medea".
- *
- *
+ *     Known problem: this driver wasn't tested on multiprocessor machine.
  */
 
-
-#undef GOODBUS16
-#define CRCASM
-#define KATYUSHA
-
-#include <linux/version.h>
-
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/fcntl.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
 #include <linux/string.h>
 #include <linux/errno.h>
-#include <linux/spinlock.h>
 
 #include <asm/io.h>
 #include <asm/types.h>
 #include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
 
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/timer.h>
-#include <linux/config.h>      /* for CONFIG_INET. do we need this?*/
+#include <linux/init.h>
 
 #include <net/arp.h>
+#include <linux/pci.h>
 
-#include <asm/uaccess.h>
-#include <linux/init.h>
 
+#ifndef MODULE
+#include <linux/string.h>
+#endif
+
+#include <linux/config.h>
 #include "sbni.h"
 
 
-static const char *version = 
-"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+/* device private data */
 
-int sbni_probe(struct net_device *dev);
-static int  sbni_probe1(struct net_device *dev, int ioaddr);
-static int  sbni_open(struct net_device *dev);
-static int  sbni_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int  sbni_close(struct net_device *dev);
-static void sbni_drop_tx_queue(struct net_device *dev);
-static struct net_device_stats *sbni_get_stats(struct net_device *dev);
-static void card_start(struct net_device *dev);
-static inline unsigned short sbni_recv(struct net_device *dev);
-void change_level(struct net_device *dev);
-static inline void sbni_xmit(struct net_device *dev);
-static inline void sbni_get_packet(struct net_device* dev);
-static void sbni_watchdog(unsigned long arg);
-static void set_multicast_list(struct net_device *dev);
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int sbni_set_mac_address(struct net_device *dev, void *addr);
-unsigned long calc_crc(char *mem, int len, unsigned initial);
-void sbni_nirvana(struct net_device *dev);
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-               void *daddr, void *saddr, unsigned len);
+struct net_local {
+       struct net_device_stats stats;
+       struct timer_list       watchdog;
 
-static int sbni_rebuild_header(struct sk_buff *skb);
-static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+       spinlock_t      lock;
+       struct sk_buff  *rx_buf_p;              /* receive buffer ptr */
+       struct sk_buff  *tx_buf_p;              /* transmit buffer ptr */
+       
+       unsigned int    framelen;               /* current frame length */
+       unsigned int    maxframe;               /* maximum valid frame length */
+       unsigned int    state;
+       unsigned int    inppos, outpos;         /* positions in rx/tx buffers */
 
-static inline void sbni_outs(int port, void *data, int len);
-static inline void sbni_ins(int port, void *data, int len);
+       /* transmitting frame number - from frames qty to 1 */
+       unsigned int    tx_frameno;
 
+       /* expected number of next receiving frame */
+       unsigned int    wait_frameno;
 
+       /* count of failed attempts to frame send - 32 attempts do before
+          error - while receiver tunes on opposite side of wire */
+       unsigned int    trans_errors;
 
-#define SIZE_OF_TIMEOUT_RXL_TAB 4
-static u_char timeout_rxl_tab[] = {
-  0x03, 0x05, 0x08, 0x0b
-};
+       /* idle time; send pong when limit exceeded */
+       unsigned int    timer_ticks;
 
-static u_char rxl_tab[] = {
-  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08, 
-  0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
-};
+       /* fields used for receive level autoselection */
+       int     delta_rxl;
+       unsigned int    cur_rxl_index, timeout_rxl;
+       unsigned long   cur_rxl_rcvd, prev_rxl_rcvd;
 
-/* A zero-terminated list of I/O addresses to be probed */
-static unsigned int netcard_portlist[] =  { 
-       0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250, 
-       0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254, 
-       0x264, 0x294, 0x2a4, 0x2b4, 0};
+       struct sbni_csr1        csr1;           /* current value of CSR1 */
+       struct sbni_in_stats    in_stats;       /* internal statistics */ 
 
-static unsigned char magic_reply[] = {
-       0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+       struct net_device               *second;        /* for ISA/dual cards */
+
+#ifdef CONFIG_SBNI_MULTILINE
+       struct net_device               *master;
+       struct net_device               *link;
+#endif
 };
 
-static int def_baud = DEF_RATE;
-static int def_rxl = DEF_RXL_DELTA;
-static long def_mac = 0;
+
+static int  sbni_card_probe( unsigned long );
+static int  sbni_pci_probe( struct net_device  * );
+static struct net_device  *sbni_probe1(struct net_device *, unsigned long, int);
+static int  sbni_open( struct net_device * );
+static int  sbni_close( struct net_device * );
+static int  sbni_start_xmit( struct sk_buff *, struct net_device * );
+static int  sbni_ioctl( struct net_device *, struct ifreq *, int );
+static struct net_device_stats  *sbni_get_stats( struct net_device * );
+static void  set_multicast_list( struct net_device * );
+
+static void  sbni_interrupt( int, void *, struct pt_regs * );
+static void  handle_channel( struct net_device * );
+static int   recv_frame( struct net_device * );
+static void  send_frame( struct net_device * );
+static int   upload_data( struct net_device *,
+                         unsigned, unsigned, unsigned, u32 );
+static void  download_data( struct net_device *, u32 * );
+static void  sbni_watchdog( unsigned long );
+static void  interpret_ack( struct net_device *, unsigned );
+static int   append_frame_to_pkt( struct net_device *, unsigned, u32 );
+static void  indicate_pkt( struct net_device * );
+static void  card_start( struct net_device * );
+static void  prepare_to_send( struct sk_buff *, struct net_device * );
+static void  drop_xmit_queue( struct net_device * );
+static void  send_frame_header( struct net_device *, u32 * );
+static int   skip_tail( unsigned int, unsigned int, u32 );
+static int   check_fhdr( u32, u32 *, u32 *, u32 *, u32 *, u32 * );
+static void  change_level( struct net_device * );
+static void  timeout_change_level( struct net_device * );
+static u32   calc_crc32( u32, u8 *, u32 );
+static struct sk_buff *  get_rx_buf( struct net_device * );
+
+#ifdef CONFIG_SBNI_MULTILINE
+static int  enslave( struct net_device *, struct net_device * );
+static int  emancipate( struct net_device * );
+#endif
+
+#define ASM_CRC 1
+
+static const char  version[] =
+       "Granch SBNI12 driver ver 5.0.1  Jun 22 2001  Denis I.Timofeev.\n";
+
+static int  skip_pci_probe     __initdata = 0;
+static int  scandone   __initdata = 0;
+static int  num                __initdata = 0;
+
+static unsigned char  rxl_tab[];
+static u32  crc32tab[];
+
+/* A list of all installed devices, for removing the driver module. */
+static struct net_device  *sbni_cards[ SBNI_MAX_NUM_CARDS ];
+
+/* Lists of device's parameters */
+static u32     io[   SBNI_MAX_NUM_CARDS ] __initdata =
+       { [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32     irq[  SBNI_MAX_NUM_CARDS ] __initdata;
+static u32     baud[ SBNI_MAX_NUM_CARDS ] __initdata;
+static u32     rxl[  SBNI_MAX_NUM_CARDS ] __initdata =
+       { [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32     mac[  SBNI_MAX_NUM_CARDS ] __initdata;
+
+#ifndef MODULE
+typedef u32  iarr[];
+static iarr  *dest[5] = { &io, &irq, &baud, &rxl, &mac };
+#endif
+
+/* A zero-terminated list of I/O addresses to be probed on ISA bus */
+static unsigned int  netcard_portlist[ ] __initdata = { 
+       0x210, 0x214, 0x220, 0x224, 0x230, 0x234, 0x240, 0x244, 0x250, 0x254,
+       0x260, 0x264, 0x270, 0x274, 0x280, 0x284, 0x290, 0x294, 0x2a0, 0x2a4,
+       0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4,
+       0 };
 
 
 /*
- * CRC-32 stuff
+ * Look for SBNI card which addr stored in dev->base_addr, if nonzero.
+ * Otherwise, look through PCI bus. If none PCI-card was found, scan ISA.
  */
 
-#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
-/* CRC generator 0xEDB88320 */
-/* CRC remainder 0x2144DF1C */
-/* CRC initial value 0x00000000 */
-#define CRC32_REMAINDER 0x2144DF1C
-#define CRC32_INITIAL 0x00000000
+static inline int __init
+sbni_isa_probe( struct net_device  *dev )
+{
+       if( dev->base_addr > 0x1ff
+           &&  !check_region( dev->base_addr, SBNI_IO_EXTENT )
+           &&  sbni_probe1( dev, dev->base_addr, dev->irq ) )
+
+               return  0;
+       else {
+               printk( KERN_ERR "sbni: base address 0x%lx is busy, or adapter "
+                       "is malfunctional!\n", dev->base_addr );
+               return  -ENODEV;
+       }
+}
 
-static unsigned long crc32tab[] = {
-       0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
-       0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
-       0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
-       0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
-       0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
-       0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
-       0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
-       0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
-       0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
-       0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
-       0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
-       0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
-       0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
-       0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
-       0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
-       0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
-       0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
-       0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
-       0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
-       0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
-       0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
-       0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
-       0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
-       0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
-       0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
-       0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
-       0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
-       0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
-       0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
-       0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,      
-       0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
-       0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
-       0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
-       0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
-       0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
-       0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
-       0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
-       0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
-       0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
-       0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
-       0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
-       0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
-       0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
-       0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
-       0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
-       0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
-       0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
-       0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
-       0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
-       0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
-       0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
-       0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
-       0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
-       0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
-       0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
-       0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
-       0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
-       0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
-       0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
-       0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
-       0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
-       0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
-       0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
-       0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
-};
 
-static inline void sbni_outs(int port, void *data, int len)
+int __init
+sbni_probe( struct net_device  *dev )
 {
-#ifdef GOODBUS16
-       outsw(port,data,len/2);
-       if(len & 1)
-               outb(((char*)data)[len - 1],port);
-#else
-       outsb(port,data,len);
-#endif
+       int  i;
+
+       static unsigned  version_printed __initdata = 0;
+       if( version_printed++ == 0 )
+               printk( KERN_INFO "%s", version );
+
+       if( !dev ) {    /* simple sanity check */
+               printk( KERN_ERR "sbni: NULL device!\n" );
+               return  -ENODEV;
+       }
+
+       SET_MODULE_OWNER( dev );
+
+       if( dev->base_addr )
+               return  sbni_isa_probe( dev );
+       /* otherwise we have to perform search our adapter */
+
+       if( io[ num ] != -1 )
+               dev->base_addr  = io[ num ],
+               dev->irq        = irq[ num ];
+       else if( scandone  ||  io[ 0 ] != -1 )
+               return  -ENODEV;
+
+       /* if io[ num ] contains non-zero address, then that is on ISA bus */
+       if( dev->base_addr )
+               return  sbni_isa_probe( dev );
+
+       /* ...otherwise - scan PCI first */
+       if( !skip_pci_probe  &&  !sbni_pci_probe( dev ) )
+               return  0;
+
+       if( io[ num ] == -1 ) {
+               /* Auto-scan will be stopped when first ISA card were found */
+               scandone = 1;
+               if( num > 0 )
+                       return  -ENODEV;
+       }
+
+       for( i = 0;  netcard_portlist[ i ];  ++i ) {
+               int  ioaddr = netcard_portlist[ i ];
+               if( !check_region( ioaddr, SBNI_IO_EXTENT )
+                   &&  sbni_probe1( dev, ioaddr, 0 ))
+                       return 0;
+       }
+
+       return  -ENODEV;
 }
 
-static inline void sbni_ins(int port, void *data, int len)
+
+int __init
+sbni_pci_probe( struct net_device  *dev )
 {
-#ifdef GOODBUS16
-       insw(port,data,len/2);
-       if(len & 1)
-               ((char*)data)[len - 1] = inb(port);
-#else
-       insb(port,data,len);
-#endif
+       struct pci_dev  *pdev = NULL;
+
+       if( !pci_present( ) )
+               return  -ENODEV;
+
+       while( (pdev = pci_find_class( PCI_CLASS_NETWORK_OTHER << 8, pdev ))
+              != NULL ) {
+               int  pci_irq_line;
+               unsigned long  pci_ioaddr;
+               u16  subsys;
+
+               if( pdev->vendor != SBNI_PCI_VENDOR
+                   &&  pdev->device != SBNI_PCI_DEVICE )
+                               continue;
+
+               pci_ioaddr = pci_resource_start( pdev, 0 );
+               pci_irq_line = pdev->irq;
+
+               /* Avoid already found cards from previous calls */
+               if( check_region( pci_ioaddr, SBNI_IO_EXTENT ) ) {
+                       pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys );
+                       if( subsys != 2  ||     /* Dual adapter is present */
+                           check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) )
+                               continue;
+               }
+
+               if( pci_irq_line <= 0  ||  pci_irq_line >= NR_IRQS )
+                       printk( KERN_WARNING "  WARNING: The PCI BIOS assigned "
+                               "this PCI card to IRQ %d, which is unlikely "
+                               "to work!.\n"
+                               KERN_WARNING " You should use the PCI BIOS "
+                               "setup to assign a valid IRQ line.\n",
+                               pci_irq_line );
+
+               /* avoiding re-enable dual adapters */
+               if( (pci_ioaddr & 7) == 0  &&  pci_enable_device( pdev ) )
+                       return  -EIO;
+               if( sbni_probe1( dev, pci_ioaddr, pci_irq_line ) )
+                       return  0;
+       }
+       return  -ENODEV;
 }
 
 
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
-          void *daddr, void *saddr, unsigned len)
+static struct net_device * __init
+sbni_probe1( struct net_device  *dev,  unsigned long  ioaddr,  int  irq )
 {
-       struct sbni_hard_header *hh = (struct sbni_hard_header *) 
-                       skb_push(skb, sizeof(struct sbni_hard_header));
-  
-  
-       if(type!=ETH_P_802_3) 
-               hh->h_proto = htons(type);
+       struct net_local  *nl;
+
+       if( !request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) )
+               return  0;
+
+       if( sbni_card_probe( ioaddr ) ) {
+               release_region( ioaddr, SBNI_IO_EXTENT );
+               return  0;
+       }
+
+       outb( 0, ioaddr + CSR0 );
+
+       if( irq < 2 ) {
+               autoirq_setup( 5 );
+               outb( EN_INT | TR_REQ, ioaddr + CSR0 );
+               outb( PR_RES, ioaddr + CSR1 );
+               irq = autoirq_report( 5 );
+               outb( 0, ioaddr + CSR0 );
+
+               if( !irq ) {
+                       printk( KERN_ERR "%s: can't detect device irq!\n",
+                               dev->name );
+                       release_region( ioaddr, SBNI_IO_EXTENT );
+                       return  0;
+               }
+       } else if( irq == 2 )
+               irq = 9;
+
+       dev->irq = irq;
+       dev->base_addr = ioaddr;
+
+       /* Allocate dev->priv and fill in sbni-specific dev fields. */
+       nl = (struct net_local *) kmalloc(sizeof(struct net_local), GFP_KERNEL);
+       if( !nl ) {
+               printk( KERN_ERR "%s: unable to get memory!\n", dev->name );
+               release_region( ioaddr, SBNI_IO_EXTENT );
+               return  0;
+       }
+
+       dev->priv = nl;
+       memset( nl, 0, sizeof(struct net_local) );
+       spin_lock_init( &nl->lock );
+
+       /* store MAC address (generate if that isn't known) */
+       *(u16 *)dev->dev_addr = htons( 0x00ff );
+       *(u32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
+               ( (mac[num]  ?  mac[num]  :  (u32)dev->priv) & 0x00ffffff) );
+
+       /* store link settings (speed, receive level ) */
+       nl->maxframe  = DEFAULT_FRAME_LEN;
+       nl->csr1.rate = baud[ num ];
+
+       if( (nl->cur_rxl_index = rxl[ num ]) == -1 )
+               /* autotune rxl */
+               nl->cur_rxl_index = DEF_RXL,
+               nl->delta_rxl = DEF_RXL_DELTA;
        else
-               hh->h_proto = htons(len);
-  
-       if(saddr)
-               memcpy(hh->h_source,saddr,dev->addr_len);
+               nl->delta_rxl = 0;
+       nl->csr1.rxl  = rxl_tab[ nl->cur_rxl_index ];
+       if( inb( ioaddr + CSR0 ) & 0x01 )
+               nl->state |= FL_SLOW_MODE;
+
+       printk( KERN_NOTICE "%s: ioaddr %#lx, irq %d, "
+               "MAC: 00:ff:01:%02x:%02x:%02x\n", 
+               dev->name, dev->base_addr, dev->irq,
+               ((u8 *) dev->dev_addr) [3],
+               ((u8 *) dev->dev_addr) [4],
+               ((u8 *) dev->dev_addr) [5] );
+
+       printk( KERN_NOTICE "%s: speed %d, receive level ", dev->name,
+               ( (nl->state & FL_SLOW_MODE)  ?  500000 : 2000000)
+               / (1 << nl->csr1.rate) );
+
+       if( nl->delta_rxl == 0 )
+               printk( "0x%x (fixed)\n", nl->cur_rxl_index ); 
        else
-               memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
-
-       if(daddr)
-       {
-               memcpy(hh->h_dest,daddr,dev->addr_len);
-               return dev->hard_header_len;
-       } 
-       return -dev->hard_header_len;
+               printk( "(auto)\n");
+
+#ifdef CONFIG_SBNI_MULTILINE
+       nl->master = dev;
+       nl->link   = NULL;
+#endif
+   
+       dev->open               = &sbni_open;
+       dev->stop               = &sbni_close;
+       dev->hard_start_xmit    = &sbni_start_xmit;
+       dev->get_stats          = &sbni_get_stats;
+       dev->set_multicast_list = &set_multicast_list;
+       dev->do_ioctl           = &sbni_ioctl;
+       ether_setup( dev );
+
+       sbni_cards[ num++ ] = dev;
+       return  dev;
 }
 
+/* -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_SBNI_MULTILINE
 
-int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int
+sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
 {
-       unsigned short type = hh->hh_type;
-       struct sbni_hard_header *sbni = (struct sbni_hard_header*)
-                                               (((u8*)hh->hh_data) - 8);
-       struct net_device *dev = neigh->dev;
-  
-  
-       if (type == htons(ETH_P_802_3))
-               return -1;
-  
-       sbni->h_proto = type;
-       memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
-       memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
-       return 0;
+       struct net_device  *p;
+
+       netif_stop_queue( dev );
+
+       /* Looking for idle device in the list */
+       for( p = dev;  p; ) {
+               struct net_local  *nl = (struct net_local *) p->priv;
+               spin_lock( &nl->lock );
+               if( nl->tx_buf_p  ||  (nl->state & FL_LINE_DOWN) ) {
+                       p = nl->link;
+                       spin_unlock( &nl->lock );
+               } else {
+                       /* Idle dev is found */
+                       prepare_to_send( skb, p );
+                       spin_unlock( &nl->lock );
+                       netif_start_queue( dev );
+                       return  0;
+               }
+       }
+
+       return  1;
 }
 
-static int sbni_rebuild_header(struct sk_buff *skb)
+#else  /* CONFIG_SBNI_MULTILINE */
+
+static int
+sbni_start_xmit( struct sk_buff  *skb,  struct net_device  *dev )
 {
-       struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
-       /*
-        *      Only ARP/IP is currently supported
-        */
+       struct net_local  *nl  = (struct net_local *) dev->priv;
 
-       /*
-        *      Try to get ARP to resolve the header.
-        */
-  
-#ifdef CONFIG_INET
-       return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;  
-#else
-       return 0;       
-#endif 
+       netif_stop_queue( dev );
+       spin_lock( &nl->lock );
+
+       prepare_to_send( skb, dev );
+
+       spin_unlock( &nl->lock );
+       return  0;
 }
 
-static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+#endif /* CONFIG_SBNI_MULTILINE */
+
+/* -------------------------------------------------------------------------- */
+
+/* interrupt handler */
+
+/*
+ *     SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
+ * be looked as two independent single-channel devices. Every channel seems
+ * as Ethernet interface but interrupt handler must be common. Really, first
+ * channel ("master") driver only registers the handler. In its struct net_local
+ * it has got pointer to "slave" channel's struct net_local and handles that's
+ * interrupts too.
+ *     dev of successfully attached ISA SBNI boards is linked to list.
+ * While next board driver is initialized, it scans this list. If one
+ * has found dev with same irq and ioaddr different by 4 then it assumes
+ * this board to be "master".
+ */ 
+
+static void
+sbni_interrupt( int  irq,  void  *dev_id,  struct pt_regs  *regs )
 {
-       memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+       struct net_device         *dev = (struct net_device *) dev_id;
+       struct net_local  *nl  = (struct net_local *) dev->priv;
+       int     repeat;
+
+       spin_lock( &nl->lock );
+       if( nl->second )
+               spin_lock( &((struct net_local *) nl->second->priv)->lock );
+
+       do {
+               repeat = 0;
+               if( inb( dev->base_addr + CSR0 ) & (RC_RDY | TR_RDY) )
+                       handle_channel( dev ),
+                       repeat = 1;
+               if( nl->second  &&      /* second channel present */
+                   (inb( nl->second->base_addr+CSR0 ) & (RC_RDY | TR_RDY)) )
+                       handle_channel( nl->second ),
+                       repeat = 1;
+       } while( repeat );
+
+       if( nl->second )
+               spin_unlock( &((struct net_local *)nl->second->priv)->lock );
+       spin_unlock( &nl->lock );
 }
 
 
+static void
+handle_channel( struct net_device  *dev )
+{
+       struct net_local        *nl    = (struct net_local *) dev->priv;
+       unsigned long           ioaddr = dev->base_addr;
 
-#ifdef HAVE_DEVLIST
-struct netdev_entry sbni_drv = {
-       "sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist 
-};
+       int  req_ans;
+       unsigned char  csr0;
 
-#else
+#ifdef CONFIG_SBNI_MULTILINE
+       /* Lock the master device because we going to change its local data */
+       if( nl->state & FL_SLAVE )
+               spin_lock( &((struct net_local *) nl->master->priv)->lock );
+#endif
 
-int __init sbni_probe(struct net_device *dev)
-{
-       int i;
-       int base_addr = dev ? dev->base_addr : 0;
-       
-       DP( printk("%s: sbni_probe\n", dev->name); )
-
-       if(base_addr > 0x1ff)   /* Check a single specified location. */
-               return sbni_probe1(dev, base_addr);
-       else if(base_addr != 0) /* Don't probe at all. */
-               return -ENXIO;
-       for(i = 0; (base_addr = netcard_portlist[i]); i++)
-       { 
-               if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
-               {
-                       /* Lock this address, or later we'll try it again */
-                       netcard_portlist[i] = 1;
-                       if(sbni_probe1(dev, base_addr) == 0)
-                               return 0;
-               }
+       outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 );
+
+       nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+       for(;;) {
+               csr0 = inb( ioaddr + CSR0 );
+               if( ( csr0 & (RC_RDY | TR_RDY) ) == 0 )
+                       break;
+
+               req_ans = !(nl->state & FL_PREV_OK);
+
+               if( csr0 & RC_RDY )
+                       req_ans = recv_frame( dev );
+
+               /*
+                * TR_RDY always equals 1 here because we have owned the marker,
+                * and we set TR_REQ when disabled interrupts
+                */
+               csr0 = inb( ioaddr + CSR0 );
+               if( !(csr0 & TR_RDY)  ||  (csr0 & RC_RDY) )
+                       printk( KERN_ERR "%s: internal error!\n", dev->name );
+
+               /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
+               if( req_ans  ||  nl->tx_frameno != 0 )
+                       send_frame( dev );
+               else
+                       /* send marker without any data */
+                       outb( inb( ioaddr + CSR0 ) & ~TR_REQ, ioaddr + CSR0 );
        }
-       return -ENODEV;
+
+       outb( inb( ioaddr + CSR0 ) | EN_INT, ioaddr + CSR0 );
+
+#ifdef CONFIG_SBNI_MULTILINE
+       if( nl->state & FL_SLAVE )
+               spin_unlock( &((struct net_local *) nl->master->priv)->lock );
+#endif
 }
 
-#endif /* have devlist*/
 
 /*
- *     The actual probe. 
+ * Routine returns 1 if it need to acknoweledge received frame.
+ * Empty frame received without errors won't be acknoweledged.
  */
 
-/*
-       Valid combinations in CSR0 (for probing):
+static int
+recv_frame( struct net_device  *dev )
+{
+       struct net_local  *nl   = (struct net_local *) dev->priv;
+       unsigned long  ioaddr   = dev->base_addr;
+
+       u32  crc = CRC32_INITIAL;
+
+       unsigned  framelen, frameno, ack;
+       unsigned  is_first, frame_ok;
+
+       if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {
+               frame_ok = framelen > 4
+                       ?  upload_data( dev, framelen, frameno, is_first, crc )
+                       :  skip_tail( ioaddr, framelen, crc );
+               if( frame_ok )
+                       interpret_ack( dev, ack );
+       } else
+               frame_ok = 0;
+
+       outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );
+       if( frame_ok ) {
+               nl->state |= FL_PREV_OK;
+               if( framelen > 4 )
+                       nl->in_stats.all_rx_number++;
+       } else
+               nl->state &= ~FL_PREV_OK,
+               change_level( dev ),
+               nl->in_stats.all_rx_number++,
+               nl->in_stats.bad_rx_number++;
+
+       return  !frame_ok  ||  framelen > 4;
+}
 
-       VALID_DECODER   0000,0011,1011,1010
 
-                                       ; 0   ; -
-                               TR_REQ  ; 1   ; +
-                       TR_RDY          ; 2   ; -
-                       TR_RDY  TR_REQ  ; 3   ; +
-               BU_EMP                  ; 4   ; +
-               BU_EMP          TR_REQ  ; 5   ; +
-               BU_EMP  TR_RDY          ; 6   ; -
-               BU_EMP  TR_RDY  TR_REQ  ; 7   ; +
-       RC_RDY                          ; 8   ; +
-       RC_RDY                  TR_REQ  ; 9   ; +
-       RC_RDY          TR_RDY          ; 10  ; -
-       RC_RDY          TR_RDY  TR_REQ  ; 11  ; -
-       RC_RDY  BU_EMP                  ; 12  ; -
-       RC_RDY  BU_EMP          TR_REQ  ; 13  ; -
-       RC_RDY  BU_EMP  TR_RDY          ; 14  ; -
-       RC_RDY  BU_EMP  TR_RDY  TR_REQ  ; 15  ; -
-*/
-#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+static void
+send_frame( struct net_device  *dev )
+{
+       struct net_local  *nl    = (struct net_local *) dev->priv;
 
-static int __init sbni_probe1(struct net_device *dev, int ioaddr)
+       u32  crc = CRC32_INITIAL;
 
-{
-       int autoirq = 0;
-       int bad_card = 0;
-       unsigned char csr0;
-       struct net_local* lp;
-       static int version_printed = 0;
-
-       DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
-       
-       if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
-               return -ENODEV;
-       if(version_printed++ == 0)
-               printk(version);
-     
-       /* check for valid combination in CSR0 */
-       csr0 = inb(ioaddr + CSR0);
-       if(csr0 == 0xff || csr0 == 0)
-               bad_card = 1;
-       else 
-       {
-               csr0 &= ~EN_INT;
-               if(csr0 & BU_EMP)
-                       csr0 |= EN_INT;
-               if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
-                       bad_card = 1;
-       }
+       if( nl->state & FL_NEED_RESEND ) {
 
-       if(bad_card)
-               return -ENODEV;
-       else
-               outb(0, ioaddr + CSR0); 
-       if(dev->irq < 2)
-       {
-               DP( printk("%s: autoprobing\n", dev->name); );
-               autoirq_setup(5);
-               outb(EN_INT | TR_REQ, ioaddr + CSR0);
-               outb(PR_RES, ioaddr + CSR1);
-               autoirq = autoirq_report(5);
-
-               if(autoirq == 0)
-               {
-                       printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
-                       return -EAGAIN;
-               }
-       }
-       /* clear FIFO buffer */
-       outb(0, ioaddr + CSR0);
-   
-       if(autoirq)
-               dev->irq = autoirq;
-
-       {
-               int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
-               if (irqval) 
-               {
-                       printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
-                       return -EAGAIN;
+               /* if frame was sended but not ACK'ed - resend it */
+               if( nl->trans_errors ) {
+                       --nl->trans_errors;
+                       if( nl->framelen != 0 )
+                               nl->in_stats.resend_tx_number++;
+               } else {
+                       /* cannot xmit with many attempts */
+#ifdef CONFIG_SBNI_MULTILINE
+                       if( (nl->state & FL_SLAVE)  ||  nl->link )
+#endif
+                       nl->state |= FL_LINE_DOWN;
+                       drop_xmit_queue( dev );
+                       goto  do_send;
                }
-       }
-     
-       /* 
-        *      Initialize the device structure. 
-        */
-
-       dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
-       if(dev->priv == NULL)
-       {
-               DP( printk("%s: cannot allocate memory\n", dev->name); )
-               free_irq(dev->irq, dev);
-               return -ENOMEM;
-       }
-   
-       memset(dev->priv, 0, sizeof(struct net_local));
-       dev->base_addr = ioaddr;
-       request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
+       } else
+               nl->trans_errors = TR_ERROR_COUNT;
 
-       /* 
-        * generate Ethernet address (0x00ff01xxxxxx)
+       send_frame_header( dev, &crc );
+       nl->state |= FL_NEED_RESEND;
+       /*
+        * FL_NEED_RESEND will be cleared after ACK, but if empty
+        * frame sended then in prepare_to_send next frame
         */
 
-       *(u16*)dev->dev_addr = htons(0x00ff);
-       *(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
-   
-       lp = dev->priv;
-       if(def_rxl < 0)
-       {
-               /* autodetect receive level */
-               lp->rxl_curr = 0xf;
-               lp->rxl_delta = -1;
-       } else {
-               /* fixed receive level */
-               lp->rxl_curr = def_rxl & 0xf;
-               lp->rxl_delta = 0;
+
+       if( nl->framelen ) {
+               download_data( dev, &crc );
+               nl->in_stats.all_tx_number++;
+               nl->state |= FL_WAIT_ACK;
        }
-       lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-       lp->csr1.rate = def_baud & 3;
-       lp->frame_len = DEF_FRAME_LEN;
-       printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n", 
-               dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
-              *(unsigned char*)(dev->dev_addr+3),
-              *(unsigned char*)(dev->dev_addr+4),
-              *(unsigned char*)(dev->dev_addr+5)
-       );
 
-       printk("%s: receive level: ", dev->name);
-       if(lp->rxl_delta == 0)
-               printk ("%#1x (fixed)", lp->rxl_curr); 
-       else
-               printk ("autodetect");
-       printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
-   
-       /*
-        *      The SBNI-specific entries in the device structure. 
-        */
-       dev->open = &sbni_open;
-       dev->hard_start_xmit = &sbni_start_xmit;
-       dev->stop = &sbni_close;
-       dev->get_stats = &sbni_get_stats;
-       dev->set_multicast_list = &set_multicast_list;
-       dev->set_mac_address = &sbni_set_mac_address;
-       dev->do_ioctl = &sbni_ioctl;
-   
-       /*
-        *      Setup the generic properties 
-        */
+       outsb( dev->base_addr + DAT, (u8 *)&crc, sizeof crc );
 
-       ether_setup(dev);
-   
-       dev->hard_header = sbni_header;
-       dev->hard_header_len = sizeof(struct sbni_hard_header);
-       dev->rebuild_header=sbni_rebuild_header;
-       dev->mtu = DEF_FRAME_LEN;
+do_send:
+       outb( inb( dev->base_addr + CSR0 ) & ~TR_REQ, dev->base_addr + CSR0 );
 
-       dev->hard_header_cache = sbni_header_cache;
-       dev->header_cache_update = sbni_header_cache_update;
-  
-       spin_lock_init(&lp->lock);
-       lp->m=dev;
-       lp->me=dev;
-       lp->next_lp=NULL;
-  
-       return 0;
+       if( nl->tx_frameno )
+               /* next frame exists - we request card to send it */
+               outb( inb( dev->base_addr + CSR0 ) | TR_REQ,
+                     dev->base_addr + CSR0 );
 }
 
+
 /*
- *     Open/initialize the board. 
+ * Write the frame data into adapter's buffer memory, and calculate CRC.
+ * Do padding if necessary.
  */
 
-static int sbni_open(struct net_device *dev)
-{
-       struct net_local* lp = (struct net_local*)dev->priv;
-       struct timer_list* watchdog = &lp->watchdog;
-       unsigned long flags;   
-      
-       DP( printk("%s: sbni_open\n", dev->name); )
-     
-       save_flags(flags);
-       cli();
-       lp->currframe = NULL;
-   
-       card_start(dev);
-       /* set timer  watchdog */
-       init_timer(watchdog);
-       watchdog->expires = jiffies + SBNI_TIMEOUT;
-       watchdog->data = (unsigned long)dev;
-       watchdog->function = sbni_watchdog;
-       add_timer(watchdog);
-       DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
-   
-       restore_flags(flags);
-          
-       netif_start_queue(dev);
-       MOD_INC_USE_COUNT;
-       return 0;
-}
-
-static int sbni_close(struct net_device *dev)
+static void
+download_data( struct net_device  *dev,  u32  *crc_p )
 {
-       int ioaddr = dev->base_addr;
-       struct net_local* lp = (struct net_local*) dev->priv;
-       struct timer_list* watchdog = &lp->watchdog;
-       unsigned long flags;
-       
-       DP( printk("%s: sbni_close\n", dev->name); )
+       struct net_local  *nl    = (struct net_local *) dev->priv;
+       struct sk_buff    *skb   = nl->tx_buf_p;
 
-       netif_stop_queue(dev);
+       unsigned  len = min( skb->len - nl->outpos, nl->framelen );
 
-       save_flags(flags);
-       cli();
-       sbni_drop_tx_queue(dev);        
-       del_timer(watchdog);
-       outb(0, ioaddr + CSR0);
-       restore_flags(flags);
+       outsb( dev->base_addr + DAT, skb->data + nl->outpos, len );
+       *crc_p = calc_crc32( *crc_p, skb->data + nl->outpos, len );
 
-       MOD_DEC_USE_COUNT;
-       return 0;
+       /* if packet too short we should write some more bytes to pad */
+       for( len = nl->framelen - len;  len--; )
+               outb( 0, dev->base_addr + DAT ),
+               *crc_p = CRC32( 0, *crc_p );
 }
 
-static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+static int
+upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
+            unsigned  is_first,  u32  crc )
 {
-       struct net_local *lp = (struct net_local*)dev->priv;
-       struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
-       unsigned long flags;
-  
-#ifdef KATYUSHA   
-       struct net_local *nl;
-       int stop;
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       int  frame_ok;
+
+       if( is_first )
+               nl->wait_frameno = frameno,
+               nl->inppos = 0;
+
+       if( nl->wait_frameno == frameno ) {
+
+               if( nl->inppos + framelen  <=  ETHER_MAX_LEN )
+                       frame_ok = append_frame_to_pkt( dev, framelen, crc );
+
+               /*
+                * if CRC is right but framelen incorrect then transmitter
+                * error was occured... drop entire packet
+                */
+               else if( (frame_ok = skip_tail( dev->base_addr, framelen, crc ))
+                        != 0 )
+                       nl->wait_frameno = 0,
+                       nl->inppos = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+                       ((struct net_local *) nl->master->priv)
+                               ->stats.rx_errors++,
+                       ((struct net_local *) nl->master->priv)
+                               ->stats.rx_missed_errors++;
+#else
+                       nl->stats.rx_errors++,
+                       nl->stats.rx_missed_errors++;
+#endif
+                       /* now skip all frames until is_first != 0 */
+       } else
+               frame_ok = skip_tail( dev->base_addr, framelen, crc );
+
+       if( is_first  &&  !frame_ok )
+               /*
+                * Frame has been broken, but we had already stored
+                * is_first... Drop entire packet.
+                */
+               nl->wait_frameno = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+               ((struct net_local *) nl->master->priv)->stats.rx_errors++,
+               ((struct net_local *) nl->master->priv)->stats.rx_crc_errors++;
+#else
+               nl->stats.rx_errors++,
+               nl->stats.rx_crc_errors++;
+#endif
+
+       return  frame_ok;
+}
+
+
+static __inline void
+send_complete( struct net_local  *nl )
+{
+#ifdef CONFIG_SBNI_MULTILINE
+       ((struct net_local *) nl->master->priv)->stats.tx_packets++;
+       ((struct net_local *) nl->master->priv)->stats.tx_bytes
+               += nl->tx_buf_p->len;
+#else
+       nl->stats.tx_packets++;
+       nl->stats.tx_bytes += nl->tx_buf_p->len;
+#endif
+       dev_kfree_skb_irq( nl->tx_buf_p );
+
+       nl->tx_buf_p = NULL;
+
+       nl->outpos = 0;
+       nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+       nl->framelen   = 0;
+}
+
+
+static void
+interpret_ack( struct net_device  *dev,  unsigned  ack )
+{
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       if( ack == FRAME_SENT_OK ) {
+               nl->state &= ~FL_NEED_RESEND;
+
+               if( nl->state & FL_WAIT_ACK ) {
+                       nl->outpos += nl->framelen;
+
+                       if( --nl->tx_frameno )
+                               nl->framelen = min( nl->maxframe,
+                                       nl->tx_buf_p->len - nl->outpos );
+                       else
+                               send_complete( nl ),
+#ifdef CONFIG_SBNI_MULTILINE
+                               netif_wake_queue( nl->master );
+#else
+                               netif_wake_queue( dev );
 #endif
-  
-       DP( printk("%s: sbni_start_xmit In \n", dev->name); );
-  
-  
-       if(lp->me != dev)
-               panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
-  
-       hh->number = 1;
-       hh->reserv = 0;
-  
-       hh->packetlen =  (skb->len - sizeof (unsigned short) - 
-                       (sizeof(struct sbni_hard_header) - SBNI_HH_SZ)) 
-                       | PACKET_SEND_OK | PACKET_FIRST_FRAME;
-  
-       /* we should use hairy method to calculate crc because of extra bytes are 
-         livin between hard header and data*/
-       hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
-       hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
-                      skb->len - sizeof(struct sbni_hard_header),
-                      hh->crc);
-  
-       spin_lock_irqsave(&lp->lock, flags);
-#ifdef KATYUSHA
-       /* looking for first idle device */
-       for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
-       {
-               if((!nl->currframe) && (nl->carrier)) /* if idle */
-               {
-                       skb->dev = lp->me;
-                       nl->currframe = skb;
-                       /* set request for transmit */
-                       outb(inb(nl->me->base_addr + CSR0) | TR_REQ, 
-                               nl->me->base_addr + CSR0);
-                       stop=1;
                }
        }
-  
-       if(!stop) /* we havent found any idle.*/
-       {
-               skb_queue_tail(&lp->queue,skb);
-               outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
-      
-       }               
-#else 
-       if (lp->currframe || 1)
-       {
-               skb_queue_tail(&lp->queue,skb);
-                 
-       }
-       else
-       {
-               lp->currframe = skb;
-       }
-       /* set request for transmit */
-       outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
-#endif
-       spin_unlock_irqrestore(&lp->lock, flags);
-       return 0;
+
+       nl->state &= ~FL_WAIT_ACK;
 }
 
-static void card_start(struct net_device *dev)
+
+/*
+ * Glue received frame with previous fragments of packet.
+ * Indicate packet when last frame would be accepted.
+ */
+
+static int
+append_frame_to_pkt( struct net_device  *dev,  unsigned  framelen,  u32  crc )
 {
-       struct net_local *lp = (struct net_local*)dev->priv;
-   
-       DP( printk("%s: card_start\n",dev->name); )
-       lp->wait_frame_number = 0;
-       lp->inppos = lp->outpos = 0;
-       lp->eth_trans_buffer_len = 0;
-       lp->tr_err = TR_ERROR_COUNT;
-       lp->last_receive_OK = FALSE;
-       lp->tr_resend = FALSE;
-       lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
-       lp->timeout_rxl = 0;
-
-       lp->waitack=0;
-       skb_queue_head_init(&lp->queue);
-       sbni_drop_tx_queue(dev);
-       /* Reset the card and set start parameters */
-       outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
-       outb(EN_INT, dev->base_addr + CSR0);
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       u8  *p;
+
+       if( nl->inppos + framelen  >  ETHER_MAX_LEN )
+               return  0;
+
+       if( !nl->rx_buf_p  &&  !(nl->rx_buf_p = get_rx_buf( dev )) )
+               return  0;
+
+       p = nl->rx_buf_p->data + nl->inppos;
+       insb( dev->base_addr + DAT, p, framelen );
+       if( calc_crc32( crc, p, framelen ) != CRC32_REMAINDER )
+               return  0;
+
+       nl->inppos += framelen - 4;
+       if( --nl->wait_frameno == 0 )           /* last frame received */
+               indicate_pkt( dev );
+
+       return  1;
 }
 
-void sbni_nirvana(struct net_device *dev)
+
+/*
+ * Prepare to start output on adapter.
+ * Transmitter will be actually activated when marker is accepted.
+ */
+
+static void
+prepare_to_send( struct sk_buff  *skb,  struct net_device  *dev )
 {
-       sbni_outs(dev->base_addr+DAT,magic_reply,9);
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       unsigned int  len;
+
+       /* nl->tx_buf_p == NULL here! */
+       if( nl->tx_buf_p )
+               printk( KERN_ERR "%s: memory leak!\n", dev->name );
+
+       nl->outpos = 0;
+       nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+
+       len = skb->len;
+       if( len < SBNI_MIN_LEN )
+               len = SBNI_MIN_LEN;
+
+       nl->tx_buf_p    = skb;
+       nl->tx_frameno  = (len + nl->maxframe - 1) / nl->maxframe;
+       nl->framelen    = len < nl->maxframe  ?  len  :  nl->maxframe;
+
+       outb( inb( dev->base_addr + CSR0 ) | TR_REQ,  dev->base_addr + CSR0 );
+#ifdef CONFIG_SBNI_MULTILINE
+       nl->master->trans_start = jiffies;
+#else
+       dev->trans_start = jiffies;
+#endif
 }
 
-static inline unsigned short sbni_recv(struct net_device *dev)
+
+static void
+drop_xmit_queue( struct net_device  *dev )
 {
-       struct net_local *lp = (struct net_local*)dev->priv;
-       unsigned long crc;
-       unsigned short packetlen = 0;
-       unsigned short packetinf, packetfirst, receiveframeresend;
-       unsigned char current_frame;
-       unsigned int i, j;
-       unsigned char delme,rcv_res=RCV_WR;
-  
-       lp->in_stats.all_rx_number++;
-  
-       if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
-       {
-               crc = CRC32_INITIAL;
-               *(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
-               crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
-               *(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
-               crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
-               packetinf = packetlen & PACKET_INF_MASK;
-               packetfirst = packetlen & PACKET_FIRST_FRAME;
-               receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
-               packetlen = packetlen & PACKET_LEN_MASK;
-    
-    
-               if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
-               {
-                       /* read frame number */
-                       current_frame = inb(dev->base_addr + DAT);
-                       crc = CRC32(current_frame, crc);
-                       /* read HandShake counter */
-                       lp->HSCounter = inb(dev->base_addr + DAT);
-                       crc = CRC32(lp->HSCounter, crc);
-                       packetlen -= 2;
-      
-                       sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
-      
-                       for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
-                       {
-                               crc = CRC32(lp->eth_rcv_buffer[i], crc);
-                       }
-      
-                       if(crc == CRC32_REMAINDER)
-                       {
-                               if(packetlen > 4) 
-                                       rcv_res=RCV_OK;
-                               else if(packetlen == 4) 
-                                       rcv_res=RCV_NO;
-               
-                               if(lp->waitack && packetinf == PACKET_RESEND)
-                                       lp->in_stats.resend_tx_number++;
-       
-       
-                               switch(packetinf)
-                               {
-                               case PACKET_SEND_OK:
-                               {
-                                       lp->tr_err = TR_ERROR_COUNT;
-                                       lp->tr_resend = FALSE;
-                                       /* if(lp->trans_frame_number){ */
-                                       lp->outpos += lp->realframelen;
-             
-                                       /* SendComplete
-                                        * not supported
-                                        */
-                                       DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
-                                       /*
-                                        *      We successfully sent current packet
-                                        */
-             
-                                       if(lp->waitack)
-                                       {
-                                               dev_kfree_skb(lp->currframe);
-                                               lp->stats.tx_packets++;
-#ifdef KATYUSHA
-                                               lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       if( nl->tx_buf_p )
+               dev_kfree_skb_any( nl->tx_buf_p ),
+               nl->tx_buf_p = NULL,
+#ifdef CONFIG_SBNI_MULTILINE
+               ((struct net_local *) nl->master->priv)
+                       ->stats.tx_errors++,
+               ((struct net_local *) nl->master->priv)
+                       ->stats.tx_carrier_errors++;
 #else
-                                               lp->currframe=skb_dequeue(&lp->queue);
-#endif                
-                                               lp->in_stats.all_tx_number++;
-                                               lp->waitack=0;
-                                       }
-             
-                                       /*
-                                        * reset output active flags
-                                        */
-                                       netif_wake_queue(dev);
-                                       /*} if */
-                               }
-                               case PACKET_RESEND:
-                               {
-                                       if(lp->tr_err) /**/
-                                               lp->tr_err--;
-                                       if(lp->ok_curr < 0xffffffff)
-                                               lp->ok_curr++;
-                                       if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
-                                       {
-                                               if(packetfirst)
-                                               {
-                                                       if(lp->wait_frame_number)
-                                                       {
-                                                               for(i = lp->inppos, j = 0; 
-                                                                       i < (lp->inppos + packetlen - 4); 
-                                                                       i++, j++)
-                                                               lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
-                                                       }
-                                                       lp->wait_frame_number = current_frame;
-                                                       lp->inppos = 0;
-                                               }
-                                               if(current_frame == lp->wait_frame_number)
-                                               {
-                                                       lp->inppos += (packetlen - 4);
-                                                       if(lp->wait_frame_number == 1)
-                                                       {
-                                                               sbni_get_packet(dev);
-                                                               lp->inppos = 0;
-                                                       }
-                                                       lp->wait_frame_number--;
-                                               }
-                                       }
-                                       lp->last_receive_OK = TRUE;
-                                       break;
-                               }
-                               default:
-                                       break;
-                               }
-                       }
-                       else 
-                       {
-                               DP(printk("%s: bad CRC32\n",dev->name));
-                               change_level(dev);
-                       }
-               }
-               else 
-               {
-                       DP(printk("%s: bad len\n ",dev->name));
-                       change_level(dev);
-                       lp->stats.rx_over_errors++;
-               }
-       }
-       else 
-       {
-               DP(printk("%s: bad sig\n",dev->name));
-               change_level(dev);
-       }
-       outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
-       return (rcv_res);
+               nl->stats.tx_errors++,
+               nl->stats.tx_carrier_errors++;
+#endif
+
+       nl->tx_frameno  = 0;
+       nl->framelen    = 0;
+       nl->outpos      = 0;
+       nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+#ifdef CONFIG_SBNI_MULTILINE
+       netif_start_queue( nl->master );
+       nl->master->trans_start = jiffies;
+#else
+       netif_start_queue( dev );
+       dev->trans_start = jiffies;
+#endif
 }
 
-void change_level(struct net_device *dev)
+
+static void
+send_frame_header( struct net_device  *dev,  u32  *crc_p )
 {
-       struct net_local *lp = (struct net_local*)dev->priv;
+       struct net_local  *nl  = (struct net_local *) dev->priv;
 
-       lp->in_stats.bad_rx_number++;
-       lp->stats.tx_errors++;
-       if(lp->rxl_delta == 0)
-               return;
-       /* 
-        * set new rxl_delta value
-        */
-       if(lp->rxl_curr == 0)
-               lp->rxl_delta = 1;
-       else if(lp->rxl_curr == 0xf)
-               lp->rxl_delta = -1;
-       else if(lp->ok_curr < lp->ok_prev)
-               lp->rxl_delta = -lp->rxl_delta;
-       /*
-        * set new rxl_curr value
-        */
-       lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
-       outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
-  
-  
-       /*
-        * update ok_prev/ok_curr counters
-        */
-       lp->ok_prev = lp->ok_curr;
-       lp->ok_curr = 0;
+       u32  crc = *crc_p;
+       u32  len_field = nl->framelen + 6;      /* CRC + frameno + reserved */
+       u8   value;
+
+       if( nl->state & FL_NEED_RESEND )
+               len_field |= FRAME_RETRY;       /* non-first attempt... */
+
+       if( nl->outpos == 0 )
+               len_field |= FRAME_FIRST;
 
-       DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
-                  dev->name,lp->rxl_curr, lp->rxl_delta); )
-     
+       len_field |= (nl->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
+       outb( SBNI_SIG, dev->base_addr + DAT );
+
+       value = (u8) len_field;
+       outb( value, dev->base_addr + DAT );
+       crc = CRC32( value, crc );
+       value = (u8) (len_field >> 8);
+       outb( value, dev->base_addr + DAT );
+       crc = CRC32( value, crc );
+
+       outb( nl->tx_frameno, dev->base_addr + DAT );
+       crc = CRC32( nl->tx_frameno, crc );
+       outb( 0, dev->base_addr + DAT );
+       crc = CRC32( 0, crc );
+       *crc_p = crc;
 }
 
-static inline void sbni_xmit(struct net_device *dev)
+
+/*
+ * if frame tail not needed (incorrect number or received twice),
+ * it won't store, but CRC will be calculated
+ */
+
+static int
+skip_tail( unsigned int  ioaddr,  unsigned int  tail_len,  u32 crc )
 {
-       struct net_local* lp = (struct net_local *)dev->priv;
-       struct sk_buff *skb;
-       skb=lp->currframe;
-  
-       DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
-         
-       /* push signature*/  
-       outb(SBNI_SIG, dev->base_addr + DAT);
-       
-       /* push frame w/o crc [HAiRY]*/
-       sbni_outs(dev->base_addr + DAT,
-             &((struct sbni_hard_header *)(skb->data))->packetlen,
-             SBNI_HH_SZ - sizeof(unsigned)); 
-       
-       sbni_outs(dev->base_addr + DAT,
-             skb->data + sizeof(struct sbni_hard_header),
-             skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */
+       while( tail_len-- )
+               crc = CRC32( inb( ioaddr + DAT ), crc );
 
-       /* push crc */
-       sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
-       
-       lp->waitack=1;
+       return  crc == CRC32_REMAINDER;
 }
 
+
 /*
- *     The typical workload of the driver:
- *     Handle the ether interface interrupts. 
+ * Preliminary checks if frame header is correct, calculates its CRC
+ * and split it to simple fields
  */
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+static int
+check_fhdr( u32  ioaddr,  u32  *framelen,  u32  *frameno,  u32  *ack,
+           u32  *is_first,  u32  *crc_p )
 {
-       struct net_device *dev = dev_id;
-       struct net_local* lp;
-       u_char csr0;
-       unsigned short rcv_res = RCV_NO;
-  
-  
-       if(dev == NULL || dev->irq != irq)
-       {
-               printk("sbni: irq %d for unknown device\n", irq);
-               return;
-       }
-   
-       csr0 = inb(dev->base_addr + CSR0);
-       DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
-     
-       lp=dev->priv;
+       u32  crc = *crc_p;
+       u8   value;
 
-       spin_lock(&lp->lock);
-  
-       if(!lp->carrier)
-               lp->carrier=1;
-  
-       /*
-        * Disable adapter interrupts
-        */
-       outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
-       lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
-       csr0 = inb(dev->base_addr + CSR0);
-   
-       if(csr0 & (TR_RDY | RC_RDY))
-       {
-               if(csr0 & RC_RDY)
-                       rcv_res = sbni_recv(dev);
-          
-               if((lp->currframe) && (rcv_res != RCV_WR))
-                       sbni_xmit(dev);
-               else if (rcv_res == RCV_OK)
-                       sbni_nirvana(dev);
-       
-               csr0 = inb(dev->base_addr + CSR0);
-               DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
-       }
-   
-  
-       DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
-     
-       /* here we should send pong */
-       outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
-       if(lp->currframe)
-               outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
-       else
-               csr0 = inb(dev->base_addr + CSR0);
-  
-       /*
-        * Enable adapter interrupts
-        */
-  
-       outb(csr0 | EN_INT, dev->base_addr + CSR0);
-       spin_unlock(&lp->lock);
+       if( inb( ioaddr + DAT ) != SBNI_SIG )
+               return  0;
+
+       value = inb( ioaddr + DAT );
+       *framelen = (u32)value;
+       crc = CRC32( value, crc );
+       value = inb( ioaddr + DAT );
+       *framelen |= ((u32)value) << 8;
+       crc = CRC32( value, crc );
+
+       *ack = *framelen & FRAME_ACK_MASK;
+       *is_first = (*framelen & FRAME_FIRST) != 0;
+
+       if( (*framelen &= FRAME_LEN_MASK) < 6
+           ||  *framelen > SBNI_MAX_FRAME - 3 )
+               return  0;
+
+       value = inb( ioaddr + DAT );
+       *frameno = (u32)value;
+       crc = CRC32( value, crc );
+
+       crc = CRC32( inb( ioaddr + DAT ), crc );        /* reserved byte */
+       *framelen -= 2;
+
+       *crc_p = crc;
+       return  1;
 }
 
-static struct net_device_stats *sbni_get_stats(struct net_device *dev)
+
+static struct sk_buff *
+get_rx_buf( struct net_device  *dev )
 {
-       struct net_local *lp = (struct net_local *)dev->priv;
-       return &lp->stats;
+       /* +2 is to compensate for the alignment fixup below */
+       struct sk_buff  *skb = dev_alloc_skb( ETHER_MAX_LEN + 2 );
+       if( !skb )
+               return  NULL;
+
+#ifdef CONFIG_SBNI_MULTILINE
+       skb->dev = ((struct net_local *) dev->priv)->master;
+#else
+       skb->dev = dev;
+#endif
+       skb_reserve( skb, 2 );          /* Align IP on longword boundaries */
+       return  skb;
 }
 
-static inline void sbni_get_packet(struct net_device* dev)
+
+static void
+indicate_pkt( struct net_device  *dev )
 {
-       struct net_local* lp = (struct net_local*)dev->priv;
-       struct sk_buff* skb;
-       unsigned char *rawp;
-    
-   
-     
-       skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
-   
-       if(skb == NULL)
-       {
-               DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
-               lp->stats.rx_dropped++;
-               return;
-       } else {
-#ifdef KATYUSHA
-               skb->dev = lp->m;
+       struct net_local  *nl  = (struct net_local *) dev->priv;
+       struct sk_buff    *skb = nl->rx_buf_p;
+
+       skb_put( skb, nl->inppos );
+
+#ifdef CONFIG_SBNI_MULTILINE
+       skb->protocol = eth_type_trans( skb, nl->master );
+       netif_rx( skb );
+       dev->last_rx = jiffies;
+       ++((struct net_local *) nl->master->priv)->stats.rx_packets;
+       ((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos;
 #else
-               skb->dev = dev;
-#endif      
-               memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
-                       lp->eth_rcv_buffer,
-                       lp->inppos);
-      
-      
-               skb->mac.raw = skb->data + 8;
-    
-               if((*(char*)lp->eth_rcv_buffer) & 1)
-               {
-                       if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
-                               skb->pkt_type=PACKET_BROADCAST;
-                       else
-                               skb->pkt_type=PACKET_MULTICAST;
-               }
-               else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
-               {
-                       if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
-                               skb->pkt_type=PACKET_OTHERHOST;
-               }
-      
-               if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
-                       skb->protocol =  *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
-               else
-               {
-                       rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
-                       if (*(unsigned short *)rawp == 0xFFFF)
-                               skb->protocol=htons(ETH_P_802_3);
-                       else
-                               skb->protocol=htons(ETH_P_802_2);
+       skb->protocol = eth_type_trans( skb, dev );
+       netif_rx( skb );
+       dev->last_rx = jiffies;
+       ++nl->stats.rx_packets;
+       nl->stats.rx_bytes += nl->inppos;
+#endif
+       nl->rx_buf_p = NULL;    /* protocol driver will clear this sk_buff */
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Routine checks periodically wire activity and regenerates marker if
+ * connect was inactive for a long time.
+ */
+
+static void
+sbni_watchdog( unsigned long  arg )
+{
+       struct net_device  *dev = (struct net_device *) arg;
+       struct net_local   *nl  = (struct net_local *) dev->priv;
+       struct timer_list  *w   = &nl->watchdog; 
+       unsigned long      flags;
+       unsigned char      csr0;
+
+       spin_lock_irqsave( &nl->lock, flags );
+
+       csr0 = inb( dev->base_addr + CSR0 );
+       if( csr0 & RC_CHK ) {
+
+               if( nl->timer_ticks ) {
+                       if( csr0 & (RC_RDY | BU_EMP) )
+                               /* receiving not active */
+                               nl->timer_ticks--;
+               } else {
+                       nl->in_stats.timeout_number++;
+                       if( nl->delta_rxl )
+                               timeout_change_level( dev );
+
+                       outb( *(u_char *)&nl->csr1 | PR_RES,
+                             dev->base_addr + CSR1 );
+                       csr0 = inb( dev->base_addr + CSR0 );
                }
-            
+       } else
+               nl->state &= ~FL_LINE_DOWN;
 
-               skb_pull(skb,SBNI_HH_SZ);
-   
-               skb->dev->last_rx = jiffies;
-               lp->stats.rx_bytes += skb->len;
-               netif_rx(skb);
-               lp->stats.rx_packets++;
-       }
-       return;
+       outb( csr0 | RC_CHK, dev->base_addr + CSR0 ); 
+
+       init_timer( w );
+       w->expires      = jiffies + SBNI_TIMEOUT;
+       w->data         = arg;
+       w->function     = sbni_watchdog;
+       add_timer( w );
+
+       spin_unlock_irqrestore( &nl->lock, flags );
 }
 
-static void sbni_watchdog(unsigned long arg)
+
+static unsigned char  rxl_tab[] = {
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
+       0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static unsigned char  timeout_rxl_tab[] = {
+       0x03, 0x05, 0x08, 0x0b
+};
+
+/* -------------------------------------------------------------------------- */
+
+static void
+card_start( struct net_device  *dev )
 {
-       struct net_device* dev = (struct net_device*)arg;
-       struct net_local* lp = (struct net_local *)dev->priv;
-       u_char csr0;
+       struct net_local  *nl = (struct net_local *) dev->priv;
 
+       nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+       nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+       nl->state |= FL_PREV_OK;
+
+       nl->inppos = nl->outpos = 0;
+       nl->wait_frameno = 0;
+       nl->tx_frameno   = 0;
+       nl->framelen     = 0;
+
+       outb( *(u_char *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+       outb( EN_INT, dev->base_addr + CSR0 );
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Receive level auto-selection */
+
+static void
+change_level( struct net_device  *dev )
+{
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       if( nl->delta_rxl == 0 )        /* do not auto-negotiate RxL */
+               return;
+
+       if( nl->cur_rxl_index == 0 )
+               nl->delta_rxl = 1;
+       else if( nl->cur_rxl_index == 15 )
+               nl->delta_rxl = -1;
+       else if( nl->cur_rxl_rcvd < nl->prev_rxl_rcvd )
+               nl->delta_rxl = -nl->delta_rxl;
+
+       nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index += nl->delta_rxl ];
+       inb( dev->base_addr + CSR0 );   /* needs for PCI cards */
+       outb( *(u8 *)&nl->csr1, dev->base_addr + CSR1 );
+
+       nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+       nl->cur_rxl_rcvd  = 0;
+}
+
+
+static void
+timeout_change_level( struct net_device  *dev )
+{
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ];
+       if( ++nl->timeout_rxl >= 4 )
+               nl->timeout_rxl = 0;
+
+       nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+       inb( dev->base_addr + CSR0 );
+       outb( *(unsigned char *)&nl->csr1, dev->base_addr + CSR1 );
+
+       nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+       nl->cur_rxl_rcvd  = 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ *     Open/initialize the board. 
+ */
+
+static int
+sbni_open( struct net_device  *dev )
+{
+       struct net_local        *nl = (struct net_local *) dev->priv;
+       struct timer_list       *w  = &nl->watchdog;
 
-  
-       DP( printk("%s: watchdog start\n",dev->name); ) 
        /*
-        * if no pong received and transmission is not in progress
-        * then assume error
+        * For double ISA adapters within "common irq" mode, we have to
+        * determine whether primary or secondary channel is initialized,
+        * and set the irq handler only in first case.
         */
-       cli();
-       csr0 = inb(dev->base_addr + CSR0);
-       if(csr0 & (RC_CHK | TR_REQ))
-       {
-               if(lp->timer_ticks)
-               {
-                       if(csr0 & (RC_RDY | BU_EMP))
-                       {
-                               lp->timer_ticks--;
-                       }
-               }
-               else 
-               {
-                       if(lp->rxl_delta)
-                       {
-                               lp->ok_prev = lp->ok_curr;
-                               lp->ok_curr = 0;
-                               lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
-                               lp->timeout_rxl++;
-                               if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
-                                       lp->timeout_rxl = 0; 
-                               lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-                               /*
-                                * update ok_prev/ok_curr counters
-                                */
-                               lp->ok_prev = lp->ok_curr;
-                               lp->ok_curr = 0;
-                       }
-                       if(lp->tr_err)
-                               lp->tr_err--;
-                       else 
-                       {
-                               /* Drop the queue of tx packets */
-                               sbni_drop_tx_queue(dev);
-                               lp->carrier=0;
+       if( dev->base_addr < 0x400 ) {          /* ISA only */
+               struct net_device  **p = sbni_cards;
+               for( ;  *p  &&  p < sbni_cards + SBNI_MAX_NUM_CARDS;  ++p )
+                       if( (*p)->irq == dev->irq
+                           &&  ((*p)->base_addr == dev->base_addr + 4
+                                ||  (*p)->base_addr == dev->base_addr - 4)
+                           &&  (*p)->flags & IFF_UP ) {
+
+                               ((struct net_local *) ((*p)->priv))
+                                       ->second = dev;
+                               printk( KERN_NOTICE "%s: using shared irq "
+                                       "with %s\n", dev->name, (*p)->name );
+                               nl->state |= FL_SECONDARY;
+                               goto  handler_attached;
                        }
-            
-                       /*
-                        * send pong
-                        */
-
-                       csr0 = inb(dev->base_addr + CSR0);
-                       outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
-                       outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
-                       lp->in_stats.timeout_number++;
-               }
        }
-       sti();
-       outb(csr0 | RC_CHK, dev->base_addr + CSR0);
-       if(netif_running(dev))
-       {
-               struct timer_list* watchdog = &lp->watchdog; 
-               init_timer(watchdog);
-               watchdog->expires = jiffies + SBNI_TIMEOUT;
-               watchdog->data = arg;
-               watchdog->function = sbni_watchdog;
-               add_timer(watchdog);
+
+       if( request_irq(dev->irq, sbni_interrupt, SA_SHIRQ, dev->name, dev) ) {
+               printk( KERN_ERR "%s: unable to get IRQ %d.\n",
+                       dev->name, dev->irq );
+               return  -EAGAIN;
        }
-}
 
-static void sbni_drop_tx_queue(struct net_device *dev)
-{
-       struct net_local* lp = (struct net_local *)dev->priv,*nl;
-       struct sk_buff *tmp;
+handler_attached:
+
+       spin_lock( &nl->lock );
+       memset( &nl->stats, 0, sizeof(struct net_device_stats) );
+       memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+
+       card_start( dev );
+
+       netif_start_queue( dev );
+
+       /* set timer watchdog */
+       init_timer( w );
+       w->expires      = jiffies + SBNI_TIMEOUT;
+       w->data         = (unsigned long) dev;
+       w->function     = sbni_watchdog;
+       add_timer( w );
    
-       /* first of all, we should try to gift our packets to another interface */
-  
-       nl=(struct net_local *)lp->m->priv;
-       if(nl==lp)
-               nl=lp->next_lp;
-  
-       if(nl)
-       {
-               /* we found device*/
-               if(lp->currframe)
-               {
-                       if(!nl->currframe)
-                       {
-                               nl->currframe=lp->currframe;
-                       }
-                       else
-                       {
-                               skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
-                       }
-               }
-               lp->currframe=NULL;
+       spin_unlock( &nl->lock );
+       return 0;
+}
 
-               if(!nl->currframe)
-                       nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
 
-               /* set request for transmit */
-               outb(inb(nl->me->base_addr + CSR0) | TR_REQ,  nl->me->base_addr + CSR0);
-    
+static int
+sbni_close( struct net_device  *dev )
+{
+       struct net_local  *nl = (struct net_local *) dev->priv;
+
+       if( nl->second  &&  nl->second->flags & IFF_UP ) {
+               printk( KERN_NOTICE "Secondary channel (%s) is active!\n",
+                       nl->second->name );
+               return  -EBUSY;
        }
+
+#ifdef CONFIG_SBNI_MULTILINE
+       if( nl->state & FL_SLAVE )
+               emancipate( dev );
        else
-       {
-               /* *sigh*, we should forget this packets */
-               nl=lp->m->priv;
-    
-               while((tmp = skb_dequeue(&nl->queue)) != NULL)
-               {
-                       dev_kfree_skb(tmp);
-                       lp->stats.tx_packets++;
-               }
-    
-               if (lp->currframe)
-               {
-                       dev_kfree_skb(lp->currframe);
-                       lp->currframe = NULL;
-                       lp->stats.tx_packets++;
-               }
-       }
-       lp->waitack=0;
-       netif_wake_queue(dev);
-       
-       DP( printk("%s: queue dropping stopped\n",dev->name); );        
+               while( nl->link )       /* it's master device! */
+                       emancipate( nl->link );
+#endif
+
+       spin_lock( &nl->lock );
+
+       nl->second = NULL;
+       drop_xmit_queue( dev ); 
+       netif_stop_queue( dev );
+   
+       del_timer( &nl->watchdog );
+
+       outb( 0, dev->base_addr + CSR0 );
+
+       if( !(nl->state & FL_SECONDARY) )
+               free_irq( dev->irq, dev );
+       nl->state &= FL_SECONDARY;
+
+       spin_unlock( &nl->lock );
+       return 0;
 }
 
+
 /*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1     Promiscuous mode, receive all packets
- * num_addrs == 0      Normal mode, clear multicast list
- * num_addrs > 0       Multicast mode, receive normal and MC packets,
- *                     and do best-effort filtering.
- */
-static void set_multicast_list(struct net_device *dev)
+       Valid combinations in CSR0 (for probing):
+
+       VALID_DECODER   0000,0011,1011,1010
+
+                                       ; 0   ; -
+                               TR_REQ  ; 1   ; +
+                       TR_RDY          ; 2   ; -
+                       TR_RDY  TR_REQ  ; 3   ; +
+               BU_EMP                  ; 4   ; +
+               BU_EMP          TR_REQ  ; 5   ; +
+               BU_EMP  TR_RDY          ; 6   ; -
+               BU_EMP  TR_RDY  TR_REQ  ; 7   ; +
+       RC_RDY                          ; 8   ; +
+       RC_RDY                  TR_REQ  ; 9   ; +
+       RC_RDY          TR_RDY          ; 10  ; -
+       RC_RDY          TR_RDY  TR_REQ  ; 11  ; -
+       RC_RDY  BU_EMP                  ; 12  ; -
+       RC_RDY  BU_EMP          TR_REQ  ; 13  ; -
+       RC_RDY  BU_EMP  TR_RDY          ; 14  ; -
+       RC_RDY  BU_EMP  TR_RDY  TR_REQ  ; 15  ; -
+*/
+
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+
+static int
+sbni_card_probe( unsigned long  ioaddr )
 {
-       /*
-        * always enabled promiscuous mode.
-       */
-       return;
-}
+       unsigned char  csr0;
 
-static int sbni_set_mac_address(struct net_device *dev, void *addr)
-{      
-       /* struct net_local *lp = (struct net_local *)dev->priv; */
-       struct sockaddr *saddr = addr;
-       
-       if(netif_running(dev))
-       {
-               /* Only possible while card isn't started */
-               return -EBUSY;
+       csr0 = inb( ioaddr + CSR0 );
+       if( csr0 != 0xff  &&  csr0 != 0x00 ) {
+               csr0 &= ~EN_INT;
+               if( csr0 & BU_EMP )
+                       csr0 |= EN_INT;
+      
+               if( VALID_DECODER & (1 << (csr0 >> 4)) )
+                       return  0;
        }
-       memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
-       return (0);
+   
+       return  -ENODEV;
 }
 
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/* -------------------------------------------------------------------------- */
+
+static int
+sbni_ioctl( struct net_device  *dev,  struct ifreq  *ifr,  int  cmd )
 {
-       struct net_local* lp = (struct net_local *)dev->priv,*tlp; 
-       struct net_device *slave;
-       int error = 0;
-       char tmpstr[6];
-  
+       struct net_local  *nl = (struct net_local *) dev->priv; 
+       struct sbni_flags  flags;
+       int  error = 0;
+
+#ifdef CONFIG_SBNI_MULTILINE
+       struct net_device  *slave_dev;
+       char  slave_name[ 8 ];
+#endif
   
-       switch(cmd)
-       {
-               case SIOCDEVGETINSTATS:
-               {
-                       struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
-                       DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
-                       if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
-                               return -EFAULT;
-                       break;
-               }
-               case SIOCDEVRESINSTATS:
-               {
-                       if(!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
-                       lp->in_stats.all_rx_number = 0;
-                       lp->in_stats.bad_rx_number = 0;
-                       lp->in_stats.timeout_number = 0;
-                       lp->in_stats.all_tx_number = 0;
-                       lp->in_stats.resend_tx_number = 0;
-                       break;
-               }
-               case SIOCDEVGHWSTATE:
-               {
-                       struct sbni_flags flags;
-                       flags.rxl = lp->rxl_curr;
-                       flags.rate = lp->csr1.rate;
-                       flags.fixed_rxl = (lp->rxl_delta == 0);
-                       flags.fixed_rate = 1;
-                       ifr->ifr_data = *(caddr_t*)&flags;
-                       DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
-                       break;
-               }
-               case SIOCDEVSHWSTATE:
-               {
-                       struct sbni_flags flags;
-                       DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
-                       /* root only */
-                       if(!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       flags = *(struct sbni_flags*)&ifr->ifr_data;
-                       if(flags.fixed_rxl)
-                       {
-                               lp->rxl_delta = 0;
-                               lp->rxl_curr = flags.rxl;
-                       }
-                       else
-                       {
-                               lp->rxl_delta = DEF_RXL_DELTA;
-                               lp->rxl_curr = DEF_RXL;
-                       }
-                       lp->csr1.rxl = rxl_tab[lp->rxl_curr];
-                       if(flags.fixed_rate)
-                               lp->csr1.rate = flags.rate;
-                       else
-                               lp->csr1.rate = DEF_RATE;
-                       /*
-                        * Don't be afraid...
-                        */
-                       outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
-
-                       DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
-                               dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
-                       break;
+       switch( cmd ) {
+       case  SIOCDEVGETINSTATS :
+               error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+                                    sizeof(struct sbni_in_stats) );
+               if( !error )
+                       copy_to_user( ifr->ifr_data, &nl->in_stats,
+                                     sizeof(struct sbni_in_stats) );
+               break;
+
+       case  SIOCDEVRESINSTATS :
+               if( current->euid != 0 )        /* root only */
+                       return  -EPERM;
+               memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+               break;
+
+       case  SIOCDEVGHWSTATE :
+               flags.mac_addr  = *(u32 *)(dev->dev_addr + 3);
+               flags.rate      = nl->csr1.rate;
+               flags.slow_mode = (nl->state & FL_SLOW_MODE) != 0;
+               flags.rxl       = nl->cur_rxl_index;
+               flags.fixed_rxl = nl->delta_rxl == 0;
+
+               error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+                                    sizeof flags );
+               if( !error )
+                       copy_to_user( ifr->ifr_data, &flags, sizeof flags );
+               break;
+
+       case  SIOCDEVSHWSTATE :
+               if( current->euid != 0 )        /* root only */
+                       return  -EPERM;
+
+               spin_lock( &nl->lock );
+               flags = *(struct sbni_flags*) &ifr->ifr_data;
+               if( flags.fixed_rxl )
+                       nl->delta_rxl = 0,
+                       nl->cur_rxl_index = flags.rxl;
+               else
+                       nl->delta_rxl = DEF_RXL_DELTA,
+                       nl->cur_rxl_index = DEF_RXL;
+
+               nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+               nl->csr1.rate = flags.rate;
+               outb( *(u8 *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+               spin_unlock( &nl->lock );
+               break;
+
+#ifdef CONFIG_SBNI_MULTILINE
+
+       case  SIOCDEVENSLAVE :
+               if( current->euid != 0 )        /* root only */
+                       return  -EPERM;
+
+               if( (error = verify_area( VERIFY_READ, ifr->ifr_data,
+                                         sizeof slave_name )) != 0 )
+                       return  error;
+
+               copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name );
+               slave_dev = dev_get_by_name( slave_name );
+               if( !slave_dev  ||  !(slave_dev->flags & IFF_UP) ) {
+                       printk( KERN_ERR "%s: trying to enslave non-active "
+                               "device %s\n", dev->name, slave_name );
+                       return  -EPERM;
                }
 
-               case SIOCDEVENSLAVE:
-                       if(!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-                       if(copy_from_user( tmpstr, ifr->ifr_data, 6))
-                               return -EFAULT;
-                       slave = dev_get_by_name(tmpstr);
-                       if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
-                       {
-                               printk("%s: Both devices should be UP to enslave!\n",dev->name);
-                               if (slave)
-                                       dev_put(slave);
-                               return -EINVAL;
-                       }
-               
-                       if(slave)
-                       {
-                               if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
-                               {
-                                       /* drop queue*/
-                                       sbni_drop_tx_queue(slave);
-                                       slave->flags |= IFF_SLAVE;
-                                       ((struct net_local *)(slave->priv))->m=dev;
-                                       while(lp->next_lp)      //tail it after last slave
-                                               lp=lp->next_lp;
-                                       lp->next_lp=slave->priv;
-                                       lp=(struct net_local *)dev->priv;
-                                       dev->flags |= IFF_MASTER;
-                                       }
-                               else
-                               {
-                                       printk("%s: one of devices is already slave!\n",dev->name);
-                                       error = -EBUSY;
-                               }
-                               dev_put(slave);
-                       }
-                       else
-                       {
-                               printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
-                               return -ENOENT;
-                       }
-                       break;    
-
-               case SIOCDEVEMANSIPATE:
-                       if(!capable(CAP_NET_ADMIN))
-                               return -EPERM;
-
-                       if(dev->flags & IFF_SLAVE)
-                       {
-                               dev->flags &= ~IFF_SLAVE;
-                               /* exclude us from masters slavelist*/
-                               for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
-                               if(tlp->next_lp)
-                               {
-                                       tlp->next_lp = lp->next_lp;
-                                       if(!((struct net_local *)lp->m->priv)->next_lp)
-                                       {
-                                               lp->m->flags &= ~IFF_MASTER;    
-                                       }
-                                       lp->next_lp=NULL;
-                                       lp->m=dev;      
-                               }
-                               else
-                               {
-                                       printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
-                                       return -EIO;
-                               }      
-                       }
-                       else
-                       {
-                               printk("%s: isn't slave device!\n",dev->name);
-                               return -EINVAL;
-                       }
-                       break;    
+               return  enslave( dev, slave_dev );
+
+       case  SIOCDEVEMANSIPATE :
+               if( current->euid != 0 )        /* root only */
+                       return  -EPERM;
+
+               return  emancipate( dev );
+
+#endif /* CONFIG_SBNI_MULTILINE */
 
-               default:
-                       DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
-                       error = -EINVAL;
+       default :
+               return  -EOPNOTSUPP;
        }
-       return (error);
-}
 
+       return  error;
+}
 
 
-#ifdef CRCASM
+#ifdef CONFIG_SBNI_MULTILINE
 
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+enslave( struct net_device  *dev,  struct net_device  *slave_dev )
 {
-       unsigned crc, dummy_len;
-       __asm__ (
-               "xorl %%eax,%%eax\n\t"
-               "1:\n\t"
-               "lodsb\n\t"
-               "xorb %%dl,%%al\n\t"
-               "shrl $8,%%edx\n\t"
-               "xorl (%%edi,%%eax,4),%%edx\n\t"
-               "loop 1b"
-               : "=d" (crc), "=c" (dummy_len)
-               : "S" (mem), "D" (&crc32tab[0]), "1" (len), "0" (initial)
-               : "eax"
-       );
-       return crc;
+       struct net_local  *nl  = (struct net_local *) dev->priv;
+       struct net_local  *snl = (struct net_local *) slave_dev->priv;
+
+       if( nl->state & FL_SLAVE )      /* This isn't master or free device */
+               return  -EBUSY;
+
+       if( snl->state & FL_SLAVE )     /* That was already enslaved */
+               return  -EBUSY;
+
+       spin_lock( &nl->lock );
+       spin_lock( &snl->lock );
+
+       /* append to list */
+       snl->link = nl->link;
+       nl->link  = slave_dev;
+       snl->master = dev;
+       snl->state |= FL_SLAVE;
+
+       /* Summary statistics of MultiLine operation will be stored
+          in master's counters */
+       memset( &snl->stats, 0, sizeof(struct net_device_stats) );
+       netif_stop_queue( slave_dev );
+       netif_wake_queue( dev );        /* Now we are able to transmit */
+
+       spin_unlock( &snl->lock );
+       spin_unlock( &nl->lock );
+       printk( KERN_NOTICE "%s: slave device (%s) attached.\n",
+               dev->name, slave_dev->name );
+       return  0;
 }
 
-#else
 
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+emancipate( struct net_device  *dev )
 {
-       unsigned crc;
-       crc = initial;
-   
-       for(;len;mem++,len--)
-       {
-               crc = CRC32(*mem, crc);
+       struct net_local   *snl = (struct net_local *) dev->priv;
+       struct net_device  *p   = snl->master;
+       struct net_local   *nl  = (struct net_local *) p->priv;
+
+       if( !(snl->state & FL_SLAVE) )
+               return  -EINVAL;
+
+       spin_lock( &nl->lock );
+       spin_lock( &snl->lock );
+       drop_xmit_queue( dev );
+
+       /* exclude from list */
+       for(;;) {       /* must be in list */
+               struct net_local  *t = (struct net_local *) p->priv;
+               if( t->link == dev ) {
+                       t->link = snl->link;
+                       break;
+               }
+               p = t->link;
        }
-       return(crc);
+
+       snl->link = NULL;
+       snl->master = dev;
+       snl->state &= ~FL_SLAVE;
+
+       netif_start_queue( dev );
+
+       spin_unlock( &snl->lock );
+       spin_unlock( &nl->lock );
+
+       dev_put( dev );
+       return  0;
 }
-#endif /* CRCASM */
+
+#endif
+
+
+static struct net_device_stats *
+sbni_get_stats( struct net_device  *dev )
+{
+       return  &((struct net_local *) dev->priv)->stats;
+}
+
+
+static void
+set_multicast_list( struct net_device  *dev )
+{
+       return;         /* sbni always operate in promiscuos mode */
+}
+
+
 #ifdef MODULE
 
-static int io[SBNI_MAX_NUM_CARDS] = { 0 };
-static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
-static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
-static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
-
-MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-
-
-static int sbniautodetect = -1;
-
-static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = {
-       {
-               "sbni0",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni1",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni2",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni3",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni4",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni5",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni6",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       },
-       {
-               "sbni7",
-               0, 0, 0, 0,             /* memory */
-               0, 0,                   /* base, irq */
-               0, 0, 0, NULL, sbni_probe 
-       }
-};
+MODULE_PARM(   io,     "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(   irq,    "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(   baud,   "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(   rxl,    "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM(   mac,    "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
 
-int init_module(void)
+MODULE_PARM(   skip_pci_probe, "i" );
+
+
+int
+init_module( void )
 {
-       int devices = 0;
-       int installed = 0;
-       int i;
+       struct net_device  *dev;
 
-       /* My simple plug for this huge init_module. "XenON */
-      
-       if(sbniautodetect != -1)
-       {
-               /* Autodetect mode */
-               printk("sbni: Autodetect mode (not recommended!) ...\n");
-               if(!sbniautodetect)
-                       sbniautodetect=SBNI_MAX_NUM_CARDS;
-               printk("Trying to find %d SBNI cards...\n", sbniautodetect);
-               if(sbniautodetect > SBNI_MAX_NUM_CARDS)
-               {
-                       sbniautodetect = SBNI_MAX_NUM_CARDS;
-                       printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+       while( num < SBNI_MAX_NUM_CARDS ) {
+               if( !(dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) ){
+                       printk( KERN_ERR "sbni: unable to allocate device!\n" );
+                       return  -ENOMEM;
                }
-               for(i = 0; i < sbniautodetect; i++)
-               {
-                       if(!register_netdev(&dev_sbni[i]))
-                               installed++;
+
+               memset( dev, 0, sizeof(struct net_device) );
+               sprintf( dev->name, "sbni%d", num );
+
+               dev->init = sbni_probe;
+               if( register_netdev( dev ) ) {
+                       kfree( dev );
+                       break;
                }
-               if(installed)
-                       return 0;
-               else
-                   return -EIO;
-       }
-       
-       /* Manual mode */
-       for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
-       {
-               if((io[i] != 0) || (irq[i] != 0))
-                       devices++;
        }
-       for(i = 0; i < devices; i++)
-       {
-               dev_sbni[i].irq = irq[i];
-               dev_sbni[i].base_addr = io[i];
-               def_rxl = rxl[i];
-               def_baud = baud[i];
-               def_mac = mac[i];
-               if(register_netdev(&dev_sbni[i]))
-                       printk("sbni: card not found!\n");
-               else
-                       installed++;
-       }
-       if(installed)
-               return 0;
-       else
-               return -EIO;
+
+       return  *sbni_cards  ?  0  :  -ENODEV;
 }
 
-void cleanup_module(void)
+void
+cleanup_module( void )
 {
-       int i;
-       for(i = 0; i < 4; i++)
-       {
-               if(dev_sbni[i].priv)
-               {
-                       free_irq(dev_sbni[i].irq, &dev_sbni[i]);
-                       release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
-                       unregister_netdev(&dev_sbni[i]);
-                       kfree(dev_sbni[i].priv);
-                       dev_sbni[i].priv = NULL;
+       struct net_device  *dev;
+       int  num;
+
+       /* No need to check MOD_IN_USE, as sys_delete_module( ) checks. */
+       for( num = 0;  num < SBNI_MAX_NUM_CARDS;  ++num )
+               if( (dev = sbni_cards[ num ]) != NULL ) {
+                       unregister_netdev( dev );
+                       release_region( dev->base_addr, SBNI_IO_EXTENT );
+                       kfree( dev->priv );
+                       kfree( dev );
                }
+}
+
+#else  /* MODULE */
+
+void __init
+sbni_setup( char  *p )
+{
+       int  n, parm;
+
+       if( *p++ != '(' )
+               goto  bad_param;
+
+       for( n = 0, parm = 0;  *p  &&  n < 8; ) {
+               (*dest[ parm ])[ n ] = simple_strtol( p, &p, 0 );
+               if( !*p  ||  *p == ')' )
+                       return;
+               if( *p == ';' )
+                       ++p, ++n, parm = 0;
+               else if( *p++ != ',' )
+                       break;
+               else
+                       if( ++parm >= 5 )
+                               break;
        }
+bad_param:
+       printk( KERN_ERR "Error in sbni kernel parameter!\n" );
+}
+
+__setup( "sbni=", sbni_setup );
+
+#endif /* MODULE */
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef ASM_CRC
+
+static u32
+calc_crc32( u32  crc,  u8  *p,  u32  len )
+{
+       register u32  _crc __asm ( "ax" );
+       _crc = crc;
+       
+       __asm __volatile (
+               "xorl   %%ebx, %%ebx\n"
+               "movl   %1, %%esi\n" 
+               "movl   %2, %%ecx\n" 
+               "movl   $crc32tab, %%edi\n"
+               "shrl   $2, %%ecx\n"
+               "jz     1f\n"
+
+               ".align 4\n"
+       "0:\n"
+               "movb   %%al, %%bl\n"
+               "movl   (%%esi), %%edx\n"
+               "shrl   $8, %%eax\n"
+               "xorb   %%dl, %%bl\n"
+               "shrl   $8, %%edx\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   %%dl, %%bl\n"
+               "shrl   $8, %%edx\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   %%dl, %%bl\n"
+               "movb   %%dh, %%dl\n" 
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   %%dl, %%bl\n"
+               "addl   $4, %%esi\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "decl   %%ecx\n"
+               "jnz    0b\n"
+
+       "1:\n"
+               "movl   %2, %%ecx\n"
+               "andl   $3, %%ecx\n"
+               "jz     2f\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   (%%esi), %%bl\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "decl   %%ecx\n"
+               "jz     2f\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   1(%%esi), %%bl\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+
+               "decl   %%ecx\n"
+               "jz     2f\n"
+
+               "movb   %%al, %%bl\n"
+               "shrl   $8, %%eax\n"
+               "xorb   2(%%esi), %%bl\n"
+               "xorl   (%%edi,%%ebx,4), %%eax\n"
+       "2:\n"
+               :
+               : "a" (_crc), "g" (p), "g" (len)
+               : "ax", "bx", "cx", "dx", "si", "di"
+       );
+
+       return  _crc;
 }
-#endif /* MODULE */
+
+#else  /* ASM_CRC */
+
+static u32
+calc_crc32( u32  crc,  u8  *p,  u32  len )
+{
+       while( len-- )
+               crc = CRC32( *p++, crc );
+
+       return  crc;
+}
+
+#endif /* ASM_CRC */
+
+
+static u32  crc32tab[] __attribute__ ((aligned(8))) = {
+       0xD202EF8D,  0xA505DF1B,  0x3C0C8EA1,  0x4B0BBE37,
+       0xD56F2B94,  0xA2681B02,  0x3B614AB8,  0x4C667A2E,
+       0xDCD967BF,  0xABDE5729,  0x32D70693,  0x45D03605,
+       0xDBB4A3A6,  0xACB39330,  0x35BAC28A,  0x42BDF21C,
+       0xCFB5FFE9,  0xB8B2CF7F,  0x21BB9EC5,  0x56BCAE53,
+       0xC8D83BF0,  0xBFDF0B66,  0x26D65ADC,  0x51D16A4A,
+       0xC16E77DB,  0xB669474D,  0x2F6016F7,  0x58672661,
+       0xC603B3C2,  0xB1048354,  0x280DD2EE,  0x5F0AE278,
+       0xE96CCF45,  0x9E6BFFD3,  0x0762AE69,  0x70659EFF,
+       0xEE010B5C,  0x99063BCA,  0x000F6A70,  0x77085AE6,
+       0xE7B74777,  0x90B077E1,  0x09B9265B,  0x7EBE16CD,
+       0xE0DA836E,  0x97DDB3F8,  0x0ED4E242,  0x79D3D2D4,
+       0xF4DBDF21,  0x83DCEFB7,  0x1AD5BE0D,  0x6DD28E9B,
+       0xF3B61B38,  0x84B12BAE,  0x1DB87A14,  0x6ABF4A82,
+       0xFA005713,  0x8D076785,  0x140E363F,  0x630906A9,
+       0xFD6D930A,  0x8A6AA39C,  0x1363F226,  0x6464C2B0,
+       0xA4DEAE1D,  0xD3D99E8B,  0x4AD0CF31,  0x3DD7FFA7,
+       0xA3B36A04,  0xD4B45A92,  0x4DBD0B28,  0x3ABA3BBE,
+       0xAA05262F,  0xDD0216B9,  0x440B4703,  0x330C7795,
+       0xAD68E236,  0xDA6FD2A0,  0x4366831A,  0x3461B38C,
+       0xB969BE79,  0xCE6E8EEF,  0x5767DF55,  0x2060EFC3,
+       0xBE047A60,  0xC9034AF6,  0x500A1B4C,  0x270D2BDA,
+       0xB7B2364B,  0xC0B506DD,  0x59BC5767,  0x2EBB67F1,
+       0xB0DFF252,  0xC7D8C2C4,  0x5ED1937E,  0x29D6A3E8,
+       0x9FB08ED5,  0xE8B7BE43,  0x71BEEFF9,  0x06B9DF6F,
+       0x98DD4ACC,  0xEFDA7A5A,  0x76D32BE0,  0x01D41B76,
+       0x916B06E7,  0xE66C3671,  0x7F6567CB,  0x0862575D,
+       0x9606C2FE,  0xE101F268,  0x7808A3D2,  0x0F0F9344,
+       0x82079EB1,  0xF500AE27,  0x6C09FF9D,  0x1B0ECF0B,
+       0x856A5AA8,  0xF26D6A3E,  0x6B643B84,  0x1C630B12,
+       0x8CDC1683,  0xFBDB2615,  0x62D277AF,  0x15D54739,
+       0x8BB1D29A,  0xFCB6E20C,  0x65BFB3B6,  0x12B88320,
+       0x3FBA6CAD,  0x48BD5C3B,  0xD1B40D81,  0xA6B33D17,
+       0x38D7A8B4,  0x4FD09822,  0xD6D9C998,  0xA1DEF90E,
+       0x3161E49F,  0x4666D409,  0xDF6F85B3,  0xA868B525,
+       0x360C2086,  0x410B1010,  0xD80241AA,  0xAF05713C,
+       0x220D7CC9,  0x550A4C5F,  0xCC031DE5,  0xBB042D73,
+       0x2560B8D0,  0x52678846,  0xCB6ED9FC,  0xBC69E96A,
+       0x2CD6F4FB,  0x5BD1C46D,  0xC2D895D7,  0xB5DFA541,
+       0x2BBB30E2,  0x5CBC0074,  0xC5B551CE,  0xB2B26158,
+       0x04D44C65,  0x73D37CF3,  0xEADA2D49,  0x9DDD1DDF,
+       0x03B9887C,  0x74BEB8EA,  0xEDB7E950,  0x9AB0D9C6,
+       0x0A0FC457,  0x7D08F4C1,  0xE401A57B,  0x930695ED,
+       0x0D62004E,  0x7A6530D8,  0xE36C6162,  0x946B51F4,
+       0x19635C01,  0x6E646C97,  0xF76D3D2D,  0x806A0DBB,
+       0x1E0E9818,  0x6909A88E,  0xF000F934,  0x8707C9A2,
+       0x17B8D433,  0x60BFE4A5,  0xF9B6B51F,  0x8EB18589,
+       0x10D5102A,  0x67D220BC,  0xFEDB7106,  0x89DC4190,
+       0x49662D3D,  0x3E611DAB,  0xA7684C11,  0xD06F7C87,
+       0x4E0BE924,  0x390CD9B2,  0xA0058808,  0xD702B89E,
+       0x47BDA50F,  0x30BA9599,  0xA9B3C423,  0xDEB4F4B5,
+       0x40D06116,  0x37D75180,  0xAEDE003A,  0xD9D930AC,
+       0x54D13D59,  0x23D60DCF,  0xBADF5C75,  0xCDD86CE3,
+       0x53BCF940,  0x24BBC9D6,  0xBDB2986C,  0xCAB5A8FA,
+       0x5A0AB56B,  0x2D0D85FD,  0xB404D447,  0xC303E4D1,
+       0x5D677172,  0x2A6041E4,  0xB369105E,  0xC46E20C8,
+       0x72080DF5,  0x050F3D63,  0x9C066CD9,  0xEB015C4F,
+       0x7565C9EC,  0x0262F97A,  0x9B6BA8C0,  0xEC6C9856,
+       0x7CD385C7,  0x0BD4B551,  0x92DDE4EB,  0xE5DAD47D,
+       0x7BBE41DE,  0x0CB97148,  0x95B020F2,  0xE2B71064,
+       0x6FBF1D91,  0x18B82D07,  0x81B17CBD,  0xF6B64C2B,
+       0x68D2D988,  0x1FD5E91E,  0x86DCB8A4,  0xF1DB8832,
+       0x616495A3,  0x1663A535,  0x8F6AF48F,  0xF86DC419,
+       0x660951BA,  0x110E612C,  0x88073096,  0xFF000000
+};
+
index ce44bea464056e3350b2bdad33b810704face792..335dbf13f4d67010f200d97e7bc64424641acdbb 100644 (file)
@@ -1,25 +1,10 @@
-/*
- * sbni.h - header file for sbni linux device driver
- *
- * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
- *
- */
-
-/*
- * SBNI12 definitions
- *
- * Revision 2.0.0  1997/08/27
- * Initial revision
- *
- * Revision 2.1.0  1999/04/26
- * dev_priv structure changed to support balancing and some other features.
- *
+/* sbni.h:  definitions for a Granch SBNI12 driver, version 5.0.0
+ * Written 2001 Denis I.Timofeev (timofeev@granch.ru)
+ * This file is distributed under the GNU GPL
  */
 
-#ifndef __SBNI_H
-#define __SBNI_H
-
-#define SBNI_DEBUG 0
+#ifndef SBNI_H
+#define SBNI_H
 
 #if SBNI_DEBUG
 #define DP( A ) A
 #define DP( A )
 #endif
 
-typedef unsigned char BOOLEAN;
 
-#define TRUE 1
-#define FALSE 0
+/* We don't have official vendor id yet... */
+#define SBNI_PCI_VENDOR        0x55 
+#define SBNI_PCI_DEVICE        0x9f
 
-#define        SBNI_IO_EXTENT  0x4
-#define SB_MAX_BUFFER_ARRAY 1023
+#define ISA_MODE 0x00
+#define PCI_MODE 0x01
 
-#define CSR0   0
-#define CSR1   1
+#define        SBNI_IO_EXTENT  4
 
-#define        DAT     2
+enum sbni_reg {
+       CSR0 = 0,
+       CSR1 = 1,
+       DAT  = 2
+};
 
 /* CSR0 mapping */
-#define BU_EMP (1 << 1)        /* r z    */
-#define        RC_CHK  (1 << 2)        /* rw     */
-#define        CT_ZER  (1 << 3)        /*  w     */
-#define        TR_REQ  (1 << 4)        /* rwz*   */
+enum {
+       BU_EMP = 0x02,
+       RC_CHK = 0x04,
+       CT_ZER = 0x08,
+       TR_REQ = 0x10,
+       TR_RDY = 0x20,
+       EN_INT = 0x40,
+       RC_RDY = 0x80
+};
 
-#define TR_RDY (1 << 5)        /* r z    */
-#define EN_INT (1 << 6)        /* rwz* */
-#define RC_RDY (1 << 7)        /* r z    */
 
 /* CSR1 mapping */
-#define PR_RES (1 << 7)        /*  w     */
+#define PR_RES 0x80
 
 struct sbni_csr1 {
-       unsigned rxl:5;
-       unsigned rate:2;
-       unsigned:1;
+       unsigned rxl    : 5;
+       unsigned rate   : 2;
+       unsigned        : 1;
 };
 
-#define DEF_RXL_DELTA  -1
-#define DEF_RXL                0xf
-#define DEF_RATE       0
-#define DEF_FRAME_LEN  (1023 - 14 - 9)
-
-#ifdef MODULE
-
-#define SBNI_MAX_NUM_CARDS 8
-#define SBNI_MAX_SLAVES 8
-
-
-#endif                         /* MODULE */
-
-#define SBNI_SIG 0x5a
-
-#define        SB_ETHER_MIN_LEN 60
-
-#define SB_FILLING_CHAR (unsigned char)0x00
-#define TR_ERROR_COUNT 32
-#define CHANGE_LEVEL_START_TICKS 4
-#define SBNI_INTERNAL_QUEUE_SIZE 10    /* 100 ? */
-
-#define PACKET_FIRST_FRAME (unsigned short)0x8000
-#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
-#define PACKET_RESEND 0x4000
-#define PACKET_SEND_OK 0x3000
-#define PACKET_LEN_MASK (unsigned short)0x03ff
-#define PACKET_INF_MASK (unsigned short)0x7000
-
-#define ETHER_ADDR_LEN 6
-
-#define SBNI_TIMEOUT HZ/10     /* ticks to wait for pong or packet */
-               /* sbni watchdog called SBNI_HZ times per sec. */
-
-struct sbni_in_stats {
-       unsigned int all_rx_number;
-       unsigned int bad_rx_number;
-       unsigned int timeout_number;
-       unsigned int all_tx_number;
-       unsigned int resend_tx_number;
+/* fields in frame header */
+#define FRAME_ACK_MASK  (unsigned short)0x7000
+#define FRAME_LEN_MASK  (unsigned short)0x03FF
+#define FRAME_FIRST     (unsigned short)0x8000
+#define FRAME_RETRY     (unsigned short)0x0800
+
+#define FRAME_SENT_BAD  (unsigned short)0x4000
+#define FRAME_SENT_OK   (unsigned short)0x3000
+
+
+/* state flags */
+enum {
+       FL_WAIT_ACK    = 0x01,
+       FL_NEED_RESEND = 0x02,
+       FL_PREV_OK     = 0x04,
+       FL_SLOW_MODE   = 0x08,
+       FL_SECONDARY   = 0x10,
+#ifdef CONFIG_SBNI_MULTILINE
+       FL_SLAVE       = 0x20,
+#endif
+       FL_LINE_DOWN   = 0x40
 };
 
 
-/*
- *    Board-specific info in dev->priv. 
- */
-struct net_local {
-       struct net_device_stats stats;
-
-       struct timer_list watchdog;
-       unsigned int realframelen;      /* the current size of the SB-frame */
-       unsigned int eth_trans_buffer_len;      /* tx buffer length */
-       unsigned int outpos;
-       unsigned int inppos;
-       unsigned int frame_len; /* The set SB-frame size */
-       unsigned int tr_err;
-       unsigned int timer_ticks;
-       BOOLEAN last_receive_OK;
-       BOOLEAN tr_resend;
-
-       unsigned char wait_frame_number;
-       unsigned char eth_trans_buffer[1520];   /* tx buffer */
-       unsigned char HSCounter;        /* Reserved field */
-       unsigned char eth_rcv_buffer[2600];     /* rx buffer */
-       struct sbni_csr1 csr1;
-       /* Internal Statistics */
-       struct sbni_in_stats in_stats;
-
-       int rxl_curr;           /* current receive level value [0..0xf] */
-       int rxl_delta;          /* receive level delta (+1, -1)
-                                  rxl_delta == 0 - receive level
-                                  autodetection
-                                  disabled            */
-       unsigned int ok_curr;   /* current ok frames received           */
-       unsigned int ok_prev;   /* previous ok frames received          */
-       unsigned int timeout_rxl;
-
-       struct sk_buff_head queue;
-       struct sk_buff *currframe;
-       BOOLEAN waitack;
-
-       struct net_device *m;   /* master */
-       struct net_device *me;  /* me */
-       struct net_local *next_lp;      /* next lp */
-
-       int carrier;
-
-       spinlock_t lock;
+enum {
+       DEFAULT_IOBASEADDR = 0x210,
+       DEFAULT_INTERRUPTNUMBER = 5,
+       DEFAULT_RATE = 0,
+       DEFAULT_FRAME_LEN = 1012
 };
 
+#define DEF_RXL_DELTA  -1
+#define DEF_RXL                0xf
 
-struct sbni_hard_header {
-
-       /* internal sbni stuff */
-       unsigned int crc;       /* 4 */
-       unsigned short packetlen;       /* 2 */
-       unsigned char number;   /* 1 */
-       unsigned char reserv;   /* 1 */
+#define SBNI_SIG 0x5a
 
-       /* 8 */
+#define        SBNI_MIN_LEN    60      /* Shortest Ethernet frame without FCS */
+#define SBNI_MAX_FRAME 1023
+#define ETHER_MAX_LEN  1518
 
-       /* ethernet stuff */
-       unsigned char h_dest[ETH_ALEN];         /* destination eth addr */
-       unsigned char h_source[ETH_ALEN];       /* source ether addr    */
-       unsigned short h_proto; /* packet type ID field */
-       /* +14 */
-       /* 22 */
+#define SBNI_TIMEOUT   (HZ/10)
 
-};
+#define TR_ERROR_COUNT 32
+#define CHANGE_LEVEL_START_TICKS 4
 
-#define SBNI_HH_SZ 22
+#define SBNI_MAX_NUM_CARDS     16
 
-struct sbni_flags {
-       unsigned rxl:4;
-       unsigned rate:2;
-       unsigned fixed_rxl:1;
-       unsigned fixed_rate:1;
+/* internal SBNI-specific statistics */
+struct sbni_in_stats {
+       u32     all_rx_number;
+       u32     bad_rx_number;
+       u32     timeout_number;
+       u32     all_tx_number;
+       u32     resend_tx_number;
 };
 
-#define RCV_NO 0
-#define RCV_OK 1
-#define RCV_WR 2
-
-
+/* SBNI ioctl params */
 #define SIOCDEVGETINSTATS      SIOCDEVPRIVATE
 #define SIOCDEVRESINSTATS      SIOCDEVPRIVATE+1
 #define SIOCDEVGHWSTATE        SIOCDEVPRIVATE+2
@@ -191,4 +114,30 @@ struct sbni_flags {
 #define SIOCDEVEMANSIPATE      SIOCDEVPRIVATE+5
 
 
-#endif                         /* __SBNI_H */
+/* data packet for SIOCDEVGHWSTATE/SIOCDEVSHWSTATE ioctl requests */
+struct sbni_flags {
+       u32     rxl             : 4;
+       u32     rate            : 2;
+       u32     fixed_rxl       : 1;
+       u32     slow_mode       : 1;
+       u32     mac_addr        : 24;
+};
+
+/*
+ * CRC-32 stuff
+ */
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+      /* CRC generator 0xEDB88320 */
+      /* CRC remainder 0x2144DF1C */
+      /* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
+
+#ifndef __initdata
+#define __initdata
+#endif
+
+#define min( x, y )    ( (x) < (y)  ?  (x)  :  (y) )
+
+#endif
+
index 40f0b3b20700f4759fa031846a18fd102e3e38a0..cd25d8781be38b0adb20bec831e2745e57b757ba 100644 (file)
@@ -57,6 +57,8 @@
 #include <pcmcia/ss.h>
 #include <pcmcia/cs.h>
 
+#include <linux/isapnp.h>
+
 /* ISA-bus controllers */
 #include "i82365.h"
 #include "cirrus.h"
@@ -816,10 +818,56 @@ static void __init add_pcic(int ns, int type)
 
 #ifdef CONFIG_ISA
 
+#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#define I82365_ISAPNP
+#endif
+
+#ifdef I82365_ISAPNP
+static struct isapnp_device_id id_table[] __initdata = {
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+               ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+               ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
+       {       ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+               ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
+       {       0 }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+static struct pci_dev *i82365_pnpdev;
+#endif
+
 static void __init isa_probe(void)
 {
     int i, j, sock, k, ns, id;
     ioaddr_t port;
+#ifdef I82365_ISAPNP
+    struct isapnp_device_id *devid;
+    struct pci_dev *dev;
+
+    for (devid = id_table; devid->vendor; devid++) {
+       if ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
+           printk("ISAPNP ");
+
+           if (dev->prepare && dev->prepare(dev) < 0) {
+               printk("prepare failed\n");
+               break;
+           }
+
+           if (dev->activate && dev->activate(dev) < 0) {
+               printk("activate failed\n");
+               break;
+           }
+
+           if ((i365_base = pci_resource_start(dev, 0))) {
+               printk("no resources ?\n");
+               break;
+           }
+           i82365_pnpdev = dev;
+           break;
+       }
+    }
+#endif
 
     if (check_region(i365_base, 2) != 0) {
        if (sockets == 0)
@@ -1604,6 +1652,10 @@ static void __exit exit_i82365(void)
        i365_set(i, I365_CSCINT, 0);
        release_region(socket[i].ioaddr, 2);
     }
+#if defined(CONFIG_ISA) && defined(I82365_ISAPNP)
+    if (i82365_pnpdev && i82365_pnpdev->deactivate)
+               i82365_pnpdev->deactivate(i82365_pnpdev);
+#endif
 } /* exit_i82365 */
 
 module_init(init_i82365);
index de0fa6cfa20127089413c714880bf695c514f9b8..86e80955606eb51e2cdc23459c1aea8d79962f91 100644 (file)
@@ -8,4 +8,8 @@ tristate 'Plug and Play support' CONFIG_PNP
 
 dep_tristate '  ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
 
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   dep_bool '  PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP
+fi
+
 endmenu
index 4fe5cab40a50d519d428e0da0bbbc0db241ea081..1619a064d153f27c0a0fa2b520f4a8145172778b 100644 (file)
@@ -35,19 +35,18 @@ fi
 
 comment 'S/390 character device drivers'
 
-tristate 'Support for locally attached 3270 tubes' CONFIG_3270
-if [ "$CONFIG_3270" = "y" ]; then
-  bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE
+tristate 'Support for locally attached 3270 tubes' CONFIG_TN3270
+if [ "$CONFIG_TN3270" = "y" ]; then
+  bool 'Support for console on 3270 line mode terminal' CONFIG_TN3270_CONSOLE
 fi
-if [ "$CONFIG_3270_CONSOLE" != "y" ]; then
-  bool 'Support for 3215 line mode terminal' CONFIG_3215
-  if [ "$CONFIG_3215" = "y" ]; then
-    bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
-  fi
+bool 'Support for 3215 line mode terminal' CONFIG_TN3215
+if [ "$CONFIG_TN3215" = "y" ]; then
+  bool 'Support for console on 3215 line mode terminal' CONFIG_TN3215_CONSOLE
 fi
 bool 'Support for HWC line mode terminal' CONFIG_HWC
 if [ "$CONFIG_HWC" = "y" ]; then
-  bool 'console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+  bool '   console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+  tristate '   Control-Program Identification' CONFIG_HWC_CPI
 fi
 tristate 'S/390 tape device support' CONFIG_S390_TAPE
 if [ "$CONFIG_S390_TAPE" != "n" ]; then
@@ -67,11 +66,18 @@ if [ "$CONFIG_NET" = "y" ]; then
 
   if [ "$CONFIG_NETDEVICES" = "y" ]; then
     tristate 'Dummy net driver support' CONFIG_DUMMY
+    tristate 'Bonding driver support' CONFIG_BONDING
+    tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+    tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
     bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
     bool 'Token Ring driver support' CONFIG_TR
     bool 'FDDI driver support' CONFIG_FDDI
     comment 'S/390 network device drivers'
-    bool 'Channel Device Configuration (Temporary Option)' CONFIG_CHANDEV
+    bool 'Channel Device Configuration' CONFIG_CHANDEV
+    if [ "$CONFIG_CHANDEV" = "y" ]; then
+       define_bool CONFIG_HOTPLUG y
+    fi
+
     tristate 'CTC device support' CONFIG_CTC
     tristate 'IUCV device support (VM only)' CONFIG_IUCV
   fi
index 0852e7c6dc8a89b9f5906b1d47dd03bf9944d794..13f62f9ad3547769ab9c3f585bd492802aa0e317 100644 (file)
@@ -6,9 +6,10 @@ O_TARGET := io.o
 
 subdir-y := block char misc net
 subdir-m := $(subdir-y)
-obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
 
-obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
+obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
 export-objs += ccwcache.o idals.o s390dyn.o s390io.o
 
+obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
+
 include $(TOPDIR)/Rules.make
index 8aeceaab7ffa922764d8ce1fb3fa14eb344431e9..58e3de6c43fc1b393337711f0a97992656e44ace 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/tqueue.h>
 #include <linux/timer.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/genhd.h>
 #include <linux/hdreg.h>
 #include <linux/interrupt.h>
 #include "dasd_diag.h"
 #endif                         /*  CONFIG_DASD_DIAG */
 
+/* SECTION: exported variables of dasd.c */
+
+debug_info_t *dasd_debug_area;
+
 MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
                    " Copyright 2000 IBM Corporation");
index efe067d63c01940d45496ac2b88f8137d28e186b..945d21938c2eadfe31b1ccd46a4a41cb952c0a32 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
 #include <linux/blk.h>
 #include <asm/ccwcache.h>
index 134169a8f45f6f779cf0f420f029d2d3fca4efc5..ed2b888cd8b56d253055bc70fe32a6b1e328bceb 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
 #include <linux/blk.h>
 #include <asm/ccwcache.h>
index 3d32750056cabe771af00da894030320e713ae42..a94017a289a554b5bb2277d6155d2ebb576f90d9 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <asm/debug.h>
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/hdreg.h>       /* HDIO_GETGEO                      */
 #include <linux/blk.h>
 #include <asm/ccwcache.h>
index 1f744fe69ea7519de305426c2f7496e843442ab1..a7af24bf971272cae131f8f607649e38da11e256 100644 (file)
@@ -74,7 +74,7 @@ char kernel_version [] = UTS_RELEASE;
 #endif /* V24 */
 #include <linux/sched.h>
 #include <linux/kernel.h> /* printk() */
-#include <linux/malloc.h> /* kmalloc() */
+#include <linux/slab.h> /* kmalloc() */
 #if (XPRAM_VERSION == 24)
 #  include <linux/devfs_fs_kernel.h>
 #endif /* V24 */
@@ -92,6 +92,7 @@ char kernel_version [] = UTS_RELEASE;
 #if (XPRAM_VERSION == 24)
 #define MAJOR_NR xpram_major /* force definitions on in blk.h */
 int xpram_major;   /* must be declared before including blk.h */
+devfs_handle_t xpram_devfs_handle;
 
 #define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
 #define DEVICE_NAME "xpram"               /* name for messaging */
@@ -999,12 +1000,18 @@ int xpram_init(void)
 #elif (XPRAM_VERSION == 24)
        result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
 #endif /* V22/V24 */
-       
        if (result < 0) {
                PRINT_ERR("Can't get major %d\n",xpram_major);
                 PRINT_ERR("Giving up xpram\n");
                return result;
        }
+#if (XPRAM_VERSION == 24)
+       xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
+       devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
+                              DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
+                              S_IFBLK | S_IRUSR | S_IWUSR,
+                              &xpram_devops, NULL);
+#endif /* V22/V24 */
        if (xpram_major == 0) xpram_major = result; /* dynamic */
        major = xpram_major; /* Use `major' later on to save typing */
 
@@ -1226,6 +1233,12 @@ void cleanup_module(void)
        kfree(xpram_offsets);
 
                                /* finally, the usual cleanup */
+#if (XPRAM_VERSION == 22)
        unregister_blkdev(major, "xpram");
+#elif (XPRAM_VERSION == 24)
+       devfs_unregister(xpram_devfs_handle);
+       if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
+               printk(KERN_WARNING "xpram: cannot unregister blkdev\n");
+#endif /* V22/V24 */
        kfree(xpram_devices);
 }
index e8e43f5d63e0d6bd5eda2db75aaf8f47f22714ee..ea4e26aa9268fb8f17cc9f4b98239d9bde7bbefa 100644 (file)
@@ -10,7 +10,7 @@
  */
 
 #include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/version.h>
 
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
index 6cf855c01200830da6b15489a97f9b0616958832..09ba9adf7791c7cbd4973f10062744c4b6a40fa7 100644 (file)
@@ -1,42 +1,33 @@
-# Makefile for the S/390 supported character devices
 #
-# 4 January 2001 Richard Hitt
-# Modeled after similar files of Michael Elizabeth Chastain
-# Rewritten to use lists instead of if-statements.
+# S/390 character devices
+#
 
-O_TARGET       := s390-char.o
+O_TARGET := s390-char.o
 
-export-objs     :=
 list-multi     := tub3270.o tape390.o
 
-obj-y          :=
-obj-m          :=
-obj-n          :=
-obj-           :=
+tub3270-objs := tuball.o tubfs.o tubtty.o \
+                     tubttyaid.o tubttybld.o tubttyscl.o \
+                     tubttyrcl.o tubttysiz.o
 
-tub3270-objs                   := tuball.o tubfs.o tubtty.o \
-                                       tubttyaid.o tubttybld.o tubttyrcl.o \
-                                       tubttyscl.o tubttysiz.o
+tape390-$(CONFIG_S390_TAPE_CHAR) += tapechar.o
+tape390-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
+tape390-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o
+tape390-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o
+tape390-objs := tape.o $(sort $(tape390-y))
 
 obj-y += ctrlchar.o
-obj-$(CONFIG_3215_CONSOLE)     += con3215.o
-obj-$(CONFIG_HWC)              += hwc_con.o hwc_rw.o hwc_tty.o
-obj-$(CONFIG_3270)             += tub3270.o
-
-tape-y                         := tape.o
-tape-$(CONFIG_S390_TAPE_CHAR)  += tapechar.o
-tape-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
-tape-$(CONFIG_S390_TAPE_3480)  += tape3480.o tape34xx.o
-tape-$(CONFIG_S390_TAPE_3490)  += tape3490.o tape34xx.o
-tape390-objs                   := $(sort $(tape-y))
-obj-$(CONFIG_S390_TAPE)                += tape390.o
-
-# Hand off to Rules.make.
+obj-$(CONFIG_TN3215) += con3215.o
+obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
+obj-$(CONFIG_HWC_CPI) += hwc_cpi.o
+obj-$(CONFIG_TN3270) += tub3270.o
+obj-$(CONFIG_S390_TAPE) += tape390.o
 
 include $(TOPDIR)/Rules.make
 
-tub3270.o:     $(tub3270-objs)
+tub3270.o: $(tub3270-objs)
        $(LD) -r -o $@ $(tub3270-objs)
 
-tape390.o:     $(tape390-objs)
+tape390.o: $(tape390-objs)
        $(LD) -r -o $@ $(tape390-objs)
+
index 1600c33bf2139331adac4fa5163ca0db7130aaa2..8823b5b4bee7d4f4e19beb5340d6df0a902054b7 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/delay.h>
 #include <asm/cpcmd.h>
 #include <asm/irq.h>
+#include <asm/setup.h>
 
 #include "ctrlchar.h"
 
@@ -115,18 +116,6 @@ static int tty3215_refcount;
 #define MIN(a,b)       ((a) < (b) ? (a) : (b))
 #endif
 
-static int __init con3215_setup(char *str)
-{
-        int vdev;
-
-        vdev = simple_strtoul(str,&str,0);
-        if (vdev >= 0 && vdev < 65536)
-                raw3215_condevice = vdev;
-        return 1;
-}
-
-__setup("condev=", con3215_setup);
-
 /*
  * Get a request structure from the free list
  */
@@ -765,7 +754,7 @@ raw3215_find_dev(int number)
         while (count <= number && irq != -ENODEV) {
                 if (get_dev_info(irq, &dinfo) == -ENODEV)
                         break;
-                if (dinfo.devno == raw3215_condevice ||
+                if (dinfo.devno == console_device ||
                     dinfo.sid_data.cu_type == 0x3215) {
                         count++;
                     if (count > number)
@@ -776,7 +765,7 @@ raw3215_find_dev(int number)
         return -1;            /* console not found */
 }
 
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
 
 /*
  * Write a string to the 3215 console
@@ -1070,14 +1059,19 @@ void __init con3215_init(void)
 {
        raw3215_info *raw;
        raw3215_req *req;
+       int irq;
        int i;
 
-       if (!MACHINE_IS_VM && !MACHINE_IS_P390)
-                return;
-        if (MACHINE_IS_VM) {
-               cpcmd("TERM CONMODE 3215", NULL, 0);
-               cpcmd("TERM AUTOCR OFF", NULL, 0);
-        }
+       /* Check if 3215 is to be the console */
+       if (!CONSOLE_IS_3215)
+               return;
+       irq = raw3215_find_dev(0);
+
+       /* Set the console mode for VM */
+       if (MACHINE_IS_VM) {
+               cpcmd("TERM CONMODE 3215", NULL, 0);
+               cpcmd("TERM AUTOCR OFF", NULL, 0);
+       }
 
        /* allocate 3215 request structures */
        raw3215_freelist = NULL;
@@ -1090,7 +1084,7 @@ void __init con3215_init(void)
 
        ctrlchar_init();
 
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
         raw3215[0] = raw = (raw3215_info *)
                 alloc_bootmem_low(sizeof(raw3215_info));
        memset(raw, 0, sizeof(raw3215_info));
@@ -1126,8 +1120,6 @@ void __init con3215_init(void)
  */
 void __init tty3215_init(void)
 {
-       if (!MACHINE_IS_VM && !MACHINE_IS_P390)
-                return;
        /*
         * Initialize the tty_driver structure
         * Entries in tty3215_driver that are NOT initialized:
index 19ce7629509f9e4a9b0acdf8cdbcc2cf306909a1..f2d3492d8e50860c664ec80fad5928fb8198fb4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  drivers/s390/char/controlchar.c
+ *  drivers/s390/char/ctrlchar.c
  *  Unified handling of special chars.
  *
  *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
index 47cd67fd443943fc2e8818ac396290150d9fced9..8a10bbd8340d12d25b1f27c88b9fefac2d1b2387 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  drivers/s390/char/controlchar.c
+ *  drivers/s390/char/ctrlchar.c
  *  Unified handling of special chars.
  *
  *    Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
@@ -7,6 +7,7 @@
  *
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/tty.h>
 
index 4e5893696538b4690c810db076c2a5b83a96de6a..4c5c6ea2adb9d793609953aa4ad58482d7e2dd58 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  * 
  * 
 #ifndef __HWC_H__
 #define __HWC_H__
 
+#define HWC_EXT_INT_PARAM_ADDR 0xFFFFFFF8
+#define HWC_EXT_INT_PARAM_PEND 0x00000001
+
 #define ET_OpCmd               0x01
 #define ET_Msg         0x02
 #define ET_StateChange 0x08
 #define ET_PMsgCmd             0x09
 #define ET_CntlProgOpCmd       0x20
+#define ET_CntlProgIdent       0x0B
 
 #define ET_OpCmd_Mask  0x80000000
 #define ET_Msg_Mask            0x40000000
 #define ET_StateChange_Mask    0x01000000
 #define ET_PMsgCmd_Mask        0x00800000
 #define ET_CtlProgOpCmd_Mask   0x00000001
+#define ET_CtlProgIdent_Mask   0x00200000
 
 #define GMF_DOM                0x8000
 #define GMF_SndAlrm    0x4000
@@ -210,7 +215,7 @@ static init_hwcb_t init_hwcb_template =
        0x0000,
        sizeof (_hwcb_mask_t),
        ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
-       ET_Msg_Mask | ET_PMsgCmd_Mask
+       ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
 };
 
 typedef struct {
index 3e9d79cf11ac00aa42bdb76adff45348e2ddf174..92e1f2d74a232365abbb885fda53410113aff38b 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  */
 
 #include <linux/config.h>
@@ -17,7 +17,6 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 
-#include "ctrlchar.h"
 #include "hwc_rw.h"
 
 #ifdef CONFIG_HWC_CONSOLE
@@ -82,20 +81,14 @@ hwc_console_unblank (void)
 void __init 
 hwc_console_init (void)
 {
-
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
-       if (MACHINE_IS_VM)
-               return;
-#endif
-       if (MACHINE_IS_P390)
+       if (!MACHINE_HAS_HWC)
                return;
 
-       ctrlchar_init ();
-  
        if (hwc_init () == 0) {
 #ifdef CONFIG_HWC_CONSOLE
 
-               register_console (&hwc_console);
+               if (CONSOLE_IS_HWC)
+                       register_console (&hwc_console);
 #endif
        } else
                panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
diff --git a/drivers/s390/char/hwc_cpi.c b/drivers/s390/char/hwc_cpi.c
new file mode 100644 (file)
index 0000000..404830c
--- /dev/null
@@ -0,0 +1,199 @@
+
+/*
+ * Author: Martin Peschke <mpeschke@de.ibm.com>
+ * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/ebcdic.h>
+#include "hwc_rw.h"
+#include "hwc.h"
+
+#define CPI_LENGTH_SYSTEM_TYPE 8
+#define CPI_LENGTH_SYSTEM_NAME 8
+#define CPI_LENGTH_SYSPLEX_NAME        8
+
+typedef struct {
+       _EBUF_HEADER
+       u8 id_format;
+       u8 reserved0;
+       u8 system_type[CPI_LENGTH_SYSTEM_TYPE];
+       u64 reserved1;
+       u8 system_name[CPI_LENGTH_SYSTEM_NAME];
+       u64 reserved2;
+       u64 system_level;
+       u64 reserved3;
+       u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
+       u8 reserved4[16];
+} __attribute__ ((packed)) 
+
+cpi_evbuf_t;
+
+typedef struct _cpi_hwcb_t {
+       _HWCB_HEADER
+       cpi_evbuf_t cpi_evbuf;
+} __attribute__ ((packed)) 
+
+cpi_hwcb_t;
+
+cpi_hwcb_t *cpi_hwcb;
+
+static int __init cpi_module_init (void);
+static void __exit cpi_module_exit (void);
+
+module_init (cpi_module_init);
+module_exit (cpi_module_exit);
+
+MODULE_AUTHOR (
+                     "Martin Peschke, IBM Deutschland Entwicklung GmbH "
+                     "<mpeschke@de.ibm.com>");
+
+MODULE_DESCRIPTION (
+  "identify this operating system instance to the S/390 or zSeries hardware");
+
+static char *system_name = NULL;
+MODULE_PARM (system_name, "s");
+MODULE_PARM_DESC (system_name, "e.g. hostname - max. 8 characters");
+
+static char *sysplex_name = NULL;
+#ifdef ALLOW_SYSPLEX_NAME
+MODULE_PARM (sysplex_name, "s");
+MODULE_PARM_DESC (sysplex_name, "if applicable - max. 8 characters");
+#endif
+
+static char *system_type = "LINUX";
+
+hwc_request_t cpi_request =
+{};
+
+hwc_callback_t cpi_callback;
+
+static DECLARE_MUTEX_LOCKED (sem);
+
+static int __init 
+cpi_module_init (void)
+{
+       int retval;
+       int system_type_length;
+       int system_name_length;
+       int sysplex_name_length = 0;
+
+       if (!MACHINE_HAS_HWC) {
+               printk ("cpi: bug: hardware console not present\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       if (!system_type) {
+               printk ("cpi: bug: no system type specified\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       system_type_length = strlen (system_type);
+       if (system_type_length > CPI_LENGTH_SYSTEM_NAME) {
+               printk ("cpi: bug: system type has length of %i characters - "
+                       "only %i characters supported\n",
+                       system_type_length,
+                       CPI_LENGTH_SYSTEM_TYPE);
+               retval = -EINVAL;
+               goto out;
+       }
+       if (!system_name) {
+               printk ("cpi: no system name specified\n");
+               retval = -EINVAL;
+               goto out;
+       }
+       system_name_length = strlen (system_name);
+       if (system_name_length > CPI_LENGTH_SYSTEM_NAME) {
+               printk ("cpi: system name has length of %i characters - "
+                       "only %i characters supported\n",
+                       system_name_length,
+                       CPI_LENGTH_SYSTEM_NAME);
+               retval = -EINVAL;
+               goto out;
+       }
+       if (sysplex_name) {
+               sysplex_name_length = strlen (sysplex_name);
+               if (sysplex_name_length > CPI_LENGTH_SYSPLEX_NAME) {
+                       printk ("cpi: sysplex name has length of %i characters - "
+                               "only %i characters supported\n",
+                               sysplex_name_length,
+                               CPI_LENGTH_SYSPLEX_NAME);
+                       retval = -EINVAL;
+                       goto out;
+               }
+       }
+       cpi_hwcb = kmalloc (sizeof (cpi_hwcb_t), GFP_KERNEL);
+       if (!cpi_hwcb) {
+               printk ("cpi: no storage to fulfill request\n");
+               retval = -ENOMEM;
+               goto out;
+       }
+       memset (cpi_hwcb, 0, sizeof (cpi_hwcb_t));
+
+       cpi_hwcb->length = sizeof (cpi_hwcb_t);
+       cpi_hwcb->cpi_evbuf.length = sizeof (cpi_evbuf_t);
+       cpi_hwcb->cpi_evbuf.type = 0x0B;
+
+       memset (cpi_hwcb->cpi_evbuf.system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
+       memcpy (cpi_hwcb->cpi_evbuf.system_type, system_type, system_type_length);
+       HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+       EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+
+       memset (cpi_hwcb->cpi_evbuf.system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
+       memcpy (cpi_hwcb->cpi_evbuf.system_name, system_name, system_name_length);
+       HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+       EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+
+       cpi_hwcb->cpi_evbuf.system_level = LINUX_VERSION_CODE;
+
+       if (sysplex_name) {
+               memset (cpi_hwcb->cpi_evbuf.sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
+               memcpy (cpi_hwcb->cpi_evbuf.sysplex_name, sysplex_name, sysplex_name_length);
+               HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+               EBC_TOUPPER (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+       }
+       cpi_request.block = cpi_hwcb;
+       cpi_request.word = HWC_CMDW_WRITEDATA;
+       cpi_request.callback = cpi_callback;
+
+       retval = hwc_send (&cpi_request);
+       if (retval) {
+               printk ("cpi: failed (%i)\n", retval);
+               goto free;
+       }
+       down (&sem);
+
+       switch (cpi_hwcb->response_code) {
+       case 0x0020:
+               printk ("cpi: succeeded\n");
+               break;
+       default:
+               printk ("cpi: failed with response code 0x%x\n",
+                       cpi_hwcb->response_code);
+       }
+
+      free:
+       kfree (cpi_hwcb);
+
+      out:
+       return retval;
+}
+
+static void __exit 
+cpi_module_exit (void)
+{
+       printk ("cpi: exit\n");
+}
+
+void 
+cpi_callback (hwc_request_t * req)
+{
+       up (&sem);
+}
index 179d5307f1905739347b0f6e492bb920514018de..37994da92f6f767a984856edd45bc8d7e8861ae3 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  * 
  *
@@ -20,6 +20,7 @@
 #include <linux/mm.h>
 #include <linux/timer.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <asm/setup.h>
 #include <asm/page.h>
 #include <asm/s390_ext.h>
+#include <asm/irq.h>
 
 #ifndef MIN
 #define MIN(a,b) (((a<b) ? a : b))
 #endif
 
-#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
-
-#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
-
 #define HWC_RW_PRINT_HEADER "hwc low level driver: "
 
 #define  USE_VM_DETECTION
 
 #define  DEFAULT_CASE_DELIMITER '%'
 
-#define DUMP_HWC_INIT_ERROR
+#undef DUMP_HWC_INIT_ERROR
 
-#define DUMP_HWC_WRITE_ERROR
+#undef DUMP_HWC_WRITE_ERROR
 
-#define DUMP_HWC_WRITE_LIST_ERROR
+#undef DUMP_HWC_WRITE_LIST_ERROR
 
-#define DUMP_HWC_READ_ERROR
+#undef DUMP_HWC_READ_ERROR
 
 #undef DUMP_HWCB_INPUT
 
@@ -179,6 +177,8 @@ static struct {
 
        hwc_high_level_calls_t *calls;
 
+       hwc_request_t *request;
+
        spinlock_t lock;
 
        struct timer_list write_timer;
@@ -222,6 +222,7 @@ static struct {
            0,
            0,
            0,
+           NULL,
            NULL
 
 };
@@ -327,15 +328,15 @@ service_call (
        return condition_code;
 }
 
-static inline unsigned char *
-ext_int_param (void)
+static inline unsigned long 
+hwc_ext_int_param (void)
 {
        u32 param;
 
        __asm__ __volatile__ ("L %0,128\n\t"
                              :"=r" (param));
 
-       return ((unsigned char *) param);
+       return (unsigned long) param;
 }
 
 static int 
@@ -417,11 +418,11 @@ sane_write_hwcb (void)
                internal_print (
                                       DELAYED_WRITE,
                                       HWC_RW_PRINT_HEADER
-                       "found invalid HWCB at address 0x%x. List corrupted. "
+                      "found invalid HWCB at address 0x%lx. List corrupted. "
                           "Lost %i HWCBs with %i characters within up to %i "
                           "messages. Saved %i HWCB with last %i characters i"
                                       "within up to %i messages.\n",
-                                      (unsigned int) bad_addr,
+                                      (unsigned long) bad_addr,
                                       lost_hwcb, lost_char, lost_msg,
                                       hwc_data.hwcb_count,
                                       ALL_HWCB_CHAR, ALL_HWCB_MTO);
@@ -747,24 +748,22 @@ flush_hwcbs (void)
 }
 
 static int 
-write_event_data_2 (void)
+write_event_data_2 (u32 ext_int_param)
 {
        write_hwcb_t *hwcb;
        int retval = 0;
 
 #ifdef DUMP_HWC_WRITE_ERROR
-       unsigned char *param;
-
-       param = ext_int_param ();
-       if (param != hwc_data.current_hwcb) {
+       if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+           != (unsigned long) hwc_data.current_hwcb) {
                internal_print (
                                       DELAYED_WRITE,
                                       HWC_RW_PRINT_HEADER
-                                      "write_event_mask_2 : "
+                                      "write_event_data_2 : "
                                       "HWCB address does not fit "
-                                      "(expected: 0x%x, got: 0x%x).\n",
-                                      hwc_data.current_hwcb,
-                                      param);
+                                      "(expected: 0x%lx, got: 0x%lx).\n",
+                                      (unsigned long) hwc_data.current_hwcb,
+                                      ext_int_param);
                return -EINVAL;
        }
 #endif
@@ -1707,7 +1706,7 @@ unconditional_read_1 (void)
 }
 
 static int 
-unconditional_read_2 (void)
+unconditional_read_2 (u32 ext_int_param)
 {
        read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
 
@@ -1844,7 +1843,7 @@ write_event_mask_1 (void)
 }
 
 static int 
-write_event_mask_2 (void)
+write_event_mask_2 (u32 ext_int_param)
 {
        init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
        int retval = 0;
@@ -1991,7 +1990,7 @@ do_hwc_init (void)
        return retval;
 }
 
-void do_hwc_interrupt (struct pt_regs *regs, __u16 code);
+void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
 
 int 
 hwc_init (void)
@@ -2005,7 +2004,7 @@ hwc_init (void)
 
 #endif
 
-       if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
+       if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
                panic ("Couldn't request external interrupts 0x2401");
 
        spin_lock_init (&hwc_data.lock);
@@ -2083,60 +2082,161 @@ hwc_unregister_calls (hwc_high_level_calls_t * calls)
        return 0;
 }
 
+int 
+hwc_send (hwc_request_t * req)
+{
+       unsigned long flags;
+       int retval;
+       int cc;
+
+       spin_lock_irqsave (&hwc_data.lock, flags);
+       if (!req || !req->callback || !req->block) {
+               retval = -EINVAL;
+               goto unlock;
+       }
+       if (hwc_data.request) {
+               retval = -ENOTSUPP;
+               goto unlock;
+       }
+       hwc_data.request = req;
+       cc = service_call (req->word, req->block);
+       switch (cc) {
+       case 0:
+               hwc_data.current_servc = req->word;
+               hwc_data.current_hwcb = req->block;
+               retval = 0;
+               break;
+       case 2:
+               retval = -EBUSY;
+               break;
+       default:
+               retval = -ENOSYS;
+
+       }
+      unlock:
+       spin_unlock_irqrestore (&hwc_data.lock, flags);
+       return retval;
+}
+
+EXPORT_SYMBOL (hwc_send);
+
 void 
-do_hwc_interrupt (struct pt_regs *regs, __u16 code)
+do_hwc_callback (u32 ext_int_param)
 {
+       if (!hwc_data.request || !hwc_data.request->callback)
+               return;
+       if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+           != (unsigned long) hwc_data.request->block)
+               return;
+       hwc_data.request->callback (hwc_data.request);
+       hwc_data.request = NULL;
+       hwc_data.current_hwcb = NULL;
+       hwc_data.current_servc = 0;
+}
 
-       if (hwc_data.flags & HWC_INIT) {
+void 
+hwc_do_interrupt (u32 ext_int_param)
+{
+       u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
+       u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
 
-               hwc_data.flags |= HWC_INTERRUPT;
-       } else if (hwc_data.flags & HWC_BROKEN) {
+       if (hwc_data.flags & HWC_PTIMER_RUNS) {
+               del_timer (&hwc_data.poll_timer);
+               hwc_data.flags &= ~HWC_PTIMER_RUNS;
+       }
+       if (finished_hwcb) {
 
-               if (!do_hwc_init ()) {
-                       hwc_data.flags &= ~HWC_BROKEN;
-                       internal_print (DELAYED_WRITE,
-                                       HWC_RW_PRINT_HEADER
-                                       "delayed HWC setup after"
-                                       " temporary breakdown\n");
+               if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
+                       internal_print (
+                                              DELAYED_WRITE,
+                                              HWC_RW_PRINT_HEADER
+                                              "interrupt: mismatch: "
+                                              "ext. int param. (0x%x) vs. "
+                                              "current HWCB (0x%x)\n",
+                                              ext_int_param,
+                                              hwc_data.current_hwcb);
+               } else {
+                       if (hwc_data.request) {
+
+                               do_hwc_callback (ext_int_param);
+                       } else {
+
+                               switch (hwc_data.current_servc) {
+
+                               case HWC_CMDW_WRITEMASK:
+
+                                       write_event_mask_2 (ext_int_param);
+                                       break;
+
+                               case HWC_CMDW_WRITEDATA:
+
+                                       write_event_data_2 (ext_int_param);
+                                       break;
+
+                               case HWC_CMDW_READDATA:
+
+                                       unconditional_read_2 (ext_int_param);
+                                       break;
+                               default:
+                               }
+                       }
                }
        } else {
-               spin_lock (&hwc_data.lock);
 
-               if (hwc_data.flags & HWC_PTIMER_RUNS) {
-                       del_timer (&hwc_data.poll_timer);
-                       hwc_data.flags &= ~HWC_PTIMER_RUNS;
+               if (hwc_data.current_hwcb) {
+                       internal_print (
+                                              DELAYED_WRITE,
+                                              HWC_RW_PRINT_HEADER
+                                              "interrupt: mismatch: "
+                                              "ext. int. param. (0x%x) vs. "
+                                              "current HWCB (0x%x)\n",
+                                              ext_int_param,
+                                              hwc_data.current_hwcb);
                }
-               if (!hwc_data.current_servc) {
+       }
 
-                       unconditional_read_1 ();
+       if (evbuf_pending) {
 
-               } else {
+               unconditional_read_1 ();
+       } else {
 
-                       switch (hwc_data.current_servc) {
+               write_event_data_1 ();
+       }
 
-                       case HWC_CMDW_WRITEMASK:
+       if (!hwc_data.calls || !hwc_data.calls->wake_up)
+               return;
+       (hwc_data.calls->wake_up) ();
+}
 
-                               write_event_mask_2 ();
-                               break;
+void 
+hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
+{
+       int cpu = smp_processor_id ();
 
-                       case HWC_CMDW_WRITEDATA:
+       u32 ext_int_param = hwc_ext_int_param ();
 
-                               write_event_data_2 ();
-                               break;
+       irq_enter (cpu, 0x2401);
 
-                       case HWC_CMDW_READDATA:
+       if (hwc_data.flags & HWC_INIT) {
 
-                               unconditional_read_2 ();
-                               break;
-                       }
+               hwc_data.flags |= HWC_INTERRUPT;
+       } else if (hwc_data.flags & HWC_BROKEN) {
 
-                       write_event_data_1 ();
+               if (!do_hwc_init ()) {
+                       hwc_data.flags &= ~HWC_BROKEN;
+                       internal_print (DELAYED_WRITE,
+                                       HWC_RW_PRINT_HEADER
+                                       "delayed HWC setup after"
+                                       " temporary breakdown"
+                                       " (ext. int. parameter=0x%x)\n",
+                                       ext_int_param);
                }
-               if (hwc_data.calls != NULL)
-                       if (hwc_data.calls->wake_up != NULL)
-                               (hwc_data.calls->wake_up) ();
+       } else {
+               spin_lock (&hwc_data.lock);
+               hwc_do_interrupt (ext_int_param);
                spin_unlock (&hwc_data.lock);
        }
+       irq_exit (cpu, 0x2401);
 }
 
 void 
index 81ddbcc22110a5865303be840d8cba5d9e3b737a..77608fca61d65697762b523cfaba1d40c4800be4 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  */
 
 #ifndef __HWC_RW_H__
@@ -19,6 +19,25 @@ typedef struct {
        void (*wake_up) (void);
 } hwc_high_level_calls_t;
 
+struct _hwc_request;
+
+typedef void hwc_callback_t (struct _hwc_request *);
+
+typedef struct _hwc_request {
+       void *block;
+       u32 word;
+       hwc_callback_t *callback;
+       void *data;
+} __attribute__ ((packed)) 
+
+hwc_request_t;
+
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
+#define HWC_ASCEBC_STR(s,c) ((MACHINE_IS_VM ? ASCEBC(s,c) : ASCEBC_500(s,c)))
+
 #define IN_HWCB      1
 #define IN_WRITE_BUF 2
 #define IN_BUFS_TOTAL        (IN_HWCB | IN_WRITE_BUF)
@@ -106,6 +125,8 @@ extern signed int hwc_register_calls (hwc_high_level_calls_t *);
 
 extern signed int hwc_unregister_calls (hwc_high_level_calls_t *);
 
+extern int hwc_send (hwc_request_t *);
+
 #endif
 
 #endif
index 6a62401e4b1d15dc95f29b0a811b60638594f015..ec0c83f8a44815a0c1447411174019bbde34f0c0 100644 (file)
@@ -4,7 +4,7 @@
  *
  *  S390 version
  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *    Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ *    Author(s): Martin Peschke <mpeschke@de.ibm.com>
  *
  *  Thanks to Martin Schwidefsky.
  */
@@ -22,6 +22,7 @@
 #include <asm/uaccess.h>
 
 #include "hwc_rw.h"
+#include "ctrlchar.h"
 
 #define HWC_TTY_PRINT_HEADER "hwc tty driver: "
 
@@ -217,13 +218,11 @@ hwc_tty_input (unsigned char *buf, unsigned int count)
 void 
 hwc_tty_init (void)
 {
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
-       if (MACHINE_IS_VM)
-               return;
-#endif
-       if (MACHINE_IS_P390)
+       if (!CONSOLE_IS_HWC)
                return;
 
+       ctrlchar_init ();
+
        memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
        memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
        hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
index 53790c4f6c8795213186874f6c8843279463044e..b3c24be217e659d703158f0c19a55f2c1d09bf09 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/kernel.h>
 #include <linux/version.h>
 #include <linux/proc_fs.h>
+#include <linux/init.h>
 #include <asm/types.h>
 #include <asm/ccwcache.h>
 #include <asm/idals.h>
@@ -26,9 +27,7 @@
 #ifdef MODULE
 #include <linux/module.h>
 #endif   
-#ifdef TAPE_DEBUG
 #include <asm/debug.h>
-#endif
 #ifdef CONFIG_S390_TAPE_DYNAMIC
 #include <asm/s390dyn.h>
 #endif
 #endif
 #define PRINTK_HEADER "T390:"
 
+
 /* state handling routines */
-inline void tapestate_set (tape_info_t * tape, int newstate);
-inline int tapestate_get (tape_info_t * tape);
-void tapestate_event (tape_info_t * tape, int event);
+inline void tapestate_set (tape_info_t * ti, int newstate);
+inline int tapestate_get (tape_info_t * ti);
+void tapestate_event (tape_info_t * ti, int event);
 
 /* our globals */
 tape_info_t *first_tape_info = NULL;
 tape_discipline_t *first_discipline = NULL;
 tape_frontend_t *first_frontend = NULL;
+devreg_t* tape_devreg[128];
+int devregct=0;
+
 #ifdef TAPE_DEBUG
 debug_info_t *tape_debug_area = NULL;
 #endif
@@ -107,17 +110,17 @@ char* event_verbose[TE_SIZE]= {
 devfs_handle_t tape_devfs_root_entry;
 
 inline void
-tape_mkdevfsroots (tape_info_t* tape
+tape_mkdevfsroots (tape_info_t* ti
 {
     char devno [5];
-    sprintf (devno,"%04X",tape->devinfo.devno);
-    tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape);
+    sprintf (devno,"%04x",ti->devinfo.devno);
+    ti->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, ti);
 }
 
 inline void
-tape_rmdevfsroots (tape_info_t* tape)
+tape_rmdevfsroots (tape_info_t* ti)
 {
-    devfs_unregister (tape->devfs_dir);
+    devfs_unregister (ti->devfs_dir);
 }
 #endif
 
@@ -135,14 +138,14 @@ static int
 tape_devices_open (struct inode *inode, struct file *file)
 {
     int size=80;
-    tape_info_t* tape;
+    tape_info_t* ti;
     tempinfo_t* tempinfo;
     char* data;
     int pos=0;
     tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL);
     if (!tempinfo)
         return -ENOMEM;
-    for (tape=first_tape_info;tape!=NULL;tape=tape->next)
+    for (ti=first_tape_info;ti!=NULL;ti=ti->next)
         size+=80; // FIXME: Guess better!
     data=vmalloc(size);
     if (!data) {
@@ -150,13 +153,13 @@ tape_devices_open (struct inode *inode, struct file *file)
         return -ENOMEM;
     }
     pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n");
-    for (tape=first_tape_info;tape!=NULL;tape=tape->next) {
-        pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2,
-                     tape->devinfo.devno,tape->devinfo.sid_data.cu_type,
-                     tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type,
-                     tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) &&
-                                                       (tapestate_get(tape) < TS_SIZE)) ?
-                     state_verbose[tapestate_get (tape)] : "TS UNKNOWN");
+    for (ti=first_tape_info;ti!=NULL;ti=ti->next) {
+        pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",ti->rew_minor/2,
+                     ti->devinfo.devno,ti->devinfo.sid_data.cu_type,
+                     ti->devinfo.sid_data.cu_model,ti->devinfo.sid_data.dev_type,
+                     ti->devinfo.sid_data.dev_model,((tapestate_get(ti) >= 0) &&
+                                                       (tapestate_get(ti) < TS_SIZE)) ?
+                     state_verbose[tapestate_get (ti)] : "TS UNKNOWN");
     }
     tempinfo->len=pos;
     tempinfo->data=data;
@@ -215,6 +218,183 @@ static struct inode_operations tape_devices_inode_ops =
 };
 #endif /* CONFIG_PROC_FS */
 
+/* SECTION: Parameters for tape */
+char *tape[256] = { NULL, };
+
+#ifndef MODULE
+static char tape_parm_string[1024] __initdata = { 0, };
+static void
+tape_split_parm_string (char *str)
+{
+       char *tmp = str;
+       int count = 0;
+       while (tmp != NULL && *tmp != '\0') {
+               char *end;
+               int len;
+               end = strchr (tmp, ',');
+               if (end == NULL) {
+                       len = strlen (tmp) + 1;
+               } else {
+                       len = (long) end - (long) tmp + 1;
+                       *end = '\0';
+                       end++;
+               }
+               tape[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
+               if (tape[count] == NULL) {
+                       printk (KERN_WARNING PRINTK_HEADER
+                               "can't store tape= parameter no %d\n",
+                               count + 1);
+                       break;
+               }
+               memset (tape[count], 0, len * sizeof (char));
+               memcpy (tape[count], tmp, len * sizeof (char));
+               count++;
+               tmp = end;
+       };
+}
+
+void __init
+tape_parm_setup (char *str, int *ints)
+{
+       int len = strlen (tape_parm_string);
+       if (len != 0) {
+               strcat (tape_parm_string, ",");
+       }
+       strcat (tape_parm_string, str);
+}
+
+int __init
+tape_parm_call_setup (char *str)
+{
+       int dummy;
+       tape_parm_setup (str, &dummy);
+       return 1;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16))
+__setup("tape=", tape_parm_call_setup);
+#endif   /* kernel <2.2.19 */
+#endif   /* not defined MODULE */
+
+static inline int
+tape_parm_strtoul (char *str, char **stra)
+{
+       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 inline devreg_t *
+tape_create_devreg (int devno)
+{
+       devreg_t *devreg = kmalloc (sizeof (devreg_t), GFP_KERNEL);
+       if (devreg != NULL) {
+               memset (devreg, 0, sizeof (devreg_t));
+               devreg->ci.devno = devno;
+               devreg->flag = DEVREG_TYPE_DEVNO;
+               devreg->oper_func = tape_oper_handler;
+       }
+       return devreg;
+}
+
+static inline void
+tape_parm_parse (char **str)
+{
+       char *temp;
+       int from, to,i,irq=0,rc,retries=0,tape_num=0;
+        s390_dev_info_t dinfo;
+        tape_info_t* ti,*tempti;
+        tape_discipline_t* disc;
+        long lockflags;
+       if (*str==NULL) {
+            /* no params present -> leave */
+            return;
+       }
+       while (*str) {
+               temp = *str;
+               from = 0;
+               to = 0;
+
+                /* turn off autodetect mode, if any range is present */
+                from = tape_parm_strtoul (temp, &temp);
+                to = from;
+                if (*temp == '-') {
+                    temp++;
+                    to = tape_parm_strtoul (temp, &temp);
+                }
+                for (i=from;i<=to;i++) {
+                    retries=0;
+                    // register for attch/detach of a devno
+                    tape_devreg[devregct]=tape_create_devreg(i);
+                    if (tape_devreg[devregct]==NULL) {
+                        PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n",i);
+                    } else {
+                        s390_device_register (tape_devreg[devregct++]);
+                    }
+                    // we are activating a device if it is present
+                    for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
+                        rc = get_dev_info_by_irq (irq, &dinfo);
+                     
+                        disc = first_discipline;
+                        while ((dinfo.devno == i) && (disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
+                            disc = (tape_discipline_t *) (disc->next);
+                        if ((disc == NULL) || (rc == -ENODEV) || (i!=dinfo.devno)) {
+                            continue;
+                        }
+#ifdef TAPE_DEBUG
+                        debug_text_event (tape_debug_area,3,"det irq:  ");
+                        debug_int_event (tape_debug_area,3,irq);
+                        debug_text_event (tape_debug_area,3,"cu:       ");
+                        debug_int_event (tape_debug_area,3,disc->cu_type);
+#endif /* TAPE_DEBUG */
+                        PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
+                        /* Allocate tape structure  */
+                        ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+                        if (ti == NULL) {
+#ifdef TAPE_DEBUG
+                            debug_text_exception (tape_debug_area,3,"ti:no mem ");
+#endif /* TAPE_DEBUG */
+                            PRINT_INFO ("tape: can't allocate memory for "
+                                        "tape info structure\n");
+                            continue;
+                        }
+                        memset(ti,0,sizeof(tape_info_t));
+                        ti->discipline = disc;
+                        disc->tape = ti;
+                        rc = tape_setup (ti, irq, tape_num);
+                        if (rc) {
+#ifdef TAPE_DEBUG
+                            debug_text_event (tape_debug_area,3,"tsetup err");
+                            debug_int_exception (tape_debug_area,3,rc);
+#endif /* TAPE_DEBUG */
+                            kfree (ti);
+                        } else {
+                            s390irq_spin_lock_irqsave (irq, lockflags);
+                            if (first_tape_info == NULL) {
+                                first_tape_info = ti;
+                            } else {
+                                tempti = first_tape_info;
+                                while (tempti->next != NULL)
+                                    tempti = tempti->next;
+                                tempti->next = ti;
+                            }
+                            s390irq_spin_unlock_irqrestore (irq, lockflags);
+                        }
+                    }
+                    tape_num+=2;
+                }
+                str++;
+        }
+}
+
+
 /* SECTION: Managing wrappers for ccwcache */
 
 #define TAPE_EMERGENCY_REQUESTS 16
@@ -286,7 +466,6 @@ tape_free_request (ccw_req_t * request)
                *((ccw_req_t **) (request->cache)) = request;
        } else {
                clear_normalized_cda ((ccw1_t *) (request->cpaddr));    // avoid memory leak caused by modeset_byte
-
                ccw_free_request (request);
        }
 }
@@ -296,12 +475,12 @@ tape_free_request (ccw_req_t * request)
  */
 inline
  ccw_req_t *
-tape_alloc_ccw_req (tape_info_t * tape, int cplength, int datasize)
+tape_alloc_ccw_req (tape_info_t * ti, int cplength, int datasize)
 {
        char tape_magic_id[] = "tape";
        ccw_req_t *cqr = NULL;
 
-       if (!tape)
+       if (!ti)
                return NULL;
        cqr = tape_alloc_request (tape_magic_id, cplength, datasize);
 
@@ -311,7 +490,7 @@ tape_alloc_ccw_req (tape_info_t * tape, int cplength, int datasize)
 #endif
        }
        cqr->magic = TAPE_MAGIC;        /* sets an identifier for tape driver   */
-       cqr->device = tape;     /* save pointer to tape info    */
+       cqr->device = ti;       /* save pointer to tape info    */
        return cqr;
 }
 
@@ -321,15 +500,15 @@ tape_alloc_ccw_req (tape_info_t * tape, int cplength, int datasize)
 static inline tape_info_t *
 tapedev_find_info (int irq)
 {
-       tape_info_t *tape;
+       tape_info_t *ti;
 
-       tape = first_tape_info;
-       if (tape != NULL)
+       ti = first_tape_info;
+       if (ti != NULL)
                do {
-                       if (tape->devinfo.irq == irq)
+                       if (ti->devinfo.irq == irq)
                                break;
-               } while ((tape = (tape_info_t *) tape->next) != NULL);
-       return tape;
+               } while ((ti = (tape_info_t *) ti->next) != NULL);
+       return ti;
 }
 
 #define QUEUE_THRESHOLD 5
@@ -340,32 +519,31 @@ tapedev_find_info (int irq)
 void
 tape_irq (int irq, void *int_parm, struct pt_regs *regs)
 {
-       tape_info_t *tape = tapedev_find_info (irq);
+       tape_info_t *ti = tapedev_find_info (irq);
 
        /* analyse devstat and fire event */
-       if (tape->devstat.dstat & DEV_STAT_UNIT_CHECK) {
-               tapestate_event (tape, TE_ERROR);
-       } else if (tape->devstat.dstat & (DEV_STAT_DEV_END)) {
-               tapestate_event (tape, TE_DONE);
+       if (ti->devstat.dstat & DEV_STAT_UNIT_CHECK) {
+               tapestate_event (ti, TE_ERROR);
+       } else if (ti->devstat.dstat & (DEV_STAT_DEV_END)) {
+               tapestate_event (ti, TE_DONE);
        } else
-               tapestate_event (tape, TE_OTHER);
+               tapestate_event (ti, TE_OTHER);
 }
 
 int 
 tape_oper_handler ( int irq, struct _devreg *dreg) {
-    tape_info_t* tape=first_tape_info;
+    tape_info_t* ti=first_tape_info;
     tape_info_t* newtape;
-    int rc,tape_num,retries=0;
+    int rc,tape_num,retries=0,i;
     s390_dev_info_t dinfo;
     tape_discipline_t* disc;
 #ifdef CONFIG_DEVFS_FS
     tape_frontend_t* frontend;
 #endif
     long lockflags;
-    PRINT_WARN ("oper handler was called\n");
-    while ((tape!=NULL) && (tape->devinfo.irq!=irq)) 
-        tape=tape->next;
-    if (tape!=NULL) {
+    while ((ti!=NULL) && (ti->devinfo.irq!=irq)) 
+        ti=ti->next;
+    if (ti!=NULL) {
         // irq is (still) used by tape. tell ingo to try again later
         PRINT_WARN ("Oper handler for irq %d called while irq still (internaly?) used.\n",irq);
         return -EAGAIN;
@@ -384,51 +562,61 @@ tape_oper_handler ( int irq, struct _devreg *dreg) {
     while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
         disc = (tape_discipline_t *) (disc->next);
     if (disc == NULL)
-        PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type);
+        PRINT_WARN ("No matching discipline for cu_type %x found, ignoring device %04x.\n",dinfo.sid_data.cu_type,dinfo.devno);
     if (rc == -ENODEV) 
         PRINT_WARN ("No device information for new dev. could be retrieved.\n");
     if ((disc == NULL) || (rc == -ENODEV))
         return -ENODEV;
     
     /* Allocate tape structure  */
-    tape = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
-    if (tape == NULL) {
-        PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+    ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+    if (ti == NULL) {
+        PRINT_INFO ( "tape: can't allocate memory for "
                     "tape info structure\n");
         return -ENOBUFS;
     }
-    memset(tape,0,sizeof(tape_info_t));
-    tape->discipline = disc;
-    disc->tape = tape;
+    memset(ti,0,sizeof(tape_info_t));
+    ti->discipline = disc;
+    disc->tape = ti;
     tape_num=0;
-    newtape=first_tape_info;
-    while (newtape!=NULL) {
-        if (newtape->rew_minor==tape_num) {
-            // tape num in use. try next one
-            tape_num+=2;
-            newtape=first_tape_info;
-        } else {
-            // tape num not used by newtape. look at next tape info
-            newtape=newtape->next;
+    if (*tape) {
+        // we have static device ranges, so fingure out the tape_num of the attached tape
+        for (i=0;i<devregct;i++)
+            if (tape_devreg[i]->ci.devno==dinfo.devno) {
+                tape_num=2*i;
+                break;
+            }
+    } else {
+        // we are running in autoprobe mode, find a free tape_num
+        newtape=first_tape_info;
+        while (newtape!=NULL) {
+            if (newtape->rew_minor==tape_num) {
+                // tape num in use. try next one
+                tape_num+=2;
+                newtape=first_tape_info;
+            } else {
+                // tape num not used by newtape. look at next tape info
+                newtape=newtape->next;
+            }
         }
     }
-    rc = tape_setup (tape, irq, tape_num);
+    rc = tape_setup (ti, irq, tape_num);
     if (rc) {
-        kfree (tape);
+        kfree (ti);
         return -ENOBUFS;
     }
 #ifdef CONFIG_DEVFS_FS
     for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) 
-        frontend->mkdevfstree(tape);
+        frontend->mkdevfstree(ti);
 #endif
     s390irq_spin_lock_irqsave (irq,lockflags);
     if (first_tape_info == NULL) {
-        first_tape_info = tape;
+        first_tape_info = ti;
     } else {
         newtape = first_tape_info;
         while (newtape->next != NULL)
             newtape = newtape->next;
-        newtape->next = tape;
+        newtape->next = ti;
     }
     s390irq_spin_unlock_irqrestore (irq, lockflags);
     return 0;
@@ -492,8 +680,11 @@ tape_noper_handler ( int irq, int status ) {
 void
 tape_dump_sense (devstat_t * stat)
 {
-       int sl;
+#ifdef TAPE_DEBUG
+        int sl;
+#endif
 #if 0
+
        PRINT_WARN ("------------I/O resulted in unit check:-----------\n");
        for (sl = 0; sl < 4; sl++) {
                PRINT_WARN ("Sense:");
@@ -542,6 +733,10 @@ tape_setup (tape_info_t * ti, int irq, int minor)
        long lockflags;
        int rc = 0;
 
+        if (minor>254) {
+            PRINT_WARN ("Device id %d on irq %d will not be accessible since this driver is restricted to 128 devices.\n",minor/2,irq);
+            return -EINVAL;
+        }
        rc = get_dev_info_by_irq (irq, &(ti->devinfo));
        if (rc == -ENODEV) {    /* end of device list */
                return rc;
@@ -560,10 +755,8 @@ tape_setup (tape_info_t * ti, int irq, int minor)
 #endif
        s390irq_spin_lock_irqsave (irq, lockflags);
        ti->next = NULL;
-       if (rc) {
-               PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
-       } else
-               PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2);
+       if (rc)
+            PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
        init_waitqueue_head (&ti->wq);
        ti->kernbuf = ti->userbuf = ti->discdata = NULL;
        tapestate_set (ti, TS_UNUSED);
@@ -599,7 +792,7 @@ tape_init (void)
 #endif /* TAPE_DEBUG */
 
         /* print banner */        
-        PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n");
+        PRINT_WARN ("IBM S/390 Tape Device Driver (v1.01).\n");
         PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n");
         opt_char=opt_block=opt_3480=opt_3490="not present";
 #ifdef CONFIG_S390_TAPE_CHAR
@@ -620,18 +813,33 @@ tape_init (void)
         PRINT_WARN ("support for 3480 compatible : %s\n",opt_3480);
         PRINT_WARN ("support for 3490 compatible : %s\n",opt_3490);
         
-
+#ifndef MODULE
+        tape_split_parm_string(tape_parm_string);
+#endif
+        if (*tape) 
+            PRINT_INFO ("Using ranges supplied in parameters, disabling autoprobe mode.\n");
+        else
+            PRINT_INFO ("No parameters supplied, enabling autoprobe mode for all supported devices.\n");
 #ifdef CONFIG_S390_TAPE_3490
-       first_discipline = tape3490_init ();
+        if (*tape)
+            first_discipline = tape3490_init (0); // no autoprobe for devices
+        else
+            first_discipline = tape3490_init (1); // do autoprobe since no parm specified
        first_discipline->next = NULL;
 #endif
 
 #ifdef CONFIG_S390_TAPE_3480
         if (first_discipline == NULL) {
-            first_discipline = tape3480_init ();
+            if (*tape)
+                first_discipline = tape3480_init (0); // no autoprobe for devices
+            else 
+                first_discipline = tape3480_init (1); // do autoprobe since no parm specified
             first_discipline->next = NULL;
         } else {
-            first_discipline->next = tape3480_init ();
+            if (*tape)
+                first_discipline->next = tape3480_init (0); // no autoprobe for devices
+            else
+                first_discipline->next = tape3480_init (1); // do autoprobe since no parm specified
             ((tape_discipline_t*) (first_discipline->next))->next=NULL;
         }
 #endif
@@ -643,33 +851,32 @@ tape_init (void)
         debug_text_event (tape_debug_area,3,"dev detect");
 #endif /* TAPE_DEBUG */
        /* Allocate the tape structures */
-       for (irq = 0; irq < NR_IRQS; irq++) {
+        if (*tape!=NULL) {
+            // we have parameters, continue with parsing the parameters and set the devices online
+            tape_parm_parse (tape);
+        } else {
+            // we are running in autodetect mode, search all devices for compatibles
+            for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
                rc = get_dev_info_by_irq (irq, &dinfo);
-
-               if (rc == -ENODEV) {
-                       retries++;
-                       if (retries > 5)
-                               irq = NR_IRQS;
-               }
                disc = first_discipline;
                while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
-                       disc = (tape_discipline_t *) (disc->next);
-
+                    disc = (tape_discipline_t *) (disc->next);
                if ((disc == NULL) || (rc == -ENODEV))
-                       continue;
+                    continue;
 #ifdef TAPE_DEBUG
                 debug_text_event (tape_debug_area,3,"det irq:  ");
                 debug_int_event (tape_debug_area,3,irq);
                 debug_text_event (tape_debug_area,3,"cu:       ");
                 debug_int_event (tape_debug_area,3,disc->cu_type);
 #endif /* TAPE_DEBUG */
+                PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
                /* Allocate tape structure  */
                ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
                if (ti == NULL) {
 #ifdef TAPE_DEBUG
                     debug_text_exception (tape_debug_area,3,"ti:no mem ");
 #endif /* TAPE_DEBUG */
-                    PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+                    PRINT_INFO ("tape: can't allocate memory for "
                                    "tape info structure\n");
                     continue;
                }
@@ -679,25 +886,26 @@ tape_init (void)
                rc = tape_setup (ti, irq, tape_num);
                if (rc) {
 #ifdef TAPE_DEBUG
-                        debug_text_event (tape_debug_area,3,"tsetup err");
-                        debug_int_exception (tape_debug_area,3,rc);
+                    debug_text_event (tape_debug_area,3,"tsetup err");
+                    debug_int_exception (tape_debug_area,3,rc);
 #endif /* TAPE_DEBUG */
-                       kfree (ti);
+                    kfree (ti);
                } else {
-                       s390irq_spin_lock_irqsave (irq, lockflags);
-                       if (first_tape_info == NULL) {
-                               first_tape_info = ti;
-                       } else {
-                               tempti = first_tape_info;
-                               while (tempti->next != NULL)
-                                       tempti = tempti->next;
-                               tempti->next = ti;
-                       }
-                       tape_num += 2;
-                       s390irq_spin_unlock_irqrestore (irq, lockflags);
+                    s390irq_spin_lock_irqsave (irq, lockflags);
+                    if (first_tape_info == NULL) {
+                        first_tape_info = ti;
+                    } else {
+                        tempti = first_tape_info;
+                        while (tempti->next != NULL)
+                            tempti = tempti->next;
+                        tempti->next = ti;
+                    }
+                    tape_num += 2;
+                    s390irq_spin_unlock_irqrestore (irq, lockflags);
                }
-       }
-
+            }
+        }
+            
        /* Allocate local buffer for the ccwcache       */
        tape_init_emergency_req ();
 #ifdef CONFIG_PROC_FS
@@ -733,6 +941,7 @@ tape_init (void)
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)");
 MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver");
+MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s");
 
 int
 init_module (void)
@@ -749,17 +958,24 @@ init_module (void)
 void
 cleanup_module (void)
 {
-        tape_info_t *tape ,*temp;
+        tape_info_t *ti ,*temp;
         tape_frontend_t* frontend, *tempfe;
         tape_discipline_t* disc ,*tempdi;
+        int i;
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"cleaup mod");
 #endif /* TAPE_DEBUG */
 
-       tape = first_tape_info;
-       while (tape != NULL) {
-               temp = tape;
-               tape = tape->next;
+        if (*tape) {
+            // we are running with parameters. we'll now deregister from our devno's
+            for (i=0;i<devregct;i++) {
+                s390_device_unregister(tape_devreg[devregct]);
+            }
+        }
+       ti = first_tape_info;
+       while (ti != NULL) {
+               temp = ti;
+               ti = ti->next;
                 //cleanup a device 
 #ifdef TAPE_DEBUG
                 debug_text_event (tape_debug_area,6,"free irq:");
@@ -781,7 +997,7 @@ cleanup_module (void)
 #endif CONFIG_DEVFS_FS
 #ifdef CONFIG_PROC_FS
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-       remove_proc_entry ("devices", &proc_root);
+       remove_proc_entry ("tapedevices", &proc_root);
 #else
        proc_unregister (&proc_root, tape_devices_entry->low_ino);
        kfree (tape_devices_entry);
@@ -801,6 +1017,10 @@ cleanup_module (void)
        }
         disc=first_discipline;
        while (disc != NULL) {
+                if (*tape)
+                    disc->shutdown(0);
+                else
+                    disc->shutdown(1);
                tempdi = disc;
                disc = disc->next;
                kfree (tempdi);
@@ -814,9 +1034,9 @@ cleanup_module (void)
 #endif                         /* MODULE */
 
 inline void
-tapestate_set (tape_info_t * tape, int newstate)
+tapestate_set (tape_info_t * ti, int newstate)
 {
-    if (tape->tape_state == TS_NOT_OPER) {
+    if (ti->tape_state == TS_NOT_OPER) {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"ts_set err");
         debug_text_exception (tape_debug_area,3,"dev n.oper");
@@ -824,11 +1044,11 @@ tapestate_set (tape_info_t * tape, int newstate)
     } else {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,4,"ts. dev:  ");
-        debug_int_event (tape_debug_area,4,tape->blk_minor);
+        debug_int_event (tape_debug_area,4,ti->blk_minor);
         debug_text_event (tape_debug_area,4,"old ts:   ");
-        debug_text_event (tape_debug_area,4,(((tapestate_get (tape) < TS_SIZE) &&
-                                             (tapestate_get (tape) >=0 )) ?
-                                            state_verbose[tapestate_get (tape)] :
+        debug_text_event (tape_debug_area,4,(((tapestate_get (ti) < TS_SIZE) &&
+                                             (tapestate_get (ti) >=0 )) ?
+                                            state_verbose[tapestate_get (ti)] :
                                             "UNKNOWN TS"));
         debug_text_event (tape_debug_area,4,"new ts:   ");
         debug_text_event (tape_debug_area,4,(((newstate < TS_SIZE) &&
@@ -836,46 +1056,46 @@ tapestate_set (tape_info_t * tape, int newstate)
                                              state_verbose[newstate] :
                                              "UNKNOWN TS"));
 #endif /* TAPE_DEBUG */
-       tape->tape_state = newstate;
+       ti->tape_state = newstate;
     }
 }
 
 inline int
-tapestate_get (tape_info_t * tape)
+tapestate_get (tape_info_t * ti)
 {
-       return (tape->tape_state);
+       return (ti->tape_state);
 }
 
 void
-tapestate_event (tape_info_t * tape, int event)
+tapestate_event (tape_info_t * ti, int event)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"te! dev:  ");
-        debug_int_event (tape_debug_area,6,tape->blk_minor);
+        debug_int_event (tape_debug_area,6,ti->blk_minor);
         debug_text_event (tape_debug_area,6,"event:");
         debug_text_event (tape_debug_area,6,((event >=0) &&
                                             (event < TE_SIZE)) ?
                          event_verbose[event] : "TE UNKNOWN");
         debug_text_event (tape_debug_area,6,"state:");
-        debug_text_event (tape_debug_area,6,((tapestate_get(tape) >= 0) &&
-                                            (tapestate_get(tape) < TS_SIZE)) ?
-                         state_verbose[tapestate_get (tape)] :
+        debug_text_event (tape_debug_area,6,((tapestate_get(ti) >= 0) &&
+                                            (tapestate_get(ti) < TS_SIZE)) ?
+                         state_verbose[tapestate_get (ti)] :
                          "TS UNKNOWN");
 #endif /* TAPE_DEBUG */    
         if (event == TE_ERROR) { 
-            tape->discipline->error_recovery(tape);
+            ti->discipline->error_recovery(ti);
         } else {
             if ((event >= 0) &&
                 (event < TE_SIZE) &&
-                (tapestate_get (tape) >= 0) &&
-                (tapestate_get (tape) < TS_SIZE) &&
-                ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL))
-               ((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape);
+                (tapestate_get (ti) >= 0) &&
+                (tapestate_get (ti) < TS_SIZE) &&
+                ((*(ti->discipline->event_table))[tapestate_get (ti)][event] != NULL))
+               ((*(ti->discipline->event_table))[tapestate_get (ti)][event]) (ti);
             else {
 #ifdef TAPE_DEBUG
                 debug_text_exception (tape_debug_area,3,"TE UNEXPEC");
 #endif /* TAPE_DEBUG */
-               tape->discipline->default_handler (tape);
+               ti->discipline->default_handler (ti);
             }
         }
 }
index 905e57fdf9b27c5f246bc875f4be1a1d604bf7a6..05bf2ad31f8d42bd74887eeb6a2fa4794ffdea39 100644 (file)
@@ -63,11 +63,12 @@ typedef enum {
     TE_START=0, TE_DONE, TE_FAILED, TE_ERROR, TE_OTHER,
     TE_SIZE } tape_events;
 
+typedef void (*tape_disc_shutdown_t) (int);
 typedef void (*tape_event_handler_t) (struct _tape_info_t*);
-typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* tape,int count);
-typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* tape,int tapeblock_major);
-typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape);
-typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape);
+typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* ti,int count);
+typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* ti,int tapeblock_major);
+typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* ti);
+typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* ti);
 typedef void (*tape_setup_assist_t) (struct _tape_info_t*);
 #ifdef CONFIG_DEVFS_FS
 typedef void (*tape_devfs_handler_t) (struct _tape_info_t*);
@@ -108,6 +109,7 @@ typedef struct _tape_discipline_t {
     tape_ccwgen_t mtmkpart;
     tape_ccwgen_t mtiocget;
     tape_ccwgen_t mtiocpos;
+    tape_disc_shutdown_t shutdown;
     int (*discipline_ioctl_overload)(struct inode *,struct file*, unsigned int,unsigned long);
     tape_event_table_t* event_table;
     tape_event_handler_t default_handler;
@@ -145,6 +147,7 @@ typedef struct _tape_info_t {
     struct request* current_request;
     int blk_retries;
     long position;
+    int medium_is_unloaded;  // Becomes true when a unload-type operation was issued, false again when medium-insert was detected
     ccw_req_t* cqr;
     atomic_t bh_scheduled;
     struct tq_struct bh_tq;
@@ -167,7 +170,7 @@ int tape_init(void);
 int tape_setup (tape_info_t * ti, int irq, int minor);
 
 /* functoins for alloc'ing ccw stuff */
-inline  ccw_req_t * tape_alloc_ccw_req (tape_info_t* tape, int cplength, int datasize);
+inline  ccw_req_t * tape_alloc_ccw_req (tape_info_t* ti, int cplength, int datasize);
 void tape_free_request (ccw_req_t * request);
 
 /* a function for dumping device sense info */
@@ -179,9 +182,9 @@ int tape_oper_handler ( int irq, struct _devreg *dreg);
 #endif
 
 /* functions for handling the status of a device */
-inline void tapestate_set (tape_info_t * tape, int newstate);
-inline int tapestate_get (tape_info_t * tape);
-void tapestate_event (tape_info_t * tape, int event);
+inline void tapestate_set (tape_info_t * ti, int newstate);
+inline int tapestate_get (tape_info_t * ti);
+void tapestate_event (tape_info_t * ti, int event);
 extern char* state_verbose[TS_SIZE];
 extern char* event_verbose[TE_SIZE];
 
index 0961a5ca4134355192fc9c90dd589140a46f22fc..0f02d12ab008594b26291b1b6851cfa76c3ecbd7 100644 (file)
@@ -72,22 +72,29 @@ devreg_t tape3480_devreg = {
 
 
 void
-tape3480_setup_assist (tape_info_t * tape)
+tape3480_setup_assist (tape_info_t * ti)
 {
        tape3480_disc_data_t *data = NULL;
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"3480 dsetu");
     debug_text_event (tape_debug_area,6,"dev:");
-    debug_int_event (tape_debug_area,6,tape->blk_minor);
+    debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif /* TAPE_DEBUG */
        while (data == NULL)
                data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL);
        data->modeset_byte = 0x00;
-       tape->discdata = (void *) data;
+       ti->discdata = (void *) data;
+}
+
+
+void
+tape3480_shutdown (int autoprobe) {
+    if (autoprobe)
+       s390_device_unregister(&tape3480_devreg);
 }
 
 tape_discipline_t *
-tape3480_init (void)
+tape3480_init (int autoprobe)
 {
        tape_discipline_t *disc;
 #ifdef TAPE_DEBUG
@@ -132,6 +139,7 @@ tape3480_init (void)
        disc->mtmkpart = tape34xx_mtmkpart;
        disc->mtiocget = tape34xx_mtiocget;
        disc->mtiocpos = tape34xx_mtiocpos;
+       disc->shutdown = tape3480_shutdown;
        disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
        disc->event_table = &tape3480_event_handler_table;
        disc->default_handler = tape34xx_default_handler;
@@ -139,7 +147,8 @@ tape3480_init (void)
        disc->free_bread = tape34xx_free_bread;
        disc->tape = NULL;      /* pointer for backreference */
        disc->next = NULL;
-       s390_device_register(&tape3480_devreg);
+       if (autoprobe)
+           s390_device_register(&tape3480_devreg);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,3,"3480 regis");
 #endif /* TAPE_DEBUG */
index 25e2fbd96c66aee392e8214778b9e8946582ae33..8f48263e6caee99707de51a98054761173ff546f 100644 (file)
@@ -19,5 +19,5 @@
 typedef struct _tape3480_disc_data_t {
     __u8 modeset_byte;
 } tape3480_disc_data_t  __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3480_init (void);
+tape_discipline_t * tape3480_init (int);
 #endif // _TAPE3480_H
index 3603024fbadb0f643999e2783fb9a5333bc9a4fb..d7c9440a82b2e4d97e77562938204edc82740d15 100644 (file)
@@ -71,22 +71,30 @@ devreg_t tape3490_devreg = {
 };
 
 void
-tape3490_setup_assist (tape_info_t * tape)
+tape3490_setup_assist (tape_info_t * ti)
 {
        tape3490_disc_data_t *data = NULL;
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"3490 dsetu");
     debug_text_event (tape_debug_area,6,"dev:");
-    debug_int_event (tape_debug_area,6,tape->blk_minor);
+    debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif /* TAPE_DEBUG */
        while (data == NULL)
                data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL);
        data->modeset_byte = 0x00;
-       tape->discdata = (void *) data;
+       ti->discdata = (void *) data;
 }
 
+
+void
+tape3490_shutdown (int autoprobe) {
+    if (autoprobe)
+       s390_device_unregister(&tape3490_devreg);
+}
+
+
 tape_discipline_t *
-tape3490_init (void)
+tape3490_init (int autoprobe)
 {
        tape_discipline_t *disc;
 #ifdef TAPE_DEBUG
@@ -131,6 +139,7 @@ tape3490_init (void)
        disc->mtmkpart = tape34xx_mtmkpart;
        disc->mtiocget = tape34xx_mtiocget;
        disc->mtiocpos = tape34xx_mtiocpos;
+       disc->shutdown = tape3490_shutdown;
        disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
        disc->event_table = &tape3490_event_handler_table;
        disc->default_handler = tape34xx_default_handler;
@@ -138,7 +147,8 @@ tape3490_init (void)
        disc->free_bread = tape34xx_free_bread;
        disc->tape = NULL;      /* pointer for backreference */
        disc->next = NULL;
-       s390_device_register(&tape3490_devreg);
+       if (autoprobe)
+           s390_device_register(&tape3490_devreg);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,3,"3490 regis");
 #endif /* TAPE_DEBUG */
index 689ed61e05aaa7f11c43665d020c79c62f105432..59f6b58b7f4eb9a1f94219f12ec8fd221e0a65c2 100644 (file)
@@ -20,5 +20,5 @@
 typedef struct _tape3490_disc_data_t {
     __u8 modeset_byte;
 } tape3490_disc_data_t  __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3490_init (void);
+tape_discipline_t * tape3490_init (int);
 #endif // _TAPE3490_H
index 9ddce22eaa506938d8cce748665be582ac0cf129..cf6754a99cde6dc21c6c6f606d1a461e16954e3b 100644 (file)
@@ -82,13 +82,13 @@ tape34xx_ioctl_overload (struct inode *inode, struct file *filp, unsigned int cm
 }
 
 ccw_req_t *
-tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_write_block (const char *data, size_t count, tape_info_t * ti)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
        void *mem;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xwbl nomem");
@@ -115,7 +115,7 @@ tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
 
        ccw->cmd_code = WRITE_CMD;
@@ -127,11 +127,11 @@ tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
                tape_free_request (cqr);
                return NULL;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = mem;
-       tape->userbuf = (void *) data;
-       tapestate_set (tape, TS_WRI_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = mem;
+       ti->userbuf = (void *) data;
+       tapestate_set (ti, TS_WRI_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xwbl ccwg");
 #endif /* TAPE_DEBUG */
@@ -139,31 +139,31 @@ tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
 }
 
 void 
-tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti)
 {
        unsigned long lockflags;
        ccw1_t *ccw;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
        ccw = cqr->cpaddr;
        ccw++;
        clear_normalized_cda (ccw);
-       kfree (tape->kernbuf);
+       kfree (ti->kernbuf);
        tape_free_request (cqr);
-       tape->kernbuf = tape->userbuf = NULL;
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       ti->kernbuf = ti->userbuf = NULL;
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xfwb free");
 #endif /* TAPE_DEBUG */
 }
 
 ccw_req_t *
-tape34xx_read_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_read_block (const char *data, size_t count, tape_info_t * ti)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
        void *mem;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xrbl nomem");
@@ -182,7 +182,7 @@ tape34xx_read_block (const char *data, size_t count, tape_info_t * tape)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
 
        ccw->cmd_code = READ_FORWARD;
@@ -194,24 +194,25 @@ tape34xx_read_block (const char *data, size_t count, tape_info_t * tape)
                tape_free_request (cqr);
                return NULL;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = mem;
-       tape->userbuf = (void *) data;
-       tapestate_set (tape, TS_RFO_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = mem;
+       ti->userbuf = (void *) data;
+       tapestate_set (ti, TS_RFO_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xrbl ccwg");
 #endif /* TAPE_DEBUG */
        return cqr;
 }
+
 ccw_req_t *
-tape34xx_read_opposite (tape_info_t * tape,int novalue)
+tape34xx_read_opposite (tape_info_t * ti,int novalue)
 {
        ccw_req_t *cqr;
        ccw1_t *ccw;
        size_t count;
        // first, retrieve the count from the old cqr.
-       cqr = tape->cqr;
+       cqr = ti->cqr;
        ccw = cqr->cpaddr;
        ccw++;
        count=ccw->count;
@@ -219,7 +220,7 @@ tape34xx_read_opposite (tape_info_t * tape,int novalue)
        clear_normalized_cda (ccw);
        tape_free_request (cqr);
        // build new cqr
-       cqr = tape_alloc_ccw_req (tape, 3, 0);
+       cqr = tape_alloc_ccw_req (ti, 3, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xrop nomem");
@@ -230,13 +231,13 @@ tape34xx_read_opposite (tape_info_t * tape,int novalue)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
 
        ccw->cmd_code = READ_BACKWARD;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = count;
-       set_normalized_cda (ccw, (unsigned long) tape->kernbuf);
+       set_normalized_cda (ccw, (unsigned long) ti->kernbuf);
        if ((ccw->cda) == 0) {
                tape_free_request (cqr);
                return NULL;
@@ -251,7 +252,7 @@ tape34xx_read_opposite (tape_info_t * tape,int novalue)
        ccw->flags = 0;
        ccw->count = 1;
        ccw->cda = (unsigned long)ccw;
-       tapestate_set (tape, TS_RBA_INIT);
+       tapestate_set (ti, TS_RBA_INIT);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xrop ccwg");
 #endif /* TAPE_DEBUG */
@@ -259,27 +260,27 @@ tape34xx_read_opposite (tape_info_t * tape,int novalue)
 }
 
 void 
-tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti)
 {
        unsigned long lockflags;
        size_t cpysize;
        ccw1_t *ccw;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
        ccw = cqr->cpaddr;
        ccw++;
-       cpysize = ccw->count - tape->devstat.rescnt;
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-       if (copy_to_user (tape->userbuf, tape->kernbuf, cpysize)) {
+       cpysize = ccw->count - ti->devstat.rescnt;
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+       if (copy_to_user (ti->userbuf, ti->kernbuf, cpysize)) {
 #ifdef TAPE_DEBUG
            debug_text_exception (tape_debug_area,6,"xfrb segf.");
 #endif /* TAPE_DEBUG */
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
        clear_normalized_cda (ccw);
-       kfree (tape->kernbuf);
+       kfree (ti->kernbuf);
        tape_free_request (cqr);
-       tape->kernbuf = tape->userbuf = NULL;
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       ti->kernbuf = ti->userbuf = NULL;
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xfrb free");
 #endif /* TAPE_DEBUG */
@@ -294,7 +295,7 @@ tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape)
  * at the EOT (End of Tape) side of the file mark.
  */
 ccw_req_t *
-tape34xx_mtfsf (tape_info_t * tape, int count)
+tape34xx_mtfsf (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -306,7 +307,7 @@ tape34xx_mtfsf (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xfsf nomem");
@@ -317,7 +318,7 @@ tape34xx_mtfsf (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = FORSPACEFILE;
@@ -330,11 +331,11 @@ tape34xx_mtfsf (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_FSF_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_FSF_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xfsf ccwg");
 #endif /* TAPE_DEBUG */
@@ -346,7 +347,7 @@ tape34xx_mtfsf (tape_info_t * tape, int count)
  * the EOT (End of Tape) side of the last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtbsf (tape_info_t * tape, int count)
+tape34xx_mtbsf (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -358,7 +359,7 @@ tape34xx_mtbsf (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xbsf nomem");
@@ -369,7 +370,7 @@ tape34xx_mtbsf (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = BACKSPACEFILE;
@@ -382,11 +383,11 @@ tape34xx_mtbsf (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_BSF_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_BSF_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xbsf ccwg");
 #endif /* TAPE_DEBUG */
@@ -398,7 +399,7 @@ tape34xx_mtbsf (tape_info_t * tape, int count)
  * via MTSETBLK.
  */
 ccw_req_t *
-tape34xx_mtfsr (tape_info_t * tape, int count)
+tape34xx_mtfsr (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -410,7 +411,7 @@ tape34xx_mtfsr (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xfsr nomem");
@@ -421,7 +422,7 @@ tape34xx_mtfsr (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = FORSPACEBLOCK;
@@ -434,11 +435,11 @@ tape34xx_mtfsr (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_FSB_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_FSB_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xfsr ccwgen");
 #endif /* TAPE_DEBUG */
@@ -450,7 +451,7 @@ tape34xx_mtfsr (tape_info_t * tape, int count)
  * (blocksize is set via MTSETBLK.
  */
 ccw_req_t *
-tape34xx_mtbsr (tape_info_t * tape, int count)
+tape34xx_mtbsr (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -462,7 +463,7 @@ tape34xx_mtbsr (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */   
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xbsr nomem");
@@ -473,7 +474,7 @@ tape34xx_mtbsr (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = BACKSPACEBLOCK;
@@ -486,11 +487,11 @@ tape34xx_mtbsr (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_BSB_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_BSB_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xbsr ccwg");
 #endif /* TAPE_DEBUG */
@@ -501,7 +502,7 @@ tape34xx_mtbsr (tape_info_t * tape, int count)
  * MTWEOF: Write 'count' file marks at the current position.
  */
 ccw_req_t *
-tape34xx_mtweof (tape_info_t * tape, int count)
+tape34xx_mtweof (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -513,7 +514,7 @@ tape34xx_mtweof (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xweo nomem");
@@ -524,7 +525,7 @@ tape34xx_mtweof (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = WRITETAPEMARK;
@@ -538,11 +539,11 @@ tape34xx_mtweof (tape_info_t * tape, int count)
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
        ccw++;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_WTM_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_WTM_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xweo ccwg");
 #endif /* TAPE_DEBUG */
@@ -553,12 +554,12 @@ tape34xx_mtweof (tape_info_t * tape, int count)
  * MTREW: Rewind the tape.
  */
 ccw_req_t *
-tape34xx_mtrew (tape_info_t * tape, int count)
+tape34xx_mtrew (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 3, 0);
+       cqr = tape_alloc_ccw_req (ti, 3, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xrew nomem");
@@ -569,7 +570,7 @@ tape34xx_mtrew (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = REWIND;
        ccw->flags = CCW_FLAG_CC;
@@ -580,11 +581,11 @@ tape34xx_mtrew (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_REW_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_REW_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xrew ccwg");
 #endif /* TAPE_DEBUG */
@@ -596,12 +597,12 @@ tape34xx_mtrew (tape_info_t * tape, int count)
  * Implement 'rewind unload'
  */
 ccw_req_t *
-tape34xx_mtoffl (tape_info_t * tape, int count)
+tape34xx_mtoffl (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 3, 32);
+       cqr = tape_alloc_ccw_req (ti, 3, 32);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xoff nomem");
@@ -612,7 +613,7 @@ tape34xx_mtoffl (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = REWIND_UNLOAD;
        ccw->flags = CCW_FLAG_CC;
@@ -623,11 +624,11 @@ tape34xx_mtoffl (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 32;
        ccw->cda = (unsigned long) cqr->cpaddr;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_RUN_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_RUN_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xoff ccwg");
 #endif /* TAPE_DEBUG */
@@ -638,12 +639,12 @@ tape34xx_mtoffl (tape_info_t * tape, int count)
  * MTNOP: 'No operation'.
  */
 ccw_req_t *
-tape34xx_mtnop (tape_info_t * tape, int count)
+tape34xx_mtnop (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 1, 0);
+       cqr = tape_alloc_ccw_req (ti, 1, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xnop nomem");
@@ -655,11 +656,11 @@ tape34xx_mtnop (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) ccw->cmd_code;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xnop ccwg");
 #endif /* TAPE_DEBUG */
@@ -672,7 +673,7 @@ tape34xx_mtnop (tape_info_t * tape, int count)
  * last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtbsfm (tape_info_t * tape, int count)
+tape34xx_mtbsfm (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -684,7 +685,7 @@ tape34xx_mtbsfm (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xbsm nomem");
@@ -695,7 +696,7 @@ tape34xx_mtbsfm (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = BACKSPACEFILE;
@@ -708,11 +709,11 @@ tape34xx_mtbsfm (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_BSF_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_BSF_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xbsm ccwg");
 #endif /* TAPE_DEBUG */
@@ -725,7 +726,7 @@ tape34xx_mtbsfm (tape_info_t * tape, int count)
  * of the last skipped file mark.
  */
 ccw_req_t *
-tape34xx_mtfsfm (tape_info_t * tape, int count)
+tape34xx_mtfsfm (tape_info_t * ti, int count)
 {
        long lockflags;
        int i;
@@ -737,7 +738,7 @@ tape34xx_mtfsfm (tape_info_t * tape, int count)
 #endif /* TAPE_DEBUG */
                return NULL;
        }
-       cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+       cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xfsm nomem");
@@ -748,7 +749,7 @@ tape34xx_mtfsfm (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        for (i = 0; i < count; i++) {
                ccw->cmd_code = FORSPACEFILE;
@@ -761,11 +762,11 @@ tape34xx_mtfsfm (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_FSF_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_FSF_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xfsm ccwg");
 #endif /* TAPE_DEBUG */
@@ -779,12 +780,12 @@ tape34xx_mtfsfm (tape_info_t * tape, int count)
  * MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
  */
 ccw_req_t *
-tape34xx_mteom (tape_info_t * tape, int count)
+tape34xx_mteom (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 4, 0);
+       cqr = tape_alloc_ccw_req (ti, 4, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xeom nomem");
@@ -795,7 +796,7 @@ tape34xx_mteom (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = FORSPACEFILE;
        ccw->flags = CCW_FLAG_CC;
@@ -811,11 +812,11 @@ tape34xx_mteom (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (cqr->cpaddr);
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_FSF_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_FSF_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xeom ccwg");
 #endif /* TAPE_DEBUG */
@@ -826,12 +827,12 @@ tape34xx_mteom (tape_info_t * tape, int count)
  * MTERASE: erases the tape.
  */
 ccw_req_t *
-tape34xx_mterase (tape_info_t * tape, int count)
+tape34xx_mterase (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 5, 0);
+       cqr = tape_alloc_ccw_req (ti, 5, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xera nomem");
@@ -842,7 +843,7 @@ tape34xx_mterase (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = REWIND;
        ccw->flags = CCW_FLAG_CC;
@@ -863,11 +864,11 @@ tape34xx_mterase (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_DSE_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_DSE_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xera ccwg");
 #endif /* TAPE_DEBUG */
@@ -878,12 +879,12 @@ tape34xx_mterase (tape_info_t * tape, int count)
  * MTSETDENSITY: set tape density.
  */
 ccw_req_t *
-tape34xx_mtsetdensity (tape_info_t * tape, int count)
+tape34xx_mtsetdensity (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xden nomem");
@@ -894,17 +895,17 @@ tape34xx_mtsetdensity (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xden ccwg");
 #endif /* TAPE_DEBUG */
@@ -915,7 +916,7 @@ tape34xx_mtsetdensity (tape_info_t * tape, int count)
  * MTSEEK: seek to the specified block.
  */
 ccw_req_t *
-tape34xx_mtseek (tape_info_t * tape, int count)
+tape34xx_mtseek (tape_info_t * ti, int count)
 {
        long lockflags;
        __u8 *data;
@@ -936,7 +937,7 @@ tape34xx_mtseek (tape_info_t * tape, int count)
                kfree(data);
                return NULL;
        }
-       if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08)     // IDRC on
+       if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)       // IDRC on
 
                data[1] = data[1] | 0x80;
        data[3] += count % 256;
@@ -946,7 +947,7 @@ tape34xx_mtseek (tape_info_t * tape, int count)
        debug_text_event (tape_debug_area,6,"xsee id:");
        debug_int_event (tape_debug_area,6,count);
 #endif /* TAPE_DEBUG */
-       cqr = tape_alloc_ccw_req (tape, 3, 0);
+       cqr = tape_alloc_ccw_req (ti, 3, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xsee nomem");
@@ -958,7 +959,7 @@ tape34xx_mtseek (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = LOCATE;
        ccw->flags = CCW_FLAG_CC;
@@ -969,11 +970,11 @@ tape34xx_mtseek (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = data;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_LBL_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = data;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_LBL_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xsee ccwg");
 #endif /* TAPE_DEBUG */
@@ -984,13 +985,13 @@ tape34xx_mtseek (tape_info_t * tape, int count)
  * MTTELL: Tell block. Return the number of block relative to current file.
  */
 ccw_req_t *
-tape34xx_mttell (tape_info_t * tape, int count)
+tape34xx_mttell (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
        void *mem;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xtel nomem");
@@ -1009,18 +1010,18 @@ tape34xx_mttell (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
 
        ccw->cmd_code = READ_BLOCK_ID;
        ccw->flags = 0;
        ccw->count = 8;
        set_normalized_cda (ccw, (unsigned long) mem);
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = mem;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_RBI_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = mem;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_RBI_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xtel ccwg");
 #endif /* TAPE_DEBUG */
@@ -1032,12 +1033,12 @@ tape34xx_mttell (tape_info_t * tape, int count)
  * Implement NOP.
  */
 ccw_req_t *
-tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count)
+tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xbuf nomem");
@@ -1048,17 +1049,17 @@ tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xbuf ccwg");
 #endif /* TAPE_DEBUG */
@@ -1070,12 +1071,12 @@ tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count)
  * Implement NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtlock (tape_info_t * tape, int count)
+tape34xx_mtlock (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xloc nomem");
@@ -1086,17 +1087,17 @@ tape34xx_mtlock (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xloc ccwg");
 #endif /* TAPE_DEBUG */
@@ -1108,12 +1109,12 @@ tape34xx_mtlock (tape_info_t * tape, int count)
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtunlock (tape_info_t * tape, int count)
+tape34xx_mtunlock (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xulk nomem");
@@ -1124,17 +1125,17 @@ tape34xx_mtunlock (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xulk ccwg");
 #endif /* TAPE_DEBUG */
@@ -1143,52 +1144,25 @@ tape34xx_mtunlock (tape_info_t * tape, int count)
 
 /*
  * MTLOAD: Loads the tape.
- * Implement the NOP CCW command.
+ * This function is not implemented and returns NULL, which causes the Frontend to wait for a medium being loaded.
+ *  The 3480/3490 type Tapes do not support a load command
  */
 ccw_req_t *
-tape34xx_mtload (tape_info_t * tape, int count)
+tape34xx_mtload (tape_info_t * ti, int count)
 {
-       long lockflags;
-       ccw_req_t *cqr;
-       ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
-       if (!cqr) {
-#ifdef TAPE_DEBUG
-               debug_text_exception (tape_debug_area,6,"xloa nomem");
-#endif /* TAPE_DEBUG */
-               return NULL;
-       }
-       ccw = cqr->cpaddr;
-       ccw->cmd_code = MODE_SET_DB;
-       ccw->flags = CCW_FLAG_CC;
-       ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
-       ccw++;
-       ccw->cmd_code = NOP;
-       ccw->flags = 0;
-       ccw->count = 0;
-       ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-#ifdef TAPE_DEBUG
-       debug_text_event (tape_debug_area,6,"xloa ccwg");
-#endif /* TAPE_DEBUG */
-       return cqr;
+         return NULL;
 }
 
 /*
  * MTUNLOAD: Rewind the tape and unload it.
  */
 ccw_req_t *
-tape34xx_mtunload (tape_info_t * tape, int count)
+tape34xx_mtunload (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 3, 32);
+       cqr = tape_alloc_ccw_req (ti, 3, 32);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xunl nomem");
@@ -1199,7 +1173,7 @@ tape34xx_mtunload (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = REWIND_UNLOAD;
        ccw->flags = CCW_FLAG_CC;
@@ -1210,11 +1184,11 @@ tape34xx_mtunload (tape_info_t * tape, int count)
        ccw->flags = 0;
        ccw->count = 32;
        ccw->cda = (unsigned long) cqr->cpaddr;
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_RUN_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_RUN_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xunl ccwg");
 #endif /* TAPE_DEBUG */
@@ -1226,7 +1200,7 @@ tape34xx_mtunload (tape_info_t * tape, int count)
  * Sets the IDRC on/off.
  */
 ccw_req_t *
-tape34xx_mtcompression (tape_info_t * tape, int count)
+tape34xx_mtcompression (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
@@ -1238,12 +1212,12 @@ tape34xx_mtcompression (tape_info_t * tape, int count)
                return NULL;
        }
        if (count == 0)
-               ((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x00;         // IDRC off
+               ((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x00;           // IDRC off
 
        else
-               ((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x08;         // IDRC on
+               ((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x08;           // IDRC on
 
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xcom nomem");
@@ -1254,17 +1228,17 @@ tape34xx_mtcompression (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xcom ccwg");
 #endif /* TAPE_DEBUG */
@@ -1276,12 +1250,12 @@ tape34xx_mtcompression (tape_info_t * tape, int count)
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtsetpart (tape_info_t * tape, int count)
+tape34xx_mtsetpart (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xspa nomem");
@@ -1292,17 +1266,17 @@ tape34xx_mtsetpart (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xspa ccwg");
 #endif /* TAPE_DEBUG */
@@ -1314,12 +1288,12 @@ tape34xx_mtsetpart (tape_info_t * tape, int count)
  * Implement the NOP CCW command.
  */
 ccw_req_t *
-tape34xx_mtmkpart (tape_info_t * tape, int count)
+tape34xx_mtmkpart (tape_info_t * ti, int count)
 {
        long lockflags;
        ccw_req_t *cqr;
        ccw1_t *ccw;
-       cqr = tape_alloc_ccw_req (tape, 2, 0);
+       cqr = tape_alloc_ccw_req (ti, 2, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xnpa nomem");
@@ -1330,17 +1304,17 @@ tape34xx_mtmkpart (tape_info_t * tape, int count)
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
        ccw++;
        ccw->cmd_code = NOP;
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->kernbuf = NULL;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_NOP_INIT);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->kernbuf = NULL;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_NOP_INIT);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xnpa ccwg");
 #endif /* TAPE_DEBUG */
@@ -1351,7 +1325,7 @@ tape34xx_mtmkpart (tape_info_t * tape, int count)
  * MTIOCGET: query the tape drive status.
  */
 ccw_req_t *
-tape34xx_mtiocget (tape_info_t * tape, int count)
+tape34xx_mtiocget (tape_info_t * ti, int count)
 {
        return NULL;
 }
@@ -1360,22 +1334,22 @@ tape34xx_mtiocget (tape_info_t * tape, int count)
  * MTIOCPOS: query the tape position.
  */
 ccw_req_t *
-tape34xx_mtiocpos (tape_info_t * tape, int count)
+tape34xx_mtiocpos (tape_info_t * ti, int count)
 {
        return NULL;
 }
 
-ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_major) {
+ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* ti,int tapeblock_major) {
        ccw_req_t *cqr;
        ccw1_t *ccw;
        __u8 *data;
-       int s2b = blksize_size[tapeblock_major][tape->blk_minor]/hardsect_size[tapeblock_major][tape->blk_minor];
+       int s2b = blksize_size[tapeblock_major][ti->blk_minor]/hardsect_size[tapeblock_major][ti->blk_minor];
        int realcount;
        int size,bhct = 0;
        struct buffer_head* bh;
        for (bh = req->bh; bh; bh = bh->b_reqnext) {
-               if (bh->b_size > blksize_size[tapeblock_major][tape->blk_minor])
-                       for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor])
+               if (bh->b_size > blksize_size[tapeblock_major][ti->blk_minor])
+                       for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor])
                                bhct++;
                else
                        bhct++;
@@ -1389,7 +1363,7 @@ ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_
        data[0] = 0x01;
        data[1] = data[2] = data[3] = 0x00;
        realcount=req->sector/s2b;
-       if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08)     // IDRC on
+       if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08)       // IDRC on
 
                data[1] = data[1] | 0x80;
        data[3] += realcount % 256;
@@ -1399,7 +1373,7 @@ ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_
        debug_text_event (tape_debug_area,6,"xBREDid:");
        debug_int_event (tape_debug_area,6,realcount);
 #endif /* TAPE_DEBUG */
-       cqr = tape_alloc_ccw_req (tape, 2+bhct+1, 0);
+       cqr = tape_alloc_ccw_req (ti, 2+bhct+1, 0);
        if (!cqr) {
 #ifdef TAPE_DEBUG
                debug_text_exception (tape_debug_area,6,"xBREDnomem");
@@ -1411,28 +1385,28 @@ ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_
        ccw->cmd_code = MODE_SET_DB;
        ccw->flags = CCW_FLAG_CC;
        ccw->count = 1;
-       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
-       if (realcount!=tape->position) {
+       set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
+       if (realcount!=ti->position) {
            ccw++;
            ccw->cmd_code = LOCATE;
            ccw->flags = CCW_FLAG_CC;
            ccw->count = 4;
            set_normalized_cda (ccw, (unsigned long) data);
        }
-       tape->position=realcount+req->nr_sectors/s2b;
+       ti->position=realcount+req->nr_sectors/s2b;
        for (bh=req->bh;bh!=NULL;) {
                ccw->flags = CCW_FLAG_CC;
-               if (bh->b_size >= blksize_size[tapeblock_major][tape->blk_minor]) {
-                       for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor]) {
+               if (bh->b_size >= blksize_size[tapeblock_major][ti->blk_minor]) {
+                       for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor]) {
                                ccw++;
                                ccw->flags = CCW_FLAG_CC;
                                ccw->cmd_code = READ_FORWARD;
-                               ccw->count = blksize_size[tapeblock_major][tape->blk_minor];
+                               ccw->count = blksize_size[tapeblock_major][ti->blk_minor];
                                set_normalized_cda (ccw, __pa (bh->b_data + size));
                        }
                        bh = bh->b_reqnext;
                } else {        /* group N bhs to fit into byt_per_blk */
-                       for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][tape->blk_minor];) {
+                       for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][ti->blk_minor];) {
                                ccw++;
                                ccw->flags = CCW_FLAG_DC;
                                ccw->cmd_code = READ_FORWARD;
@@ -1441,10 +1415,10 @@ ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_
                                size += bh->b_size;
                                bh = bh->b_reqnext;
                        }
-                       if (size != blksize_size[tapeblock_major][tape->blk_minor]) {
+                       if (size != blksize_size[tapeblock_major][ti->blk_minor]) {
                                PRINT_WARN ("Cannot fulfill small request %d vs. %d (%ld sects)\n",
                                            size,
-                                           blksize_size[tapeblock_major][tape->blk_minor],
+                                           blksize_size[tapeblock_major][ti->blk_minor],
                                            req->nr_sectors);
                                kfree(data);
                                tape_free_request (cqr);
@@ -1459,15 +1433,15 @@ ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_
        ccw->flags = 0;
        ccw->count = 0;
        ccw->cda = (unsigned long) (&(ccw->cmd_code));
-       tape->kernbuf = data;
-       tape->userbuf = NULL;
-       tapestate_set (tape, TS_BLOCK_INIT);
+       ti->kernbuf = data;
+       ti->userbuf = NULL;
+       tapestate_set (ti, TS_BLOCK_INIT);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"xBREDccwg");
 #endif /* TAPE_DEBUG */
        return cqr;
 }
-void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* tape) {
+void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* ti) {
     ccw1_t* ccw;
     for (ccw=(ccw1_t*)cqr->cpaddr;(ccw->flags & CCW_FLAG_CC)||(ccw->flags & CCW_FLAG_DC);ccw++) 
        if ((ccw->cmd_code == MODE_SET_DB) ||
@@ -1475,49 +1449,60 @@ void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* tape) {
            (ccw->cmd_code == READ_FORWARD))
            clear_normalized_cda(ccw);
     tape_free_request(cqr);
-    kfree(tape->kernbuf);
-    tape->kernbuf=NULL;
+    kfree(ti->kernbuf);
+    ti->kernbuf=NULL;
 }
 
 /* event handlers */
 void
-tape34xx_default_handler (tape_info_t * tape)
+tape34xx_default_handler (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,6,"xdefhandle");
 #endif /* TAPE_DEBUG */
-       tapestate_set (tape, TS_FAILED);
        PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
        PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n");
        PRINT_ERR ("TAPE34XX: Current state is: %s",
-                  (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
-                   state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-"));
-       tape_dump_sense (&tape->devstat);
-       tape->rc = -EIO;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+                  (((tapestate_get (ti) < TS_SIZE) && (tapestate_get (ti) >= 0)) ?
+                   state_verbose[tapestate_get (ti)] : "->UNKNOWN STATE<-"));
+       tape_dump_sense (&ti->devstat);
+       ti->rc = -EIO;
+       ti->wanna_wakeup=1;
+        switch (tapestate_get(ti)) {
+        case TS_REW_RELEASE_INIT:
+            tapestate_set(ti,TS_FAILED);
+            wake_up (&ti->wq);
+            break;
+        case TS_BLOCK_INIT:
+            tapestate_set(ti,TS_FAILED);
+            schedule_tapeblock_exec_IO(ti);
+            break;
+        default:
+            tapestate_set(ti,TS_FAILED);
+            wake_up_interruptible (&ti->wq);
+        }      
 }
 
 void
-tape34xx_unexpect_uchk_handler (tape_info_t * tape)
+tape34xx_unexpect_uchk_handler (tape_info_t * ti)
 {
-       if ((tape->devstat.ii.sense.data[0] == 0x40) &&
-           (tape->devstat.ii.sense.data[1] == 0x40) &&
-           (tape->devstat.ii.sense.data[3] == 0x43)) {
+       if ((ti->devstat.ii.sense.data[0] == 0x40) &&
+           (ti->devstat.ii.sense.data[1] == 0x40) &&
+           (ti->devstat.ii.sense.data[3] == 0x43)) {
                // no tape in the drive
-               PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2);
+               PRINT_INFO ("Drive %d not ready. No volume loaded.\n", ti->rew_minor / 2);
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,3,"xuuh nomed");
 #endif /* TAPE_DEBUG */
-               tapestate_set (tape, TS_FAILED);
-               tape->rc = -ENOMEDIUM;
-               tape->wanna_wakeup=1;
-               wake_up_interruptible (&tape->wq);
-       } else if ((tape->devstat.ii.sense.data[0] == 0x42) &&
-                  (tape->devstat.ii.sense.data[1] == 0x44) &&
-                  (tape->devstat.ii.sense.data[3] == 0x3b)) {
+               tapestate_set (ti, TS_FAILED);
+               ti->rc = -ENOMEDIUM;
+               ti->wanna_wakeup=1;
+               wake_up_interruptible (&ti->wq);
+       } else if ((ti->devstat.ii.sense.data[0] == 0x42) &&
+                  (ti->devstat.ii.sense.data[1] == 0x44) &&
+                  (ti->devstat.ii.sense.data[3] == 0x3b)) {
                        PRINT_INFO ("Media in drive %d was changed!\n",
-                           tape->rew_minor / 2);
+                           ti->rew_minor / 2);
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,3,"xuuh medchg");
 #endif
@@ -1526,261 +1511,273 @@ tape34xx_unexpect_uchk_handler (tape_info_t * tape)
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,3,"xuuh unexp");
                debug_text_event (tape_debug_area,3,"state:");
-               debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) && 
-                                                    (tapestate_get (tape) >= 0)) ?
-                                 state_verbose[tapestate_get (tape)] : 
+               debug_text_event (tape_debug_area,3,((tapestate_get (ti) < TS_SIZE) && 
+                                                    (tapestate_get (ti) >= 0)) ?
+                                 state_verbose[tapestate_get (ti)] : 
                                  "TS UNKNOWN");
 #endif /* TAPE_DEBUG */
-               tape34xx_default_handler (tape);
+               tape34xx_default_handler (ti);
        }
 }
 
 void
-tape34xx_unused_done (tape_info_t * tape)
+tape34xx_unused_done (tape_info_t * ti)
 {
-       if ((tape->devstat.ii.sense.data[0] == 0x40) &&
-           (tape->devstat.ii.sense.data[1] == 0x40) &&
-           (tape->devstat.ii.sense.data[3] == 0x43)) {
-           // A medium was inserted in the drive!
+    if (ti->medium_is_unloaded) {
+       // A medium was inserted in the drive!
 #ifdef TAPE_DEBUG
-           debug_text_event (tape_debug_area,6,"xuud med");
+       debug_text_event (tape_debug_area,6,"xuui med");
 #endif /* TAPE_DEBUG */
-       } else {
+       PRINT_WARN ("A medium was inserted into the tape.\n");
+       ti->medium_is_unloaded=0;
+    } else {
 #ifdef TAPE_DEBUG
-               debug_text_event (tape_debug_area,3,"unsol.irq!");
-               debug_text_event (tape_debug_area,3,"dev end");
-               debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+        debug_text_event (tape_debug_area,3,"unsol.irq!");
+        debug_text_event (tape_debug_area,3,"dev end");
+        debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
 #endif /* TAPE_DEBUG */
-               PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
-               tape_dump_sense (&tape->devstat);
-       }
+       PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
+       tape_dump_sense (&ti->devstat);
+    }
 }
 
 
 void
-tape34xx_idle_done (tape_info_t * tape)
+tape34xx_idle_done (tape_info_t * ti)
 {
+    if (ti->medium_is_unloaded) {
+       // A medium was inserted in the drive!
+#ifdef TAPE_DEBUG
+       debug_text_event (tape_debug_area,6,"xuud med");
+#endif /* TAPE_DEBUG */
+       PRINT_WARN ("A medium was inserted into the tape.\n");
+       ti->medium_is_unloaded=0;
+       wake_up_interruptible (&ti->wq);
+    } else {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"unsol.irq!");
         debug_text_event (tape_debug_area,3,"dev end");
-        debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+        debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
 #endif /* TAPE_DEBUG */
        PRINT_WARN ("Unsolicited IRQ (Device End) caught in idle state.\n");
-       tape_dump_sense (&tape->devstat);
+       tape_dump_sense (&ti->devstat);
+    }
 }
 
 void
-tape34xx_block_done (tape_info_t * tape)
+tape34xx_block_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"x:bREQdone");
 #endif /* TAPE_DEBUG */
-       tapestate_set(tape,TS_DONE);
-       schedule_tapeblock_exec_IO(tape);
+       tapestate_set(ti,TS_DONE);
+       schedule_tapeblock_exec_IO(ti);
 }
 
 void
-tape34xx_bsf_init_done (tape_info_t * tape)
+tape34xx_bsf_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"bsf done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_dse_init_done (tape_info_t * tape)
+tape34xx_dse_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"dse done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_fsf_init_done (tape_info_t * tape)
+tape34xx_fsf_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"fsf done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_fsb_init_done (tape_info_t * tape)
+tape34xx_fsb_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"fsb done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_bsb_init_done (tape_info_t * tape)
+tape34xx_bsb_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"bsb done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_lbl_init_done (tape_info_t * tape)
+tape34xx_lbl_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"lbl done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
        //s390irq_spin_unlock(tape->devinfo.irq);
-       tape->wanna_wakeup=1;
-       wake_up (&tape->wq);
+       ti->wanna_wakeup=1;
+       wake_up (&ti->wq);
 }
 
 void
-tape34xx_nop_init_done (tape_info_t * tape)
+tape34xx_nop_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"nop done..");
         debug_text_exception (tape_debug_area,6,"or rew/rel");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
        //s390irq_spin_unlock(tape->devinfo.irq);
-       tape->wanna_wakeup=1;
-       wake_up (&tape->wq);
+       ti->wanna_wakeup=1;
+       wake_up (&ti->wq);
 }
 
 void
-tape34xx_rfo_init_done (tape_info_t * tape)
+tape34xx_rfo_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rfo done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rbi_init_done (tape_info_t * tape)
+tape34xx_rbi_init_done (tape_info_t * ti)
 {
        __u8 *data;
+#ifdef TAPE_DEBUG
        int i;
-       tapestate_set (tape, TS_FAILED);
-       data = tape->kernbuf;
-       tape->rc = data[3];
-       tape->rc += 256 * data[2];
-       tape->rc += 65536 * (data[1] & 0x3F);
+#endif
+       tapestate_set (ti, TS_FAILED);
+       data = ti->kernbuf;
+       ti->rc = data[3];
+       ti->rc += 256 * data[2];
+       ti->rc += 65536 * (data[1] & 0x3F);
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rbi done");
         debug_text_event (tape_debug_area,6,"data:");
        for (i=0;i<8;i++)
            debug_int_event (tape_debug_area,6,data[i]);
 #endif
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rew_init_done (tape_info_t * tape)
+tape34xx_rew_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rew done");
 #endif
        //BH: use irqsave
        //s390irq_spin_lock(tape->devinfo.irq);
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
        //s390irq_spin_unlock(tape->devinfo.irq);
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_rew_release_init_done (tape_info_t * tape)
+tape34xx_rew_release_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rewR done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
        //s390irq_spin_unlock(tape->devinfo.irq);
-       tape->wanna_wakeup=1;
-       wake_up (&tape->wq);
+       ti->wanna_wakeup=1;
+       wake_up (&ti->wq);
 }
 
 void
-tape34xx_run_init_done (tape_info_t * tape)
+tape34xx_run_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"rew done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_wri_init_done (tape_info_t * tape)
+tape34xx_wri_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"wri done");
 #endif
        //BH: use irqsave
-       //s390irq_spin_lock(tape->devinfo.irq);
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       //s390irq_spin_unlock(tape->devinfo.irq);
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       //s390irq_spin_lock(ti->devinfo.irq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       //s390irq_spin_unlock(ti->devinfo.irq);
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 void
-tape34xx_wtm_init_done (tape_info_t * tape)
+tape34xx_wtm_init_done (tape_info_t * ti)
 {
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,3,"wtm done");
 #endif
-       tapestate_set (tape, TS_DONE);
-       tape->rc = 0;
-       tape->wanna_wakeup=1;
-       wake_up_interruptible (&tape->wq);
+       tapestate_set (ti, TS_DONE);
+       ti->rc = 0;
+       ti->wanna_wakeup=1;
+       wake_up_interruptible (&ti->wq);
 }
 
 /* This function analyses the tape's sense-data in case of a unit-check. If possible,
    it tries to recover from the error. Else the user is informed about the problem. */
 void
-tape34xx_error_recovery (tape_info_t* tape)
+tape34xx_error_recovery (tape_info_t* ti)
 {
-    __u8* sense=tape->devstat.ii.sense.data;
+    __u8* sense=ti->devstat.ii.sense.data;
     int inhibit_cu_recovery=0;
-    int cu_type=tape->discipline->cu_type;
-    if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
-    if (tapestate_get(tape)==TS_BLOCK_INIT) {
+    int cu_type=ti->discipline->cu_type;
+    if ((((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
+    if (tapestate_get(ti)==TS_BLOCK_INIT) {
        // no recovery for block device, bottom half will retry...
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     }
     if (sense[0]&SENSE_COMMAND_REJECT)
-       switch (tapestate_get(tape)) {
+       switch (tapestate_get(ti)) {
        case TS_BLOCK_INIT:
        case TS_DSE_INIT:
        case TS_EGA_INIT:
@@ -1788,33 +1785,33 @@ tape34xx_error_recovery (tape_info_t* tape)
        case TS_WTM_INIT:
            if (sense[1]&SENSE_WRITE_PROTECT) {
                // trying to write, but medium is write protected
-               tape34xx_error_recovery_has_failed(tape,EACCES);
+               tape34xx_error_recovery_has_failed(ti,EACCES);
                return;
            }
        default:
-           tape34xx_error_recovery_HWBUG(tape,1);
+           tape34xx_error_recovery_HWBUG(ti,1);
            return;
        }
     // special cases for various tape-states when reaching end of recorded area
     if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) &&
        ((sense[1]==0x40) || (sense[1]==0x0c)))
-       switch (tapestate_get(tape)) {
+       switch (tapestate_get(ti)) {
        case TS_FSF_INIT:
            // Trying to seek beyond end of recorded area
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        case TS_LBL_INIT:
            // Block could not be located.
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        case TS_RFO_INIT:
            // Try to read beyond end of recorded area -> 0 bytes read
-           tape34xx_error_recovery_has_failed(tape,0);
+           tape34xx_error_recovery_has_failed(ti,0);
            return;
        }
     // Sensing special bits
     if (sense[0]&SENSE_BUS_OUT_CHECK) {
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     }
     if (sense[0]&SENSE_DATA_CHECK) {
@@ -1826,12 +1823,12 @@ tape34xx_error_recovery (tape_info_t* tape)
                (inhibit_cu_recovery)) {
                // data check is not permanent, may be recovered. 
                // We always use async-mode with cu-recovery, so this should *never* happen.
-               tape34xx_error_recovery_HWBUG(tape,2);
+               tape34xx_error_recovery_HWBUG(ti,2);
                return;
            } else {
                // data check is permanent, CU recovery has failed
                PRINT_WARN("Permanent read error, recovery failed!\n");
-               tape34xx_error_recovery_has_failed(tape,EIO);
+               tape34xx_error_recovery_has_failed(ti,EIO);
                return;
            }
        case 0x25:
@@ -1840,38 +1837,38 @@ tape34xx_error_recovery (tape_info_t* tape)
                (inhibit_cu_recovery)) {
                // data check is not permanent, may be recovered.
                // We always use async-mode with cu-recovery, so this should *never* happen.
-               tape34xx_error_recovery_HWBUG(tape,3);
+               tape34xx_error_recovery_HWBUG(ti,3);
                return;
            } else {
                // data check is permanent, cu-recovery has failed
                PRINT_WARN("Permanent write error, recovery failed!\n");
-               tape34xx_error_recovery_has_failed(tape,EIO);
+               tape34xx_error_recovery_has_failed(ti,EIO);
                return;
            }
        case 0x26:
            // Data Check (read opposite) occurred. We'll recover this.
-           tape34xx_error_recovery_read_opposite(tape);
+           tape34xx_error_recovery_read_opposite(ti);
            return;
        case 0x28:
            // The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit.
            PRINT_WARN("ID-Mark could not be written. Check your hardware!\n");
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        case 0x31:
            // Tape void. Tried to read beyond end of device. We'll report and exit.
            PRINT_WARN("Try to read beyond end of recorded area!\n");
-           tape34xx_error_recovery_has_failed(tape,ENOSPC);
+           tape34xx_error_recovery_has_failed(ti,ENOSPC);
            return;
        case 0x41:
            // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
            PRINT_WARN("Illegal block-id sequence found!\n");
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
            default:
            // well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug
            // On 3490, other data-check conditions do exist.
                if (cu_type==0x3480) {
-                   tape34xx_error_recovery_HWBUG(tape,4);
+                   tape34xx_error_recovery_HWBUG(ti,4);
                    return;
                }
        }
@@ -1881,11 +1878,11 @@ tape34xx_error_recovery (tape_info_t* tape)
        switch (sense[3]) {
        case 0x40: // overrun error
            PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n");
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        default:
            // Overrun bit is set, but erpa does not show overrun error. This is a bug.
-           tape34xx_error_recovery_HWBUG(tape,5);
+           tape34xx_error_recovery_HWBUG(ti,5);
            return;
        }
     }
@@ -1894,11 +1891,11 @@ tape34xx_error_recovery (tape_info_t* tape)
        case 0x41:
            // Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
            PRINT_WARN("Illegal block-id sequence found!\n");
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        default:
            // Record sequence error bit is set, but erpa does not show record sequence error. This is a bug.
-           tape34xx_error_recovery_HWBUG(tape,6);
+           tape34xx_error_recovery_HWBUG(ti,6);
            return;
        }
     }
@@ -1911,119 +1908,119 @@ tape34xx_error_recovery (tape_info_t* tape)
     case 0x21:
        // Data streaming not operational. Cu switches to interlock mode, we reissue the command.
        PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n");
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x22:
        // Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load.
        // All of the above are not recoverable
        PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n");
        PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x23:
        // Read data check. Should have been be covered earlier -> Bug!
-       tape34xx_error_recovery_HWBUG(tape,7);
+       tape34xx_error_recovery_HWBUG(ti,7);
        return;
     case 0x24:
        // Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end".
-       tape34xx_error_recovery_succeded(tape);
+       tape34xx_error_recovery_succeded(ti);
        return;
     case 0x25:
        // Write data check. Should have been covered earlier -> Bug!
-       tape34xx_error_recovery_HWBUG(tape,8);
+       tape34xx_error_recovery_HWBUG(ti,8);
        return;
     case 0x26:
        // Data check (read opposite). Should have been covered earlier -> Bug!
-       tape34xx_error_recovery_HWBUG(tape,9);
+       tape34xx_error_recovery_HWBUG(ti,9);
        return;
     case 0x27:
        // Command reject. May indicate illegal channel program or buffer over/underrun. 
        // Since all channel programms are issued by this driver and ought be correct,
        // we assume a over/underrun situaltion and retry the channel program.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x28:
        // Write id mark check. Should have beed covered earlier -> bug!
-       tape34xx_error_recovery_HWBUG(tape,10);
+       tape34xx_error_recovery_HWBUG(ti,10);
        return;
     case 0x29:
        // Function incompatible. Either idrc is on but hardware not capable doing idrc 
        // or a perform subsystem func is issued and the cu is not online. Anyway, this 
        // cannot be recovered and is an I/O error.
        PRINT_WARN ("Function incompatible. Try to switch off idrc! \n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x2a:
        // Unsolicited environmental data. An internal counter overflows, we can ignore
        // this and reissue the cmd.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x2b:
        // Environmental data present. Indicates either unload completed ok or read buffered 
        // log command completed ok. 
-       if (tapestate_get(tape)==TS_RUN_INIT) {
+       if (tapestate_get(ti)==TS_RUN_INIT) {
            // Rewind unload completed ok.
-           tape34xx_error_recovery_succeded(tape);
+           tape34xx_error_recovery_succeded(ti);
            return;
        }
        // Since we do not issue read buffered log commands, this should never occur -> bug.
-       tape34xx_error_recovery_HWBUG(tape,11);
+       tape34xx_error_recovery_HWBUG(ti,11);
        return;
     case 0x2c:
        // Permanent equipment check. cu has tried recovery, but did not succeed. This is an
        // I/O error.
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x2d:
        // Data security erase failure.
-       if (tapestate_get(tape)==TS_DSE_INIT) {
+       if (tapestate_get(ti)==TS_DSE_INIT) {
            // report an I/O error
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        }
        // Data security erase failure, but no such command issued. This is a bug.
-       tape34xx_error_recovery_HWBUG(tape,12);
+       tape34xx_error_recovery_HWBUG(ti,12);
        return;
     case 0x2e:
        // Not capable. This indicates either that the drive fails reading the format id mark
        // or that that format specified is not supported by the drive. We write a message and
        // return an I/O error.
        PRINT_WARN("Drive not capable processing the tape format!");
-       tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+       tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
        return;
     case 0x2f:
        // This erpa is reserved. This is a bug.
-       tape34xx_error_recovery_HWBUG(tape,13);
+       tape34xx_error_recovery_HWBUG(ti,13);
        return;
     case 0x30:
        // The medium is write protected, while trying to write on it. We'll report this.
        PRINT_WARN("Medium is write protected!\n");
-       tape34xx_error_recovery_has_failed(tape,EACCES);
+       tape34xx_error_recovery_has_failed(ti,EACCES);
        return;
     case 0x31:
        // Tape void. Should have beed covered ealier -> bug
-       tape34xx_error_recovery_HWBUG(tape,14);
+       tape34xx_error_recovery_HWBUG(ti,14);
        return;
     case 0x32:
        // Tension loss. We cannot recover this, it's an I/O error.
        PRINT_WARN("The drive lost tape tension.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x33:
        // Load Failure. The catridge was not inserted correctly or the tape is not threaded
        // correctly. We cannot recover this, the user has to reload the catridge.
        PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x34:
        // Unload failure. The drive cannot maintain tape tension and control tape movement 
        // during an unload operation. 
        PRINT_WARN("Failure during cartridge unload. Please try manually.\n");
-       if (tapestate_get(tape)!=TS_RUN_INIT) {
-           tape34xx_error_recovery_HWBUG(tape,15);
+       if (tapestate_get(ti)!=TS_RUN_INIT) {
+           tape34xx_error_recovery_HWBUG(ti,15);
            return;
        }
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x35:
        // Drive equipment check. One of the following:
@@ -2032,335 +2029,335 @@ tape34xx_error_recovery (tape_info_t* tape)
        // - the cartridge loader does not respond correctly
        // - a failure occurs during an index, load, or unload cycle
        PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x36:
        switch (cu_type) {
        case 0x3480:
            // This erpa is reserved for 3480 -> BUG
-           tape34xx_error_recovery_HWBUG(tape,16);
+           tape34xx_error_recovery_HWBUG(ti,16);
            return;
        case 0x3490:
            // End of data. This is a permanent I/O error, which cannot be recovered.
            // A read-type command has reached the end-of-data mark.
-           tape34xx_error_recovery_has_failed(tape,EIO);
+           tape34xx_error_recovery_has_failed(ti,EIO);
            return;
        }
     case 0x37:
        // Tape length error. The tape is shorter than reported in the beginning-of-tape data.
        PRINT_WARN("Tape length error.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x38:
        // Physical end of tape. A read/write operation reached the physical end of tape.
-       if (tapestate_get(tape)==TS_WRI_INIT) {
-           tape34xx_error_recovery_has_failed(tape,ENOSPC);
+       if (tapestate_get(ti)==TS_WRI_INIT) {
+           tape34xx_error_recovery_has_failed(ti,ENOSPC);
        }
        return;
     case 0x39:
        // Backward at BOT. The drive is at BOT and is requestet to move backward.
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x3a:
        // Drive switched not ready, but the command needs the drive to be ready.
        PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x3b:
        // Manual rewind or unload. This causes an I/O error.
-       PRINT_WARN("Medium is rewinded or unloaded manually.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       PRINT_WARN("Medium was rewound or unloaded manually. Expect errors! Please do only use the mtoffl and mtrew ioctl to unload tapes or rewind tapes.\n");
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x3c:
     case 0x3d:
     case 0x3e:
     case 0x3f:
        // These erpas are reserved -> BUG
-       tape34xx_error_recovery_HWBUG(tape,17);
+       tape34xx_error_recovery_HWBUG(ti,17);
        return;
     case 0x40:
        // Overrun error. This should have been covered earlier -> bug.
-       tape34xx_error_recovery_HWBUG(tape,18);
+       tape34xx_error_recovery_HWBUG(ti,18);
        return;
     case 0x41:
        // Record sequence error. This should have been covered earlier -> bug.
-       tape34xx_error_recovery_HWBUG(tape,19);
+       tape34xx_error_recovery_HWBUG(ti,19);
        return;
     case 0x42:
        // Degraded mode. A condition that can cause degraded performace is detected.
        PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n");
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x43:
        // Drive not ready. Probably swith the ready/not ready switch to ready?
        PRINT_WARN("The drive is not ready. Maybe no medium in?\n");
-       tape34xx_error_recovery_has_failed(tape,ENOMEDIUM);
+       tape34xx_error_recovery_has_failed(ti,ENOMEDIUM);
        return;
     case 0x44:
        // Locate Block unsuccessfull. We'll report this.
-       if ((tapestate_get(tape)!=TS_BLOCK_INIT) &&
-           (tapestate_get(tape)!=TS_LBL_INIT)) {
-           tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued...
+       if ((tapestate_get(ti)!=TS_BLOCK_INIT) &&
+           (tapestate_get(ti)!=TS_LBL_INIT)) {
+           tape34xx_error_recovery_HWBUG(ti,20); // No locate block was issued...
            return;
        }
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x45:
        // The drive is assigned elsewhere [to a different channel path/computer].
        PRINT_WARN("The drive is assigned elsewhere.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x46:
        // Drive not online. Drive may be switched offline, the power supply may be switched off 
        // or the drive address may not be set correctly.
        PRINT_WARN("The drive is not online.");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x47:
        // Volume fenced. cu reports volume integrity is lost! 
        PRINT_WARN("Volume fenced. The volume integrity is lost! \n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x48:
        // Log sense data and retry request. We'll do so...
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x49:
        // Bus out check. A parity check error on the bus was found.    PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x4a:
        // Control unit erp failed. We'll report this.
        PRINT_WARN("The control unit failed recovering an I/O error.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x4b:
        // Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu.
        PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x4c:
        // Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x4d:
        switch (cu_type) {
        case 0x3480:
            // This erpa is reserved for 3480 -> bug
-           tape34xx_error_recovery_HWBUG(tape,21);
+           tape34xx_error_recovery_HWBUG(ti,21);
            return;
        case 0x3490:
            // Resetting event recieved. Since the driver does not support resetting event recovery
            // (which has to be handled by the I/O Layer), we'll report and retry our command.
-           tape34xx_error_recovery_do_retry(tape);
+           tape34xx_error_recovery_do_retry(ti);
            return;
        }
     case 0x4e:
        switch (cu_type) {
        case 0x3480:
            // This erpa is reserved for 3480 -> bug.
-           tape34xx_error_recovery_HWBUG(tape,22);
+           tape34xx_error_recovery_HWBUG(ti,22);
            return;
        case 0x3490:
            // Maximum block size exeeded. This indicates, that the block to be written is larger
            // than allowed for buffered mode. We'll report this...
            PRINT_WARN("Maximum block size for buffered mode exceeded.\n");
-           tape34xx_error_recovery_has_failed(tape,ENOBUFS);
+           tape34xx_error_recovery_has_failed(ti,ENOBUFS);
            return;
        }
     case 0x4f:
        // These erpas are reserved -> bug
-       tape34xx_error_recovery_HWBUG(tape,23);
+       tape34xx_error_recovery_HWBUG(ti,23);
        return;
     case 0x50:
        // Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows.
        // This should never happen, since we're never running in extended buffered log mode -> bug.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x51:
        // Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode.
        // This should never happen, since we're never running in extended buffered log mode -> bug.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x52:
        // End of Volume complete. Rewind unload completed ok. We'll report to the user...
-       if (tapestate_get(tape)!=TS_RUN_INIT) {
-           tape34xx_error_recovery_HWBUG(tape,24);
+       if (tapestate_get(ti)!=TS_RUN_INIT) {
+           tape34xx_error_recovery_HWBUG(ti,24);
            return;
        }
-       tape34xx_error_recovery_succeded(tape);
+       tape34xx_error_recovery_succeded(ti);
        return;
     case 0x53:
        // Global command intercept. We'll have to reissue our command.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x54:
        // Channel interface recovery (temporary). This can be recovered by reissuing the command.
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        return;
     case 0x55:
        // Channel interface recovery (permanent). This cannot be recovered, we'll inform the user.
        PRINT_WARN("A permanent channel interface error occurred.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x56:
        // Channel protocol error. This cannot be recovered.
        PRINT_WARN("A channel protocol error occurred.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x57:
        switch (cu_type) {
        case 0x3480:
            // Attention intercept. We have to reissue the command.
            PRINT_WARN("An attention intercept occurred, which will be recovered.\n");
-           tape34xx_error_recovery_do_retry(tape);
+           tape34xx_error_recovery_do_retry(ti);
            return;
        case 0x3490:
            // Global status intercept. We have to reissue the command.
            PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
-           tape34xx_error_recovery_do_retry(tape);
+           tape34xx_error_recovery_do_retry(ti);
            return;
        }
     case 0x58:
     case 0x59:
        // These erpas are reserved -> bug.
-       tape34xx_error_recovery_HWBUG(tape,25);
+       tape34xx_error_recovery_HWBUG(ti,25);
        return;
     case 0x5a:
        // Tape length incompatible. The tape inserted is too long, 
        // which could cause damage to the tape or the drive.
        PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x5b:
        // Format 3480 XF incompatible
        if (sense[1]&SENSE_BEGINNING_OF_TAPE) {
            // Everything is fine. The tape will be overwritten in a different format.
-           tape34xx_error_recovery_do_retry(tape);
+           tape34xx_error_recovery_do_retry(ti);
            return;
        }
        PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x5c:
        // Format 3480-2 XF incompatible
        PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n");
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        return;
     case 0x5d:
        // Tape length violation. 
        PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n");
-       tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+       tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
        return;
     case 0x5e:
        // Compaction algorithm incompatible.
        PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n");
-       tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+       tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
        return;
     default:
        // Reserved erpas -> bug
-       tape34xx_error_recovery_HWBUG(tape,26);
+       tape34xx_error_recovery_HWBUG(ti,26);
        return;
     }
 }
 
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) {
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp fail");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-                     (tapestate_get (tape) >= 0)) ?
-       state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+                     (tapestate_get (ti) >= 0)) ?
+       state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
-       tape_dump_sense(&tape->devstat);
-       tape->rc = -error_id;
-       tape->wanna_wakeup=1;
-       switch (tapestate_get(tape)) {
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+       tape_dump_sense(&ti->devstat);
+       ti->rc = -error_id;
+       ti->wanna_wakeup=1;
+       switch (tapestate_get(ti)) {
        case TS_REW_RELEASE_INIT:
-           tapestate_set(tape,TS_FAILED);
-           wake_up (&tape->wq);
+           tapestate_set(ti,TS_FAILED);
+           wake_up (&ti->wq);
            break;
        case TS_BLOCK_INIT:
-           tapestate_set(tape,TS_FAILED);
-           schedule_tapeblock_exec_IO(tape);
+           tapestate_set(ti,TS_FAILED);
+           schedule_tapeblock_exec_IO(ti);
            break;
        default:
-           tapestate_set(tape,TS_FAILED);
-           wake_up_interruptible (&tape->wq);
+           tapestate_set(ti,TS_FAILED);
+           wake_up_interruptible (&ti->wq);
        }
     } else {
        PRINT_WARN("Recieved an unsolicited IRQ.\n");
-       tape_dump_sense(&tape->devstat);
+       tape_dump_sense(&ti->devstat);
     }
 }    
 
-void tape34xx_error_recovery_succeded(tape_info_t* tape) {
+void tape34xx_error_recovery_succeded(tape_info_t* ti) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp done");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-                     (tapestate_get (tape) >= 0)) ?
-       state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+                     (tapestate_get (ti) >= 0)) ?
+       state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) {
-       tapestate_event (tape, TE_DONE);
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_DONE)) {
+       tapestate_event (ti, TE_DONE);
     } else {
        PRINT_WARN("Recieved an unsolicited IRQ.\n");
-       tape_dump_sense(&tape->devstat);
+       tape_dump_sense(&ti->devstat);
     }
 }
 
-void tape34xx_error_recovery_do_retry(tape_info_t* tape) {
+void tape34xx_error_recovery_do_retry(tape_info_t* ti) {
 #ifdef TAPE_DEBUG
     debug_text_event (tape_debug_area,3,"xerp retr");
-    debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) && 
-                                         (tapestate_get (tape) >= 0)) ?
-                                        state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+    debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) && 
+                                         (tapestate_get (ti) >= 0)) ?
+                                        state_verbose[tapestate_get (ti)] : "UNKNOWN"));
 #endif
-    if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
-       tape_dump_sense(&tape->devstat);
-       while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options));
+    if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+       tape_dump_sense(&ti->devstat);
+       while (do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 0x00, ti->cqr->options));
     } else {
        PRINT_WARN("Recieved an unsolicited IRQ.\n");
-       tape_dump_sense(&tape->devstat);
+       tape_dump_sense(&ti->devstat);
     }
 }
     
 void 
-tape34xx_error_recovery_read_opposite (tape_info_t* tape) {
-    switch (tapestate_get(tape)) {
+tape34xx_error_recovery_read_opposite (tape_info_t* ti) {
+    switch (tapestate_get(ti)) {
     case TS_RFO_INIT:
        // We did read forward, but the data could not be read *correctly*.
        // We will read backward and then skip forward again.
-       tape->cqr=tape34xx_read_opposite(tape,0);
-       if (tape->cqr==NULL)
-           tape34xx_error_recovery_has_failed(tape,EIO);
+       ti->cqr=tape34xx_read_opposite(ti,0);
+       if (ti->cqr==NULL)
+           tape34xx_error_recovery_has_failed(ti,EIO);
        else
-           tape34xx_error_recovery_do_retry(tape);
+           tape34xx_error_recovery_do_retry(ti);
        break;
     case TS_RBA_INIT:
        // We tried to read forward and backward, but hat no success -> failed.
-       tape34xx_error_recovery_has_failed(tape,EIO);
+       tape34xx_error_recovery_has_failed(ti,EIO);
        break;
     case TS_BLOCK_INIT:
-       tape34xx_error_recovery_do_retry(tape);
+       tape34xx_error_recovery_do_retry(ti);
        break;
     default:
        PRINT_WARN("read_opposite_recovery_called_with_state:%s\n",
-                  (((tapestate_get (tape) < TS_SIZE) && 
-                    (tapestate_get (tape) >= 0)) ?
-                   state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+                  (((tapestate_get (ti) < TS_SIZE) && 
+                    (tapestate_get (ti) >= 0)) ?
+                   state_verbose[tapestate_get (ti)] : "UNKNOWN"));
     }
 }
 
 void 
-tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) {
-    devstat_t* stat=&tape->devstat;
+tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno) {
+    devstat_t* stat=&ti->devstat;
     PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
     PRINT_WARN("Please report this incident.\n");
     PRINT_WARN("State of the tape:%s\n",
-              (((tapestate_get (tape) < TS_SIZE) && 
-                (tapestate_get (tape) >= 0)) ?
-               state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+              (((tapestate_get (ti) < TS_SIZE) && 
+                (tapestate_get (ti) >= 0)) ?
+               state_verbose[tapestate_get (ti)] : "UNKNOWN"));
     PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X "
                " %02X%02X%02X%02X %02X%02X%02X%02X \n",
                stat->ii.sense.data[0], stat->ii.sense.data[1],
@@ -2381,5 +2378,5 @@ tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) {
                stat->ii.sense.data[26], stat->ii.sense.data[27],
                stat->ii.sense.data[28], stat->ii.sense.data[29],
                stat->ii.sense.data[30], stat->ii.sense.data[31]);
-    tape34xx_error_recovery_has_failed(tape,EIO);
+    tape34xx_error_recovery_has_failed(ti,EIO);
 }
index 810fe22abf3f4ce62e7f98b0aa8620f25db8a79f..48435e4b47923c446e33506489cf1e6da00ed813 100644 (file)
@@ -115,69 +115,69 @@ typedef struct _tape34xx_disc_data_t {
 
 /* discipline functions */
 int tape34xx_ioctl_overload (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
-ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * tape);
-void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * tape);
-void  tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape);
-void  tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_mtfsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtweof (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtrew (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtoffl (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtnop (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mteom (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mterase (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdensity (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtseek (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mttell (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtcompression (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtmkpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocget (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocpos (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* tape,int tapeblock_major);
-ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* tape,int tapeblock_major);
+ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * ti);
+void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * ti);
+void  tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti);
+void  tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_mtfsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtweof (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtrew (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtoffl (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtnop (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mteom (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mterase (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdensity (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtseek (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mttell (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtcompression (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtmkpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocget (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocpos (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* ti,int tapeblock_major);
+ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* ti,int tapeblock_major);
 void tape34xx_free_bread (ccw_req_t*,struct _tape_info_t*);
 void tape34xx_free_bwrite (ccw_req_t*,struct _tape_info_t*);
 
 /* Event handlers */
-void tape34xx_default_handler (tape_info_t * tape);
-void tape34xx_unexpect_uchk_handler (tape_info_t * tape);
-void tape34xx_unused_done(tape_info_t* tape);
-void tape34xx_idle_done(tape_info_t* tape);
-void tape34xx_block_done(tape_info_t* tape);
-void tape34xx_bsf_init_done(tape_info_t* tape);
-void tape34xx_dse_init_done(tape_info_t* tape);
-void tape34xx_fsf_init_done(tape_info_t* tape);
-void tape34xx_bsb_init_done(tape_info_t* tape);
-void tape34xx_fsb_init_done(tape_info_t* tape);
-void tape34xx_lbl_init_done(tape_info_t* tape);
-void tape34xx_nop_init_done(tape_info_t* tape);
-void tape34xx_rfo_init_done(tape_info_t* tape);
-void tape34xx_rbi_init_done(tape_info_t* tape);
-void tape34xx_rew_init_done(tape_info_t* tape);
-void tape34xx_rew_release_init_done(tape_info_t* tape);
-void tape34xx_run_init_done(tape_info_t* tape);
-void tape34xx_wri_init_done(tape_info_t* tape);
-void tape34xx_wtm_init_done(tape_info_t* tape);
-
-extern void schedule_tapeblock_exec_IO (tape_info_t *tape);
+void tape34xx_default_handler (tape_info_t * ti);
+void tape34xx_unexpect_uchk_handler (tape_info_t * ti);
+void tape34xx_unused_done(tape_info_t* ti);
+void tape34xx_idle_done(tape_info_t* ti);
+void tape34xx_block_done(tape_info_t* ti);
+void tape34xx_bsf_init_done(tape_info_t* ti);
+void tape34xx_dse_init_done(tape_info_t* ti);
+void tape34xx_fsf_init_done(tape_info_t* ti);
+void tape34xx_bsb_init_done(tape_info_t* ti);
+void tape34xx_fsb_init_done(tape_info_t* ti);
+void tape34xx_lbl_init_done(tape_info_t* ti);
+void tape34xx_nop_init_done(tape_info_t* ti);
+void tape34xx_rfo_init_done(tape_info_t* ti);
+void tape34xx_rbi_init_done(tape_info_t* ti);
+void tape34xx_rew_init_done(tape_info_t* ti);
+void tape34xx_rew_release_init_done(tape_info_t* ti);
+void tape34xx_run_init_done(tape_info_t* ti);
+void tape34xx_wri_init_done(tape_info_t* ti);
+void tape34xx_wtm_init_done(tape_info_t* ti);
+
+extern void schedule_tapeblock_exec_IO (tape_info_t *ti);
 
 // the error recovery stuff:
-void tape34xx_error_recovery (tape_info_t* tape);
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id);
-void tape34xx_error_recovery_succeded(tape_info_t* tape);
-void tape34xx_error_recovery_do_retry(tape_info_t* tape);
-void tape34xx_error_recovery_read_opposite (tape_info_t* tape);
-void  tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno);
+void tape34xx_error_recovery (tape_info_t* ti);
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id);
+void tape34xx_error_recovery_succeded(tape_info_t* ti);
+void tape34xx_error_recovery_do_retry(tape_info_t* ti);
+void tape34xx_error_recovery_read_opposite (tape_info_t* ti);
+void  tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno);
 #endif // _TAPE34XX_H
diff --git a/drivers/s390/char/tape3590.c b/drivers/s390/char/tape3590.c
new file mode 100644 (file)
index 0000000..7ac83d7
--- /dev/null
@@ -0,0 +1 @@
+// tbd
diff --git a/drivers/s390/char/tape3590.h b/drivers/s390/char/tape3590.h
new file mode 100644 (file)
index 0000000..7ac83d7
--- /dev/null
@@ -0,0 +1 @@
+// tbd
index e5815d362b77faf72ef29f04d4399b0085399712..e27219cbff63e9703eb369546836b99ce9383ca5 100644 (file)
@@ -56,29 +56,29 @@ static request_queue_t* tapeblock_getqueue (kdev_t kdev);
 
 #ifdef CONFIG_DEVFS_FS
 void
-tapeblock_mkdevfstree (tape_info_t* tape) {
-    tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape);
-    tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
-                                   tapeblock_major, tape->blk_minor,
-                                   TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape);
+tapeblock_mkdevfstree (tape_info_t* ti) {
+    ti->devfs_block_dir=devfs_mk_dir (ti->devfs_dir, "block", ti);
+    ti->devfs_disc=devfs_register(ti->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
+                                   tapeblock_major, ti->blk_minor,
+                                   TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, ti);
 }
 
 void
-tapeblock_rmdevfstree (tape_info_t* tape) {
-    devfs_unregister(tape->devfs_disc);
-    devfs_unregister(tape->devfs_block_dir);
+tapeblock_rmdevfstree (tape_info_t* ti) {
+    devfs_unregister(ti->devfs_disc);
+    devfs_unregister(ti->devfs_block_dir);
 }
 #endif
 
 void 
-tapeblock_setup(tape_info_t* tape) {
-    blk_size[tapeblock_major][tape->blk_minor]=0; // this will be detected
-    blksize_size[tapeblock_major][tape->blk_minor]=2048; // blocks are 2k by default.
-    hardsect_size[tapeblock_major][tape->blk_minor]=512;
-    blk_init_queue (&tape->request_queue, tape_request_fn); 
-    blk_queue_headactive (&tape->request_queue, 0); 
+tapeblock_setup(tape_info_t* ti) {
+    blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
+    blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default.
+    hardsect_size[tapeblock_major][ti->blk_minor]=512;
+    blk_init_queue (&ti->request_queue, tape_request_fn); 
+    blk_queue_headactive (&ti->request_queue, 0); 
 #ifdef CONFIG_DEVFS_FS
-    tapeblock_mkdevfstree(tape);
+    tapeblock_mkdevfstree(ti);
 #endif
 }
 
@@ -86,7 +86,7 @@ int
 tapeblock_init(void) {
     int result;
     tape_frontend_t* blkfront,*temp;
-    tape_info_t* tape;
+    tape_info_t* ti;
 
     tape_init();
     /* Register the tape major number to the kernel */
@@ -127,10 +127,10 @@ tapeblock_init(void) {
        temp=temp->next;
        temp->next=blkfront;
     }
-    tape=first_tape_info;
-    while (tape!=NULL) {
-       tapeblock_setup(tape);
-       tape=tape->next;
+    ti=first_tape_info;
+    while (ti!=NULL) {
+       tapeblock_setup(ti);
+       ti=ti->next;
     }
     return 0;
 }
@@ -171,7 +171,12 @@ tapeblock_open(struct inode *inode, struct file *filp) {
         
        s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
         rc=tapeblock_mediumdetect(ti);
-        if (rc) return rc; // in case of errors, we don't have a size of the medium
+        if (rc) {
+           s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+           tapestate_set (ti, TS_UNUSED);
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+           return rc; // in case of errors, we don't have a size of the medium
+       }
        dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev));   /* Get the device */
        s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
        ti->blk_filp = filp;
@@ -224,171 +229,171 @@ tapeblock_release(struct inode *inode, struct file *filp) {
 }
 
 static void
-tapeblock_end_request(tape_info_t* tape) {
+tapeblock_end_request(tape_info_t* ti) {
     struct buffer_head *bh;
     int uptodate;
-    if ((tapestate_get(tape)!=TS_FAILED) &&
-       (tapestate_get(tape)!=TS_DONE))
+    if ((tapestate_get(ti)!=TS_FAILED) &&
+       (tapestate_get(ti)!=TS_DONE))
        BUG(); // A request has to be completed to end it
-    uptodate=(tapestate_get(tape)==TS_DONE); // is the buffer up to date?
+    uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?
 #ifdef TAPE_DEBUG
     if (uptodate) {
        debug_text_event (tape_debug_area,6,"b:done:");
-       debug_int_event (tape_debug_area,6,(long)tape->cqr);
+       debug_int_event (tape_debug_area,6,(long)ti->cqr);
     } else {
        debug_text_event (tape_debug_area,3,"b:failed:");
-       debug_int_event (tape_debug_area,3,(long)tape->cqr);
+       debug_int_event (tape_debug_area,3,(long)ti->cqr);
     }
 #endif
     // now inform ll_rw_block about a request status
-    while ((bh = tape->current_request->bh) != NULL) {
-       tape->current_request->bh = bh->b_reqnext;
+    while ((bh = ti->current_request->bh) != NULL) {
+       ti->current_request->bh = bh->b_reqnext;
        bh->b_reqnext = NULL;
        bh->b_end_io (bh, uptodate);
     }
-    if (!end_that_request_first (tape->current_request, uptodate, "tBLK")) {
+    if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {
 #ifndef DEVICE_NO_RANDOM
-       add_blkdev_randomness (MAJOR (tape->current_request->rq_dev));
+       add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));
 #endif
-       end_that_request_last (tape->current_request);
+       end_that_request_last (ti->current_request);
     }
-    tape->discipline->free_bread(tape->cqr,tape);
-    tape->cqr=NULL;
-    tape->current_request=NULL;
-    if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE);
+    ti->discipline->free_bread(ti->cqr,ti);
+    ti->cqr=NULL;
+    ti->current_request=NULL;
+    if (tapestate_get(ti)!=TS_NOT_OPER) tapestate_set(ti,TS_IDLE);
     return;
 }
 
 static void
-tapeblock_exec_IO (tape_info_t* tape) {
+tapeblock_exec_IO (tape_info_t* ti) {
     int rc;
     struct request* req;
-    if (tape->cqr) { // process done/failed request
-       while ((tapestate_get(tape)==TS_FAILED) &&
-           tape->blk_retries>0) {
-           tape->blk_retries--;
-           tape->position=-1;
-           tapestate_set(tape,TS_BLOCK_INIT);
+    if (ti->cqr) { // process done/failed request
+       while ((tapestate_get(ti)==TS_FAILED) &&
+           ti->blk_retries>0) {
+           ti->blk_retries--;
+           ti->position=-1;
+           tapestate_set(ti,TS_BLOCK_INIT);
 #ifdef TAPE_DEBUG
            debug_text_event (tape_debug_area,3,"b:retryreq:");
-           debug_int_event (tape_debug_area,3,(long)tape->cqr);
+           debug_int_event (tape_debug_area,3,(long)ti->cqr);
 #endif
-           rc = do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 
-                       0x00, tape->cqr->options);
+           rc = do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 
+                       0x00, ti->cqr->options);
            if (rc) {
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,3,"b:doIOfail:");
-               debug_int_event (tape_debug_area,3,(long)tape->cqr);
+               debug_int_event (tape_debug_area,3,(long)ti->cqr);
 #endif 
                continue; // one retry lost 'cause doIO failed
            }
            return;
        }
-       tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
+       tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
     }
-    if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
-    if (tapestate_get (tape) == TS_NOT_OPER) {
-       tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-       tape->devinfo.irq=-1;
+    if (ti->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
+    if (tapestate_get (ti) == TS_NOT_OPER) {
+       ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+       ti->devinfo.irq=-1;
        return;
     }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-       if (list_empty (&tape->request_queue.queue_head)) {
+       if (list_empty (&ti->request_queue.queue_head)) {
 #else
-       if (tape->request_queue==NULL) {
+       if (ti->request_queue==NULL) {
 #endif
        // nothing more to do or device has dissapeared;)
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"b:Qempty");
 #endif
-       tapestate_set(tape,TS_IDLE);
+       tapestate_set(ti,TS_IDLE);
        return;
     }
     // queue is not empty, fetch a request and start IO!
-    req=tape->current_request=tape_next_request(&tape->request_queue);
+    req=ti->current_request=tape_next_request(&ti->request_queue);
     if (req==NULL) {
        BUG(); // Yo. The queue was not reported empy, but no request found. This is _bad_.
     }
     if (req->cmd!=READ) { // we only support reading
-       tapestate_set(tape,TS_FAILED);
-       tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
-       tapestate_set(tape,TS_BLOCK_INIT);
-       schedule_tapeblock_exec_IO(tape);
+       tapestate_set(ti,TS_FAILED);
+       tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
+       tapestate_set(ti,TS_BLOCK_INIT);
+       schedule_tapeblock_exec_IO(ti);
        return;
     }
-    tape->cqr=tape->discipline->bread(req,tape,tapeblock_major); //build channel program from request
-    if (!tape->cqr) {
+    ti->cqr=ti->discipline->bread(req,ti,tapeblock_major); //build channel program from request
+    if (!ti->cqr) {
        // ccw generation failed. we try again later.
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,3,"b:cqrNULL");
 #endif
-       schedule_tapeblock_exec_IO(tape);
-       tape->current_request=NULL;
+       schedule_tapeblock_exec_IO(ti);
+       ti->current_request=NULL;
        return;
     }
-    tape->blk_retries = TAPEBLOCK_RETRIES;
-    rc= do_IO (tape->devinfo.irq, tape->cqr->cpaddr, 
-              (unsigned long) tape->cqr, 0x00, tape->cqr->options);
+    ti->blk_retries = TAPEBLOCK_RETRIES;
+    rc= do_IO (ti->devinfo.irq, ti->cqr->cpaddr, 
+              (unsigned long) ti->cqr, 0x00, ti->cqr->options);
     if (rc) {
        // okay. ssch failed. we try later.
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,3,"b:doIOfail");
 #endif
-       tape->discipline->free_bread(tape->cqr,tape);
-       tape->cqr=NULL;
-       tape->current_request=NULL;
-       schedule_tapeblock_exec_IO(tape);
+       ti->discipline->free_bread(ti->cqr,ti);
+       ti->cqr=NULL;
+       ti->current_request=NULL;
+       schedule_tapeblock_exec_IO(ti);
        return;
     }
     // our request is in IO. we remove it from the queue and exit
-    tape_dequeue_request (&tape->request_queue,req);
+    tape_dequeue_request (&ti->request_queue,req);
 }
 
 static void 
 do_tape_request (request_queue_t * queue) {
-    tape_info_t* tape;
+    tape_info_t* ti;
     long lockflags;
-    for (tape=first_tape_info;
-        ((tape!=NULL) && ((&tape->request_queue)!=queue));
-        tape=tape->next);
-    if (tape==NULL) BUG();
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    if (tapestate_get(tape)!=TS_IDLE) {
-       s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+    for (ti=first_tape_info;
+        ((ti!=NULL) && ((&ti->request_queue)!=queue));
+        ti=ti->next);
+    if (ti==NULL) BUG();
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    if (tapestate_get(ti)!=TS_IDLE) {
+       s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
        return;
     }
-    if (tapestate_get(tape)!=TS_IDLE) BUG();
-    tapestate_set(tape,TS_BLOCK_INIT);
-    tapeblock_exec_IO(tape);
-    s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+    if (tapestate_get(ti)!=TS_IDLE) BUG();
+    tapestate_set(ti,TS_BLOCK_INIT);
+    tapeblock_exec_IO(ti);
+    s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
 }
 
 static void
-run_tapeblock_exec_IO (tape_info_t* tape) {
+run_tapeblock_exec_IO (tape_info_t* ti) {
     long flags_390irq,flags_ior;
     spin_lock_irqsave (&io_request_lock, flags_ior);
-    s390irq_spin_lock_irqsave(tape->devinfo.irq,flags_390irq);
-    atomic_set(&tape->bh_scheduled,0);
-    tapeblock_exec_IO(tape);
-    s390irq_spin_unlock_irqrestore(tape->devinfo.irq,flags_390irq);
+    s390irq_spin_lock_irqsave(ti->devinfo.irq,flags_390irq);
+    atomic_set(&ti->bh_scheduled,0);
+    tapeblock_exec_IO(ti);
+    s390irq_spin_unlock_irqrestore(ti->devinfo.irq,flags_390irq);
     spin_unlock_irqrestore (&io_request_lock, flags_ior);
 }
 
 void
-schedule_tapeblock_exec_IO (tape_info_t *tape)
+schedule_tapeblock_exec_IO (tape_info_t *ti)
 {
        /* Protect against rescheduling, when already running */
-        if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) {
+        if (atomic_compare_and_swap(0,1,&ti->bh_scheduled)) {
                 return;
         }
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-       INIT_LIST_HEAD(&tape->bh_tq.list);
+       INIT_LIST_HEAD(&ti->bh_tq.list);
 #endif
-       tape->bh_tq.sync = 0;
-       tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
-       tape->bh_tq.data = tape;
+       ti->bh_tq.sync = 0;
+       ti->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
+       ti->bh_tq.data = ti;
 
-       queue_task (&tape->bh_tq, &tq_immediate);
+       queue_task (&ti->bh_tq, &tq_immediate);
        mark_bh (IMMEDIATE_BH);
        return;
 }
@@ -396,10 +401,10 @@ schedule_tapeblock_exec_IO (tape_info_t *tape)
 /* wrappers around do_tape_request for different kernel versions */
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
 static void tape_request_fn (void) {
-    tape_info_t* tape=first_tape_info;
-    while (tape!=NULL) {
-       do_tape_request(&tape->request_queue);
-       tape=tape->next;
+    tape_info_t* ti=first_tape_info;
+    while (ti!=NULL) {
+       do_tape_request(&ti->request_queue);
+       ti=ti->next;
     }
 }
 #else
@@ -409,14 +414,14 @@ static void  tape_request_fn (request_queue_t* queue) {
 #endif
 
 static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
-    tape_info_t* tape=first_tape_info;
-    while ((tape!=NULL) && (MINOR(kdev)!=tape->blk_minor)) 
-        tape=tape->next;
-    if (tape!=NULL) return &tape->request_queue;
+    tape_info_t* ti=first_tape_info;
+    while ((ti!=NULL) && (MINOR(kdev)!=ti->blk_minor)) 
+        ti=ti->next;
+    if (ti!=NULL) return &ti->request_queue;
     return NULL;
 }
 
-int tapeblock_mediumdetect(tape_info_t* tape) {
+int tapeblock_mediumdetect(tape_info_t* ti) {
         ccw_req_t* cqr;
     int losize=1,hisize=1,rc;
     long lockflags;
@@ -426,168 +431,168 @@ int tapeblock_mediumdetect(tape_info_t* tape) {
     PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n");
     while (1) { //is interruped by break
        hisize=hisize << 1; // try twice the size tested before 
-       cqr=tape->discipline->mtseek (tape, hisize);
+       cqr=ti->discipline->mtseek (ti, hisize);
        if (cqr == NULL) {
 #ifdef TAPE_DEBUG
            debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
            return -ENOSPC;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->cqr = cqr;
-       tape->wanna_wakeup=0;
-       rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->cqr = cqr;
+       ti->wanna_wakeup=0;
+       rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        if (rc) return -EIO;
-       wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-       tape->cqr = NULL;
+       wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+       ti->cqr = NULL;
        tape_free_request (cqr);
-       if (tape->kernbuf) {
-           kfree (tape->kernbuf);
-           tape->kernbuf=NULL;
+       if (ti->kernbuf) {
+           kfree (ti->kernbuf);
+           ti->kernbuf=NULL;
        }
        if (signal_pending (current)) {
-               tapestate_set (tape, TS_IDLE);
+               tapestate_set (ti, TS_IDLE);
                return -ERESTARTSYS;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       if (tapestate_get (tape) == TS_FAILED) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       if (tapestate_get (ti) == TS_FAILED) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                break;
        }
-       if (tapestate_get (tape) == TS_NOT_OPER) {
-           tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-           tape->devinfo.irq=-1;
-           s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+       if (tapestate_get (ti) == TS_NOT_OPER) {
+           ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+           ti->devinfo.irq=-1;
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
            return -ENODEV;
        }
-       if (tapestate_get (tape) != TS_DONE) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       if (tapestate_get (ti) != TS_DONE) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                return -EIO;
        }
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        losize=hisize;
     }
-    cqr = tape->discipline->mtrew (tape, 1);
+    cqr = ti->discipline->mtrew (ti, 1);
     if (cqr == NULL) {
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
        return -ENOSPC;
     }
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    tape->cqr = cqr;
-    tape->wanna_wakeup=0;
-    rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-    wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-    tape->cqr = NULL;
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    ti->cqr = cqr;
+    ti->wanna_wakeup=0;
+    rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+    wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+    ti->cqr = NULL;
     tape_free_request (cqr);
     if (signal_pending (current)) {
-       tapestate_set (tape, TS_IDLE);
+       tapestate_set (ti, TS_IDLE);
        return -ERESTARTSYS;
     }
-    s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-    if (tapestate_get (tape) == TS_FAILED) {
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+    if (tapestate_get (ti) == TS_FAILED) {
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        return -EIO;
     }
-    if (tapestate_get (tape) == TS_NOT_OPER) {
-       tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-       tape->devinfo.irq=-1;
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+    if (tapestate_get (ti) == TS_NOT_OPER) {
+       ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+       ti->devinfo.irq=-1;
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
        return -ENODEV;
     }
-    if (tapestate_get (tape) != TS_DONE) {
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    if (tapestate_get (ti) != TS_DONE) {
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        return -EIO;
     }
-    tapestate_set (tape, TS_IDLE);
-    s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+    tapestate_set (ti, TS_IDLE);
+    s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
     while (losize!=hisize) {
-       cqr=tape->discipline->mtseek (tape, (hisize+losize)/2+1);
+       cqr=ti->discipline->mtseek (ti, (hisize+losize)/2+1);
        if (cqr == NULL) {
 #ifdef TAPE_DEBUG
            debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
            return -ENOSPC;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->cqr = cqr;
-       tape->wanna_wakeup=0;
-       rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->cqr = cqr;
+       ti->wanna_wakeup=0;
+       rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        if (rc) return -EIO;
-       wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-       tape->cqr = NULL;
+       wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+       ti->cqr = NULL;
        tape_free_request (cqr);
-       if (tape->kernbuf) {
-           kfree (tape->kernbuf);
-           tape->kernbuf=NULL;
+       if (ti->kernbuf) {
+           kfree (ti->kernbuf);
+           ti->kernbuf=NULL;
        }
        if (signal_pending (current)) {
-               tapestate_set (tape, TS_IDLE);
+               tapestate_set (ti, TS_IDLE);
                return -ERESTARTSYS;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       if (tapestate_get (tape) == TS_NOT_OPER) {
-           tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-           tape->devinfo.irq=-1;
-           s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       if (tapestate_get (ti) == TS_NOT_OPER) {
+           ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+           ti->devinfo.irq=-1;
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
            return -ENODEV;
        }
-       if (tapestate_get (tape) == TS_FAILED) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       if (tapestate_get (ti) == TS_FAILED) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                hisize=(hisize+losize)/2;
-               cqr = tape->discipline->mtrew (tape, 1);
+               cqr = ti->discipline->mtrew (ti, 1);
                if (cqr == NULL) {
 #ifdef TAPE_DEBUG
                    debug_text_event (tape_debug_area,6,"b:ccwg fail");
 #endif
                    return -ENOSPC;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->cqr = cqr;
-               tape->wanna_wakeup=0;
-               rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-               tape->cqr = NULL;
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->cqr = cqr;
+               ti->wanna_wakeup=0;
+               rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+               ti->cqr = NULL;
                tape_free_request (cqr);
                if (signal_pending (current)) {
-                   tapestate_set (tape, TS_IDLE);
+                   tapestate_set (ti, TS_IDLE);
                    return -ERESTARTSYS;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               if (tapestate_get (tape) == TS_FAILED) {
-                   tapestate_set (tape, TS_IDLE);
-                   s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               if (tapestate_get (ti) == TS_FAILED) {
+                   tapestate_set (ti, TS_IDLE);
+                   s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                    return -EIO;
                }
-               if (tapestate_get (tape) != TS_DONE) {
-                   tapestate_set (tape, TS_IDLE);
-                   s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               if (tapestate_get (ti) != TS_DONE) {
+                   tapestate_set (ti, TS_IDLE);
+                   s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                    return -EIO;
                }
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                continue;
        }
-       if (tapestate_get (tape) != TS_DONE) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       if (tapestate_get (ti) != TS_DONE) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                return -EIO;
        }
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        losize=(hisize+losize)/2+1;
     }
-    blk_size[tapeblock_major][tape->blk_minor]=(losize)*(blksize_size[tapeblock_major][tape->blk_minor]/1024);
+    blk_size[tapeblock_major][ti->blk_minor]=(losize)*(blksize_size[tapeblock_major][ti->blk_minor]/1024);
     return 0;
 }
index 9adb327955283157ec4b30abe32f4df0d8607234..c4a57bba0e70ab58c014f2520ab2c00d191d2768 100644 (file)
 
 int tapeblock_open(struct inode *, struct file *);
 int tapeblock_release(struct inode *, struct file *);
-void tapeblock_setup(tape_info_t* tape);
-void schedule_tapeblock_exec_IO (tape_info_t *tape);
-int tapeblock_mediumdetect(tape_info_t* tape);
+void tapeblock_setup(tape_info_t* ti);
+void schedule_tapeblock_exec_IO (tape_info_t *ti);
+int tapeblock_mediumdetect(tape_info_t* ti);
 #ifdef CONFIG_DEVFS_FS
-void tapeblock_mkdevfstree (tape_info_t* tape);
+void tapeblock_mkdevfstree (tape_info_t* ti);
 #endif
 int tapeblock_init (void);
 void tapeblock_uninit (void);
index 9115baf203dc26f8adb6735007fe33c78c3182b9..61ddecbeffaf3bfb735f9ab2c748d1dfe4dd68cb 100644 (file)
@@ -58,30 +58,30 @@ int tape_major = TAPE_MAJOR;
 
 #ifdef CONFIG_DEVFS_FS
 void
-tapechar_mkdevfstree (tape_info_t* tape) {
-    tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape);
-    tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding",
+tapechar_mkdevfstree (tape_info_t* ti) {
+    ti->devfs_char_dir=devfs_mk_dir (ti->devfs_dir, "char", ti);
+    ti->devfs_nonrewinding=devfs_register(ti->devfs_char_dir, "nonrewinding",
                                            DEVFS_FL_DEFAULT,tape_major, 
-                                           tape->nor_minor, TAPECHAR_DEFAULTMODE, 
-                                           &tape_fops, tape);
-    tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding",
-                                        DEVFS_FL_DEFAULT, tape_major, tape->rew_minor,
-                                        TAPECHAR_DEFAULTMODE, &tape_fops, tape);
+                                           ti->nor_minor, TAPECHAR_DEFAULTMODE, 
+                                           &tape_fops, ti);
+    ti->devfs_rewinding=devfs_register(ti->devfs_char_dir, "rewinding",
+                                        DEVFS_FL_DEFAULT, tape_major, ti->rew_minor,
+                                        TAPECHAR_DEFAULTMODE, &tape_fops, ti);
 }
 
 void
-tapechar_rmdevfstree (tape_info_t* tape) {
-    devfs_unregister(tape->devfs_nonrewinding);
-    devfs_unregister(tape->devfs_rewinding);
-    devfs_unregister(tape->devfs_char_dir);
+tapechar_rmdevfstree (tape_info_t* ti) {
+    devfs_unregister(ti->devfs_nonrewinding);
+    devfs_unregister(ti->devfs_rewinding);
+    devfs_unregister(ti->devfs_char_dir);
 }
 #endif
 
 void
-tapechar_setup (tape_info_t * tape)
+tapechar_setup (tape_info_t * ti)
 {
 #ifdef CONFIG_DEVFS_FS
-    tapechar_mkdevfstree(tape);
+    tapechar_mkdevfstree(ti);
 #endif
 }
 
@@ -90,7 +90,7 @@ tapechar_init (void)
 {
        int result;
        tape_frontend_t *charfront,*temp;
-       tape_info_t* tape;
+       tape_info_t* ti;
 
        tape_init();
 
@@ -137,10 +137,10 @@ tapechar_init (void)
                temp=temp->next;
            temp->next=charfront;
        }
-       tape=first_tape_info;
-       while (tape!=NULL) {
-           tapechar_setup(tape);
-           tape=tape->next;
+       ti=first_tape_info;
+       while (ti!=NULL) {
+           tapechar_setup(ti);
+           ti=ti->next;
        }
 }
 
@@ -157,17 +157,17 @@ ssize_t
 tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
 {
        long lockflags;
-       tape_info_t *tape;
+       tape_info_t *ti;
        size_t block_size;
        ccw_req_t *cqr;
        int rc;
 #ifdef TAPE_DEBUG
         debug_text_event (tape_debug_area,6,"c:read");
 #endif /* TAPE_DEBUG */
-       tape = first_tape_info;
-       while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
-               tape = (tape_info_t *) tape->next;
-       if (tape == NULL) {
+       ti = first_tape_info;
+       while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+               ti = (tape_info_t *) ti->next;
+       if (ti == NULL) {
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:nodev");
 #endif /* TAPE_DEBUG */
@@ -180,62 +180,62 @@ tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
 #endif /* TAPE_DEBUG */
                return -EOVERFLOW;      /* errno=75 Value too large for def. data type */
        }
-       if (tape->block_size == 0) {
+       if (ti->block_size == 0) {
                block_size = count;
        } else {
-               block_size = tape->block_size;
+               block_size = ti->block_size;
        }
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"c:nbytes:");
        debug_int_event (tape_debug_area,6,block_size);
 #endif
-       cqr = tape->discipline->read_block (data, block_size, tape);
+       cqr = ti->discipline->read_block (data, block_size, ti);
        if (!cqr) {
                return -ENOBUFS;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->cqr = cqr;
-       tape->wanna_wakeup=0;
-       rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->cqr = cqr;
+       ti->wanna_wakeup=0;
+       rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
        if (rc) {
-           tapestate_set(tape,TS_IDLE);
+           tapestate_set(ti,TS_IDLE);
            kfree (cqr);
-           s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
            return rc;
        }
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-       wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-       tape->cqr = NULL;
-       tape->discipline->free_read_block (cqr, tape);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+       wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+       ti->cqr = NULL;
+       ti->discipline->free_read_block (cqr, ti);
        if (signal_pending (current)) {
-               tapestate_set (tape, TS_IDLE);
+               tapestate_set (ti, TS_IDLE);
                return -ERESTARTSYS;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       if (tapestate_get (tape) == TS_FAILED) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               return tape->rc;
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       if (tapestate_get (ti) == TS_FAILED) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               return ti->rc;
        }
-       if (tapestate_get (tape) == TS_NOT_OPER) {
-           tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-           tape->devinfo.irq=-1;
-           s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+       if (tapestate_get (ti) == TS_NOT_OPER) {
+           ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+           ti->devinfo.irq=-1;
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
            return -ENODEV;
        }
-       if (tapestate_get (tape) != TS_DONE) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       if (tapestate_get (ti) != TS_DONE) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                return -EIO;
        }
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"c:rbytes:");
-       debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+       debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
 #endif /* TAPE_DEBUG */
-       filp->f_pos += block_size - tape->devstat.rescnt;
-       return block_size - tape->devstat.rescnt;
+       filp->f_pos += block_size - ti->devstat.rescnt;
+       return block_size - ti->devstat.rescnt;
 }
 
 /*
@@ -245,7 +245,7 @@ ssize_t
 tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 {
        long lockflags;
-       tape_info_t *tape;
+       tape_info_t *ti;
        size_t block_size;
        ccw_req_t *cqr;
        int nblocks, i, rc;
@@ -253,10 +253,10 @@ tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"c:write");
 #endif
-       tape = first_tape_info;
-       while ((tape != NULL) && (tape->nor_filp != filp) && (tape->rew_filp != filp))
-               tape = (tape_info_t *) tape->next;
-       if (tape == NULL)
+       ti = first_tape_info;
+       while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp))
+               ti = (tape_info_t *) ti->next;
+       if (ti == NULL)
                return -ENODEV;
        if (ppos != &filp->f_pos) {
                /* "A request was outside the capabilities of the device." */
@@ -265,14 +265,14 @@ tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 #endif
                return -EOVERFLOW;      /* errno=75 Value too large for def. data type */
        }
-       if ((tape->block_size != 0) && (count % tape->block_size != 0))
+       if ((ti->block_size != 0) && (count % ti->block_size != 0))
                return -EIO;
-       if (tape->block_size == 0) {
+       if (ti->block_size == 0) {
                block_size = count;
                nblocks = 1;
        } else {
-               block_size = tape->block_size;
-               nblocks = count / (tape->block_size);
+               block_size = ti->block_size;
+               nblocks = count / (ti->block_size);
        }
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:nbytes:");
@@ -281,50 +281,50 @@ tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
                debug_int_event (tape_debug_area,6,nblocks);
 #endif
        for (i = 0; i < nblocks; i++) {
-               cqr = tape->discipline->write_block (data + i * block_size, block_size, tape);
+               cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
                if (!cqr) {
                        return -ENOBUFS;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->cqr = cqr;
-               tape->wanna_wakeup=0;
-               rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-               tape->cqr = NULL;
-               tape->discipline->free_write_block (cqr, tape);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->cqr = cqr;
+               ti->wanna_wakeup=0;
+               rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+               ti->cqr = NULL;
+               ti->discipline->free_write_block (cqr, ti);
                if (signal_pending (current)) {
-                       tapestate_set (tape, TS_IDLE);
+                       tapestate_set (ti, TS_IDLE);
                        return -ERESTARTSYS;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               if (tapestate_get (tape) == TS_FAILED) {
-                       tapestate_set (tape, TS_IDLE);
-                       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-                        if ((tape->rc==-ENOSPC) && (i!=0))
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               if (tapestate_get (ti) == TS_FAILED) {
+                       tapestate_set (ti, TS_IDLE);
+                       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+                        if ((ti->rc==-ENOSPC) && (i!=0))
                          return i*block_size;
-                       return tape->rc;
+                       return ti->rc;
                }
-               if (tapestate_get (tape) == TS_NOT_OPER) {
-                   tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-                   tape->devinfo.irq=-1;
-                   s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+               if (tapestate_get (ti) == TS_NOT_OPER) {
+                   ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+                   ti->devinfo.irq=-1;
+                   s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
                    return -ENODEV;
                }
-               if (tapestate_get (tape) != TS_DONE) {
-                       tapestate_set (tape, TS_IDLE);
-                       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               if (tapestate_get (ti) != TS_DONE) {
+                       tapestate_set (ti, TS_IDLE);
+                       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                        return -EIO;
                }
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:wbytes:"); 
-               debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+               debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
 #endif
-               filp->f_pos += block_size - tape->devstat.rescnt;
-               written += block_size - tape->devstat.rescnt;
-               if (tape->devstat.rescnt > 0)
+               filp->f_pos += block_size - ti->devstat.rescnt;
+               written += block_size - ti->devstat.rescnt;
+               if (ti->devstat.rescnt > 0)
                        return written;
        }
 #ifdef TAPE_DEBUG
@@ -337,7 +337,7 @@ tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
 static int
 tape_mtioctop (struct file *filp, short mt_op, int mt_count)
 {
-       tape_info_t *tape;
+       tape_info_t *ti;
        ccw_req_t *cqr = NULL;
        int rc;
        long lockflags;
@@ -348,113 +348,118 @@ tape_mtioctop (struct file *filp, short mt_op, int mt_count)
        debug_text_event (tape_debug_area,6,"c:arg:");
        debug_int_event (tape_debug_area,6,mt_count);
 #endif
-       tape = first_tape_info;
-       while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
-               tape = (tape_info_t *) tape->next;
-       if (tape == NULL)
+       ti = first_tape_info;
+       while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+               ti = (tape_info_t *) ti->next;
+       if (ti == NULL)
                return -ENODEV;
        switch (mt_op) {
        case MTREW:             // rewind
 
-               cqr = tape->discipline->mtrew (tape, mt_count);
+               cqr = ti->discipline->mtrew (ti, mt_count);
                break;
        case MTOFFL:            // put drive offline
 
-               cqr = tape->discipline->mtoffl (tape, mt_count);
+               cqr = ti->discipline->mtoffl (ti, mt_count);
                break;
        case MTUNLOAD:          // unload the tape
 
-               cqr = tape->discipline->mtunload (tape, mt_count);
+               cqr = ti->discipline->mtunload (ti, mt_count);
                break;
        case MTWEOF:            // write tapemark
 
-               cqr = tape->discipline->mtweof (tape, mt_count);
+               cqr = ti->discipline->mtweof (ti, mt_count);
                break;
        case MTFSF:             // forward space file
 
-               cqr = tape->discipline->mtfsf (tape, mt_count);
+               cqr = ti->discipline->mtfsf (ti, mt_count);
                break;
        case MTBSF:             // backward space file
 
-               cqr = tape->discipline->mtbsf (tape, mt_count);
+               cqr = ti->discipline->mtbsf (ti, mt_count);
                break;
        case MTFSFM:            // forward space file, stop at BOT side
 
-               cqr = tape->discipline->mtfsfm (tape, mt_count);
+               cqr = ti->discipline->mtfsfm (ti, mt_count);
                break;
        case MTBSFM:            // backward space file, stop at BOT side
 
-               cqr = tape->discipline->mtbsfm (tape, mt_count);
+               cqr = ti->discipline->mtbsfm (ti, mt_count);
                break;
        case MTFSR:             // forward space file
 
-               cqr = tape->discipline->mtfsr (tape, mt_count);
+               cqr = ti->discipline->mtfsr (ti, mt_count);
                break;
        case MTBSR:             // backward space file
 
-               cqr = tape->discipline->mtbsr (tape, mt_count);
+               cqr = ti->discipline->mtbsr (ti, mt_count);
                break;
        case MTNOP:
-               cqr = tape->discipline->mtnop (tape, mt_count);
+               cqr = ti->discipline->mtnop (ti, mt_count);
                break;
        case MTEOM:             // postion at the end of portion
 
        case MTRETEN:           // retension the tape
 
-               cqr = tape->discipline->mteom (tape, mt_count);
+               cqr = ti->discipline->mteom (ti, mt_count);
                break;
        case MTERASE:
-               cqr = tape->discipline->mterase (tape, mt_count);
+               cqr = ti->discipline->mterase (ti, mt_count);
                break;
        case MTSETDENSITY:
-               cqr = tape->discipline->mtsetdensity (tape, mt_count);
+               cqr = ti->discipline->mtsetdensity (ti, mt_count);
                break;
        case MTSEEK:
-               cqr = tape->discipline->mtseek (tape, mt_count);
+               cqr = ti->discipline->mtseek (ti, mt_count);
                break;
        case MTSETDRVBUFFER:
-               cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+               cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
                break;
        case MTLOCK:
-               cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+               cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
                break;
        case MTUNLOCK:
-               cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+               cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
                break;
        case MTLOAD:
-               cqr = tape->discipline->mtload (tape, mt_count);
-               break;
+               cqr = ti->discipline->mtload (ti, mt_count);
+               if (cqr!=NULL) break; // if backend driver has an load function ->use it
+               // if no medium is in, wait until it gets inserted
+               if (ti->medium_is_unloaded) {
+                   wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
+               }
+               return 0;
        case MTCOMPRESSION:
-               cqr = tape->discipline->mtcompression (tape, mt_count);
+               cqr = ti->discipline->mtcompression (ti, mt_count);
                break;
        case MTSETPART:
-               cqr = tape->discipline->mtsetpart (tape, mt_count);
+               cqr = ti->discipline->mtsetpart (ti, mt_count);
                break;
        case MTMKPART:
-               cqr = tape->discipline->mtmkpart (tape, mt_count);
+               cqr = ti->discipline->mtmkpart (ti, mt_count);
                break;
        case MTTELL:            // return number of block relative to current file
 
-               cqr = tape->discipline->mttell (tape, mt_count);
+               cqr = ti->discipline->mttell (ti, mt_count);
                break;
        case MTSETBLK:
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->block_size = mt_count;
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->block_size = mt_count;
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:setblk:");
                debug_int_event (tape_debug_area,6,mt_count);
 #endif
                return 0;
        case MTRESET:
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->kernbuf = tape->userbuf = NULL;
-               tapestate_set (tape, TS_IDLE);
-               tape->block_size = 0;
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->kernbuf = ti->userbuf = NULL;
+               tapestate_set (ti, TS_IDLE);
+               ti->block_size = 0;
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:devreset:");
-               debug_int_event (tape_debug_area,6,tape->blk_minor);
+               debug_int_event (tape_debug_area,6,ti->blk_minor);
 #endif
                return 0;
        default:
@@ -469,43 +474,49 @@ tape_mtioctop (struct file *filp, short mt_op, int mt_count)
 #endif
                return -ENOSPC;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       tape->cqr = cqr;
-       tape->wanna_wakeup=0;
-       rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-       wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-       tape->cqr = NULL;
-       if (tape->kernbuf != NULL) {
-               kfree (tape->kernbuf);
-               tape->kernbuf = NULL;
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       ti->cqr = cqr;
+       ti->wanna_wakeup=0;
+       rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+       wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+       ti->cqr = NULL;
+       if (ti->kernbuf != NULL) {
+               kfree (ti->kernbuf);
+               ti->kernbuf = NULL;
        }
        tape_free_request (cqr);
+       // if medium was unloaded, update the corresponding variable.
+       switch (mt_op) {
+       case MTOFFL:
+       case MTUNLOAD:
+           ti->medium_is_unloaded=1;
+       }
        if (signal_pending (current)) {
-               tapestate_set (tape, TS_IDLE);
+               tapestate_set (ti, TS_IDLE);
                return -ERESTARTSYS;
        }
-       s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-       if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (tape) == TS_FAILED))
-               tapestate_set (tape, TS_DONE);
-       if (tapestate_get (tape) == TS_FAILED) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               return tape->rc;
-       }
-       if (tapestate_get (tape) == TS_NOT_OPER) {
-           tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
-           tape->devinfo.irq=-1;
-           s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+       s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+       if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
+               tapestate_set (ti, TS_DONE);
+       if (tapestate_get (ti) == TS_FAILED) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               return ti->rc;
+       }
+       if (tapestate_get (ti) == TS_NOT_OPER) {
+           ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+           ti->devinfo.irq=-1;
+           s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
            return -ENODEV;
        }
-       if (tapestate_get (tape) != TS_DONE) {
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       if (tapestate_get (ti) != TS_DONE) {
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                return -EIO;
        }
-       tapestate_set (tape, TS_IDLE);
-       s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+       tapestate_set (ti, TS_IDLE);
+       s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
        switch (mt_op) {
        case MTRETEN:           //need to rewind the tape after moving to eom
 
@@ -531,7 +542,7 @@ tape_ioctl (struct inode *inode, struct file *filp,
            unsigned int cmd, unsigned long arg)
 {
        long lockflags;
-       tape_info_t *tape;
+       tape_info_t *ti;
        ccw_req_t *cqr;
        struct mtop op;         /* structure for MTIOCTOP */
        struct mtpos pos;       /* structure for MTIOCPOS */
@@ -541,19 +552,19 @@ tape_ioctl (struct inode *inode, struct file *filp,
 #ifdef TAPE_DEBUG
        debug_text_event (tape_debug_area,6,"c:ioct");
 #endif
-       tape = first_tape_info;
-       while ((tape != NULL) &&
-              (tape->rew_minor != MINOR (inode->i_rdev)) &&
-              (tape->nor_minor != MINOR (inode->i_rdev)))
-               tape = (tape_info_t *) tape->next;
-       if (tape == NULL) {
+       ti = first_tape_info;
+       while ((ti != NULL) &&
+              (ti->rew_minor != MINOR (inode->i_rdev)) &&
+              (ti->nor_minor != MINOR (inode->i_rdev)))
+               ti = (tape_info_t *) ti->next;
+       if (ti == NULL) {
 #ifdef TAPE_DEBUG
                debug_text_event (tape_debug_area,6,"c:nodev");
 #endif
                return -ENODEV;
        }
        // check for discipline ioctl overloading
-       if ((rc = tape->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
+       if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
            != -EINVAL) {
 #ifdef TAPE_DEBUG
            debug_text_event (tape_debug_area,6,"c:ioverloa");
@@ -563,71 +574,72 @@ tape_ioctl (struct inode *inode, struct file *filp,
 
        switch (cmd) {
        case MTIOCTOP:          /* tape op command */
-               if (copy_from_user (&op, (char *) arg, sizeof (struct mtop)))
+               if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
                         return -EFAULT;
+               }
                return (tape_mtioctop (filp, op.mt_op, op.mt_count));
        case MTIOCPOS:          /* query tape position */
-               cqr = tape->discipline->mttell (tape, 0);
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->cqr = cqr;
-               tape->wanna_wakeup=0;
-               do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-               pos.mt_blkno = tape->rc;
-               tape->cqr = NULL;
-               if (tape->kernbuf != NULL) {
-                       kfree (tape->kernbuf);
-                       tape->kernbuf = NULL;
+               cqr = ti->discipline->mttell (ti, 0);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->cqr = cqr;
+               ti->wanna_wakeup=0;
+               do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+               pos.mt_blkno = ti->rc;
+               ti->cqr = NULL;
+               if (ti->kernbuf != NULL) {
+                       kfree (ti->kernbuf);
+                       ti->kernbuf = NULL;
                }
                tape_free_request (cqr);
                if (signal_pending (current)) {
-                       tapestate_set (tape, TS_IDLE);
+                       tapestate_set (ti, TS_IDLE);
                        return -ERESTARTSYS;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
                         return -EFAULT;
                return 0;
        case MTIOCGET:
-               get.mt_erreg = tape->rc;
-               cqr = tape->discipline->mttell (tape, 0);
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tape->cqr = cqr;
-               tape->wanna_wakeup=0;
-               do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-               wait_event_interruptible (tape->wq,tape->wanna_wakeup);
-               get.mt_blkno = tape->rc;
+               get.mt_erreg = ti->rc;
+               cqr = ti->discipline->mttell (ti, 0);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               ti->cqr = cqr;
+               ti->wanna_wakeup=0;
+               do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+               wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+               get.mt_blkno = ti->rc;
                get.mt_fileno = 0;
                get.mt_type = MT_ISUNKNOWN;
-               get.mt_resid = tape->devstat.rescnt;
-               get.mt_dsreg = tape->devstat.ii.sense.data[3];
+               get.mt_resid = ti->devstat.rescnt;
+               get.mt_dsreg = ti->devstat.ii.sense.data[3];
                get.mt_gstat = 0;
-               if (tape->devstat.ii.sense.data[1] & 0x08)
+               if (ti->devstat.ii.sense.data[1] & 0x08)
                        get.mt_gstat &= GMT_BOT (1);    // BOT
 
-               if (tape->devstat.ii.sense.data[1] & 0x02)
+               if (ti->devstat.ii.sense.data[1] & 0x02)
                        get.mt_gstat &= GMT_WR_PROT (1);        // write protected
 
-               if (tape->devstat.ii.sense.data[1] & 0x40)
+               if (ti->devstat.ii.sense.data[1] & 0x40)
                        get.mt_gstat &= GMT_ONLINE (1);         //drive online
 
-               tape->cqr = NULL;
-               if (tape->kernbuf != NULL) {
-                       kfree (tape->kernbuf);
-                       tape->kernbuf = NULL;
+               ti->cqr = NULL;
+               if (ti->kernbuf != NULL) {
+                       kfree (ti->kernbuf);
+                       ti->kernbuf = NULL;
                }
                tape_free_request (cqr);
                if (signal_pending (current)) {
-                       tapestate_set (tape, TS_IDLE);
+                       tapestate_set (ti, TS_IDLE);
                        return -ERESTARTSYS;
                }
-               s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
-               tapestate_set (tape, TS_IDLE);
-               s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+               s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+               tapestate_set (ti, TS_IDLE);
+               s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
                if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
                         return -EFAULT;
                return 0;
index 68520b72cb210a51ff405402ba8f1651330892c6..eb4c35b6d6479836b59e29581c3d7e157150dd52 100644 (file)
@@ -27,7 +27,7 @@ int tape_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
 int tape_open (struct inode *,struct file *);
 int tape_release (struct inode *,struct file *);
 #ifdef CONFIG_DEVFS_FS
-void tapechar_mkdevfstree (tape_info_t* tape);
+void tapechar_mkdevfstree (tape_info_t* ti);
 #endif
 void tapechar_init (void);
 void tapechar_uninit (void);
index a16f1436d19450e521811d6065ebf34643260883..fa714c2c46effc272014b349d2320c43b4761b3d 100644 (file)
  ***********************************************************************
  */
 
+/* Kernel Version Compatibility section */
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>
+#include <asm/irq.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
 #define TAPE_DEBUG               // use s390 debug feature
+#else
+#undef TAPE_DEBUG                // debug feature not supported by our 2.2.16 code
+static inline void set_normalized_cda ( ccw1_t * cp, unsigned long address ) {
+    cp -> cda = address;
+}
+static inline void clear_normalized_cda ( ccw1_t * ccw ) {
+    ccw -> cda = 0;
+}
+#define BUG() PRINT_FATAL("tape390: CRITICAL INTERNAL ERROR OCCURED. REPORT THIS BACK TO LINUX390@DE.IBM.COM\n")
+#endif
 #define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly
 #define TAPEBLOCK_RETRIES 20     // number of retries, when a block-dev request fails.
 
 
-/* Kernel Version Compatibility section */
-#include <linux/version.h>
-#include <linux/blkdev.h>
-#include <linux/blk.h>
 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
 #define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
 do { \
index b6762444e475c2a3203797d3dcf4f2e36a47363b..1da6748ad47053a413469396f9fb89febf8abe5a 100644 (file)
@@ -23,8 +23,7 @@
 
 /* Module parameters */
 int tubdebug;
-int tubscrolltime;
-int tubscrollparm;
+int tubscrolltime = -1;
 int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
 #ifdef MODULE
 MODULE_PARM(tubdebug, "i");
@@ -67,14 +66,14 @@ unsigned char tub_ebcgraf[64] =
          0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
          0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
 
-static int tub3270_init(void);
+int tub3270_init(void);
 
 #ifndef MODULE
 
 /*
  * Can't have this driver a module & support console at the same time
  */
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 static kdev_t tub3270_con_device(struct console *);
 static void tub3270_con_unblank(void);
 static void tub3270_con_write(struct console *, const char *,
@@ -94,7 +93,6 @@ static struct console tub3270_con = {
        NULL                    /* next */
 };
 
-int tub3270_con_devno = -1;            /* set by tub3270_con_setup() */
 bcb_t tub3270_con_bcb;                 /* Buffer that receives con writes */
 spinlock_t tub3270_con_bcblock;                /* Lock for the buffer */
 int tub3270_con_irq = -1;              /* set nonneg by _activate() */
@@ -102,54 +100,45 @@ tub_t *tub3270_con_tubp;          /* set nonzero by _activate() */
 struct tty_driver tty3270_con_driver;  /* for /dev/console at 4, 64 */
 
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+int tub3270_con_devno = -1;            /* set by tub3270_con_setup() */
 __initfunc(void tub3270_con_setup(char *str, int *ints))
-#else
-static int __init tub3270_con_setup(char *str)
-#endif
 {
        int vdev;
 
        vdev = simple_strtoul(str, 0, 16);
        if (vdev >= 0 && vdev < 65536)
                tub3270_con_devno = vdev;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
        return;
-#else
-       return 1;
-#endif
 }
 
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
-__setup("condev=", tub3270_con_setup);
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 __initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
-#else
-void __init tub3270_con_init(void)
-#endif
 {
        tub3270_con_bcb.bc_len = 65536;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
        if (!MACHINE_IS_VM && !MACHINE_IS_P390)
                return kmem_start;
        tub3270_con_bcb.bc_buf = (void *)kmem_start;
        kmem_start += tub3270_con_bcb.bc_len;
        register_console(&tub3270_con);
        return kmem_start;
+}
 #else
-       if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+#define tub3270_con_devno console_device
+
+void __init tub3270_con_init(void)
+{
+       tub3270_con_bcb.bc_len = 65536;
+       if (!CONSOLE_IS_3270)
                return;
        tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
                tub3270_con_bcb.bc_len);
        register_console(&tub3270_con);
-#endif
 }
+#endif
 
 static kdev_t
 tub3270_con_device(struct console *conp)
 {
-       return MKDEV(IBM_TTY3270_MAJOR, conp->index);
+       return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
 }
 
 static void
@@ -164,7 +153,7 @@ static void
 tub3270_con_write(struct console *conp,
        const char *buf, unsigned int count)
 {
-       int flags;
+       long flags;
        tub_t *tubp = tub3270_con_tubp;
        void tty3270_sched_bh(tub_t *);
        int rc;
@@ -176,7 +165,7 @@ tub3270_con_write(struct console *conp,
        obcb.bc_rd = 0;
 
        spin_lock_irqsave(&tub3270_con_bcblock, flags);
-       rc = tub3270_movedata(&obcb, &tub3270_con_bcb);
+       rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);
        spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
 
        if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
@@ -187,27 +176,15 @@ tub3270_con_write(struct console *conp,
        
 int tub3270_con_copy(tub_t *tubp)
 {
-       int flags;
+       long flags;
        int rc;
 
        spin_lock_irqsave(&tub3270_con_bcblock, flags);
-       rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb);
+       rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);
        spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
        return rc;
 }
-#endif /* CONFIG_3270_CONSOLE */
-
-
-
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-__initfunc(void tub3270_initfunc(void))
-#else
-void __init tub3270_initfunc(void)
-#endif
-{
-       tub3270_init();
-}
+#endif /* CONFIG_TN3270_CONSOLE */
 #else /* If generated as a MODULE */
 /*
  * module init:  find tubes; get a major nbr
@@ -249,21 +226,12 @@ tub_dec_use_count(void)
 /*
  * tub3270_init() called by kernel or module initialization
  */
-static int
+int
 tub3270_init(void)
 {
        s390_dev_info_t d;
        int i, rc;
 
-       /*
-        * Initialize default scrolltime to either -1 or the
-        * module parameter tubscrolltime.
-        */
-       if (tubscrolltime)
-               tubscrollparm = tubscrolltime;
-       else
-               tubscrollparm = -1;
-
        /*
         * Copy and correct ebcdic - ascii translate tables
         */
@@ -283,30 +251,41 @@ tub3270_init(void)
        if (rc != 0)
                return rc;
 
+       if (fs3270_init() || tty3270_init()) {
+               printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
+               fs3270_fini();
+               tty3270_fini();
+               tubfiniminors();
+               return -1;
+       }
+
        for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
                if ((rc = get_dev_info_by_irq(i, &d)))
                        continue;
                if (d.status)
                        continue;
-#ifdef CONFIG_3270_CONSOLE
+
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
                        cpcmd("TERM CONMODE 3270", NULL, 0);
                        d.sid_data.cu_type = 0x3270;
                }
-#endif /* CONFIG_3270_CONSOLE */
+#else
+               if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {
+                       cpcmd("TERM CONMODE 3270", NULL, 0);
+                       d.sid_data.cu_type = 0x3270;
+               }
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
                if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
                        continue;
 
                rc = tubmakemin(i, &d);
                if (rc < 0) {
-                       if (tubnummins == 1) {  /* if first time */
-                               tubfiniminors();
-                               printk(KERN_ERR "No kernel memory available"
-                                       " for 3270 tube devices.\n");
-                               return rc;
-                       }
-                       printk(KERN_WARNING "3270 tube registration ran out of memory"
-                               " after %d devices\n", tubnummins - 1);
+                       printk(KERN_WARNING 
+                              "3270 tube registration ran out of memory"
+                              " after %d devices\n", tubnummins - 1);
                        break;
                } else {
                        printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
@@ -314,14 +293,6 @@ tub3270_init(void)
                }
        }
 
-       if (fs3270_init() || tty3270_init()) {
-               printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
-               fs3270_fini();
-               tty3270_fini();
-               tubfiniminors();
-               return -1;
-       }
-
        return 0;
 }
 
@@ -329,7 +300,7 @@ tub3270_init(void)
  * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
  */
 int
-tub3270_movedata(bcb_t *ib, bcb_t *ob)
+tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
 {
        int count;                      /* Total move length */
        int rc;
@@ -354,11 +325,21 @@ tub3270_movedata(bcb_t *ib, bcb_t *ob)
                                len2 = ob->bc_len - ob->bc_wr;
                        if (len2 > len1)
                                len2 = len1;
-
-                       memcpy(ob->bc_buf + ob->bc_wr,
-                               ib->bc_buf + ib->bc_rd,
-                               len2);
-
+                       
+                       if (fromuser) {
+                               len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
+                                                      ib->bc_buf + ib->bc_rd,
+                                                      len2);
+                               if (len2 == 0) {
+                                       if (!rc)
+                                               rc = -EFAULT;
+                                       break;
+                               }
+                       } else
+                               memcpy(ob->bc_buf + ob->bc_wr,
+                                      ib->bc_buf + ib->bc_rd,
+                                      len2);
+                       
                        ib->bc_rd += len2;
                        if (ib->bc_rd == ib->bc_len)
                                ib->bc_rd = 0;
@@ -422,7 +403,7 @@ tubmakemin(int irq, s390_dev_info_t *dp)
 {
        tub_t *tubp;
        int minor;
-       int flags;
+       long flags;
 
        if ((minor = ++tubnummins) == TUBMAXMINS)
                return -ENODEV;
@@ -446,7 +427,7 @@ tubmakemin(int irq, s390_dev_info_t *dp)
 
        tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
        tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
-               GFP_KERNEL);
+               GFP_KERNEL|GFP_DMA);
        if (tubp->tty_bcb.bc_buf == NULL) {
                TUBUNLOCK(tubp->irq, flags);
                tubdelbyirq(tubp, irq);
@@ -457,24 +438,34 @@ tubmakemin(int irq, s390_dev_info_t *dp)
        tubp->tty_bcb.bc_wr = 0;
        tubp->tty_bcb.bc_rd = 0;
        (*tubminors)[minor] = tubp;
-#ifdef CONFIG_3270_CONSOLE
-       if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL &&
-           (tub3270_con_devno == -1 ||
-            tub3270_con_devno == dp->devno)) {
-               extern void tty3270_int(tub_t *, devstat_t *);
-               tubp->cmd = TBC_CONOPEN;
-               tubp->flags |= TUB_OPEN_STET;
-               tty3270_size(tubp, &flags);
-               tty3270_aid_init(tubp);
-               tty3270_scl_init(tubp);
-               tub3270_con_irq = tubp->irq;
-               tub3270_con_tubp = tubp;
-               tubp->intv = tty3270_int;
-               tubp->cmd = TBC_UPDSTAT;
-               tty3270_build(tubp);
+
+#ifdef CONFIG_TN3270_CONSOLE
+       if (CONSOLE_IS_3270) {
+               if (tub3270_con_tubp == NULL && 
+                   tub3270_con_bcb.bc_buf != NULL &&
+                   (tub3270_con_devno == -1 ||
+                    tub3270_con_devno == dp->devno)) {
+                       extern void tty3270_int(tub_t *, devstat_t *);
+                       
+                       tub3270_con_devno = dp->devno;
+                       tubp->cmd = TBC_CONOPEN;
+                       tubp->flags |= TUB_OPEN_STET;
+                       tty3270_size(tubp, &flags);
+                       tty3270_aid_init(tubp);
+                       tty3270_scl_init(tubp);
+                       tub3270_con_irq = tubp->irq;
+                       tub3270_con_tubp = tubp;
+                       tubp->intv = tty3270_int;
+                       tubp->cmd = TBC_UPDSTAT;
+                       tty3270_build(tubp);
+               }
        }
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
+
+#ifdef CONFIG_DEVFS_FS
+       fs3270_devfs_register(tubp);
+#endif
+
        TUBUNLOCK(tubp->irq, flags);
        return minor;
 }
@@ -495,6 +486,9 @@ tubfiniminors(void)
        for (i = 0; i < TUBMAXMINS; i++) {
                tubpp = &(*tubminors)[i];
                if ((tubp = *tubpp)) {
+#ifdef CONFIG_DEVFS_FS
+                       fs3270_devfs_unregister(tubp);
+#endif
                        tubdelbyirq(tubp, tubp->irq);
                        tty3270_rcl_fini(tubp);
                        kfree(tubp->tty_bcb.bc_buf);
index a17c9990b278221c274988b3079ef505ca97a316..ec0df1343eeb980c37992a206aaaafb452cdc525 100644 (file)
@@ -16,9 +16,9 @@ int fs3270_major = -1;                        /* init to impossible -1 */
 static int fs3270_open(struct inode *, struct file *);
 static int fs3270_close(struct inode *, struct file *);
 static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-static int fs3270_read(struct file *, char *, size_t, loff_t *);
-static int fs3270_write(struct file *, const char *, size_t, loff_t *);
-static int fs3270_wait(tub_t *, int *);
+static ssize_t fs3270_read(struct file *, char *, size_t, loff_t *);
+static ssize_t fs3270_write(struct file *, const char *, size_t, loff_t *);
+static int fs3270_wait(tub_t *, long *);
 static void fs3270_int(tub_t *tubp, devstat_t *dsp);
 extern void tty3270_refresh(tub_t *);
 
@@ -33,6 +33,42 @@ static struct file_operations fs3270_fops = {
        release:fs3270_close,   /* release */
 };
 
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t fs3270_devfs_dir;
+devfs_handle_t fs3270_devfs_tub;
+extern struct file_operations tty_fops;
+
+void fs3270_devfs_register(tub_t *tubp)
+{
+       char name[16];
+
+       sprintf(name, "tub%x", tubp->devno);
+       devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
+                      IBM_FS3270_MAJOR, tubp->minor,
+                      S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
+       sprintf(name, "tty%x", tubp->devno);
+       tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
+                               fs3270_devfs_dir, name);
+}
+
+void fs3270_devfs_unregister(tub_t *tubp)
+{
+       char name[16];
+       devfs_handle_t handle;
+
+       sprintf(name, "tub%x", tubp->devno);
+       handle = devfs_find_handle (fs3270_devfs_dir, name,
+                                   IBM_FS3270_MAJOR, tubp->minor,
+                                   DEVFS_SPECIAL_CHR, 0);
+       devfs_unregister (handle);
+       sprintf(name, "tty%x", tubp->devno);
+       handle = devfs_find_handle (fs3270_devfs_dir, name,
+                                   IBM_TTY3270_MAJOR, tubp->minor,
+                                   DEVFS_SPECIAL_CHR, 0);
+       devfs_unregister(handle);
+}
+#endif
+
 /*
  * fs3270_init() -- Initialize fullscreen tubes
  */
@@ -41,15 +77,29 @@ fs3270_init(void)
 {
        int rc;
 
+#ifdef CONFIG_DEVFS_FS
+       rc = devfs_register_chrdev (IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
+       if (rc) {
+               printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
+                       IBM_FS3270_MAJOR, rc);
+               return -1;
+       }
+       fs3270_devfs_dir = devfs_mk_dir(NULL, "3270", NULL);
+       fs3270_devfs_tub = 
+               devfs_register(fs3270_devfs_dir, "tub", DEVFS_FL_DEFAULT,
+                              IBM_FS3270_MAJOR, 0,
+                              S_IFCHR | S_IRUSR | S_IWUSR, 
+                              &fs3270_fops, NULL);
+#else
        rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
        if (rc) {
                printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
                        IBM_FS3270_MAJOR, rc);
                return -1;
-       } else {
-               fs3270_major = IBM_FS3270_MAJOR;
-               return 0;
        }
+#endif
+       fs3270_major = IBM_FS3270_MAJOR;
+       return 0;
 }
 
 /*
@@ -59,6 +109,10 @@ void
 fs3270_fini(void)
 {
        if (fs3270_major != -1) {
+#ifdef CONFIG_DEVFS_FS
+               devfs_unregister(fs3270_devfs_tub);
+               devfs_unregister(fs3270_devfs_dir);
+#endif
                unregister_chrdev(fs3270_major, "fs3270");
                fs3270_major = -1;
        }
@@ -71,7 +125,7 @@ static int
 fs3270_open(struct inode *ip, struct file *fp)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
 
        /* See INODE2TUB(ip) for handling of "/dev/3270/tub" */
        if ((tubp = INODE2TUB(ip)) == NULL)
@@ -101,7 +155,7 @@ static int
 fs3270_close(struct inode *ip, struct file *fp)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
 
        if ((tubp = INODE2TUB(ip)) == NULL)
                return -ENODEV;
@@ -123,7 +177,7 @@ fs3270_close(struct inode *ip, struct file *fp)
 void
 fs3270_release(tub_t *tubp)
 {
-       int flags;
+       long flags;
 
        if (tubp->mode != TBM_FS)
                return;
@@ -145,7 +199,7 @@ fs3270_release(tub_t *tubp)
  *      * Value is 0 or -ERESTARTSYS
  */
 static int
-fs3270_wait(tub_t *tubp, int *flags)
+fs3270_wait(tub_t *tubp, long *flags)
 {
        DECLARE_WAITQUEUE(wait, current);
 
@@ -185,7 +239,7 @@ fs3270_io(tub_t *tubp, ccw1_t *ccwp)
 static void
 fs3270_bh(void *data)
 {
-       int flags;
+       long flags;
        tub_t *tubp;
 
        tubp = data;
@@ -283,7 +337,8 @@ fs3270_ioctl(struct inode *ip, struct file *fp,
        unsigned int cmd, unsigned long arg)
 {
        tub_t *tubp;
-       int rc = 0, flags;
+       int rc = 0;
+       long flags;
 
        if ((tubp = INODE2TUB(ip)) == NULL)
                return -ENODEV;
@@ -310,13 +365,14 @@ fs3270_ioctl(struct inode *ip, struct file *fp,
 /*
  * process read commands for the tube driver
  */
-static int
+static ssize_t
 fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
 {
        tub_t *tubp;
        char *kp;
        ccw1_t *cp;
-       int rc, flags;
+       int rc;
+       long flags;
 
        if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
                return -ENODEV;
@@ -325,7 +381,7 @@ fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
                return rc;
        }
 
-       kp = kmalloc(len, GFP_KERNEL);
+       kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
        if (kp == NULL) {
                TUBUNLOCK(tubp->irq, flags);
                return -ENOMEM;
@@ -352,10 +408,10 @@ fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
        if (tubdebug & 1)
                printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
                        tubp->minor,
-                       *(int*)((int)kp + 0),
-                       *(int*)((int)kp + 4),
-                       *(int*)((int)kp + 8),
-                       *(int*)((int)kp + 12));
+                       *(int*)((long)kp + 0),
+                       *(int*)((long)kp + 4),
+                       *(int*)((long)kp + 8),
+                       *(int*)((long)kp + 12));
        copy_to_user(dp, kp, len);
        kfree(kp);
        return len;
@@ -364,12 +420,13 @@ fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
 /*
  * process write commands for the tube driver
  */
-static int
+static ssize_t
 fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
 {
        tub_t *tubp;
        ccw1_t *cp;
-       int rc, flags;
+       int rc;
+       long flags;
        void *kb;
 
        /* Locate the tube */
@@ -377,7 +434,7 @@ fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
                return -ENODEV;
 
        /* Copy data to write from user address space */
-       if ((kb = kmalloc(len, GFP_KERNEL)) == NULL)
+       if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
                return -ENOMEM;
        if (copy_from_user(kb, dp, len) != 0) {
                kfree(kb);
index 750111942b90da85e37e8f99562347de98911204..806b42bcfaecd7f1c3c577e0cb2119ac1c0caff2 100644 (file)
@@ -23,7 +23,7 @@
 #endif /* IBM_FS3270_MAJOR */
 
 
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 #include <linux/console.h>
@@ -31,6 +31,9 @@
 #include <asm/ebcdic.h>
 #include <asm/uaccess.h>
 #include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#include <linux/devfs_fs_kernel.h>
+#endif
 
 #define TUB(x) (('3'<<8)|(x))
 #define TUBICMD TUB(3)
@@ -280,11 +283,15 @@ typedef struct tub_s {
 #define        TUB_OPEN_STET   0x0400          /* No screen clear on open */
 #define        TUB_UE_BUSY     0x0800
 
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 /*
  * Extra stuff for 3270 console support
  */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 #define        S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64)
+#else
+#define        S390_CONSOLE_DEV MKDEV(TTYAUX_MAJOR, 1)
+#endif
 extern int tub3270_con_devno;
 extern char (*tub3270_con_output)[];
 extern int tub3270_con_outputl;
@@ -293,7 +300,7 @@ extern int tub3270_con_oucount;
 extern int tub3270_con_irq;
 extern tub_t *tub3270_con_tubp;
 extern struct tty_driver tty3270_con_driver;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
 extern int tubnummins;
 extern tub_t *(*tubminors)[TUBMAXMINS];
@@ -306,6 +313,12 @@ extern int fs3270_major;
 extern int tty3270_major;
 extern int tty3270_proc_misc;
 extern enum tubwhat tty3270_proc_what;
+extern struct tty_driver tty3270_driver;
+#ifdef CONFIG_DEVFS_FS
+extern devfs_handle_t fs3270_devfs_dir;
+extern void fs3270_devfs_register(tub_t *);
+extern void fs3270_devfs_unregister(tub_t *);
+#endif
 
 #ifndef spin_trylock_irqsave
 #define spin_trylock_irqsave(lock, flags) \
@@ -343,67 +356,50 @@ extern tub_t *tubfindbyirq(int);
  * Find tub_t * given fullscreen device's inode pointer
  * This algorithm takes into account /dev/3270/tub.
  */
-#ifdef CONFIG_3270_CONSOLE
-#define INODE2TUB(ip) \
-({ \
-       unsigned int minor; \
-       tub_t *tubp = NULL; \
-       minor = MINOR((ip)->i_rdev); \
-       if (minor == 0 && current->tty != NULL) { \
-               if (tub3270_con_tubp != NULL && \
-                   current->tty->device == S390_CONSOLE_DEV) \
-                       minor = tub3270_con_tubp->minor; \
-               else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
-                       minor = MINOR(current->tty->device); \
-       } \
-       if (minor <= tubnummins && minor > 0) \
-               tubp = (*tubminors)[minor]; \
-       tubp; \
-})
-#else /* not CONFIG_3270_CONSOLE */
-#define INODE2TUB(ip) \
-({ \
-       unsigned int minor; \
-       tub_t *tubp = NULL; \
-       minor = MINOR((ip)->i_rdev); \
-       if (minor == 0 && current->tty != NULL && \
-           MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
-               minor = MINOR(current->tty->device); \
-       if (minor <= tubnummins && minor > 0) \
-               tubp = (*tubminors)[minor]; \
-       tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *INODE2TUB(struct inode *ip)
+{
+       unsigned int minor = MINOR(ip->i_rdev);
+       tub_t *tubp = NULL;
+       if (minor == 0 && current->tty != NULL) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+               if (tub3270_con_tubp != NULL &&
+                   current->tty->device == S390_CONSOLE_DEV)
+                       minor = tub3270_con_tubp->minor;
+               else
+#endif
+#endif
+               if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR)
+                       minor = MINOR(current->tty->device);
+       }
+       if (minor >= tubnummins && minor > 0)
+               tubp = (*tubminors)[minor];
+       return tubp;
+}
+
 /*
  * Find tub_t * given non-fullscreen (tty) device's tty_struct pointer
  */
-#ifdef CONFIG_3270_CONSOLE
-#define TTY2TUB(tty) \
-({ \
-       unsigned int minor; \
-       tub_t *tubp = NULL; \
-       minor = MINOR(tty->device); \
-       if (tty->device == S390_CONSOLE_DEV) \
-               tubp = tub3270_con_tubp; \
-       else if (minor <= tubnummins && minor > 0) \
-               tubp = (*tubminors)[minor]; \
-       tubp; \
-})
-#else /* if not CONFIG_3270_CONSOLE */
-#define TTY2TUB(tty) \
-({ \
-       unsigned int minor; \
-       tub_t *tubp = NULL; \
-       minor = MINOR(tty->device); \
-       if (minor <= tubnummins && minor > 0) \
-               tubp = (*tubminors)[minor]; \
-       tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *TTY2TUB(struct tty_struct *tty)
+{
+       unsigned int minor = MINOR(tty->device);
+       tub_t *tubp = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+       if (tty->device == S390_CONSOLE_DEV)
+               tubp = tub3270_con_tubp;
+       else
+#endif
+#endif
+       if (minor <= tubnummins && minor > 0)
+               tubp = (*tubminors)[minor];
+       return tubp;
+}
 
 extern void tub_inc_use_count(void);
 extern void tub_dec_use_count(void);
-extern int tub3270_movedata(bcb_t *, bcb_t *);
+extern int tub3270_movedata(bcb_t *, bcb_t *, int);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
 extern int tubmakemin(int, dev_info_t *);
 #else
@@ -418,7 +414,7 @@ extern void tty3270_rcl_put(tub_t *, char *, int);
 extern void tty3270_rcl_sync(tub_t *);
 extern void tty3270_rcl_purge(tub_t *);
 extern int tty3270_rcl_resize(tub_t *, int);
-extern int tty3270_size(tub_t *, int *);
+extern int tty3270_size(tub_t *, long *);
 extern int tty3270_aid_init(tub_t *);
 extern void tty3270_aid_fini(tub_t *);
 extern void tty3270_aid_reinit(tub_t *);
index f941f368484a91af6864bc3c79c7850c185748e3..262c6f5277ce8ff939d1a632e93c13d01b9b8bf9 100644 (file)
@@ -37,7 +37,7 @@ static int tty3270_write_proc(struct file *, const char *,
 /* tty3270 utility functions */
 static void tty3270_bh(void *);
        void tty3270_sched_bh(tub_t *);
-static int tty3270_wait(tub_t *, int *);
+static int tty3270_wait(tub_t *, long *);
        void tty3270_int(tub_t *, devstat_t *);
        int tty3270_try_logging(tub_t *);
 static void tty3270_start_input(tub_t *);
@@ -48,20 +48,19 @@ static void tty3270_do_showi(tub_t *, char *, int);
 static int tty3270_show_tube(int, char *, int);
 
 int tty3270_major = -1;
-char tty3270_major_string[16];
 struct tty_driver tty3270_driver;
 int tty3270_refcount;
 struct tty_struct *tty3270_table[TUBMAXMINS];
 struct termios *tty3270_termios[TUBMAXMINS];
 struct termios *tty3270_termios_locked[TUBMAXMINS];
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
 int con3270_major = -1;
 struct tty_driver con3270_driver;
 int con3270_refcount;
 struct tty_struct *con3270_table[1];
 struct termios *con3270_termios[1];
 struct termios *con3270_termios_locked[1];
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
 int tty3270_proc_index;
 int tty3270_proc_data;
@@ -88,6 +87,9 @@ tty3270_init(void)
        td->subtype = SYSTEM_TYPE_TTY;
        td->init_termios = tty_std_termios;
        td->flags = TTY_DRIVER_RESET_TERMIOS;
+#ifdef CONFIG_DEVFS_FS
+       td->flags |= TTY_DRIVER_NO_DEVFS;
+#endif
        td->refcount = &tty3270_refcount;
        td->table = tty3270_table;
        td->termios = tty3270_termios;
@@ -121,32 +123,36 @@ tty3270_init(void)
                printk(KERN_ERR "tty3270 registration failed with %d\n", rc);
        } else {
                tty3270_major = IBM_TTY3270_MAJOR;
-               sprintf(tty3270_major_string, "%d", tty3270_major);
                if (td->proc_entry != NULL)
                        td->proc_entry->mode = S_IRUGO | S_IWUGO;
        }
-#ifdef CONFIG_3270_CONSOLE
-       tty3270_con_driver = *td;
-       td = &tty3270_con_driver;
-       td->driver_name = "con3270";
-       td->name = "con3270";
-       td->major = MAJOR(S390_CONSOLE_DEV);
-       td->minor_start = MINOR(S390_CONSOLE_DEV);
-       td->num = 1;
-       td->refcount = &con3270_refcount;
-       td->table = con3270_table;
-       td->termios = con3270_termios;
-       td->termios_locked = con3270_termios_locked;
-
-       rc = tty_register_driver(td);
-       if (rc) {
-               printk(KERN_ERR "con3270 registration failed with %d\n", rc);
-       } else {
-               con3270_major = MAJOR(S390_CONSOLE_DEV);
-               if (td->proc_entry != NULL)
-                       td->proc_entry->mode = S_IRUGO | S_IWUGO;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+       if (CONSOLE_IS_3270) {
+               tty3270_con_driver = *td;
+               td = &tty3270_con_driver;
+               td->driver_name = "con3270";
+               td->name = "con3270";
+               td->major = MAJOR(S390_CONSOLE_DEV);
+               td->minor_start = MINOR(S390_CONSOLE_DEV);
+               td->num = 1;
+               td->refcount = &con3270_refcount;
+               td->table = con3270_table;
+               td->termios = con3270_termios;
+               td->termios_locked = con3270_termios_locked;
+
+               rc = tty_register_driver(td);
+               if (rc) {
+                       printk(KERN_ERR
+                              "con3270 registration failed with %d\n", rc);
+               } else {
+                       con3270_major = MAJOR(S390_CONSOLE_DEV);
+                       if (td->proc_entry != NULL)
+                               td->proc_entry->mode = S_IRUGO | S_IWUGO;
+               }
        }
-#endif /* if CONFIG_3270_CONSOLE */
+#endif /* ifdef CONFIG_TN3270_CONSOLE */
+#endif /* if LINUX_VERSION_CODE */
 
        return rc;
 }
@@ -161,8 +167,8 @@ tty3270_fini(void)
                tty_unregister_driver(&tty3270_driver);
                tty3270_major = -1;
        }
-#ifdef CONFIG_3270_CONSOLE
-       if (con3270_major != -1) {
+#ifdef CONFIG_TN3270_CONSOLE
+       if (CONSOLE_IS_3270 && con3270_major != -1) {
                tty_unregister_driver(&con3270_driver);
                con3270_major = -1;
        }
@@ -173,7 +179,7 @@ static int
 tty3270_open(struct tty_struct *tty, struct file *filp)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
        int rc;
        int cmd;
 
@@ -229,7 +235,7 @@ static void
 tty3270_close(struct tty_struct *tty, struct file *filp)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
 
        if ((tubp = tty->driver_data) == NULL)
                return;
@@ -252,24 +258,24 @@ tty3270_write(struct tty_struct *tty, int fromuser,
                const unsigned char *buf, int count)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
        bcb_t obcb;
        int rc = 0;
 
        if ((tubp = tty->driver_data) == NULL)
                return -1;
 
-#ifdef CONFIG_3270_CONSOLE
-       if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+       if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
                tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
 
        obcb.bc_buf = (char *)buf;
        obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
        obcb.bc_rd = 0;
 
        TUBLOCK(tubp->irq, flags);
-       rc = tub3270_movedata(&obcb, &tubp->tty_bcb);
+       rc = tub3270_movedata(&obcb, &tubp->tty_bcb, fromuser);
        tty3270_try_logging(tubp);
        TUBUNLOCK(tubp->irq, flags);
        return rc;
@@ -278,7 +284,7 @@ tty3270_write(struct tty_struct *tty, int fromuser,
 static void
 tty3270_put_char(struct tty_struct *tty, unsigned char ch)
 {
-       int flags;
+       long flags;
        tub_t *tubp;
        bcb_t *ob;
 
@@ -301,7 +307,7 @@ static void
 tty3270_flush_chars(struct tty_struct *tty)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
 
        if ((tubp = tty->driver_data) == NULL)
                return;
@@ -342,7 +348,7 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file,
                unsigned int cmd, unsigned long arg)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
        int ret = 0;
        struct termios termios;
 
@@ -394,7 +400,7 @@ static void
 tty3270_set_termios(struct tty_struct *tty, struct termios *old)
 {
        tub_t *tubp;
-       int flags;
+       long flags;
        int new;
 
        if ((tubp = tty->driver_data) == NULL)
@@ -420,7 +426,7 @@ tty3270_flush_buffer(struct tty_struct *tty)
 {
        tub_t *tubp;
        bcb_t *ob;
-       int flags;
+       long flags;
 
        if ((tubp = tty->driver_data) == NULL)
                return;
@@ -452,7 +458,6 @@ tty3270_read_proc(char *buf, char **start, off_t off, int count,
        int i;
        int rc;
        int len = 0;
-       char *majstr;
 
        if (tty3270_proc_what == TW_CONFIG) {
                /*
@@ -464,13 +469,14 @@ tty3270_read_proc(char *buf, char **start, off_t off, int count,
                len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
                for (i = 1; i <= tubnummins; i++) {
                        tubp = (*tubminors)[i];
-                       majstr = tty3270_major_string;
-#ifdef CONFIG_3270_CONSOLE
-                       if (tubp == tub3270_con_tubp)
-                               majstr = "CONSOLE";
-#endif /* CONFIG_3270_CONSOLE */
-                       len += sprintf(buf + len, "%.3x %s %d\n",
-                               tubp->devno, majstr, i);
+#ifdef CONFIG_TN3270_CONSOLE
+                       if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
+                               len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+                                              tubp->devno, i);
+                       else
+#endif
+                               len += sprintf(buf + len, "%.3x %d %d\n",
+                                              tubp->devno, tty3270_major, i);
                        if (begin + len > off + count)
                                break;
                        if (begin + len < off) {
@@ -536,10 +542,12 @@ tty3270_write_proc(struct file *file, const char *buffer,
        if (device) {
                if (MAJOR(device) == IBM_TTY3270_MAJOR)
                        tubp = (*tubminors)[MINOR(device)];
-#ifdef CONFIG_3270_CONSOLE
-               if (device == S390_CONSOLE_DEV)
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
                        tubp = tub3270_con_tubp;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
        }
        if (tubp) {
                if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
@@ -595,7 +603,7 @@ tty3270_hangup(struct tty_struct *tty)
 static void
 tty3270_bh(void *data)
 {
-       int flags;
+       long flags;
        tub_t *tubp;
        struct tty_struct *tty;
 
@@ -675,7 +683,7 @@ tty3270_io(tub_t *tubp)
  * On entry the lock must not be held; on exit it is held.
  */
 static int
-tty3270_wait(tub_t *tubp, int *flags)
+tty3270_wait(tub_t *tubp, long *flags)
 {
        DECLARE_WAITQUEUE(wait, current);
 
@@ -766,10 +774,10 @@ tty3270_try_logging(tub_t *tubp)
                return 0;
        if (tubp->stat == TBS_MORE)
                return 0;
-#ifdef CONFIG_3270_CONSOLE
-       if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+       if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
                tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
        if (tubp->tty_bcb.bc_cnt == 0)
                return 0;
        if (tubp->intv != tty3270_int)
@@ -953,48 +961,44 @@ tty3270_show_tube(int minor, char *buf, int count)
        if (minor < 0 || minor > tubnummins ||
            (tubp = (*tubminors)[minor]) == NULL)
                return sprintf(buf, "No tube at index=%d\n", minor);
-
+       
        tty = tubp->tty;
        len = 0;
 
-       len += sprintf(buf+len,
-"Info for tub_t[%d] at %.8x:\n",
-       minor, (int)tubp);
+       len += sprintf(buf+len, "Info for tub_t[%d] at %p:\n", minor, tubp);
 
-       len += sprintf(buf+len, "inattr is at %.8x\n",
-               (int)&tubp->tty_inattr);
+       len += sprintf(buf+len, "inattr is at %p\n", &tubp->tty_inattr);
 
 
-       len += sprintf(buf+len,
-"    geom:  rows=%.2d cols=%.2d model=%.1d\n",
-       tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
+       len += sprintf(buf+len, "    geom:  rows=%.2d cols=%.2d model=%.1d\n",
+                      tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
 
        len += sprintf(buf+len,
-"    lnopen=%-2d     fsopen=%-2d   waitq=%.8x\n",
-       tubp->lnopen, tubp->fsopen, (int)&tubp->waitq);
+                      "    lnopen=%-2d     fsopen=%-2d   waitq=%p\n",
+                      tubp->lnopen, tubp->fsopen, &tubp->waitq);
 
-       len += sprintf(buf+len,
-"    dstat=%.2x      mode=%-2d     stat=%-2d     flags=%-4x\n",
-       tubp->dstat, tubp->mode, tubp->stat, tubp->flags);
+       len += sprintf(buf+len, "    dstat=%.2x      mode=%-2d     "
+                      "stat=%-2d     flags=%-4x\n", tubp->dstat,
+                      tubp->mode, tubp->stat, tubp->flags);
 
 #ifdef RBH_FIXTHIS
        len += sprintf(buf+len,
-"    oucount=%-4d  ourd=%-5d  ouwr=%-5d  nextlogx=%-5d\n",
-       tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr,
-       tubp->tty_nextlogx);
+                      "    oucount=%-4d  ourd=%-5d  ouwr=%-5d"
+                      "  nextlogx=%-5d\n", tubp->tty_oucount,
+                      tubp->tty_ourd, tubp->tty_ouwr, tubp->tty_nextlogx);
 #endif
 
-       len += sprintf(buf+len,
-"    tty=%.8x\n",
-       (int)tubp->tty);
+       len += sprintf(buf+len, "    tty=%p\n",tubp->tty);
 
-       if (tty) len += sprintf(buf+len,
-"    write_wait=%.8x read_wait=%.8x\n",
-       (int)&tty->write_wait, (int)&tty->read_wait);
+       if (tty)
+               len += sprintf(buf+len,
+                               "    write_wait=%.8x read_wait=%.8x\n",
+                               tty->write_wait, tty->read_wait);
 
-       if (tty && ((mp = tty->termios))) len += sprintf(buf+len,
-"    iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n",
-       mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag);
+       if (tty && ((mp = tty->termios)))
+               len += sprintf(buf+len,"    iflag=%.8x oflag=%.8x "
+                              "cflag=%.8x lflag=%.8x\n", mp->c_iflag,
+                              mp->c_oflag, mp->c_cflag, mp->c_lflag);
 
 
        return len;
index a49c1605826e3b36fb2fade7b11bc3e368c50643..6375192b325fb5168aca70653c9832347bf026b2 100644 (file)
@@ -48,7 +48,7 @@ static void
 tty3270_scl_timeout(unsigned long data)
 {
        tub_t *tubp = (void *)data;
-       int flags;
+       long flags;
 
        TUBLOCK(tubp->irq, flags);
        tubp->stat = TBS_RUNNING;
@@ -72,9 +72,9 @@ tty3270_scl_set(tub_t *tubp, char *buf, int count)
 int
 tty3270_scl_init(tub_t *tubp)
 {
-       extern int tubscrollparm;
+       extern int tubscrolltime;
 
-       tubp->tty_scrolltime = tubscrollparm;
+       tubp->tty_scrolltime = tubscrolltime;
        if (tubp->tty_scrolltime < 0)
                tubp->tty_scrolltime = DEFAULT_SCROLLTIME;
        return 0;
index f016a4ceccab82a0520eb8bb242f02630703f553..b07ba1f946dfd510873ef27efc98cf1f96e3d320 100644 (file)
@@ -12,7 +12,7 @@
 #include "tubio.h"
 static int tty3270_size_io(tub_t *tubp);
 static void tty3270_size_int(tub_t *tubp, devstat_t *dsp);
-static int tty3270_size_wait(tub_t *tubp, int *flags, int stat);
+static int tty3270_size_wait(tub_t *tubp, long *flags, int stat);
 
 /*
  * Structure representing Usable Area Query Reply Base
@@ -71,7 +71,7 @@ typedef struct {
  * Try to determine screen size using Read Partition (Query)
  */
 int
-tty3270_size(tub_t *tubp, int *flags)
+tty3270_size(tub_t *tubp, long *flags)
 {
        char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
        int     rc = 0;
@@ -285,7 +285,7 @@ tty3270_size_int(tub_t *tubp, devstat_t *dsp)
  * Return 0 unless signal pending, in which case -ERESTARTSYS.
  */
 static int
-tty3270_size_wait(tub_t *tubp, int *flags, int stat)
+tty3270_size_wait(tub_t *tubp, long *flags, int stat)
 {
        DECLARE_WAITQUEUE(wait, current);
 
index 1c64521d9dcc49c2db155c0c3d1992892deedeec..7950e5c5ff00f1ba37bef6ed462b9670a99ed60c 100644 (file)
 
 #include <linux/module.h>
 #include <linux/config.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 
 #include <asm/irq.h>
 #include <asm/idals.h>
 
 #ifdef CONFIG_ARCH_S390X
-#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
-#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
-void 
-set_normalized_cda ( ccw1_t * cp, unsigned long address )
+
+unsigned long __create_idal (unsigned long address, int count)
 {
        int nridaws;
-       idaw_t *idal;
-        int count = cp->count;
+       unsigned long *idal, *tmp;
 
-       if (cp->flags & CCW_FLAG_IDA)
-               BUG();
-       if (((address + count) >> 31) == 0) { 
-               cp -> cda = address;
-               return;
-       }
         nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count + 
                   (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
        idal = idal_alloc(nridaws);
-       if ( idal == NULL ) {
-               /* probably we should have a fallback here */
-               panic ("Cannot allocate memory for IDAL\n");
+       if (idal != NULL) {
+               tmp = idal;
+               *tmp++ = address;
+               address &= -IDA_BLOCK_SIZE;
+               while (--nridaws > 0) {
+                       address += IDA_BLOCK_SIZE;
+                       *tmp++ = address;
+               }
        }
-       cp->flags |= CCW_FLAG_IDA;
-       cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
-        do {
-               *idal++ = address;
-               address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
-               nridaws --;
-        } while ( nridaws > 0 );
-       return;
+       return (unsigned long) idal;
 }
 
-EXPORT_SYMBOL (set_normalized_cda);
+EXPORT_SYMBOL (__create_idal);
 
 #endif
index a32d1b1759800c1d6890b03e174f076521831000..12d759963823a6fa4c1c3b39dedf4a8c5e1f8ac9 100644 (file)
 #include <asm/s390dyn.h>
 #include <asm/queue.h>
 #include <linux/kmod.h>
+#ifndef MIN
+#define MIN(a,b) ((a<b)?a:b)
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a>b)?a:b)
+#endif
+
+
 
 typedef struct chandev_model_info chandev_model_info;
 struct chandev_model_info
@@ -35,7 +43,9 @@ struct chandev_model_info
        s32 dev_type;     /* device type -1 = don't care */
        s16 dev_model;    /* device model -1 = don't care */
        u8  max_port_no;
-       int      auto_msck_recovery;
+       int auto_msck_recovery;
+       u8  default_checksum_received_ip_pkts;
+       u8  default_use_hw_stats; /* where available e.g. lcs */
        devreg_t drinfo;
 };
 
@@ -44,12 +54,7 @@ struct chandev
 {
        struct chandev *next;
        chandev_model_info *model_info;
-       u16 cu_type;      /* control unit type */
-       u8  cu_model;     /* control unit model */
-       u16 dev_type;     /* device type */
-       u8  dev_model;    /* device model */
-       u16 devno;
-       unsigned int irq;
+       chandev_subchannel_info sch;
        int owned;
 };
 
@@ -66,28 +71,32 @@ struct chandev_force
 {
        struct chandev_force *next;
        chandev_type chan_type;
-       s32     devif_num; /* -1 don't care e.g. tr0 implies 0 */
-        u16     read_devno;
-       u16     write_devno;
+       s32     devif_num; /* -1 don't care, -2 we are forcing a range e.g. tr0 implies 0 */
+        u16     read_lo_devno;
+       u16     write_hi_devno;
+       u16     data_devno; /* only used by gigabit ethernet */
+       s32     memory_usage_in_k;
         s16     port_protocol_no; /* where available e.g. lcs,-1 don't care */
        u8      checksum_received_ip_pkts;
        u8      use_hw_stats; /* where available e.g. lcs */
+       /* claw specific stuff */
+       chandev_claw_info  claw;
 };
 
 typedef struct chandev_probelist chandev_probelist;
 struct chandev_probelist
 {
-       struct chandev_probelist *next;
-       chandev_probefunc       probefunc;
-       chandev_shutdownfunc    shutdownfunc;
-       chandev_reoperfunc      reoperfunc;
-       chandev_type            chan_type;
-       int                     devices_found;
+       struct chandev_probelist            *next;
+       chandev_probefunc                   probefunc;
+       chandev_shutdownfunc                shutdownfunc;
+       chandev_msck_notification_func      msck_notfunc;
+       chandev_type                        chan_type;
+       int                                 devices_found;
 };
 
 
 
-#define default_msck_bits ((1<<(not_oper-1))|(1<<(no_path-1))|(1<<(revalidate-1))|(1<<(gone-1)))
+#define default_msck_bits ((1<<(chandev_status_not_oper-1))|(1<<(chandev_status_no_path-1))|(1<<(chandev_status_revalidate-1))|(1<<(chandev_status_gone-1)))
 
 
 static char *msck_status_strs[]=
@@ -113,14 +122,13 @@ static chandev_msck_range *chandev_msck_range_head=NULL;
 typedef struct chandev_irqinfo chandev_irqinfo;
 struct chandev_irqinfo
 {
-       chandev_irqinfo      *next;
-       chandev_msck_status  msck_status;
-       u16                  devno;
-       unsigned int         irq;
-       void                 (*handler)(int, void *, struct pt_regs *);
-       unsigned long        irqflags;
-       void                 *dev_id;
-       char                 devname[0];
+       chandev_irqinfo         *next;
+       chandev_subchannel_info sch;
+       chandev_msck_status     msck_status;
+       void                    (*handler)(int, void *, struct pt_regs *);
+       unsigned long           irqflags;
+       void                    *dev_id;
+       char                    devname[0];
 };
 
 
@@ -131,34 +139,33 @@ struct chandev_parms
 {
        chandev_parms      *next;
        chandev_type       chan_type;
+       u16                lo_devno;
+       u16                hi_devno;
        char               parmstr[0];
 };
 
+static chandev_type chandev_persistent=0; 
+
 chandev_parms *chandev_parms_head=NULL;
 
 
 typedef struct chandev_activelist chandev_activelist;
 struct chandev_activelist
 {
-       struct chandev_activelist *next;
-       chandev_irqinfo         *read_irqinfo;
-       chandev_irqinfo         *write_irqinfo;
-       u16                     cu_type;      /* control unit type */
-       u8                      cu_model;     /* control unit model */
-       u16                     dev_type;     /* device type */
-       u8                      dev_model;    /* device model */
-       chandev_probefunc       probefunc;
-       chandev_shutdownfunc    shutdownfunc;
-       chandev_reoperfunc      reoperfunc;
-       chandev_unregfunc       unreg_dev;
-       chandev_type            chan_type;
-       u8                      port_no;
-       chandev_category        category;
-       int                     saved_busy_flag;
-       
-
-       void                    *dev_ptr;
-       char                    devname[0];
+       struct chandev_activelist        *next;
+       chandev_irqinfo                  *read_irqinfo;
+       chandev_irqinfo                  *write_irqinfo;
+       chandev_irqinfo                  *data_irqinfo;
+       chandev_probefunc                probefunc;
+       chandev_shutdownfunc             shutdownfunc;
+       chandev_msck_notification_func   msck_notfunc;
+       chandev_unregfunc                unreg_dev;
+       chandev_type                     chan_type;
+       u8                               port_no;
+       chandev_category                 category;
+       s32                              memory_usage_in_k;
+       void                             *dev_ptr;
+       char                             devname[0];
 };
 
 
@@ -172,10 +179,11 @@ static chandev_force *chandev_force_head=NULL;
 static chandev_probelist *chandev_probelist_head=NULL;
 static chandev_activelist *chandev_activelist_head=NULL;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-static int use_devno_names=FALSE;
+int chandev_use_devno_names=FALSE;
 #endif
-static int chandev_conf_read=FALSE;
-static int chandev_initialised=FALSE;
+static int chandev_cautious_auto_detect=TRUE;
+static atomic_t chandev_conf_read=ATOMIC_INIT(FALSE);
+static atomic_t chandev_initialised=ATOMIC_INIT(FALSE);
 
 
 static unsigned long chandev_last_machine_check;
@@ -186,22 +194,38 @@ static atomic_t chandev_msck_thread_lock;
 static atomic_t chandev_new_msck;
 static unsigned long chandev_last_startmsck_list_update;
 
-typedef struct chandev_startmsck_list chandev_startmsck_list;
-struct chandev_startmsck_list
+
+typedef enum
+{
+       chandev_start,
+       chandev_first_tag=chandev_start,
+       chandev_msck,
+       chandev_num_notify_tags
+} chandev_userland_notify_tag;
+
+static char *userland_notify_strs[]=
+{
+       "start",
+       "machine_check"
+};
+
+typedef struct chandev_userland_notify_list chandev_userland_notify_list;
+struct chandev_userland_notify_list
 {
-       chandev_startmsck_list    *next;
-       chandev_msck_status       pre_recovery_action_status;
-       chandev_msck_status       post_recovery_action_status;
+       chandev_userland_notify_list    *next;
+       chandev_userland_notify_tag      tag;
+       chandev_msck_status              prev_status;
+       chandev_msck_status              curr_status;
        char                      devname[0];
 };
 
 
-static chandev_startmsck_list *startlist_head=NULL;
-static chandev_startmsck_list *mscklist_head=NULL;
+static chandev_userland_notify_list *chandev_userland_notify_head=NULL;
 
 
 
 
+static void chandev_read_conf_if_necessary(void);
 static void chandev_read_conf(void);
 
 #if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
@@ -233,7 +257,56 @@ static __inline__ void netif_start_queue(net_device *dev)
 static long                 chandev_lock_owner;
 static int                  chandev_lock_cnt; 
 static spinlock_t           chandev_spinlock;
-void                        *chandev_firstlock_addr,*chandev_lastlock_addr; 
+#define CHANDEV_LOCK_DEBUG 0
+#if CHANDEV_LOCK_DEBUG && !defined(CONFIG_ARCH_S390X)
+#define CHANDEV_BACKTRACE_LOOPCNT 10
+void                        *chandev_first_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+                           *chandev_last_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+                           *chandev_last_unlock_addr[CHANDEV_BACKTRACE_LOOPCNT];
+#define CHANDEV_BACKTRACE(variable) \
+memset((variable),0,sizeof(void *)*CHANDEV_BACKTRACE_LOOPCNT); \
+(variable)[0]=__builtin_return_address(0); \
+if(((long)variable[0])&0x80000000)         \
+{                                          \
+(variable)[1]=__builtin_return_address(1); \
+if(((long)variable[1])&0x80000000)         \
+{                                          \
+(variable)[2]=__builtin_return_address(2); \
+if(((long)variable[2])&0x80000000)         \
+{                                          \
+(variable)[3]=__builtin_return_address(3); \
+if(((long)variable[3])&0x80000000)         \
+{                                          \
+(variable)[4]=__builtin_return_address(4); \
+if(((long)variable[4])&0x80000000)         \
+{                                          \
+(variable)[5]=__builtin_return_address(5); \
+if(((long)variable[5])&0x80000000)         \
+{                                          \
+(variable)[6]=__builtin_return_address(6); \
+if(((long)variable[6])&0x80000000)         \
+{                                          \
+(variable)[7]=__builtin_return_address(7); \
+if(((long)variable[7])&0x80000000)         \
+{                                          \
+(variable)[8]=__builtin_return_address(8); \
+if(((long)variable[8])&0x80000000)         \
+{                                          \
+(variable)[9]=__builtin_return_address(9); \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+}
+#else
+#define CHANDEV_BACKTRACE(variable)
+#endif
+
+
 
 typedef struct chandev_not_oper_struct chandev_not_oper_struct;
 
@@ -250,7 +323,6 @@ struct  chandev_not_oper_struct
  */
 static qheader chandev_not_oper_head={NULL,NULL};
 static spinlock_t           chandev_not_oper_spinlock;
-static char           exec_script[]="/bin/chandev";
 
 #define chandev_interrupt_check() \
 if(in_interrupt())                \
@@ -260,22 +332,30 @@ if(in_interrupt())                \
 #define for_each(variable,head) \
 for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)
 
+#define for_each_allow_delete(variable,nextmember,head) \
+for((variable)=(head),(nextmember)=((head) ? (head)->next:NULL); \
+(variable)!=NULL; (variable)=(nextmember),(nextmember)=((nextmember) ? (nextmember->next) : NULL))
+
+#define for_each_allow_delete2(variable,nextmember,head) \
+for((variable)=(head);(variable)!=NULL;(variable)=(nextmember))
+
 
 static void chandev_lock(void)
 {
-       chandev_interrupt_check();
        eieio();
+       chandev_interrupt_check();
        if(chandev_lock_owner!=(long)current)
        {
-               spin_lock(&chandev_spinlock);
+               while(!spin_trylock(&chandev_spinlock))
+                       schedule();
                chandev_lock_cnt=1;
                chandev_lock_owner=(long)current;
-               chandev_firstlock_addr=__builtin_return_address(0);
+               CHANDEV_BACKTRACE(chandev_first_lock_addr)
        }
        else
        {
                chandev_lock_cnt++;
-               chandev_lastlock_addr=__builtin_return_address(0);
+               CHANDEV_BACKTRACE(chandev_last_lock_addr)
        }
        if(chandev_lock_cnt<0||chandev_lock_cnt>100)
        {
@@ -301,6 +381,7 @@ static void chandev_unlock(void)
                      (long)current,
                      chandev_lock_owner,
                      chandev_lock_cnt);
+       CHANDEV_BACKTRACE(chandev_last_unlock_addr)
        if(--chandev_lock_cnt==0)
        {
                chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
@@ -315,13 +396,6 @@ static void chandev_unlock(void)
 }
 
 
-void chandev_relock(int saved_lock_cnt)
-{
-       
-       chandev_lock();
-       chandev_lock_cnt=saved_lock_cnt;
-}
-
 
 void *chandev_alloc(size_t size)
 {
@@ -369,6 +443,7 @@ static int chandev_remove_from_queue(qheader *qhead,queue *member)
 
 void chandev_free_listmember(list **listhead,list *member)
 {
+       chandev_lock();
        if(member)
        {
                if(chandev_remove_from_list(listhead,member))
@@ -377,18 +452,21 @@ void chandev_free_listmember(list **listhead,list *member)
                        printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
                               "listmember listhead=%p member %p\n",listhead,member);
        }
+       chandev_unlock();
 }
 
 void chandev_free_queuemember(qheader *qhead,queue *member)
 {
+       chandev_lock();
        if(member)
        {
                if(chandev_remove_from_queue(qhead,member))
                        kfree(member);
                else
-                       printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
-                              "listmember qhead=%p member %p\n",qhead,member);
+                       printk(KERN_CRIT"chandev_free_queuemember detected nonexistant"
+                              "queuemember qhead=%p member %p\n",qhead,member);
        }
+       chandev_unlock();
 }
 
 
@@ -397,27 +475,45 @@ void chandev_free_all_list(list **listhead)
 {
        list *head;
 
+       chandev_lock();
        while((head=remove_listhead(listhead)))
                kfree(head);
+       chandev_unlock();
 }
 
 void chandev_free_all_queue(qheader *qhead)
 {
+       chandev_lock();
        while(qhead->head)
                chandev_free_queuemember(qhead,qhead->head);
+       chandev_unlock();
 }
 
+static void chandev_wait_for_root_fs(void)
+{
+       wait_queue_head_t      wait;
 
+       init_waitqueue_head(&wait);
+       /* We need to wait till there is a root filesystem */
+       while(init_task.fs->root==NULL)
+       {
+               sleep_on_timeout(&wait,HZ);
+       }
+}
 
+/* We are now hotplug compliant i.e. */
+/* we typically get called in /sbin/hotplug chandev our parameters */
 static int chandev_exec_start_script(void *unused)
 {
        
        char **argv,*tempname;
        int retval=-ENOMEM;
-       int loopcnt,argc;
+       int argc,loopcnt;
        size_t allocsize;
-       chandev_startmsck_list *member;
+       chandev_userland_notify_list *member;
        wait_queue_head_t      wait;
+       int                    have_tag[chandev_num_notify_tags]={FALSE,};
+       chandev_userland_notify_tag tagidx;
        static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
        
        init_waitqueue_head(&wait);
@@ -427,17 +523,33 @@ static int chandev_exec_start_script(void *unused)
        {
                sleep_on_timeout(&wait,HZ);
        }
+       if(!chandev_userland_notify_head)
+               return(0);
        chandev_lock();
-       argc=1;
-       if(startlist_head)
-               argc++;
-       for_each(member,startlist_head)
-               argc++;
-       if(mscklist_head)
-               argc+=3;
-       for_each(member,mscklist_head)
-               argc++;
+       argc=2;
+       for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
+       {
+               for_each(member,chandev_userland_notify_head)
+               {
+                       if(member->tag==tagidx)
+                       {
+                               switch(tagidx)
+                               {
+                               case chandev_start:
+                                       argc++;
+                                       break;
+                               case chandev_msck:
+                                       argc+=3;
+                                       break;
+                               default:
+                               }
+                               if(have_tag[tagidx]==FALSE)
+                                       argc++;
+                               have_tag[tagidx]=TRUE;
 
+                       }
+               }
+       }
        allocsize=(argc+1)*sizeof(char *);
         /* Warning possible stack overflow */
        /* We can't kmalloc the parameters here as execve will */
@@ -446,58 +558,51 @@ static int chandev_exec_start_script(void *unused)
        if(argv)
        {
                memset(argv,0,allocsize);
-               argc=0;
-               argv[argc++]=exec_script;
-               if(startlist_head)
-                       argv[argc++]="start";
-               for_each(member,startlist_head)
-               {
-                       tempname=alloca(strlen(member->devname)+1);
-                       if(tempname)
-                       {
-                               strcpy(tempname,member->devname);
-                               argv[argc++]=tempname;
-                       }
-                       else
-                               goto Fail;
-               }
-               if(mscklist_head)
-                       argv[argc++]="machine_check";
-               for_each(member,mscklist_head)
+               argv[0]=hotplug_path;
+               argv[1]="chandev";
+               argc=2;
+               for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
                {
-                       tempname=alloca(strlen(member->devname)+1);
-                       if(tempname)
+                       if(have_tag[tagidx])
                        {
-                               strcpy(tempname,member->devname);
-                               argv[argc++]=tempname;
+                               argv[argc++]=userland_notify_strs[tagidx];
+                               for_each(member,chandev_userland_notify_head)
+                               {
+                                       if(member->tag==tagidx)
+                                       {
+                                               tempname=alloca(strlen(member->devname)+1);
+                                               if(tempname)
+                                               {
+                                                       strcpy(tempname,member->devname);
+                                                       argv[argc++]=tempname;
+                                               }
+                                               else
+                                                       goto Fail;
+                                               if(member->tag==chandev_msck)
+                                               {
+                                                       argv[argc++]=msck_status_strs[member->prev_status];
+                                                       argv[argc++]=msck_status_strs[member->curr_status];
+                                               }
+                                       }
+                               }
                        }
-                       else
-                               goto Fail;
-                       argv[loopcnt++]=msck_status_strs[member->pre_recovery_action_status];
-                       argv[loopcnt++]=msck_status_strs[member->post_recovery_action_status];
                }
-               chandev_free_all_list((list **)&startlist_head);
-               chandev_free_all_list((list **)&mscklist_head);
+               chandev_free_all_list((list **)&chandev_userland_notify_head);
                chandev_unlock();
-
-               /* We need to wait till there is a root filesystem */
-               while(init_task.fs->root==NULL)
-               {
-                       sleep_on_timeout(&wait,HZ);
-               }
+               chandev_wait_for_root_fs();
                /* We are basically execve'ing here there normally is no */
                /* return */
-               retval=exec_usermodehelper(exec_script, argv, envp);
+               retval=exec_usermodehelper(hotplug_path, argv, envp);
                goto Fail2;
        }
  Fail:
        
        chandev_unlock();
  Fail2:
-       /* We don't really need to report /bin/chandev not existing */
+       /* We don't really need to report /sbin/hotplug not existing */
        if(retval!=-ENOENT)
           printk("chandev_exec_start_script failed retval=%d\n",retval);
-       return(0);
+       return(retval);
 }
 
 
@@ -513,27 +618,25 @@ void *chandev_allocstr(const char *str,size_t offset)
 }
 
 
-static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname,
-chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status)
+static int chandev_add_to_userland_notify_list(chandev_userland_notify_tag tag,
+char *devname, chandev_msck_status prev_status,chandev_msck_status curr_status)
 {
-       chandev_startmsck_list *member;
+       chandev_userland_notify_list *member,*nextmember;
        int pid;
        
        chandev_lock();
        /* remove operations still outstanding for this device */
-       for_each(member,startlist_head)
-               if(strcmp(member->devname,devname)==0)
-                       chandev_remove_from_list((list **)&startlist_head,(list *)member);
-       for_each(member,mscklist_head)
+       for_each_allow_delete(member,nextmember,chandev_userland_notify_head)
                if(strcmp(member->devname,devname)==0)
-                       chandev_remove_from_list((list **)&mscklist_head,(list *)member);
+                       chandev_free_listmember((list **)&chandev_userland_notify_head,(list *)member);
        
 
-       if((member=chandev_allocstr(devname,offsetof(chandev_startmsck_list,devname))))
+       if((member=chandev_allocstr(devname,offsetof(chandev_userland_notify_list,devname))))
        {
-               member->pre_recovery_action_status=pre_recovery_action_status;
-               member->post_recovery_action_status=post_recovery_action_status;
-               add_to_list((list **)listhead,(list *)member);
+               member->tag=tag;
+               member->prev_status=prev_status;
+               member->curr_status=curr_status;
+               add_to_list((list **)&chandev_userland_notify_head,(list *)member);
                chandev_last_startmsck_list_update=jiffies;
                chandev_unlock();
                pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD);
@@ -596,7 +699,7 @@ chandev_irqinfo *chandev_get_irqinfo_by_irq(int irq)
 {
        chandev_irqinfo *curr_irqinfo;
        for_each(curr_irqinfo,chandev_irqinfo_head)
-               if(irq==curr_irqinfo->irq)
+               if(irq==curr_irqinfo->sch.irq)
                        return(curr_irqinfo);
        return(NULL);
 }
@@ -606,7 +709,7 @@ chandev *chandev_get_by_irq(int irq)
        chandev *curr_chandev;
 
        for_each(curr_chandev,(chandev *)chandev_head.head)
-               if(curr_chandev->irq==irq)
+               if(curr_chandev->sch.irq==irq)
                {
                        return(curr_chandev);
                }
@@ -619,8 +722,9 @@ chandev_activelist *chandev_get_activelist_by_irq(int irq)
 
        for_each(curr_device,chandev_activelist_head)
        {
-                       if(curr_device->read_irqinfo->irq==irq||
-                          curr_device->write_irqinfo->irq==irq)
+                       if(curr_device->read_irqinfo->sch.irq==irq||
+                          curr_device->write_irqinfo->sch.irq==irq||
+                          (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.irq==irq))
                                return(curr_device);
        }
        return(NULL);
@@ -630,16 +734,50 @@ chandev_activelist *chandev_get_activelist_by_irq(int irq)
 void chandev_remove_irqinfo_by_irq(unsigned int irq)
 {
        chandev_irqinfo *remove_irqinfo;
+       chandev_activelist *curr_device;
 
        chandev_lock();
        /* remove any orphan irqinfo left lying around. */
         if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq)))
-               chandev_remove_from_list((list **)&chandev_irqinfo_head,
+       {
+               for_each(curr_device,chandev_activelist_head)
+               {
+                       if(curr_device->read_irqinfo==remove_irqinfo)
+                       {
+                               curr_device->read_irqinfo=NULL;
+                               break;
+                       }
+                       if(curr_device->write_irqinfo==remove_irqinfo)
+                       {
+                               curr_device->write_irqinfo=NULL;
+                               break;
+                       }
+                       if(curr_device->data_irqinfo&&curr_device->data_irqinfo==remove_irqinfo)
+                       {
+                               curr_device->data_irqinfo=NULL;
+                               break;
+                       }
+               }
+               chandev_free_listmember((list **)&chandev_irqinfo_head,
                                         (list *)remove_irqinfo);
+       }
        chandev_unlock();
        
 }
 
+int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
+{
+       schib_t *new_schib;
+       
+       if((new_schib=s390_get_schib(irq)))
+       {
+               sch->pim=new_schib->pmcw.pim;
+               memcpy(&sch->chpid,&new_schib->pmcw.chpid,sizeof(sch->chpid));
+               return(0);
+       }
+       return(-ENODEV);
+}
+
 int chandev_request_irq(unsigned int   irq,
                       void           (*handler)(int, void *, struct pt_regs *),
                       unsigned long  irqflags,
@@ -674,10 +812,16 @@ int chandev_request_irq(unsigned int   irq,
                        kfree(new_irqinfo);
                else
                {
-                       new_irqinfo->irq=irq;
+                       new_irqinfo->msck_status=chandev_status_good;
+                       new_irqinfo->sch.devno=devinfo.devno;
+                       new_irqinfo->sch.irq=irq;
+                       new_irqinfo->sch.cu_type=devinfo.sid_data.cu_type; /* control unit type */
+                       new_irqinfo->sch.cu_model=devinfo.sid_data.cu_model; /* control unit model */
+                       new_irqinfo->sch.dev_type=devinfo.sid_data.dev_type; /* device type */
+                       new_irqinfo->sch.dev_model=devinfo.sid_data.dev_model; /* device model */
+                       chandev_add_schib_info(irq,&new_irqinfo->sch);
                        new_irqinfo->handler=handler;
                        new_irqinfo->dev_id=dev_id;
-                       new_irqinfo->devno=devinfo.devno;
                        chandev_add_to_list((list **)&chandev_irqinfo_head,new_irqinfo);
                }
        }
@@ -689,13 +833,32 @@ int chandev_request_irq(unsigned int   irq,
        return(retval);
 }
 
+/* This should be safe to call even multiple times. */
 void chandev_free_irq(unsigned int irq, void *dev_id)
 {
+       s390_dev_info_t devinfo;
+       int err;
+       
        /* remove any orphan irqinfo left lying around. */
        chandev_remove_irqinfo_by_irq(irq);
-       free_irq(irq,dev_id);
+       if((err=get_dev_info_by_irq(irq,&devinfo)))
+       {
+               printk("chandev_free_irq get_dev_info_by_irq reported err=%X on irq %d\n"
+                      "should not happen\n",err,irq);
+               return;
+        }
+       if(devinfo.status&DEVSTAT_DEVICE_OWNED)
+          free_irq(irq,dev_id);
 }
 
+/* This should be safe even if chandev_free_irq is already called by the device */
+void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
+{
+       if(irqinfo)
+               chandev_free_irq(irqinfo->sch.irq,irqinfo->dev_id);
+}
+
+
 
 void chandev_sprint_type_model(char *buff,s32 type,s16 model)
 {
@@ -716,37 +879,66 @@ void chandev_sprint_devinfo(char *buff,s32 cu_type,s16 cu_model,s32 dev_type,s16
        chandev_sprint_type_model(&buff[strlen(buff)],dev_type,dev_model);
 }
 
-void chandev_remove_parms(chandev_type chan_type,int exact_match)
+void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
 {
-       chandev_parms      *curr_parms;
+       chandev_parms      *curr_parms,*next_parms;
 
        chandev_lock();
-       for_each(curr_parms,chandev_parms_head)
+       for_each_allow_delete(curr_parms,next_parms,chandev_parms_head)
        {
-               if((chan_type&(curr_parms->chan_type)&&!exact_match)||
-                   (chan_type==(curr_parms->chan_type)&&exact_match))
-                   chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
+               if(((chan_type&(curr_parms->chan_type)&&!exact_match)||
+                  (chan_type==(curr_parms->chan_type)&&exact_match))&&
+                  (lo_devno==-1||lo_devno==curr_parms->lo_devno))
+                       chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
        }
        chandev_unlock();
 }
 
-void chandev_add_parms(chandev_type chan_type,char *parmstr)
+
+void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
 {
-       chandev_parms      *new_parms;
-       
-       if((new_parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+       chandev_parms      *parms;
+
+       if(lo_devno>hi_devno)
        {
-               chandev_remove_parms(chan_type,TRUE);
-               new_parms->chan_type=chan_type;
-               chandev_add_to_list((list **)&chandev_parms_head,(void *)new_parms);
+               printk("chandev_add_parms detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
+                      (int)lo_devno,(int)hi_devno);
+               return;
+       }
+       chandev_lock();
+       for_each(parms,chandev_parms_head)
+       {
+               if(chan_type&(parms->chan_type))
+               {
+                       u16 lomax=MAX(parms->lo_devno,lo_devno),
+                               himin=MIN(parms->hi_devno,lo_devno);
+                       if(lomax<=himin)
+                       {
+                               chandev_unlock();
+                               printk("chandev_add_parms detected overlapping "
+                                      "parameter definitions for chan_type=0x%02x"
+                                      " lo_devno=0x%04x  hi_devno=0x%04x\n,"
+                                      " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno);
+                               return;
+                       }
+               }
+       }
+       chandev_unlock();
+       if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+       {
+               parms->chan_type=chan_type;
+               parms->lo_devno=lo_devno;
+               parms->hi_devno=hi_devno;
+               chandev_add_to_list((list **)&chandev_parms_head,(void *)parms);
        }
        else
-               printk("chandev_add_parmstr memory request failed\n");
+               printk("chandev_add_parms memory request failed\n");
 }
 
 
 void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
-                      s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery)
+                      s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+                      u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats)
 {
        chandev_model_info *newmodel;
        int                err;
@@ -762,7 +954,8 @@ void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
                newmodel->dev_model=dev_model;
                newmodel->max_port_no=max_port_no;
                newmodel->auto_msck_recovery=auto_msck_recovery;
-               
+               newmodel->default_checksum_received_ip_pkts=default_checksum_received_ip_pkts;
+               newmodel->default_use_hw_stats=default_use_hw_stats; /* where available e.g. lcs */
                if(cu_type==-1&&dev_type==-1)
                {
                        chandev_sprint_devinfo(buff,newmodel->cu_type,newmodel->cu_model,
@@ -771,17 +964,15 @@ void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
                        kfree(newmodel);
                        return;
                }
-               /* We ignore errors as they are likely to
-                  occur owing to incompatibilities with
-                  Ingos layer 
-               */
                drinfo->flag=DEVREG_TYPE_DEVCHARS;
-               if(dev_model==-1)
-                       drinfo->flag|=(dev_type==-1 ? DEVREG_NO_DEV_INFO:DEVREG_MATCH_DEV_TYPE);
-               if(cu_model==-1)
-                       drinfo->flag|=(cu_type==-1 ? DEVREG_NO_CU_INFO:DEVREG_MATCH_CU_TYPE);
-               else if(dev_model!=-1&&cu_type!=-1)
-                       drinfo->flag|=DEVREG_EXACT_MATCH;
+               if(cu_type!=-1)
+                       drinfo->flag|=DEVREG_MATCH_CU_TYPE;
+               if(cu_model!=-1)
+                       drinfo->flag|=DEVREG_MATCH_CU_MODEL;
+               if(dev_type!=-1)
+                       drinfo->flag|=DEVREG_MATCH_DEV_TYPE;
+               if(dev_model!=-1)
+                       drinfo->flag|=DEVREG_MATCH_DEV_MODEL;
                drinfo->ci.hc.ctype=cu_type;
                drinfo->ci.hc.cmode=cu_model;
                drinfo->ci.hc.dtype=dev_type;
@@ -813,10 +1004,10 @@ void chandev_remove_all(void)
 
 void chandev_remove_model(chandev_model_info *model)
 {
-       chandev *curr_chandev;
+       chandev *curr_chandev,*next_chandev;
 
        chandev_lock();
-       for_each(curr_chandev,(chandev *)chandev_head.head)
+       for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
                if(curr_chandev->model_info==model)
                        chandev_remove(curr_chandev);
        if(model->drinfo.oper_func)
@@ -835,10 +1026,10 @@ void chandev_remove_all_models(void)
 
 void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
 {
-       chandev_model_info *curr_model;
+       chandev_model_info *curr_model,*next_model;
        
        chandev_lock();
-       for_each(curr_model,chandev_models_head)
+       for_each_allow_delete(curr_model,next_model,chandev_models_head)
                if((curr_model->cu_type==cu_type||cu_type==-1)&&
                   (curr_model->cu_model==cu_model||cu_model==-1)&&
                   (curr_model->dev_type==dev_type||dev_type==-1)&&
@@ -849,31 +1040,34 @@ void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
 
 static void chandev_init_default_models(void)
 {
-       /* P390/Planter 3172 emulation assume maximum 16 to be safe. */
-       chandev_add_model(lcs,0x3088,0x1,-1,-1,15,default_msck_bits);   
+       /* Usually P390/Planter 3172 emulation assume maximum 16 to be safe. */
+       chandev_add_model(chandev_type_lcs,0x3088,0x1,-1,-1,15,default_msck_bits,FALSE,FALSE);  
 
        /* 3172/2216 Paralell the 2216 allows 16 ports per card the */
        /* the original 3172 only allows 4 we will assume the max of 16 */
-       chandev_add_model(lcs|ctc,0x3088,0x8,-1,-1,15,default_msck_bits);
+       chandev_add_model(chandev_type_lcs|chandev_type_ctc,0x3088,0x8,-1,-1,15,default_msck_bits,FALSE,FALSE);
 
        /* 3172/2216 Escon serial the 2216 allows 16 ports per card the */
        /* the original 3172 only allows 4 we will assume the max of 16 */
-       chandev_add_model(lcs|escon,0x3088,0x1F,-1,-1,15,default_msck_bits);
+       chandev_add_model(chandev_type_lcs|chandev_type_escon,0x3088,0x1F,-1,-1,15,default_msck_bits,FALSE,FALSE);
 
        /* Only 2 ports allowed on OSA2 cards model 0x60 */
-       chandev_add_model(lcs,0x3088,0x60,-1,-1,1,default_msck_bits);
-       /* qeth has relative adapter concept so we give it 16 */
-       chandev_add_model(qeth,0x1731,0x1,0x1732,0x1,15,default_msck_bits);
+       chandev_add_model(chandev_type_lcs,0x3088,0x60,-1,-1,1,default_msck_bits,FALSE,FALSE);
+       /* qeth gigabit ethernet */
+       chandev_add_model(chandev_type_qeth,0x1731,0x1,0x1732,0x1,0,default_msck_bits,FALSE,FALSE);
+       chandev_add_model(chandev_type_qeth,0x1731,0x5,0x1732,0x5,0,default_msck_bits,FALSE,FALSE);
        /* Osa-D we currently aren't too emotionally involved with this */
-       chandev_add_model(osad,0x3088,0x62,-1,-1,0,default_msck_bits);
+       chandev_add_model(chandev_type_osad,0x3088,0x62,-1,-1,0,default_msck_bits,FALSE,FALSE);
+       /* claw */
+       chandev_add_model(chandev_type_claw,0x3088,0x61,-1,-1,0,default_msck_bits,FALSE,FALSE);
 }
 
 
 void chandev_del_noauto(u16 devno)
 {
-       chandev_noauto_range *curr_noauto;
+       chandev_noauto_range *curr_noauto,*next_noauto;
        chandev_lock();
-       for_each(curr_noauto,chandev_noauto_head)
+       for_each_allow_delete(curr_noauto,next_noauto,chandev_noauto_head)
                if(curr_noauto->lo_devno<=devno&&curr_noauto->hi_devno>=devno)
                        chandev_free_listmember((list **)&chandev_noauto_head,(list *)curr_noauto); 
        chandev_unlock();
@@ -881,9 +1075,9 @@ void chandev_del_noauto(u16 devno)
 
 void chandev_del_msck(u16 devno)
 {
-       chandev_msck_range *curr_msck_range;
+       chandev_msck_range *curr_msck_range,*next_msck_range;
        chandev_lock();
-       for_each(curr_msck_range,chandev_msck_range_head)
+       for_each_allow_delete(curr_msck_range,next_msck_range,chandev_msck_range_head)
                if(curr_msck_range->lo_devno<=devno&&curr_msck_range->hi_devno>=devno)
                        chandev_free_listmember((list **)&chandev_msck_range_head,(list *)curr_msck_range); 
        chandev_unlock();
@@ -897,12 +1091,13 @@ void chandev_add(s390_dev_info_t  *newdevinfo,chandev_model_info *newmodelinfo)
        if((new_chandev=chandev_alloc(sizeof(chandev))))
        {
                new_chandev->model_info=newmodelinfo;
-               new_chandev->cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
-               new_chandev->cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
-               new_chandev->dev_type=newdevinfo->sid_data.dev_type; /* device type */
-               new_chandev->dev_model=newdevinfo->sid_data.dev_model; /* device model */
-               new_chandev->devno=newdevinfo->devno;
-               new_chandev->irq=newdevinfo->irq;
+               new_chandev->sch.devno=newdevinfo->devno;
+               new_chandev->sch.irq=newdevinfo->irq;
+               new_chandev->sch.cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
+               new_chandev->sch.cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
+               new_chandev->sch.dev_type=newdevinfo->sid_data.dev_type; /* device type */
+               new_chandev->sch.dev_model=newdevinfo->sid_data.dev_model; /* device model */
+               chandev_add_schib_info(newdevinfo->irq,&new_chandev->sch);
                new_chandev->owned=(newdevinfo->status&DEVSTAT_DEVICE_OWNED ? TRUE:FALSE);
                chandev_queuemember(&chandev_head,new_chandev);
        }
@@ -910,16 +1105,29 @@ void chandev_add(s390_dev_info_t  *newdevinfo,chandev_model_info *newmodelinfo)
 
 void chandev_unregister_probe(chandev_probefunc probefunc)
 {
-       chandev_probelist *curr_probe;
+       chandev_probelist *curr_probe,*next_probe;
 
        chandev_lock();
-       for_each(curr_probe,chandev_probelist_head)
+       for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
                if(curr_probe->probefunc==probefunc)
                        chandev_free_listmember((list **)&chandev_probelist_head,
                                                (list *)curr_probe);
        chandev_unlock();
 }
 
+void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
+{
+       chandev_probelist *curr_probe,*next_probe;
+
+       chandev_lock();
+       for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
+               if(curr_probe->chan_type==chan_type)
+                       chandev_free_listmember((list **)&chandev_probelist_head,
+                                               (list *)curr_probe);
+       chandev_unlock();
+}
+
+
 
 void chandev_reset(void)
 {
@@ -928,36 +1136,62 @@ void chandev_reset(void)
        chandev_free_all_list((list **)&chandev_noauto_head);
        chandev_free_all_list((list **)&chandev_msck_range_head);
        chandev_free_all_list((list **)&chandev_force_head);
-       chandev_remove_parms(-1,FALSE);
+       chandev_remove_parms(-1,FALSE,-1);
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-       use_devno_names=FALSE;
+       chandev_use_devno_names=FALSE;
 #endif
-       chandev_conf_read=FALSE;
        chandev_unlock();
 }
 
 
-chandev_model_info *chandev_is_chandev(int irq,s390_dev_info_t *devinfo)
+int chandev_is_chandev(int irq,s390_dev_info_t *devinfo,chandev_force **forceinfo,chandev_model_info **ret_model)
 {
+       chandev_force *curr_force;
        chandev_model_info *curr_model=NULL;
        int err;
+       int retval=FALSE;
+
+       if(forceinfo)
+               *forceinfo=NULL;
+       if(ret_model)
+               *ret_model=NULL;
        if((err=get_dev_info_by_irq(irq,devinfo)))
        {
                printk("chandev_is_chandev get_dev_info_by_irq reported err=%X on irq %d\n"
                       "should not happen\n",err,irq);
-                       return(NULL);
+                       return FALSE;
        }
        chandev_lock();
+       
        for_each(curr_model,chandev_models_head)
        {
                if(((curr_model->cu_type==devinfo->sid_data.cu_type)||(curr_model->cu_type==-1))&&
                   ((curr_model->cu_model==devinfo->sid_data.cu_model)||(curr_model->cu_model==-1))&&
                   ((curr_model->dev_type==devinfo->sid_data.dev_type)||(curr_model->dev_type==-1))&&
                   ((curr_model->dev_model==devinfo->sid_data.dev_model)||(curr_model->dev_model==-1)))
+               {
+                       retval=TRUE;
+                       if(ret_model)
+                               *ret_model=curr_model;
+                       break;
+               }
+       }
+       for_each(curr_force,chandev_force_head)
+       {
+               if(((curr_force->read_lo_devno==devinfo->devno)&&
+                  (curr_force->write_hi_devno==devinfo->devno)&&
+                   (curr_force->devif_num!=-2))||
+                  ((curr_force->read_lo_devno>=devinfo->devno)&&
+                   (curr_force->write_hi_devno<=devinfo->devno)&&
+                   (curr_force->devif_num==-2)))
+               {
+                       if(forceinfo)
+                               *forceinfo=curr_force;
                        break;
+               }
        }
        chandev_unlock();
-       return(curr_model);
+       return(retval);
 }
 
 void chandev_collect_devices(void)
@@ -982,39 +1216,70 @@ void chandev_collect_devices(void)
                        break;
                }
                chandev_lock();
-               if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+               if(chandev_is_chandev(curr_irq,&curr_devinfo,NULL,&curr_model))
                        chandev_add(&curr_devinfo,curr_model);
                chandev_unlock();
        }
 }
 
-void chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_devno,
-u16 write_devno,s16 port_protocol_no,u8 checksum_received_ip_pkts,u8 use_hw_stats)
-
+int chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_lo_devno,
+u16 write_hi_devno,u16 data_devno,s32 memory_usage_in_k,s16 port_protocol_no,u8 checksum_received_ip_pkts,
+u8 use_hw_stats,char *host_name,char *adapter_name,char *api_type)
 {
        chandev_force *new_chandev_force;
-
+       
+       if(devif_num==-2&&read_lo_devno>write_hi_devno)
+       {
+               printk("chandev_add_force detected bad device range lo_devno=0x%04x  hi_devno=0x%04x\n,",
+                      (int)read_lo_devno,(int)write_hi_devno);
+               return(-1);
+       }
+       if(memory_usage_in_k<0)
+       {
+               printk("chandev_add_force memory_usage_in_k is bad\n");
+               return(-1);
+       }
+       if(chan_type==chandev_type_claw)
+       {
+               int host_name_len=strlen(host_name),
+                       adapter_name_len=strlen(adapter_name),
+                       api_type_len=strlen(api_type);
+               if(host_name_len>=CLAW_NAMELEN||host_name_len==0||
+                  adapter_name_len>=CLAW_NAMELEN||adapter_name_len==0||
+                  api_type_len>=CLAW_NAMELEN||api_type_len==0)
+                       return(-1);
+       }
        if((new_chandev_force=chandev_alloc(sizeof(chandev_force))))
        {
                new_chandev_force->chan_type=chan_type;
                new_chandev_force->devif_num=devif_num;
-               new_chandev_force->read_devno=read_devno;
-               new_chandev_force->write_devno=write_devno;
+               new_chandev_force->read_lo_devno=read_lo_devno;
+               new_chandev_force->write_hi_devno=write_hi_devno;
+               new_chandev_force->data_devno=data_devno;
+               new_chandev_force->memory_usage_in_k=memory_usage_in_k;
                new_chandev_force->port_protocol_no=port_protocol_no;
                new_chandev_force->checksum_received_ip_pkts=checksum_received_ip_pkts;
                new_chandev_force->use_hw_stats=use_hw_stats;
+               
+               if(chan_type==chandev_type_claw)
+               {
+                       strcpy(new_chandev_force->claw.host_name,host_name);
+                       strcpy(new_chandev_force->claw.adapter_name,adapter_name);
+                       strcpy(new_chandev_force->claw.api_type,api_type);
+               }
                chandev_add_to_list((list **)&chandev_force_head,new_chandev_force);
        }
+       return(0);
 }
 
-void chandev_del_force(u16 read_devno)
+void chandev_del_force(int read_lo_devno)
 {
-       chandev_force *curr_force;
+       chandev_force *curr_force,*next_force;
        
        chandev_lock();
-       for_each(curr_force,chandev_force_head)
+       for_each_allow_delete(curr_force,next_force,chandev_force_head)
        {
-               if(curr_force->read_devno==read_devno)
+               if(curr_force->read_lo_devno==read_lo_devno||read_lo_devno==-1)
                        chandev_free_listmember((list **)&chandev_force_head,
                                                (list *)curr_force);
        }
@@ -1024,26 +1289,35 @@ void chandev_del_force(u16 read_devno)
 
 void chandev_shutdown(chandev_activelist *curr_device)
 {
-       int saved_lock_cnt;
+       int err=0;
        chandev_lock();
 
-       if(curr_device->category==network_device)
+
+       /* unregister_netdev calls the dev->close so we shouldn't do this */
+       /* this otherwise we crash */
+       if(curr_device->unreg_dev)
        {
-               /* unregister_netdev calls the dev->close so we shouldn't do this */
-               /* this otherwise we crash */
-               if(curr_device->unreg_dev)
-               {
-                       saved_lock_cnt=chandev_full_unlock();
-                       curr_device->unreg_dev(curr_device->dev_ptr);
-                       chandev_relock(saved_lock_cnt);
-               }
+               curr_device->unreg_dev(curr_device->dev_ptr);
+               curr_device->unreg_dev=NULL;
        }
-       saved_lock_cnt=chandev_full_unlock();
-       curr_device->shutdownfunc(curr_device->dev_ptr);
-       chandev_relock(saved_lock_cnt);
-       kfree(curr_device->dev_ptr);
-       chandev_free_listmember((list **)&chandev_activelist_head,
+       if(curr_device->shutdownfunc)
+       {
+               err=curr_device->shutdownfunc(curr_device->dev_ptr);
+       }
+       if(err)
+               printk("chandev_shutdown unable to fully shutdown & unload %s err=%d\n"
+                      "probably some upper layer still requires the device to exist\n",
+                      curr_device->devname,err);
+       else
+       {
+               
+               chandev_free_irq_by_irqinfo(curr_device->read_irqinfo);
+               chandev_free_irq_by_irqinfo(curr_device->write_irqinfo);
+               if(curr_device->data_irqinfo)
+                       chandev_free_irq_by_irqinfo(curr_device->data_irqinfo);
+               chandev_free_listmember((list **)&chandev_activelist_head,
                                (list *)curr_device);
+       }
        chandev_unlock();
 }
 
@@ -1071,8 +1345,9 @@ static chandev_activelist *chandev_active(u16 devno)
        chandev_activelist *curr_device;
 
        for_each(curr_device,chandev_activelist_head)
-               if(curr_device->read_irqinfo->devno==devno||
-                  curr_device->write_irqinfo->devno==devno)
+               if(curr_device->read_irqinfo->sch.devno==devno||
+                  curr_device->write_irqinfo->sch.devno==devno||
+                  (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.devno==devno))
                {
                        return(curr_device);
                }
@@ -1105,7 +1380,7 @@ int chandev_pack_args(char *str)
                        str++;
                        continue;
                }
-               if(isspace(*str)||((*str)=='-'))
+               if(isspace(*str))
                {
                        *str=',';
                        goto pack_dn;
@@ -1159,7 +1434,7 @@ chandev_strval chandev_strcmp(char *teststr,char **str,long *endlong)
 
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,chandev_category category,chandev_unregfunc unreg_dev)
 {
-       chandev_activelist *newdevice;
+       chandev_activelist *newdevice,*curr_device;
 
        chandev_interrupt_check();
        if(probeinfo->newdevice!=NULL)
@@ -1167,70 +1442,117 @@ int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,cha
                printk("probeinfo->newdevice!=NULL in chandev_initdevice for %s",devname);
                return(-EPERM);
        }
-       
 
+
+       chandev_lock();
+       for_each(curr_device,chandev_activelist_head)
+       {
+               if(strcmp(curr_device->devname,devname)==0)
+               {
+                       printk("chandev_initdevice detected duplicate devicename %s\n",devname);
+                       chandev_unlock();
+                       return(-EPERM);
+               }
+       }
        if((newdevice=chandev_allocstr(devname,offsetof(chandev_activelist,devname))))
        {
-               probeinfo->newdevice=newdevice;
-               chandev_lock();
-               newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read_irq);
-               newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write_irq);
+               newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read.irq);
+               newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write.irq);
+               if(probeinfo->data_exists)
+                       newdevice->data_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->data.irq);
                chandev_unlock();
-               if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL)
+               if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL||
+                  (probeinfo->data_exists&&newdevice->data_irqinfo==NULL))
                {
                        printk("chandev_initdevice, it appears that chandev_request_irq was not "
-                              "called for devname=%s read_irq=%d write_irq=%d\n",devname,probeinfo->read_irq,probeinfo->write_irq);
+                              "called for devname=%s read_irq=%d write_irq=%d data_irq=%d\n",
+                              devname,probeinfo->read.irq,probeinfo->write.irq,probeinfo->data.irq);
                        kfree(newdevice);
                        return(-EPERM);
                }
-               newdevice->cu_type=probeinfo->cu_type;
-               newdevice->cu_model=probeinfo->cu_model;
-               newdevice->dev_type=probeinfo->dev_type;
-               newdevice->dev_model=probeinfo->dev_model;
                newdevice->chan_type=probeinfo->chan_type;              
                newdevice->dev_ptr=dev_ptr;
                newdevice->port_no=port_no;
+               newdevice->memory_usage_in_k=probeinfo->memory_usage_in_k;
                newdevice->category=category;
                newdevice->unreg_dev=unreg_dev;
+               probeinfo->newdevice=newdevice;
                return(0);
        }
+       chandev_unlock();
        return(-ENOMEM);
 }
 
+
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname)
+{
+       if (chandev_use_devno_names&&(!probeinfo->device_forced||probeinfo->devif_num==-1)) 
+               sprintf(destnamebuff,"%s%04x",basename,(int)probeinfo->read.devno);
+       else
+       {
+               if(probeinfo->devif_num==-1)
+               {
+                       if(buildfullname)
+                       {
+                               int idx,len=strlen(basename);
+                               
+                               chandev_activelist *curr_device;
+                               for(idx=0;idx<0xffff;idx++)
+                               {
+                                       for_each(curr_device,chandev_activelist_head)
+                                       {
+                                               if(strncmp(curr_device->devname,basename,len)==0)
+                                               {
+                                                       char numbuff[10];
+                                                       sprintf(numbuff,"%d",idx);
+                                                       if(strcmp(&curr_device->devname[len],numbuff)==0)
+                                                               goto next_idx;
+                                               }
+                                       }
+                                       sprintf(destnamebuff,"%s%d",basename,idx);
+                                       return(destnamebuff);
+                               next_idx:
+                               }
+                               printk("chandev_build_device_name was usable to build a unique name for %s\n",basename);
+                               return(NULL);
+                       }
+                       else
+                               sprintf(destnamebuff,"%s%%d",basename);
+               }
+               else
+               {
+                       sprintf(destnamebuff,"%s%d",basename,(int)probeinfo->devif_num);
+               }
+       }
+       return(destnamebuff);
+}
+
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct net_device *dev, int sizeof_priv, char *basename, 
-struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct net_device *dev))
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv))
 #else
-struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct device *dev, int sizeof_priv, char *basename,
-struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct device *dev))
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv))
 #endif
 {
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
        struct net_device *retdevice=NULL;
-       int new_device = 0;
+       int new_device = FALSE;
 #else
        struct device *retdevice=NULL;
 #endif
+       
 
+       chandev_interrupt_check();
        if (!init_netdevfunc) 
        {
-               printk("init_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+               printk("init_netdevfunc=NULL in chandev_init_netdev, it should not be valid.\n");
                return NULL;
        }
-       if (!unreg_netdevfunc) 
-       {
-               printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
-               return NULL;
-       }
-
-       chandev_interrupt_check();
-
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-        /* Allocate a device if one is not provided. */
+       /* Allocate a device if one is not provided. */
         if (dev == NULL) 
        {
                /* ensure 32-byte alignment of the private area */
@@ -1247,48 +1569,101 @@ void (*unreg_netdevfunc)(struct device *dev))
 
                if (sizeof_priv)
                        dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
-
-               if (probeinfo->devif_num != -1) 
-                       sprintf(dev->name,"%s%d",basename,(int)probeinfo->devif_num);
-               else if (use_devno_names) 
-                       sprintf(dev->name,"%s0x%04x",basename,(int)probeinfo->read_devno);
-
-               new_device = 1;
+               new_device=TRUE;
        }
+       chandev_build_device_name(probeinfo,dev->name,basename,FALSE);
 #endif
-
        retdevice=init_netdevfunc(dev,sizeof_priv);
-
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
        /* Register device if necessary */
+       /* we need to do this as init_netdev doesn't call register_netdevice */
+       /* for already allocated devices */
        if (retdevice && new_device)
                register_netdev(retdevice);
 #endif
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+       /* We allocated it, so we should free it on error */
+       if (!retdevice && new_device) 
+               kfree(dev);
+#endif
+       return retdevice;
+}
+
 
+
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct net_device *dev, int sizeof_priv, char *basename, 
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct net_device *dev))
+#else
+struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct device *dev, int sizeof_priv, char *basename,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct device *dev))
+#endif
+{
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+       struct net_device *retdevice=NULL;
+       int new_device=(dev==NULL);
+#else
+       struct device *retdevice=NULL;
+#endif
+
+       if (!unreg_netdevfunc) 
+       {
+               printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+               return NULL;
+       }
+       chandev_interrupt_check();
+       retdevice=chandev_init_netdev(probeinfo,basename,dev,sizeof_priv,init_netdevfunc);
        if (retdevice) 
        {
                if (chandev_initdevice(probeinfo,retdevice,port_no,retdevice->name,
-                                     network_device,(chandev_unregfunc)unreg_netdevfunc)) 
+                                     chandev_category_network_device,(chandev_unregfunc)unreg_netdevfunc)) 
                {
                        unreg_netdevfunc(retdevice);
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+                       /* We allocated it, so we should free it on error */
+                       if(new_device)
+                               kfree(dev);
+#endif
+
                        retdevice = NULL;
                }
        }
+       return retdevice;
+}
 
-#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-       /* We allocated it, so we should free it on error */
-       if (!retdevice && new_device) 
-               kfree(dev);
-#endif
 
-       return retdevice;
+int chandev_compare_chpid_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+       return (chan1->pim!=chan2->pim || *chan1->chpid!=*chan2->chpid);
 }
 
+int chandev_compare_cu_dev_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+       return ((chan1->cu_type != chan2->cu_type)||
+               (chan1->cu_model != chan2->cu_model)||
+               (chan1->dev_type != chan2->dev_type)||
+               (chan1->dev_model != chan2->dev_model));
+}
 
+int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+       return((chan1->devno == chan2->devno) &&
+              (chan1->cu_type == chan2->cu_type) &&
+              (chan1->cu_model == chan2->cu_model) &&
+              (chan1->dev_type == chan2->dev_type) &&
+              (chan1->dev_model == chan2->dev_model) &&
+              (chan1->pim == chan2->pim) &&
+              (*chan1->chpid == *chan2->chpid));
+}
 
 
-int chandev_doprobe(chandev_force *force,chandev *read_chandev,
-chandev *write_chandev)
+int chandev_doprobe(chandev_force *force,chandev *read,
+chandev *write,chandev *data)
 {
        chandev_probelist *probe;
        chandev_model_info *model_info;
@@ -1296,41 +1671,60 @@ chandev *write_chandev)
        int               rc=-1,hint=-1;
        chandev_activelist *newdevice;
        chandev_probefunc  probefunc;
-       int                saved_lock_cnt;
        chandev_parms      *curr_parms;
+       chandev_model_info dummy_model_info;
 
        memset(&probeinfo,0,sizeof(probeinfo));
-       model_info=read_chandev->model_info;
-       if(read_chandev->model_info!=write_chandev->model_info||
-          (force&&((force->chan_type&model_info->chan_type)==0))||
-          (!force&&((read_chandev->cu_type!=write_chandev->cu_type)||
-                   (read_chandev->cu_model!=write_chandev->cu_model)||
-                   (read_chandev->dev_type!=write_chandev->dev_type)||
-                  (read_chandev->dev_model!=write_chandev->dev_model))))
-               return(-1); /* inconsistent */
+       memset(&dummy_model_info,0,sizeof(dummy_model_info));
+       probeinfo.device_forced=(force!=NULL);
+       probeinfo.chpid_info_inconsistent=chandev_compare_chpid_info(&read->sch,&write->sch)||
+                (data&&chandev_compare_chpid_info(&read->sch,&data->sch));
+       probeinfo.cu_dev_info_inconsistent=chandev_compare_cu_dev_info(&read->sch,&write->sch)||
+                (data&&chandev_compare_cu_dev_info(&read->sch,&data->sch));
+       if(read->model_info)
+               model_info=read->model_info;
+       else
+       {
+               dummy_model_info.chan_type=chandev_type_none;
+               dummy_model_info.max_port_no=16;
+               model_info=&dummy_model_info;
+       }
        for_each(probe,chandev_probelist_head)
        {
-               probeinfo.chan_type=(probe->chan_type&model_info->chan_type);
-               if(probeinfo.chan_type)
+               if(force)
+                       probeinfo.chan_type = ( probe->chan_type & force->chan_type );
+               else
+               {
+                       if(chandev_cautious_auto_detect)
+                               probeinfo.chan_type = ( probe->chan_type == model_info->chan_type ? 
+                                                      probe->chan_type : chandev_type_none );
+                       else
+                               probeinfo.chan_type = ( probe->chan_type & model_info->chan_type );
+               }
+               if(probeinfo.chan_type && (force || ( !probeinfo.cu_dev_info_inconsistent &&
+                 ((probe->chan_type&(chandev_type_ctc|chandev_type_escon)) ||
+                  !probeinfo.chpid_info_inconsistent))))
                {
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-                       if(use_devno_names)
-                               probeinfo.devif_num=read_chandev->devno;
+                       if(chandev_use_devno_names)
+                               probeinfo.devif_num=read->sch.devno;
                        else
 #endif
                                probeinfo.devif_num=-1;
-                       probeinfo.read_irq=read_chandev->irq;
-                       probeinfo.write_irq=write_chandev->irq;
-                       probeinfo.read_devno=read_chandev->devno;
-                       probeinfo.write_devno=write_chandev->devno;
-                       probeinfo.max_port_no=model_info->max_port_no;
-                       probeinfo.cu_type=read_chandev->cu_type;
-                       probeinfo.cu_model=read_chandev->cu_model;
-                       probeinfo.dev_type=read_chandev->dev_type;
-                       probeinfo.dev_model=read_chandev->dev_model;
+                       probeinfo.read=read->sch;
+                       probeinfo.write=write->sch;
+                       if(data)
+                       {
+                               probeinfo.data=data->sch;
+                               probeinfo.data_exists=TRUE;
+                       }
+                       probeinfo.max_port_no=(force&&(force->port_protocol_no!=-1) ? 
+                             force->port_protocol_no : model_info->max_port_no);
                        for_each(curr_parms,chandev_parms_head)
                        {
-                               if(probe->chan_type==curr_parms->chan_type)
+                               if(probe->chan_type==curr_parms->chan_type&&
+                                  read->sch.devno>=curr_parms->lo_devno&&
+                                       read->sch.devno<=curr_parms->hi_devno)
                                {
                                        probeinfo.parmstr=curr_parms->parmstr;
                                        break;
@@ -1338,25 +1732,26 @@ chandev *write_chandev)
                        }
                        if(force)
                        {
+                               if(force->chan_type==chandev_type_claw)
+                                       memcpy(&probeinfo.claw,&force->claw,sizeof(chandev_claw_info));
                                probeinfo.port_protocol_no=force->port_protocol_no;
-                               if(force->devif_num!=-1)
+                               if(force->devif_num==-1&&force->devif_num==-2)
+                                       probeinfo.devif_num=-1;
+                               else
                                        probeinfo.devif_num=force->devif_num;
+                               probeinfo.memory_usage_in_k=force->memory_usage_in_k;
                                probeinfo.checksum_received_ip_pkts=force->checksum_received_ip_pkts;
                                probeinfo.use_hw_stats=force->use_hw_stats;
-                               
                        }
                        else
                        {
-                               probeinfo.port_protocol_no=-1;
-                               probeinfo.checksum_received_ip_pkts=FALSE;
-                               probeinfo.use_hw_stats=FALSE;
-                               if(probe->chan_type&lcs)
+                               probeinfo.port_protocol_no=0;
+                               probeinfo.checksum_received_ip_pkts=model_info->default_checksum_received_ip_pkts;
+                               probeinfo.use_hw_stats=model_info->default_use_hw_stats;
+                               probeinfo.memory_usage_in_k=0;
+                               if(probe->chan_type&chandev_type_lcs)
                                {
-                                       if((probeinfo.read_devno&1)||
-                                          ((probeinfo.read_devno|1)!=
-                                           (probeinfo.write_devno)))
-                                               return(-1);
-                                       hint=(read_chandev->devno&0xFF)>>1;
+                                       hint=(read->sch.devno&0xFF)>>1;
                                        if(hint>model_info->max_port_no)
                                        {
                                /* The card is possibly emulated e.g P/390 */
@@ -1368,12 +1763,7 @@ chandev *write_chandev)
                        }
                        probeinfo.hint_port_no=hint;
                        probefunc=probe->probefunc;
-                       saved_lock_cnt=chandev_full_unlock();
-                       /* We have to leave the lock go here */
-                       /* as probefunctions can call schedule & */
-                        /* reenter to do a kernel thread & we may deadlock */
                        rc=probefunc(&probeinfo);
-                       chandev_relock(saved_lock_cnt);
                        if(rc==0)
                        {
                                newdevice=probeinfo.newdevice;
@@ -1381,47 +1771,174 @@ chandev *write_chandev)
                                {
                                        newdevice->probefunc=probe->probefunc;
                                        newdevice->shutdownfunc=probe->shutdownfunc;
-                                       newdevice->reoperfunc=probe->reoperfunc;
+                                       newdevice->msck_notfunc=probe->msck_notfunc;
                                        probe->devices_found++;
                                        chandev_add_to_list((list **)&chandev_activelist_head,
                                                            newdevice);
-                                       chandev_add_to_startmsck_list(&startlist_head,
-                                                                     newdevice->devname,good,good);
-                                       
+                                       chandev_add_to_userland_notify_list(chandev_start,
+                                                                     newdevice->devname,chandev_status_good,chandev_status_good);
                                }
                                else
                                {
-                                       printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read_irq);
+                                       printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read.irq);
                                }
                                break;
+                               
                        }
                }
        }
+       chandev_remove(read);
+       chandev_remove(write);
+       if(data)
+               chandev_remove(data);
        return(rc);
 }
 
 
 int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
 {
-       int retval=s390_request_irq_special(irqinfo->irq,
+       int retval=s390_request_irq_special(irqinfo->sch.irq,
                                   irqinfo->handler,
                                   chandev_not_oper_handler,
                                   irqinfo->irqflags,
                                   irqinfo->devname,
                                   irqinfo->dev_id);
        if(retval==0)
+       {
+               irqinfo->msck_status=chandev_status_good;
                this_chandev->owned=TRUE;
+       }
        return(retval);
 }
 
 void chandev_irqallocerr(chandev_irqinfo *irqinfo,int err)
 {
-       printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->irq,irqinfo->devname,err);
+       printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->sch.irq,irqinfo->devname,err);
+}
+
+
+void chandev_call_notification_func(chandev_activelist *curr_device,chandev_irqinfo *curr_irqinfo,
+chandev_msck_status prevstatus)
+{
+       if(curr_irqinfo->msck_status!=prevstatus)
+       {
+               chandev_msck_status new_msck_status=curr_irqinfo->msck_status;
+               if(curr_irqinfo->msck_status==chandev_status_good)
+               {
+                       if(curr_device->read_irqinfo->msck_status==chandev_status_good&&
+                          curr_device->write_irqinfo->msck_status==chandev_status_good)
+                       {
+                               if(curr_device->data_irqinfo)
+                               {
+                                       if(curr_device->data_irqinfo->msck_status==chandev_status_good)
+                                               new_msck_status=chandev_status_all_chans_good;
+                               }
+                               else
+                                       new_msck_status=chandev_status_all_chans_good;
+                       }
+               }
+               if(curr_device->msck_notfunc)
+               {
+                       curr_device->msck_notfunc(curr_device->dev_ptr,
+                                             curr_irqinfo->sch.irq,
+                                             prevstatus,new_msck_status);
+               }
+               if(new_msck_status!=chandev_status_good)
+               {
+                       /* No point in sending a machine check if only one channel is good */
+                       chandev_add_to_userland_notify_list(chandev_msck,curr_device->devname,
+                                                     prevstatus,curr_irqinfo->msck_status);
+               }
+       }
+}
+
+int chandev_find_eligible_channels(chandev *first_chandev_to_check,
+                              chandev **read,chandev **write,chandev **data,chandev **next,
+                                  chandev_type chan_type)
+{
+       chandev *curr_chandev;
+       int eligible_found=FALSE,changed;
+       
+       *next=first_chandev_to_check->next;
+       *read=*write=*data=NULL;
+       for_each(curr_chandev,first_chandev_to_check)
+               if((curr_chandev->sch.devno&1)==0&&curr_chandev->model_info->chan_type!=chandev_type_claw)
+               {
+                       *read=curr_chandev;
+                       if(chan_type==chandev_type_none)
+                               chan_type=(*read)->model_info->chan_type;
+                       break;
+               }
+       if(*read)
+       {
+               for_each(curr_chandev,(chandev *)chandev_head.head)
+                       if((((*read)->sch.devno|1)==curr_chandev->sch.devno)&&
+                          (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+                          ((chan_type&(chandev_type_ctc|chandev_type_escon))||
+                           chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+                       {
+                               *write=curr_chandev;
+                               break;
+                       }
+       }
+       if((chan_type&chandev_type_qeth))
+       {
+               if(*write)
+               {
+                       for_each(curr_chandev,(chandev *)chandev_head.head)
+                               if((curr_chandev!=*read&&curr_chandev!=*write)&&
+                                  (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+                                  (chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+                               {
+                                       *data=curr_chandev;
+                                       break;
+                               }
+                       if(*data)
+                               eligible_found=TRUE;
+               }
+               
+       }
+       else
+               if(*write)
+                       eligible_found=TRUE;
+       if(eligible_found)
+       {
+               do
+               {
+                       changed=FALSE;
+                       if(*next&&
+                          ((*read&&(*read==*next))||
+                          (*write&&(*write==*next))||
+                          (*data&&(*data==*next))))
+                       {
+                               *next=(*next)->next;
+                               changed=TRUE;
+                       }
+               }while(changed==TRUE);
+       }
+       return(eligible_found);
+}
+
+chandev *chandev_get_free_chandev_by_devno(int devno)
+{
+       chandev *curr_chandev;
+       if(devno==-1)
+               return(NULL);
+       for_each(curr_chandev,(chandev *)chandev_head.head)
+               if(curr_chandev->sch.devno==devno)
+               {
+                       if(chandev_active(devno))
+                               return(NULL);
+                       else
+                               return(curr_chandev);
+               }
+       return(NULL);
+
 }
 
 void chandev_probe(void)
 {
-       chandev *read_chandev,*write_chandev,*curr_chandev;
+       chandev *read_chandev,*write_chandev,*data_chandev,*curr_chandev,*next_chandev;
        chandev_force *curr_force;
        chandev_noauto_range *curr_noauto;
        chandev_activelist *curr_device;
@@ -1434,16 +1951,17 @@ void chandev_probe(void)
 
 
        chandev_interrupt_check();
+       chandev_read_conf_if_necessary();
        chandev_collect_devices();
        chandev_lock();
        for_each(curr_irqinfo,chandev_irqinfo_head)
        {
-               if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->irq)))
+               if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->sch.irq)))
                {
                        prevstatus=curr_irqinfo->msck_status;
-                       if(curr_irqinfo->msck_status!=good)
+                       if(curr_irqinfo->msck_status!=chandev_status_good)
                        {
-                               curr_chandev=chandev_get_by_irq(curr_irqinfo->irq);
+                               curr_chandev=chandev_get_by_irq(curr_irqinfo->sch.irq);
                                if(curr_chandev)
                                {
                                        auto_msck_recovery=curr_chandev->model_info->
@@ -1454,9 +1972,9 @@ void chandev_probe(void)
                                for_each(curr_msck_range,chandev_msck_range_head)
                                {
                                        if(curr_msck_range->lo_devno<=
-                                          curr_irqinfo->devno&&
+                                          curr_irqinfo->sch.devno&&
                                           curr_msck_range->hi_devno>=
-                                          curr_irqinfo->devno)
+                                          curr_irqinfo->sch.devno)
                                        {
                                                auto_msck_recovery=
                                                        curr_msck_range->
@@ -1466,28 +1984,32 @@ void chandev_probe(void)
                                }
                                if((1<<(curr_irqinfo->msck_status-1))&auto_msck_recovery)
                                {
-                                       if(curr_irqinfo->msck_status==revalidate)
+                                       if(curr_irqinfo->msck_status==chandev_status_revalidate)
                                        {
-                                               if((get_dev_info_by_irq(curr_irqinfo->irq,&curr_devinfo)==0))
+                                               if((get_dev_info_by_irq(curr_irqinfo->sch.irq,&curr_devinfo)==0))
                                                {
-                                                       curr_irqinfo->devno=curr_devinfo.devno;
-                                                       curr_irqinfo->msck_status=good;
-                                                       goto remove;
+                                                       curr_irqinfo->sch.devno=curr_devinfo.devno;
+                                                       curr_irqinfo->msck_status=chandev_status_good;
                                                }
                                        }
                                        else
                                        {
-                                               if((curr_chandev=chandev_get_by_irq(curr_irqinfo->irq)))
+                                               if(curr_chandev)
                                                {
                                                        /* Has the device reappeared */
-                                                       if(curr_chandev->cu_type==curr_device->cu_type&&
-                                                          curr_chandev->cu_model==curr_device->cu_model&&
-                                                          curr_chandev->dev_type==curr_device->dev_type&&
-                                                          curr_chandev->dev_model==curr_device->dev_model&&
-                                                          curr_chandev->devno==curr_irqinfo->devno)
+                                                       if(chandev_compare_subchannel_info(
+                                                               &curr_chandev->sch,
+                                                               &curr_device->read_irqinfo->sch)||
+                                                          chandev_compare_subchannel_info(
+                                                               &curr_chandev->sch,
+                                                               &curr_device->write_irqinfo->sch)||
+                                                          (curr_device->data_irqinfo&&
+                                                           chandev_compare_subchannel_info(
+                                                                   &curr_chandev->sch,
+                                                                   &curr_device->data_irqinfo->sch)))
                                                        {
                                                                if((err=chandev_request_irq_from_irqinfo(curr_irqinfo,curr_chandev))==0)
-                                                                       curr_irqinfo->msck_status=good;
+                                                                       curr_irqinfo->msck_status=chandev_status_good;
                                                                else
                                                                        chandev_irqallocerr(curr_irqinfo,err);
                                                        }
@@ -1496,86 +2018,89 @@ void chandev_probe(void)
                                        }
                                }
                        }
-                       if(curr_irqinfo->msck_status==good&&prevstatus!=good)
-                       {
-                               if(curr_device->reoperfunc)
-                               {
-                                       int saved_lock_cnt=chandev_full_unlock();
-                                       curr_device->reoperfunc(curr_device->dev_ptr,
-                                                               (curr_device->read_irqinfo==curr_irqinfo),
-                                                               prevstatus);
-                                       chandev_relock(saved_lock_cnt);
-                               }
-                               if(curr_device->category==network_device&&
-                                  curr_device->write_irqinfo==curr_irqinfo)
-                               {
-                                       net_device *dev=(net_device *)curr_device->dev_ptr;
-                                       if(dev->flags&IFF_UP)
-                                               netif_start_queue(dev);
-                               }
-                               chandev_add_to_startmsck_list(&mscklist_head,curr_device->devname,
-                                                             prevstatus,curr_irqinfo->msck_status);
-                       }
+                       chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
                }
                /* This is required because the device can go & come back */
                 /* even before we realize it is gone owing to the waits in our kernel threads */
                /* & the device will be marked as not owned but its status will be good */
                 /* & an attempt to accidently reprobe it may be done. */ 
                remove:
-               chandev_remove(chandev_get_by_irq(curr_irqinfo->irq));
+               chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
                
        }
        /* extra sanity */
-       for_each(curr_chandev,(chandev *)chandev_head.head)
+       for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
                if(curr_chandev->owned)
                        chandev_remove(curr_chandev);
        for_each(curr_force,chandev_force_head)
        {
-               for_each(read_chandev,(chandev *)chandev_head.head)
-                       if(read_chandev->devno==curr_force->read_devno&&
-                               !chandev_active(curr_force->read_devno))
+               if(curr_force->devif_num==-2)
+               {
+                       for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
                        {
-                               for_each(write_chandev,(chandev *)chandev_head.head)
-                                       if(write_chandev->devno==
-                                          curr_force->write_devno&&
-                                          !chandev_active(curr_force->write_devno))
+                               if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+                                                                 &write_chandev,&data_chandev,
+                                                                 &next_chandev,
+                                                                 curr_force->chan_type));
+                               {
+                                       if((curr_force->read_lo_devno>=read_chandev->sch.devno)&&
+                                          (curr_force->write_hi_devno<=read_chandev->sch.devno)&&
+                                          (curr_force->read_lo_devno>=write_chandev->sch.devno)&&
+                                          (curr_force->write_hi_devno<=write_chandev->sch.devno)&&
+                                          (!data_chandev||(data_chandev&&
+                                          (curr_force->read_lo_devno>=data_chandev->sch.devno)&&
+                                          (curr_force->write_hi_devno<=data_chandev->sch.devno))))
+                                               chandev_doprobe(curr_force,read_chandev,write_chandev,
+                                                               data_chandev);
+                               }
+                       }
+               }
+               else
+               {
+                       read_chandev=chandev_get_free_chandev_by_devno(curr_force->read_lo_devno);
+                       if(read_chandev)
+                       {
+                               write_chandev=chandev_get_free_chandev_by_devno(curr_force->write_hi_devno);
+                               if(write_chandev)
+                               {
+                                       if(curr_force->chan_type==chandev_type_qeth)
                                        {
-                                               if(chandev_doprobe(curr_force,
-                                                               read_chandev,
-                                                               write_chandev)==0)
-                                               {
-                                                       chandev_remove(read_chandev);
-                                                       chandev_remove(write_chandev);
-                                                       goto chandev_probe_skip;
-                                               }
+
+                                               data_chandev=chandev_get_free_chandev_by_devno(curr_force->data_devno);
+                                               if(data_chandev==NULL)
+                                                       printk("chandev_probe unable to force gigabit_ethernet driver invalid device  no 0x%04x given\n",curr_force->data_devno);
                                        }
+                                       else
+                                               data_chandev=NULL;
+                                       chandev_doprobe(curr_force,read_chandev,write_chandev,
+                                                       data_chandev);
+                               }
                        }
-       chandev_probe_skip:
+               }
        }
-       for_each(curr_chandev,(chandev *)chandev_head.head)
+       for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
        {
                for_each(curr_noauto,chandev_noauto_head)
                {
-                       if(curr_chandev->devno>=curr_noauto->lo_devno&&
-                          curr_chandev->devno<=curr_noauto->hi_devno)
+                       if(curr_chandev->sch.devno>=curr_noauto->lo_devno&&
+                          curr_chandev->sch.devno<=curr_noauto->hi_devno)
                        {
                                chandev_remove(curr_chandev);
                                break;
                        }
                }
        }
-       for_each(curr_chandev,(chandev *)chandev_head.head)
+       for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
        {
-               if(curr_chandev->next&&curr_chandev->model_info==
-                  curr_chandev->next->model_info)
-               {
-                       
-                       chandev_doprobe(NULL,curr_chandev,curr_chandev->next);
-                       curr_chandev=curr_chandev->next;
-               }
+               if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+                                                 &write_chandev,&data_chandev,
+                                                 &next_chandev,
+                                                 chandev_type_none))
+                       chandev_doprobe(NULL,read_chandev,write_chandev,
+                                       data_chandev);
        }
-       chandev_unlock();
        chandev_remove_all();
+       chandev_unlock();
 }
 
 static void chandev_not_oper_func(int irq,int status)
@@ -1585,49 +2110,40 @@ static void chandev_not_oper_func(int irq,int status)
        
        chandev_lock();
        for_each(curr_irqinfo,chandev_irqinfo_head)
-               if(curr_irqinfo->irq==irq)
+               if(curr_irqinfo->sch.irq==irq)
                {
+                       chandev_msck_status prevstatus=curr_irqinfo->msck_status;
                        switch(status)
                        {
                                /* Currently defined but not used in kernel */
                                /* Despite being in specs */
                        case DEVSTAT_NOT_OPER:
-                               curr_irqinfo->msck_status=not_oper;
+                               curr_irqinfo->msck_status=chandev_status_not_oper;
                                break;
 #ifdef DEVSTAT_NO_PATH
                                /* Kernel hasn't this defined currently. */
                                /* Despite being in specs */
                        case DEVSTAT_NO_PATH:
-                               curr_irqinfo->msck_status=no_path;
+                               curr_irqinfo->msck_status=chandev_status_no_path;
                                break;
 #endif
                        case DEVSTAT_REVALIDATE:
-                               curr_irqinfo->msck_status=revalidate;
+                               curr_irqinfo->msck_status=chandev_status_revalidate;
                                break;
                        case DEVSTAT_DEVICE_GONE:
-                               curr_irqinfo->msck_status=gone;
-                               break;
-                       }
-                       for_each(curr_device,chandev_activelist_head)
-                       {
-                               if(curr_device->write_irqinfo==curr_irqinfo)
-                               {
-                                       if(curr_device->category==network_device)
-                                       {
-                                               net_device *dev=(net_device *)curr_device->dev_ptr;
-                                               if(dev->flags&IFF_UP)
-                                                       netif_stop_queue(dev);
-                                       }
-                               }
+                               curr_irqinfo->msck_status=chandev_status_gone;
                                break;
-                       }
-                       break;
+                        }
+                        if((curr_device=chandev_get_activelist_by_irq(irq)))
+                                       chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
+                       else
+                               printk("chandev_not_oper_func received channel check for unowned irq %d",irq);
                }
        chandev_unlock();
 }
 
 
-static void chandev_msck_task(void *unused)
+static int chandev_msck_thread(void *unused)
 {
        int loopcnt,not_oper_probe_required=FALSE;
        wait_queue_head_t    wait;
@@ -1663,9 +2179,17 @@ static void chandev_msck_task(void *unused)
        }
        if(not_oper_probe_required)
                chandev_probe();
+       return(0);
 }
 
-
+static void chandev_msck_task(void *unused)
+{
+       if(kernel_thread(chandev_msck_thread,NULL,SIGCHLD)<0)
+       {
+               atomic_set(&chandev_msck_thread_lock,1);
+               printk("error making chandev_msck_thread kernel thread\n");
+       }
+}
 
 
 
@@ -1686,6 +2210,8 @@ static char *argstrs[]=
        "use_devno_names",
        "dont_use_devno_names",
 #endif
+       "cautious_auto_detect",
+       "non_cautious_auto_detect",
        "add_model",
        "del_model",
        "auto_msck",
@@ -1696,8 +2222,10 @@ static char *argstrs[]=
        "shutdown",
        "reprobe",
        "unregister_probe",
+       "unregister_probe_by_chan_type",
        "read_conf",
        "dont_read_conf",
+       "persistent"
 };
 
 typedef enum
@@ -1719,6 +2247,8 @@ typedef enum
        use_devno_names_stridx,
        dont_use_devno_names_stridx,
 #endif
+       cautious_auto_detect_stridx,
+       non_cautious_auto_detect_stridx,
        add_model_stridx,
        del_model_stridx,
        auto_msck_stridx,
@@ -1729,8 +2259,10 @@ typedef enum
        shutdown_stridx,
        reprobe_stridx,
        unregister_probe_stridx,
+       unregister_probe_by_chan_type_stridx,
        read_conf_stridx,
        dont_read_conf_stridx,
+       persistent_stridx,
        last_stridx,
 } chandev_str_enum;
 
@@ -1799,16 +2331,18 @@ static chandev_int chandev_get_option(char **str,chandev_int *pint)
     return 1;
 }
 
+
 static char *chandev_get_options(char *str, int nints, chandev_int *ints)
 {
        int res,i=1;
 
-    while (i<nints) {
-        res = chandev_get_option(&str, ints+i);
-        if (res==0) break;
-        i++;
-        if (res==1) break;
-    }
+       while (i<nints) 
+       {
+               res = chandev_get_option(&str, ints+i);
+               if (res==0) break;
+               i++;
+               if (res==1) break;
+       }
        ints[0] = i-1;
        return(str);
 }
@@ -1816,6 +2350,43 @@ static char *chandev_get_options(char *str, int nints, chandev_int *ints)
 #define chandev_get_option get_option
 #define chandev_get_options get_options
 #endif
+/*
+ * Read an string from an option string; if available accept a subsequent
+ * comma as well & set this comma to a null character when returning the string.
+ *
+ * Return values:
+ * 0 : no string found
+ * 1 : string found, no subsequent comma
+ * 2 : string found including a subsequent comma
+ */
+static int chandev_get_string(char **instr,char **outstr)
+{
+       char *cur = *instr;
+
+       if (!cur ||*cur==0)
+       {
+               *outstr=NULL;
+               return 0;
+       }
+       *outstr=*instr;
+       for(;;)
+       {
+               if(*(++cur)==',')
+               {
+                       *cur=0;
+                       *instr=cur+1;
+                       return 2;
+               }
+               else if(*cur==0)
+               {
+                       *instr=cur+1;
+                       return 1;
+               }
+       }
+}
+
+
+
 
 static int chandev_setup(char *instr,char *errstr,int lineno)
 {
@@ -1826,15 +2397,15 @@ static int chandev_setup(char *instr,char *errstr,int lineno)
        char             *str,*currstr,*interpretstr=NULL;
        int              cnt,strcnt;
        int              retval=0;
-#define CHANDEV_MAX_EXTRA_INTS 8
+#define CHANDEV_MAX_EXTRA_INTS 12
        chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1];
-       memset(ints,0,sizeof(ints));
        currstr=alloca(strlen(instr)+1);
        strcpy(currstr,instr);
        strcnt=chandev_pack_args(currstr);
        for(cnt=1;cnt<=strcnt;cnt++)
        {
                interpretstr=currstr;
+               memset(ints,0,sizeof(ints));
                for(stridx=first_stridx;stridx<last_stridx;stridx++)
                {
                        str=currstr;
@@ -1844,29 +2415,36 @@ static int chandev_setup(char *instr,char *errstr,int lineno)
                currstr=str;
                if(val)
                {
-                       if(val&iscomma)
+                       val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
+                       switch(val)
                        {
-                               if(stridx==add_parms_stridx&&(val==(isstr|iscomma)))
+                       case (add_parms_stridx*stridx_mult)|iscomma:
+                               currstr=chandev_get_options(currstr,4,ints);
+                               if(*currstr&&ints[0]>=1)
                                {
-                                       str=currstr;
-                                       if(chandev_get_option(&str,&ints[0])==2)
+                                       if(ints[0]==1)
                                        {
-                                               chandev_add_parms(ints[0],str);
-                                               currstr=str+strlen(str)+1;
-                                               continue;
+                                               ints[2]=0;
+                                               ints[3]=0xffff;
                                        }
-                                       else
-                                               goto BadArgs;
+                                       else if(ints[0]==2)
+                                               ints[3]=ints[2];
+                                       chandev_add_parms(ints[1],ints[2],ints[3],currstr);
+//                                     currstr=currstr+strlen(currstr)+1;
+                                       continue;
                                }
                                else
-                                       currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints)+1;
-                       }
-                       else
-                       {
-                               ints[0]=0;
-                               currstr++;
+                                       goto BadArgs;
+                               break;
+                       case (claw_stridx*stridx_mult)|isnum|iscomma:
+                       case (claw_stridx*stridx_mult)|iscomma:
+                               currstr=chandev_get_options(str,6,ints);
+                               break;
+                       default:
+                               if(val&iscomma)
+                                       currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints);
+                               break;
                        }
-                       val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
                        switch(val)
                        {
                        case noauto_stridx*stridx_mult:
@@ -1924,59 +2502,105 @@ static int chandev_setup(char *instr,char *errstr,int lineno)
                                else
                                        goto BadArgs;
                                break;
+                       case (qeth_stridx*stridx_mult)|isnum|iscomma:
+                               if(ints[0]<3||ints[0]>7)
+                                       goto BadArgs;
+                               chandev_add_force(chandev_type_qeth,endlong,ints[1],ints[2],
+                                                 ints[3],ints[4],ints[5],ints[6],ints[7],
+                                                 NULL,NULL,NULL);
+                               break;
                        case (ctc_stridx*stridx_mult)|isnum|iscomma:
                        case (escon_stridx*stridx_mult)|isnum|iscomma:
                        case (lcs_stridx*stridx_mult)|isnum|iscomma:
                        case (osad_stridx*stridx_mult)|isnum|iscomma:
-                       case (qeth_stridx*stridx_mult)|isnum|iscomma:
-                       case (claw_stridx*stridx_mult)|isnum|iscomma:
-                               switch(val)
+                       case (ctc_stridx*stridx_mult)|iscomma:
+                       case (escon_stridx*stridx_mult)|iscomma:
+                       case (lcs_stridx*stridx_mult)|iscomma:
+                       case (osad_stridx*stridx_mult)|iscomma:
+                               switch(val&~(isnum|iscomma))
                                {
-                               case (ctc_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=ctc;
-                                       break;
-                               case (escon_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=escon;
+                               case (ctc_stridx*stridx_mult):
+                                       chan_type=chandev_type_ctc;
                                        break;
-                               case (lcs_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=lcs;
+                               case (escon_stridx*stridx_mult):
+                                       chan_type=chandev_type_escon;
                                        break;
-                               case (osad_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=osad;
+                               case (lcs_stridx*stridx_mult):
+                                       chan_type=chandev_type_lcs;
                                        break;
-                               case (qeth_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=qeth;
+                               case (osad_stridx*stridx_mult):
+                                       chan_type=chandev_type_osad;
                                        break;
-                               case (claw_stridx*stridx_mult)|isnum|iscomma:
-                                       chan_type=claw;
+                               case (qeth_stridx*stridx_mult):
+                                       chan_type=chandev_type_qeth;
                                        break;
                                default:
                                        goto BadArgs;
                                }
+                               if((val&isnum)==0)
+                                       endlong=-2;
+                               if(ints[0]<2||ints[0]>6)
+                                       goto BadArgs;
                                chandev_add_force(chan_type,endlong,ints[1],ints[2],
-                                                 ints[3],ints[4],ints[5]);
+                                                 0,ints[3],ints[4],ints[5],ints[6],
+                                                 NULL,NULL,NULL);
+                               break;
+                       case (claw_stridx*stridx_mult)|isnum|iscomma:
+                       case (claw_stridx*stridx_mult)|iscomma:
+                               if(ints[0]>=2&&ints[0]<=5)
+                               {
+                                       char    *host_name,*adapter_name,*api_type;
+                                       char    *clawstr=alloca(strlen(currstr)+1);
+                                       
+                                       strcpy(clawstr,currstr);
+                                       if(!(chandev_get_string(&clawstr,&host_name)==2&&
+                                            chandev_get_string(&clawstr,&adapter_name)==2&&
+                                            chandev_get_string(&clawstr,&api_type)==1&&
+                                            chandev_add_force(chandev_type_claw,
+                                                              endlong,ints[1],ints[2],0,
+                                                              ints[3],0,ints[4],ints[5],
+                                                              host_name,adapter_name,api_type)==0))
+                                               goto BadArgs;
+                                               
+                               }
+                               else
+                                       goto BadArgs;
                                break;
                        case (del_parms_stridx*stridx_mult):
                                ints[1]=-1;
                        case (del_parms_stridx*stridx_mult)|iscomma:
-                               if(ints[0]==1)
+                               if(ints[0]==0)
+                                       ints[1]=-1;
+                               if(ints[0]<=1)
                                        ints[2]=FALSE;
-                               if(ints[0]>2)
+                               if(ints[0]<=2)
+                                       ints[3]=-1;
+                               if(ints[0]>3)
                                        goto BadArgs;
-                               chandev_remove_parms(ints[1],ints[2]);
+                               chandev_remove_parms(ints[1],ints[2],ints[3]);
                                break;
                        case (del_force_stridx*stridx_mult)|iscomma:
                                if(ints[0]!=1)
                                        goto BadArgs;
                                chandev_del_force(ints[1]);
                                break;
+                       case (del_force_stridx*stridx_mult):
+                               chandev_del_force(-1);
+                               break;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
                        case (use_devno_names_stridx*stridx_mult):
-                               use_devno_names=1;
+                               chandev_use_devno_names=TRUE;
                                break;
                        case (dont_use_devno_names_stridx*stridx_mult):
-                               use_devno_names=0;
+                               chandev_use_devno_names=FALSE;
+                               break;
 #endif
+                       case (cautious_auto_detect_stridx*stridx_mult):
+                               chandev_cautious_auto_detect=TRUE;
+                               break;
+                       case (non_cautious_auto_detect_stridx*stridx_mult):
+                               chandev_cautious_auto_detect=FALSE;
+                               break;
                        case (add_model_stridx*stridx_mult)|iscomma:
                                if(ints[0]<3)
                                        goto BadArgs;
@@ -1988,9 +2612,13 @@ static int chandev_setup(char *instr,char *errstr,int lineno)
                                        ints[6]=-1;
                                if(ints[0]<=6)
                                        ints[7]=default_msck_bits;
+                               if(ints[0]<=7)
+                                       ints[8]=FALSE;
+                               if(ints[0]<=8)
+                                       ints[9]=FALSE;
                                ints[0]=7;
                                chandev_add_model(ints[1],ints[2],ints[3],
-                                                 ints[4],ints[5],ints[6],ints[7]);
+                                                 ints[4],ints[5],ints[6],ints[7],ints[8],ints[9]);
                                break;
                        case (del_model_stridx*stridx_mult)|iscomma:
                                if(ints[0]<2||ints[0]>4)
@@ -2042,41 +2670,53 @@ static int chandev_setup(char *instr,char *errstr,int lineno)
                                        goto BadArgs;
                                chandev_unregister_probe((chandev_probefunc)ints[1]);
                                break;
+                       case (unregister_probe_by_chan_type_stridx*stridx_mult)|iscomma:
+                               if(ints[0]!=1)
+                                       goto BadArgs;
+                               chandev_unregister_probe_by_chan_type((chandev_type)ints[1]);
+                               break;
                        case read_conf_stridx*stridx_mult:
                                chandev_read_conf();
                                break;
                        case dont_read_conf_stridx*stridx_mult:
-                               chandev_conf_read=TRUE;
+                               atomic_set(&chandev_conf_read,TRUE);
+                               break;
+                       case (persistent_stridx*stridx_mult)|iscomma:
+                               if(ints[0]==1)
+                                       chandev_persistent=ints[1];
+                               else
+                                       goto BadArgs;
                                break;
                        default:
                                goto BadArgs;
-                       }               
+                       }
                }
                else
                        goto BadArgs;
+               if(cnt<strcnt)
+               {
+                       /* eat up stuff till next string */
+                       while(*(currstr++));
+               }
        }
        retval=1;
  BadArgs:
        if(!retval)
        {
-               printk("chandev_setup bad argument %s",instr);
+               printk("chandev_setup %s %s",(val==0 ? "unknown verb":"bad argument"),instr);
                if(errstr)
                {
                        printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
                        if(strcnt>1)
-                               printk(" before semicolon no %d",cnt);
+                       {
+                               if(cnt==strcnt)
+                                       printk(" after the last semicolon\n");
+                               else
+                                       printk(" before semicolon no %d",cnt);
+                       }
                }
                printk(".\n Type man chandev for more info.\n\n");
        }
-       eieio();
-       if(chandev_lock_owner==(long)current)
-       {
-               printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n"
-                       "firstlock_retaddr=%p last_lock_returnaddr=%p\n",
-                      chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr,
-                      chandev_lastlock_addr);
-               chandev_full_unlock();
-        }
        return(retval);
 }
 #define CHANDEV_KEYWORD "chandev="
@@ -2166,9 +2806,15 @@ static void chandev_read_conf(void)
        char        *buff;
        int         curr,left,len,fd;
 
+       /* if called from chandev_register_and_probe & 
+          the driver is compiled into the kernel the
+          parameters will need to be passed in from
+          the kernel boot parameter line as the root
+          fs is not mounted yet, we can't wait here.
+       */
        if(in_interrupt()||current->fs->root==NULL)
                return;
-       chandev_conf_read=TRUE;
+       atomic_set(&chandev_conf_read,TRUE);
        set_fs(KERNEL_DS);
        if(stat(CHANDEV_FILE,&statbuf)==0)
        {
@@ -2198,7 +2844,9 @@ static void chandev_read_conf(void)
 
 static void chandev_read_conf_if_necessary(void)
 {
-       if(!chandev_conf_read)
+       if(in_interrupt()||current->fs->root==NULL)
+               return;
+       if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_conf_read))
                chandev_read_conf();
 }
 
@@ -2218,7 +2866,7 @@ void sprintf_msck(char *buff,int auto_msck_recovery)
        chandev_msck_status idx;
        int first_time=TRUE;
        buff[0]=0;
-       for(idx=first_msck;idx<last_msck;idx++)
+       for(idx=chandev_status_first_msck;idx<chandev_status_last_msck;idx++)
        {
                if((1<<(idx-1))&auto_msck_recovery)
                {
@@ -2243,34 +2891,39 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
        chandev_msck_range *curr_msck_range;
        s390_dev_info_t   curr_devinfo;
        int pass,chandevs_detected,curr_irq,loopcnt;
-       chandev_irqinfo *read_irqinfo,*write_irqinfo;
-       char buff[40],buff2[80];    
+       chandev_irqinfo *read_irqinfo,*write_irqinfo,*data_irqinfo;
+       char buff[3][80];    
 
        chandev_lock();
-       chandev_read_conf_if_necessary();
        chandev_printf(chan_exit,"\n%s\n"
                       "*'s for cu/dev type/models indicate don't cares\n",chandev_keydescript);
+       chandev_printf(chan_exit,"\ncautious_auto_detect: %s\n",chandev_cautious_auto_detect ? "on":"off");
+       chandev_printf(chan_exit,"\nchandev_persistent = 0x%02x\n",chandev_persistent);
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-       chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",use_devno_names ? "on":"off");
+       chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",chandev_use_devno_names ? "on":"off");
 #endif
+       
        if(chandev_models_head)
        {
                chandev_printf(chan_exit,"Channels enabled for detection\n");      
-               chandev_printf(chan_exit,"  chan     cu      cu     dev   dev    max     auto recovery\n");
-               chandev_printf(chan_exit,"  type    type    model  type  model  port_no.      type    \n");
-               chandev_printf(chan_exit,"============================================================\n");
+               chandev_printf(chan_exit,"  chan     cu      cu     dev   dev    max     checksum  use hw  auto recovery\n");
+               chandev_printf(chan_exit,"  type    type    model  type  model  port_no. received   stats      type\n");
+               chandev_printf(chan_exit,"==============================================================================\n");
                for_each(curr_model,chandev_models_head)
                {
                        
                        
-                       chandev_sprint_devinfo(buff,curr_model->cu_type,
+                       chandev_sprint_devinfo(buff[0],curr_model->cu_type,
                                               curr_model->cu_model,
                                               curr_model->dev_type,
                                               curr_model->dev_model);
-                       sprintf_msck(buff2,curr_model->auto_msck_recovery);
-                       chandev_printf(chan_exit,"  0x%02x  %s%3d %s\n",
-                                      curr_model->chan_type,buff,
-                                      (int)curr_model->max_port_no,buff2);         
+                       sprintf_msck(buff[1],curr_model->auto_msck_recovery);
+                       chandev_printf(chan_exit,"  0x%02x  %s%3d %s     %s     %s\n",
+                                      curr_model->chan_type,buff[0],
+                                      (int)curr_model->max_port_no,
+                                      curr_model->default_checksum_received_ip_pkts ? "yes":"no ",
+                                      curr_model->default_use_hw_stats ? "yes":"no ",
+                                      buff[1]);         
                }
        }
         
@@ -2294,65 +2947,78 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
                chandev_printf(chan_exit,"===========================================\n");
                for_each(curr_msck_range,chandev_msck_range_head)
                {
-                       sprintf_msck(buff2,curr_msck_range->auto_msck_recovery);
+                       sprintf_msck(buff[0],curr_msck_range->auto_msck_recovery);
                        chandev_printf(chan_exit,"  0x%04x     0x%04x %s\n",
                                       curr_msck_range->lo_devno,
-                                      curr_msck_range->hi_devno,buff2)
+                                      curr_msck_range->hi_devno,buff[0])
                }
        }
        if(chandev_force_head)
        {
                chandev_printf(chan_exit,"\nForced devices\n");
-               chandev_printf(chan_exit,"  chan defif read   write     port         ip    hw\n");
-               chandev_printf(chan_exit,"  type  num  devno  devno  protocol no.  chksum stats\n");
-               chandev_printf(chan_exit,"======================================================\n");
+               chandev_printf(chan_exit,"  chan defif read   write  data   memory      port         ip    hw   host       adapter   api\n");
+               chandev_printf(chan_exit,"  type  num  devno  devno  devno  usage(k) protocol no.  chksum stats name        name     name\n");
+               chandev_printf(chan_exit,"===============================================================================================\n");
                for_each(curr_force,chandev_force_head)
                {
-                       chandev_printf(chan_exit,"  0x%02x  %3d  0x%04x 0x%04x       %3d       %1d    %1d\n",
-                                      curr_force->chan_type,curr_force->devif_num,
-                                      curr_force->read_devno,curr_force->write_devno,
-                                      curr_force->port_protocol_no,curr_force->checksum_received_ip_pkts,
-                                      curr_force->use_hw_stats);
+                       if(curr_force->memory_usage_in_k==0)
+                               strcpy(buff[0],"default");
+                       else
+                               sprintf(buff[0],"%6d",curr_force->memory_usage_in_k);
+                       chandev_printf(chan_exit,"  0x%02x  %3d  0x%04x 0x%04x 0x%04x %7s       %3d       %1d    %1d%s",
+                                      (int)curr_force->chan_type,(int)curr_force->devif_num,
+                                      (int)curr_force->read_lo_devno,(int)curr_force->write_hi_devno,
+                                      (int)curr_force->data_devno,buff[0],
+                                      (int)curr_force->port_protocol_no,(int)curr_force->checksum_received_ip_pkts,
+                                      (int)curr_force->use_hw_stats,curr_force->chan_type==chandev_type_claw ? "":"\n");
+                       if(curr_force->chan_type==chandev_type_claw)
+                       {
+                               chandev_printf(chan_exit," %9s %9s %9s\n",
+                                              curr_force->claw.host_name,
+                                              curr_force->claw.adapter_name,
+                                              curr_force->claw.api_type);
+                       }
+
                }
        }
        if(chandev_probelist_head)
        {
 #if CONFIG_ARCH_S390X
                chandev_printf(chan_exit,"\nRegistered probe functions\n"
-                                        "probefunc            shutdownfunc         reoperfunc         chan  devices\n"
-                                         "                                                             type   found\n"
-                                        "==========================================================================\n");
+                                        "probefunc            shutdownfunc        msck_notfunc        chan  devices devices\n"
+                                         "                                                             type   found  active\n"
+                                        "==================================================================================\n");
 #else
                chandev_printf(chan_exit,"\nRegistered probe functions\n"
-                                        "probefunc   shutdownfunc  reoperfunc chan  devices\n"
-                                         "                                     type   found\n"
-                                        "==================================================\n");
+                                        "probefunc   shutdownfunc   msck_notfunc   chan  devices devices\n"
+                                         "                                          type   found  active\n"
+                                        "===============================================================\n");
 #endif
                for_each(curr_probe,chandev_probelist_head)
                {
-                       chandev_printf(chan_exit,"0x%p   0x%p   0x%p   0x%02x      %d\n",
+                       int devices_active=0;
+                       for_each(curr_device,chandev_activelist_head)
+                       {
+                               if(curr_device->probefunc==curr_probe->probefunc)
+                                       devices_active++;
+                       }
+                       chandev_printf(chan_exit,"0x%p   0x%p   0x%p       0x%02x     %d      %d\n",
                                       curr_probe->probefunc,
                                       curr_probe->shutdownfunc,
-                                      curr_probe->reoperfunc,
+                                      curr_probe->msck_notfunc,
                                       curr_probe->chan_type,
-                                      curr_probe->devices_found);
+                                      curr_probe->devices_found,
+                                      devices_active);
                }
        }
        if(chandev_activelist_head)
        {
-#if CONFIG_ARCH_S390X
+               unsigned long long total_memory_usage_in_k=0;
                chandev_printf(chan_exit,
                               "\nInitialised Devices\n"
-                              " read   write  read   write chan port  dev             dev        read msck   write msck\n"
-                              " irq    irq    devno  devno type no.   ptr             name        status      status   \n"
-                              "========================================================================================\n");
-#else
-               chandev_printf(chan_exit,
-                              "\nInitialised Devices\n"
-                              " read   write  read   write chan port  dev     dev        read msck   write msck\n"
-                              " irq    irq    devno  devno type no.   ptr     name        status      status   \n"
-                              "================================================================================\n");
-#endif
+                              " read   write  data  read   write  data  chan port  dev     dev         memory   read msck    write msck    data msck\n"
+                              " irq     irq    irq  devno  devno  devno type no.   ptr     name        usage(k)  status       status        status\n"
+                              "=====================================================================================================================\n");
                /* We print this list backwards for cosmetic reasons */
                for(curr_device=chandev_activelist_head;
                    curr_device->next!=NULL;curr_device=curr_device->next);
@@ -2360,19 +3026,44 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
                {
                        read_irqinfo=curr_device->read_irqinfo;
                        write_irqinfo=curr_device->write_irqinfo;
+                       data_irqinfo=curr_device->data_irqinfo;
+                       if(data_irqinfo)
+                       {
+                               sprintf(buff[0],"0x%04x",data_irqinfo->sch.irq);
+                               sprintf(buff[1],"0x%04x",(int)data_irqinfo->sch.devno);
+                       }
+                       else
+                       {
+                               strcpy(buff[0],"  n/a ");
+                               strcpy(buff[1],"  n/a ");
+                       }
+                       if(curr_device->memory_usage_in_k<0)
+                       {
+                               sprintf(buff[2],"%d",(int)-curr_device->memory_usage_in_k);
+                               total_memory_usage_in_k-=curr_device->memory_usage_in_k;
+                       }
+                       else
+                               strcpy(buff[2],"  n/a ");
                        chandev_printf(chan_exit,
-                                      "0x%04x 0x%04x 0x%04x 0x%04x 0x%02x %2d 0x%p %-10s   %-12s %-12s\n",
-                                      curr_device->read_irqinfo->irq,curr_device->write_irqinfo->irq,
-                                      (int)read_irqinfo->devno,
-                                      (int)write_irqinfo->devno,
+                                      "0x%04x 0x%04x %s 0x%04x 0x%04x %s 0x%02x %2d 0x%p %-10s  %6s   %-12s %-12s %-12s\n",
+                                      read_irqinfo->sch.irq,
+                                      write_irqinfo->sch.irq,
+                                      buff[0],
+                                      (int)read_irqinfo->sch.devno,
+                                      (int)write_irqinfo->sch.devno,
+                                      buff[1],
                                       curr_device->chan_type,(int)curr_device->port_no,
                                       curr_device->dev_ptr,curr_device->devname,
+                                      buff[2],
                                       msck_status_strs[read_irqinfo->msck_status],
-                                      msck_status_strs[write_irqinfo->msck_status]);
+                                      msck_status_strs[write_irqinfo->msck_status],
+                                      data_irqinfo ? msck_status_strs[data_irqinfo->msck_status] :
+                                      "not applicable");
                        get_prev((list *)chandev_activelist_head,
                                 (list *)curr_device,
                                 (list **)&curr_device);
                }
+               chandev_printf(chan_exit,"\nTotal device memory usage %Luk.\n",total_memory_usage_in_k);
        }
        chandevs_detected=FALSE;
        for(pass=FALSE;pass<=TRUE;pass++)
@@ -2380,9 +3071,9 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
                if(pass&&chandevs_detected)
                {
                        chandev_printf(chan_exit,"\nchannels detected\n");
-                       chandev_printf(chan_exit,"              chan    cu    cu   dev    dev   in   chandev\n");
-                       chandev_printf(chan_exit,"  irq  devno  type   type  model type  model  use    reg.\n");
-                       chandev_printf(chan_exit,"==========================================================\n");
+                       chandev_printf(chan_exit,"              chan    cu    cu   dev    dev                          in chandev\n");
+                       chandev_printf(chan_exit,"  irq  devno  type   type  model type  model pim      chpids         use  reg.\n");
+                       chandev_printf(chan_exit,"===============================================================================\n");
                }
                for(curr_irq=get_irq_first(),loopcnt=0;curr_irq>=0; curr_irq=get_irq_next(curr_irq),loopcnt++)
                {
@@ -2391,20 +3082,26 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
                                printk(KERN_ERR"chandev_read_proc detected infinite loop bug in get_irq_next\n");
                                goto chan_error;
                        }
-                       if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+                       if(chandev_is_chandev(curr_irq,&curr_devinfo,&curr_force,&curr_model))
                        {
+                               schib_t *curr_schib;
+                               curr_schib=s390_get_schib(curr_irq);
                                chandevs_detected=TRUE;
                                if(pass)
                                {
-                                       chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x  0x%04x 0x%02x  0x%04x 0x%02x  %-5s %-5s\n",
+                                       chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x  0x%04x 0x%02x  0x%04x 0x%02x 0x%02x 0x%016Lx  %-5s %-5s\n",
                                                       curr_irq,curr_devinfo.devno,
-                                                      curr_model->chan_type,
+                                                      ( curr_force ? curr_force->chan_type : 
+                                                      ( curr_model ? curr_model->chan_type : 
+                                                        chandev_type_none )),
                                                       (int)curr_devinfo.sid_data.cu_type,
                                                       (int)curr_devinfo.sid_data.cu_model,
                                                       (int)curr_devinfo.sid_data.dev_type,
                                                       (int)curr_devinfo.sid_data.dev_model,
-                                                      (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no",
-                                                      (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no"));
+                                                      (int)(curr_schib ? curr_schib->pmcw.pim : 0),
+                                                      *(long long *)(curr_schib ? &curr_schib->pmcw.chpid[0] : 0),
+                                                      (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no ",
+                                                      (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no "));
                                                       
                                                       
                                }
@@ -2418,14 +3115,14 @@ static int chandev_read_proc(char *page, char **start, off_t offset,
                chandev_parms      *curr_parms;
 
                chandev_printf(chan_exit,"\n driver specific parameters\n");
-               chandev_printf(chan_exit,"chan    driver\n");
-               chandev_printf(chan_exit,"type  parameters\n");
+               chandev_printf(chan_exit,"chan    lo    hi      driver\n");
+               chandev_printf(chan_exit,"type  devno  devno  parameters\n");
                chandev_printf(chan_exit,"=============================================================================\n");
                for_each(curr_parms,chandev_parms_head)
                {
-                       chandev_printf(chan_exit,"0x%02x    %s\n",
-                                      curr_parms->chan_type,
-                                      curr_parms->parmstr);
+                       chandev_printf(chan_exit,"0x%02x 0x%04x 0x%04x  %s\n",
+                                      curr_parms->chan_type,(int)curr_parms->lo_devno,
+                                      (int)curr_parms->hi_devno,curr_parms->parmstr);
                }
        }
  chan_error:
@@ -2448,7 +3145,6 @@ static int chandev_write_proc(struct file *file, const char *buffer,
        int         rc;
        char        *buff;
        
-       chandev_read_conf_if_necessary();
        buff=vmalloc(count+1);
        if(buff)
        {
@@ -2485,29 +3181,26 @@ static
 #endif
 int __init chandev_init(void)
 {
-       if(!chandev_initialised)
-       {
-               chandev_parse_args();
-               chandev_init_default_models();
+       atomic_set(&chandev_initialised,TRUE);
+       chandev_parse_args();
+       chandev_init_default_models();
 #if CONFIG_PROC_FS
-               chandev_create_proc();
+       chandev_create_proc();
 #endif
-               chandev_msck_task_tq.routine=
+       chandev_msck_task_tq.routine=
                chandev_msck_task;
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-               INIT_LIST_HEAD(&chandev_msck_task_tq.list);
-               chandev_msck_task_tq.sync=0;
+       INIT_LIST_HEAD(&chandev_msck_task_tq.list);
+       chandev_msck_task_tq.sync=0;
 #endif
-               chandev_msck_task_tq.data=NULL;
-               chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
-               atomic_set(&chandev_msck_thread_lock,1);
-               chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
-               chandev_lock_cnt=0;
-               spin_lock_init(&chandev_spinlock);
-               spin_lock_init(&chandev_not_oper_spinlock);
-               chandev_initialised=TRUE;
-               atomic_set(&chandev_new_msck,FALSE);
-       }
+       chandev_msck_task_tq.data=NULL;
+       chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
+       atomic_set(&chandev_msck_thread_lock,1);
+       chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
+       chandev_lock_cnt=0;
+       spin_lock_init(&chandev_spinlock);
+       spin_lock_init(&chandev_not_oper_spinlock);
+       atomic_set(&chandev_new_msck,FALSE);
        return(0);
 }
 #if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
@@ -2516,7 +3209,7 @@ __initcall(chandev_init);
 
 int chandev_register_and_probe(chandev_probefunc probefunc,
                               chandev_shutdownfunc shutdownfunc,
-                              chandev_reoperfunc reoperfunc,
+                              chandev_msck_notification_func msck_notfunc,
                               chandev_type chan_type)
 {
        chandev_probelist *new_probe;
@@ -2524,14 +3217,13 @@ int chandev_register_and_probe(chandev_probefunc probefunc,
        /* are initialised. */
 
        chandev_interrupt_check();
-       if(!chandev_initialised)
+       if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_initialised))
                chandev_init();
-       chandev_read_conf_if_necessary();
        if((new_probe=chandev_alloc(sizeof(chandev_probelist))))
        {
                new_probe->probefunc=probefunc;
                new_probe->shutdownfunc=shutdownfunc;
-               new_probe->reoperfunc=reoperfunc;
+               new_probe->msck_notfunc=msck_notfunc;
                new_probe->chan_type=chan_type;
                new_probe->devices_found=0;
                chandev_add_to_list((list **)&chandev_probelist_head,new_probe);
@@ -2543,7 +3235,7 @@ int chandev_register_and_probe(chandev_probefunc probefunc,
 void chandev_unregister(chandev_probefunc probefunc,int call_shutdown)
 {
        chandev_probelist *curr_probe=NULL;
-       chandev_activelist *curr_device;
+       chandev_activelist *curr_device,*next_device;
        
        chandev_interrupt_check();
        chandev_lock();
@@ -2551,27 +3243,33 @@ void chandev_unregister(chandev_probefunc probefunc,int call_shutdown)
        {
                if(curr_probe->probefunc==probefunc)
                {
-                       for_each(curr_device,chandev_activelist_head)
-                               if(curr_device->probefunc==probefunc)
-                               {
-                                       if(call_shutdown)
-                                       {
-                                               chandev_shutdown(curr_device);
-                                       }
-                               }
+                       for_each_allow_delete(curr_device,next_device,chandev_activelist_head)
+                               if(curr_device->probefunc==probefunc&&call_shutdown)
+                                       chandev_shutdown(curr_device);
                        chandev_free_listmember((list **)&chandev_probelist_head,
                                                (list *)curr_probe);
+                       break;
                }
        }
        chandev_unlock();
 }
 
+
+int chandev_persist(chandev_type chan_type)
+{
+       return((chandev_persistent&chan_type) ? TRUE:FALSE);
+}
+
 EXPORT_SYMBOL(chandev_register_and_probe);
 EXPORT_SYMBOL(chandev_request_irq);
-EXPORT_SYMBOL(chandev_free_irq);
 EXPORT_SYMBOL(chandev_unregister);
 EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_build_device_name);
 EXPORT_SYMBOL(chandev_initnetdevice);
-
-
+EXPORT_SYMBOL(chandev_init_netdev);
+EXPORT_SYMBOL(chandev_use_devno_names);
+EXPORT_SYMBOL(chandev_free_irq);
+EXPORT_SYMBOL(chandev_add_model);
+EXPORT_SYMBOL(chandev_del_model);
+EXPORT_SYMBOL(chandev_persist);
 
index c33e4f7a41cd8b3e7a80ebf8f87913715bdf4c23..5300da79f37183f049e4a4b4d5b010445b7e12a1 100644 (file)
@@ -5,11 +5,11 @@
 O_TARGET := s390-net.o
 
 list-multi := ctc.o
-export-objs := iucv.o
+export-objs := iucv.o fsm.o
 
-ctc-objs := ctcmain.o ctctty.o fsm.o
+ctc-objs := ctcmain.o ctctty.o
 
-obj-y += iucv.o
+obj-y += iucv.o fsm.o
 obj-$(CONFIG_CTC) += ctc.o
 obj-$(CONFIG_IUCV) += netiucv.o
 
index 2ca0aac0bd8605e47312b27487ace37b9ee7f7ae..f14c4a486cbeb59ee03e38e3a9d5675ddf936c64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctcmain.c,v 1.46 2001/07/05 17:36:41 felfert Exp $
  *
  * CTC / ESCON network driver
  *
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Log: ctcmain.c,v $
- * Revision 1.17  2001/01/23 14:23:51  felfert
- * Added ctc based tty.
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.46 $
  *
- * Revision 1.16  2001/01/18 16:10:53  felfert
- * Added fixes by acme@conectiva.com.br.
- *
- * Revision 1.15  2001/01/12 15:40:11  felfert
- * Fixed ITPM# PL030052IME (Unitchecks when using real escon).
- *
- * Revision 1.14  2001/01/11 17:43:52  felfert
- * Fixed ITPM# PL030051IME (Initialization of escon).
- *
- * Revision 1.13  2001/01/11 16:40:26  smolinsk
- * resolved name space conflict with LVM and renamed
- *  dev_info_t to s390_dev_info_t
- * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c
- *
- * Revision 1.12  2000/12/27 09:40:45  tonn
- * upgrade to test12
- *
- * Revision 1.11  2000/12/15 19:34:54  bird
- * struct ctc_priv_t: set type of tbusy to "unsigned long"
- *
- * Revision 1.10  2000/12/14 16:49:50  bird
- * ch_action_txretry(): added missing clear_normalized_cda()
- *
- * Revision 1.9  2000/12/14 13:56:53  felfert
- * Eliminated a compiler warning when building in old kernel.
- *
- * Revision 1.8  2000/12/14 13:11:59  felfert
- * static ccws now separately allocated.
- * remove locally allocated ccw for setup.
- *
- * Revision 1.7  2000/12/14 03:32:15  bird
- * Fixes for >2GB memory.   Switch on checksumming.
- *
- * Revision 1.6  2000/12/07 20:08:30  felfert
- * Modified RX channel initialization to be compatible with VM TCP
- *
- * Revision 1.5  2000/12/07 18:15:05  felfert
- * Added workaround against VM TCP bug.
- * Fixed an error message.
- *
- * Revision 1.4  2000/12/06 16:55:57  felfert
- * Removed check for double call of ctc_setup().
- * ctc_setup can now handle mutiple calls.
- *
- * Revision 1.3  2000/12/06 16:48:44  felfert
- * New initialization.
- * Removed old cvs log from 2.2 kernel.
- *
- * Revision 1.2  2000/12/06 14:13:46  felfert
- * New unified configuration.
- *
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
  */
 \f
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
+#ifdef CONFIG_CHANDEV
+#define CTC_CHANDEV
+#endif
 
-#define CTC_USE_IDALS 1
-#if CTC_USE_IDALS
+#ifdef CTC_CHANDEV
+#include <asm/chandev.h>
+#define REQUEST_IRQ chandev_request_irq
+#define FREE_IRQ chandev_free_irq
+#else
+#define REQUEST_IRQ request_irq
+#define FREE_IRQ free_irq
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020213
 #  include <asm/idals.h>
 #else
 #  define set_normalized_cda(ccw, addr) ((ccw)->cda = (addr))
 #  define clear_normalized_cda(ccw)
 #endif
+#if LINUX_VERSION_CODE < 0x020400
+#  define s390_dev_info_t dev_info_t
+#  define dev_kfree_skb_irq(a) dev_kfree_skb(a)
+#endif
 
 #include <asm/irq.h>
 
 #ifdef MODULE
 MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
 MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+#ifndef CTC_CHANDEV
 MODULE_PARM(ctc, "s");
 MODULE_PARM_DESC(ctc,
 "One or more definitions in the same format like the kernel param for ctc.\n"
 "E.g.: ctc0:0x700:0x701:0:ctc1:0x702:0x703:0\n");
 
 char *ctc = NULL;
+#endif
 #else
 /**
  * Number of devices in monolithic (not module) driver version.
@@ -162,7 +124,8 @@ char *ctc = NULL;
 #define CTC_PROTO_S390          0
 #define CTC_PROTO_LINUX         1
 #define CTC_PROTO_LINUX_TTY     2
-#define CTC_PROTO_MAX           2
+#define CTC_PROTO_OS390         3
+#define CTC_PROTO_MAX           3
 
 #define CTC_BUFSIZE_LIMIT       65535
 #define CTC_BUFSIZE_DEFAULT     32768
@@ -206,13 +169,16 @@ enum channel_types {
 
 typedef enum channel_types channel_type_t;
 
+#ifndef CTC_CHANDEV
 static int ctc_no_auto = 0;
+#endif
 
 /**
  * If running on 64 bit, this must be changed. XXX Why? (bird)
  */
 typedef unsigned long intparm_t;
 
+#ifndef CTC_CHANDEV
 /**
  * Definition of a per device parameter block
  */
@@ -226,6 +192,7 @@ typedef struct param_t {
 } param;
 
 static param *params = NULL;
+#endif
 \f
 typedef struct {
        unsigned long maxmulti;
@@ -246,7 +213,6 @@ typedef struct channel_t {
         * Pointer to next channel in list.
         */
        struct channel_t    *next;
-
        __u16               devno;
        int                 irq;
 
@@ -278,19 +244,14 @@ typedef struct channel_t {
        struct tq_struct    tq;
 
        /**
-        * RX/TX buffer for init sequence.
-        */
-       __u16               dummy_buf;
-
-       /**
-        * RX buffer size
+        * RX/TX buffer size
         */
        int                 max_bufsize;
 
        /**
-        * Receive buffer.
+        * Transmit/Receive buffer.
         */
-       struct sk_buff      *rx_skb;
+       struct sk_buff      *trans_skb;
 
        /**
         * Universal I/O queue.
@@ -312,16 +273,6 @@ typedef struct channel_t {
         */
        spinlock_t          collect_lock;
 
-       /**
-        * Pointer to dynamic allocated CCWs for TX
-        */
-       ccw1_t              *dccw;
-
-       /**
-        * Number of dynamic allocated CCWs needed for clearing IDALs.
-        */
-       int                 dccw_count;
-
        /**
         * Timer for detecting unresposive
         * I/O operations.
@@ -347,9 +298,10 @@ typedef struct channel_t {
        ctc_profile         prof;
 } channel;
 
-#define CHANNEL_FLAGS_READ   0
-#define CHANNEL_FLAGS_WRITE  1
-#define CHANNEL_FLAGS_INUSE  2
+#define CHANNEL_FLAGS_READ            0
+#define CHANNEL_FLAGS_WRITE           1
+#define CHANNEL_FLAGS_INUSE           2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
 #define CHANNEL_FLAGS_RWMASK 1
 #define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
 
@@ -358,6 +310,10 @@ typedef struct channel_t {
  */
 static channel *channels = NULL;
 
+#ifdef CTC_CHANDEV
+static int activated;
+#endif
+
 typedef struct ctc_priv_t {
        struct net_device_stats stats;
 #if LINUX_VERSION_CODE >= 0x02032D
@@ -375,6 +331,7 @@ typedef struct ctc_priv_t {
        struct proc_dir_entry   *proc_dentry;
        struct proc_dir_entry   *proc_stat_entry;
        struct proc_dir_entry   *proc_ctrl_entry;
+       int                     proc_registered;
 } ctc_priv;
 
 /**
@@ -425,7 +382,7 @@ static __inline__ int ctc_test_and_set_busy(net_device *dev)
  */
 static void print_banner(void) {
        static int printed = 0;
-       char vbuf[] = "$Revision: 1.17 $";
+       char vbuf[] = "$Revision: 1.46 $";
        char *version = vbuf;
 
        if (printed)
@@ -440,6 +397,8 @@ static void print_banner(void) {
        printed = 1;
 }
 \f
+
+#ifndef CTC_CHANDEV
 /**
  * Return type of a detected device.
  */
@@ -502,6 +461,8 @@ static channel_type_t channel_type (senseid_t *id) {
        }
        return type;
 }
+#endif
+
 \f
 /**
  * States of the interface statemachine.
@@ -592,6 +553,12 @@ enum ch_events {
         */
        CH_EVENT_SC_UNKNOWN,
 
+       /**
+        * Events, representing machine checks
+        */
+       CH_EVENT_MC_FAIL,
+       CH_EVENT_MC_GOOD,
+
        /**
         * Event, representing normal IRQ
         */
@@ -637,6 +604,9 @@ static const char *ch_event_names[] = {
 
        "SubChannel check Unknown",
 
+       "Machine check failure",
+       "Machine check operational",
+
        "IRQ normal",
        "IRQ final",
 
@@ -673,6 +643,7 @@ enum ch_states {
        CH_STATE_TXERR,
        CH_STATE_TERM,
        CH_STATE_DTERM,
+       CH_STATE_NOTOP,
 
        /**
         * MUST be always the last element!!
@@ -696,9 +667,11 @@ static const char *ch_state_names[] = {
        "TX error",
        "Terminating",
        "Restarting",
+       "Not operational",
 };
 \f
 
+#ifdef DEBUG
 /**
  * Dump header and first 16 bytes of an sk_buff for debugging purposes.
  *
@@ -729,114 +702,120 @@ static void ctc_dump_skb(struct sk_buff *skb, int offset)
                bl = 16;
        printk(KERN_DEBUG "data: ");
        for (i = 0; i < bl; i++)
-               printk("%02x ", *p++);
+               printk("%02x%s", *p++, (i % 16) ? " " : "\n<7>");
        printk("\n");
 }
+#endif
 
 /**
- * Bottom half routine.
+ * Unpack a just received skb and hand it over to
+ * upper layers.
  *
- * @param ch The channel to work on.
+ * @param ch The channel where this skb has been received.
+ * @param pskb The received skb.
  */
-static void ctc_bh(channel *ch)
+static __inline__ void ctc_unpack_skb(channel *ch, struct sk_buff *pskb)
 {
        net_device     *dev = ch->netdev;
        ctc_priv       *privptr = (ctc_priv *)dev->priv;
-       struct sk_buff *skb;
 
-       while ((skb = skb_dequeue(&ch->io_queue))) {
-               __u16 len = *((__u16*)skb->data);
-
-               skb_put(skb, 2 + LL_HEADER_LENGTH);
-               skb_pull(skb, 2);
-               skb->dev = dev;
-               skb->ip_summed = CHECKSUM_NONE;
-               while (len > 0) {
-                       ll_header *header = (ll_header *)skb->data;
-                       skb_pull(skb, LL_HEADER_LENGTH);
-                       if ((ch->protocol == CTC_PROTO_S390) &&
-                           (header->type != ETH_P_IP)) {
-                               /**
-                                * Check packet type only if we stick strictly
-                                * to S/390's protocol of OS390. This only
-                                * supports IP. Otherwise allow any packet
-                                * type.
-                                */
-                               printk(KERN_WARNING
-                                      "%s Illegal packet type 0x%04x "
-                                      "received, dropping\n",
-                                      dev->name, header->type);
-                               ctc_dump_skb(skb, -6);
-                               privptr->stats.rx_dropped++;
-                               privptr->stats.rx_frame_errors++;
-                               dev_kfree_skb(skb);
-                               goto again;
-                       }
-                       skb->protocol = ntohs(header->type);
-                       header->length -= LL_HEADER_LENGTH;
-                       if ((header->length > dev->mtu) ||
-                           (header->length == 0)) {
-                               printk(KERN_WARNING
-                                      "%s Illegal packet size %d "
-                                      "received (MTU=%d), "
-                                      "dropping\n", dev->name, header->length,
-                                      dev->mtu);
-                               ctc_dump_skb(skb, -6);
-                               privptr->stats.rx_dropped++;
-                               privptr->stats.rx_length_errors++;
-                               dev_kfree_skb(skb);
-                               goto again;
-                       }
-                       skb_put(skb, header->length);
-                       skb->mac.raw = skb->data;
+       __u16 len = *((__u16*)pskb->data);
+       skb_put(pskb, 2 + LL_HEADER_LENGTH);
+       skb_pull(pskb, 2);
+       pskb->dev = dev;
+       pskb->ip_summed = CHECKSUM_UNNECESSARY;
+       while (len > 0) {
+               struct sk_buff *skb;
+               ll_header *header = (ll_header *)pskb->data;
+
+               skb_pull(pskb, LL_HEADER_LENGTH);
+               if ((ch->protocol == CTC_PROTO_S390) &&
+                   (header->type != ETH_P_IP)) {
                        /**
-                        * Set truesize here to make the kernel's
-                        * socket layer happy. If this is not done,
-                        * the RX-routines of the socket code are dropping
-                        * most of the received packets, because they "think"
-                        * there isn't enough buffer space for the incoming
-                        * data.
+                        * Check packet type only if we stick strictly
+                        * to S/390's protocol of OS390. This only
+                        * supports IP. Otherwise allow any packet
+                        * type.
                         */
-                       skb->truesize = skb->len;
-                       len -= (LL_HEADER_LENGTH + header->length);
-                       if (len > 0) {
-                               /**
-                                * Clone the skb only if there are still
-                                * sub-packets.
-                                */
-                               struct sk_buff *skb2 =
-                                       skb_clone(skb, GFP_ATOMIC);
-                               if (!skb2) {
-                                       printk(KERN_WARNING "%s Out of memory"
-                                              " in ctc_bh\n",
-                                              dev->name);
-                                       privptr->stats.rx_dropped++;
-                                       dev_kfree_skb(skb);
-                                       goto again;
-                               }
-                               if (ch->protocol == CTC_PROTO_LINUX_TTY)
-                                       ctc_tty_netif_rx(skb2);
-                               else
-                                       netif_rx(skb2);
-                               privptr->stats.rx_packets++;
-                               privptr->stats.rx_bytes += skb2->len;
-                               /**
-                                * Advance pointers to next sub-packet.
-                                */
-                               skb_pull(skb, header->length);
-                               skb_put(skb, LL_HEADER_LENGTH);
-                       } else {
-                               if (ch->protocol == CTC_PROTO_LINUX_TTY)
-                                       ctc_tty_netif_rx(skb);
-                               else
-                                       netif_rx(skb);
-                               privptr->stats.rx_packets++;
-                               privptr->stats.rx_bytes += skb->len;
-                       }
+                       printk(KERN_WARNING
+                              "%s Illegal packet type 0x%04x "
+                              "received, dropping\n",
+                              dev->name, header->type);
+#ifdef DEBUG
+                       ctc_dump_skb(pskb, -6);
+#endif
+                       privptr->stats.rx_dropped++;
+                       privptr->stats.rx_frame_errors++;
+                       return;
+               }
+               pskb->protocol = ntohs(header->type);
+               header->length -= LL_HEADER_LENGTH;
+               if ((header->length == 0) ||
+                   (header->length > skb_tailroom(pskb))) {
+                       printk(KERN_WARNING
+                              "%s Illegal packet size %d "
+                              "received (MTU=%d), "
+                              "dropping\n", dev->name, header->length,
+                              dev->mtu);
+#ifdef DEBUG
+                       ctc_dump_skb(pskb, -6);
+#endif
+                       privptr->stats.rx_dropped++;
+                       privptr->stats.rx_length_errors++;
+                       return;
+               }
+               if (header->length > skb_tailroom(pskb)) {
+                       printk(KERN_WARNING
+                              "%s Illegal packet size %d "
+                              "(beyond the end of received data), "
+                              "dropping\n", dev->name, header->length);
+#ifdef DEBUG
+                       ctc_dump_skb(pskb, -6);
+#endif
+                       privptr->stats.rx_dropped++;
+                       privptr->stats.rx_length_errors++;
+                       return;
+               }
+               skb_put(pskb, header->length);
+               pskb->mac.raw = pskb->data;
+               len -= (LL_HEADER_LENGTH + header->length);
+               skb = dev_alloc_skb(pskb->len);
+               if (!skb) {
+                       printk(KERN_WARNING
+                              "%s Out of memory in ctc_unpack_skb\n",
+                              dev->name);
+                       privptr->stats.rx_dropped++;
+                       return;
+               }
+               memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
+               skb->mac.raw = skb->data;
+               skb->dev = pskb->dev;
+               skb->protocol = pskb->protocol;
+               pskb->ip_summed = CHECKSUM_UNNECESSARY;
+               if (ch->protocol == CTC_PROTO_LINUX_TTY)
+                       ctc_tty_netif_rx(skb);
+               else
+                       netif_rx(skb);
+               privptr->stats.rx_packets++;
+               privptr->stats.rx_bytes += skb->len;
+               if (len > 0) {
+                       skb_pull(pskb, header->length);
+                       skb_put(pskb, LL_HEADER_LENGTH);
                }
-       again:
        }
-       return;
+}
+
+/**
+ * Bottom half routine.
+ *
+ * @param ch The channel to work on.
+ */
+static void ctc_bh(channel *ch)
+{
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&ch->io_queue)))
+               ctc_unpack_skb(ch, skb);
 }
 
 /**
@@ -883,9 +862,10 @@ static void inline ccw_check_return_code (channel *ch, int return_code)
 static void inline ccw_unit_check (channel *ch, unsigned char sense) {
        if (sense & SNS0_INTERVENTION_REQ) {
                if (sense & 0x01)  {
-                       printk(KERN_DEBUG
-                              "ch-%04x: Interface disc. or Sel. reset "
-                              "(remote)\n", ch->devno);
+                       if (ch->protocol != CTC_PROTO_LINUX_TTY)
+                               printk(KERN_DEBUG
+                                      "ch-%04x: Interface disc. or Sel. reset "
+                                      "(remote)\n", ch->devno);
                        fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
                } else {
                        printk(KERN_DEBUG "ch-%04x: System reset (remote)\n",
@@ -917,7 +897,8 @@ static void inline ccw_unit_check (channel *ch, unsigned char sense) {
                        fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch);
                }
        } else if (sense & SNS0_CMD_REJECT) {
-                       printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno);
+                       printk(KERN_WARNING "ch-%04x: Command reject\n",
+                              ch->devno);
        } else if (sense == 0) {
                printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno);
                fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch);
@@ -935,8 +916,42 @@ static void ctc_purge_skb_queue(struct sk_buff_head *q)
 
        while ((skb = skb_dequeue(q))) {
                atomic_dec(&skb->users);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_irq(skb);
+       }
+}
+
+static __inline__ int ctc_checkalloc_buffer(channel *ch, int warn) {
+       if ((ch->trans_skb == NULL) ||
+           (ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED)) {
+               if (ch->trans_skb != NULL)
+                       dev_kfree_skb(ch->trans_skb);
+               ch->trans_skb = dev_alloc_skb(ch->max_bufsize);
+               if (ch->trans_skb == NULL) {
+                       if (warn)
+                               printk(KERN_WARNING
+                                      "ch-%04x: Couldn't alloc %s trans_skb\n",
+                                      ch->devno,
+                                      (CHANNEL_DIRECTION(ch->flags) == READ) ?
+                                      "RX" : "TX");
+                       return -ENOMEM;
+               }
+               set_normalized_cda(&ch->ccw[1],
+                                  virt_to_phys(ch->trans_skb->data));
+               if (ch->ccw[1].cda == 0) {
+                       dev_kfree_skb(ch->trans_skb);
+                       ch->trans_skb = NULL;
+                       if (warn)
+                               printk(KERN_WARNING
+                                      "ch-%04x: set_normalized_cda for %s "
+                                      "trans_skb failed, dropping packets\n",
+                                      ch->devno,
+                                      (CHANNEL_DIRECTION(ch->flags) == READ) ?
+                                      "RX" : "TX");
+                       return -ENOMEM;
+               }
+               ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED;
        }
+       return 0;
 }
 
 /**
@@ -988,73 +1003,47 @@ static void ch_action_txdone(fsm_instance *fi, int event, void *arg)
                        first = 0;
                }
                atomic_dec(&skb->users);
-               dev_kfree_skb(skb);
+               dev_kfree_skb_irq(skb);
        }
        spin_lock(&ch->collect_lock);
-       if (ch->dccw) {
-               for (i = 0; i < ch->dccw_count; i++)
-                       clear_normalized_cda(&ch->dccw[i]);
-               kfree(ch->dccw);
-               ch->dccw = NULL;
-       }
+       clear_normalized_cda(&ch->ccw[4]);
        if (ch->collect_len > 0) {
                int rc;
 
-               ch->dccw_count = skb_queue_len(&ch->collect_queue) + 1;
-               if (ch->prof.maxmulti < (ch->collect_len + 2))
-                       ch->prof.maxmulti = ch->collect_len + 2;
-               if (ch->prof.maxcqueue < ch->dccw_count)
-                       ch->prof.maxcqueue = ch->dccw_count;
-
-               ch->dccw = kmalloc(ch->dccw_count *
-                                  sizeof(ccw1_t), GFP_ATOMIC|GFP_DMA);
-               if (!ch->dccw) {
+               if (ctc_checkalloc_buffer(ch, 1)) {
                        spin_unlock(&ch->collect_lock);
-                       printk(KERN_WARNING
-                              "%s: Unable to alloc dynamic ccws\n",
-                              dev->name);
                        return;
                }
-
-               ch->dccw[0].cmd_code = CCW_CMD_PREPARE;
-               ch->dccw[0].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
-               ch->dccw[0].count    = 0;
-               ch->dccw[0].cda      = 0;
-               i = 1;
+               ch->trans_skb->tail = ch->trans_skb->data;
+               ch->trans_skb->len = 0;
+               if (ch->prof.maxmulti < (ch->collect_len + 2))
+                       ch->prof.maxmulti = ch->collect_len + 2;
+               if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
+                       ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
+               ch->ccw[1].count = ch->collect_len + 2;
+               *((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
+               i = 0;
                while ((skb = skb_dequeue(&ch->collect_queue))) {
-                       ch->prof.txlen += (skb->len - LL_HEADER_LENGTH);
-                       if (i == 1)
-                               *((__u16 *)skb_push(skb, 2)) =
-                                       ch->collect_len + 2;
-                       ch->dccw[i].cmd_code = CCW_CMD_WRITE;
-                       ch->dccw[i].flags    = CCW_FLAG_SLI |
-                               ((skb_queue_len(&ch->collect_queue))
-                                ? CCW_FLAG_DC : 0);
-                       ch->dccw[i].count    = skb->len;
-                       set_normalized_cda(&ch->dccw[i],
-                                          virt_to_phys(skb->data));
-                       skb_queue_tail(&ch->io_queue, skb);
+                       memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+                              skb->len);
+                       privptr->stats.tx_packets++;
+                       privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
+                       atomic_dec(&skb->users);
+                       dev_kfree_skb_irq(skb);
                        i++;
                }
                ch->collect_len = 0;
                fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
                ch->prof.send_stamp = xtime;
-               rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
+               rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
                ch->prof.doios_multi++;
                if (rc != 0) {
+                       privptr->stats.tx_dropped += i;
+                       privptr->stats.tx_errors += i;
                        fsm_deltimer(&ch->timer);
-                       i = 0;
-                       while ((skb = skb_dequeue(&ch->io_queue))) {
-                               privptr->stats.tx_dropped++;
-                               privptr->stats.tx_errors++;
-                               atomic_dec(&skb->users);
-                               dev_kfree_skb(skb);
-                               i++;
-                       }
-                       kfree(ch->dccw);
-                       ch->dccw = NULL;
-                       if (i != ch->dccw_count)
-                               printk(KERN_WARNING "ctc: i != nccws !!!\n");
                        ccw_check_return_code(ch, rc);
                }
        } else
@@ -1096,10 +1085,10 @@ static void ch_action_rx(fsm_instance *fi, int event, void *arg)
        net_device     *dev = ch->netdev;
        ctc_priv       *privptr = dev->priv;
        int            len = ch->max_bufsize - ch->devstat->rescnt;
-       struct sk_buff *skb = ch->rx_skb;
+       struct sk_buff *skb = ch->trans_skb;
        __u16          block_len = *((__u16*)skb->data);
        char           *saved_data = skb->data;
-       int            queued = 0;
+       int            check_len;
        int            rc;
 
        fsm_deltimer(&ch->timer);
@@ -1117,17 +1106,26 @@ static void ch_action_rx(fsm_instance *fi, int event, void *arg)
                privptr->stats.rx_length_errors++;
                goto again;
        }
+
        /**
         * VM TCP seems to have a bug sending 2 trailing bytes of garbage.
         */
-       if ((len < block_len) ||
-           ((len > block_len) && (ch->protocol != CTC_PROTO_S390)) ||
-           ((len > (block_len + 2)) && (ch->protocol == CTC_PROTO_S390))) {
-               printk(KERN_WARNING
-                      "%s: got block length %d != rx length %d\n", dev->name,
-                      block_len, len);
-               *((__u16*)skb->data) = len;
+       switch (ch->protocol) {
+               case CTC_PROTO_S390:
+               case CTC_PROTO_OS390:
+                       check_len = block_len + 2;
+                       break;
+               default:
+                       check_len = block_len;
+                       break;
+       }
+       if ((len < block_len) || (len > check_len)) {
+               printk(KERN_WARNING "%s: got block length %d != rx length %d\n",
+                      dev->name, block_len, len);
+#ifdef DEBUG
                ctc_dump_skb(skb, 0);
+#endif
+               *((__u16*)skb->data) = len;
                privptr->stats.rx_dropped++;
                privptr->stats.rx_length_errors++;
                goto again;
@@ -1135,31 +1133,24 @@ static void ch_action_rx(fsm_instance *fi, int event, void *arg)
        block_len -= 2;
        if (block_len > 0) {
                *((__u16*)skb->data) = block_len;
-               skb_queue_tail(&ch->io_queue, skb);
-               queued++;
+               ctc_unpack_skb(ch, skb);
        }
  again:
-       if (queued) {
-               queue_task(&ch->tq, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
-               ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
-               if (ch->rx_skb == NULL) {
-                       printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
-                              "ch_action_rx\n", dev->name);
-                       /* TODO: retry after bottom half */
-                       return;
-               }
-       } else {
-               skb->data = skb->tail = saved_data;
-               skb->len = 0;
-       }
+       skb->data = skb->tail = saved_data;
+       skb->len = 0;
+       if (ctc_checkalloc_buffer(ch, 1))
+               return;
        ch->ccw[1].count = ch->max_bufsize;
-       set_normalized_cda(&ch->ccw[1], virt_to_phys(ch->rx_skb->data));
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
        rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
        if (rc != 0)
                ccw_check_return_code(ch, rc);
 }
 
+static void ch_action_rxidle(fsm_instance *fi, int event, void *arg);
+
 /**
  * Initialize connection by sending a __u16 of value 0.
  *
@@ -1176,6 +1167,25 @@ static void ch_action_firstio(fsm_instance *fi, int event, void *arg)
                printk(KERN_DEBUG "ch-%04x: remote side issued READ?, "
                       "init ...\n", ch->devno);
        fsm_deltimer(&ch->timer);
+       if (ctc_checkalloc_buffer(ch, 1))
+               return;
+       if ((fsm_getstate(fi) == CH_STATE_SETUPWAIT) &&
+           (ch->protocol == CTC_PROTO_OS390)) {
+               /* OS/390 resp. z/OS */
+               if (CHANNEL_DIRECTION(ch->flags) == READ) {
+                       *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
+                       fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+                                    CH_EVENT_TIMER, ch);
+                       ch_action_rxidle(fi, event, arg);
+               } else {
+                       net_device *dev = ch->netdev;
+                       fsm_newstate(fi, CH_STATE_TXIDLE);
+                       fsm_event(((ctc_priv *)dev->priv)->fsm,
+                                 DEV_EVENT_TXUP, dev);
+               }
+               return;
+       }
+
        /**
         * Don´t setup a timer for receiving the initial RX frame
         * if in compatibility mode, since VM TCP delays the initial
@@ -1185,9 +1195,12 @@ static void ch_action_firstio(fsm_instance *fi, int event, void *arg)
            (ch->protocol != CTC_PROTO_S390))
                fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
 
-       ch->dummy_buf    = CTC_INITIAL_BLOCKLEN;
+       *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
        ch->ccw[1].count = 2; /* Transfer only length */
-       set_normalized_cda(&ch->ccw[1], virt_to_phys(&ch->dummy_buf));
+
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
        fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == READ)
                     ? CH_STATE_RXINIT : CH_STATE_TXINIT);
        rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
@@ -1223,20 +1236,22 @@ static void ch_action_rxidle(fsm_instance *fi, int event, void *arg)
 {
        channel    *ch = (channel *)arg;
        net_device *dev = ch->netdev;
+       __u16      buflen;
        int        rc;
 
        fsm_deltimer(&ch->timer);
-       if (ch->dummy_buf >= CTC_INITIAL_BLOCKLEN) {
-               ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
-               if (ch->rx_skb == NULL) {
-                       printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
-                              "ch_action_rxidle\n", dev->name);
+       buflen = *((__u16 *)ch->trans_skb->data);
+#ifdef DEBUG
+       printk(KERN_DEBUG "%s: Initial RX count %d\n", dev->name, buflen);
+#endif
+       if (buflen >= CTC_INITIAL_BLOCKLEN) {
+               if (ctc_checkalloc_buffer(ch, 1))
                        return;
-               }
                ch->ccw[1].count = ch->max_bufsize;
-               set_normalized_cda(&ch->ccw[1],
-                                  virt_to_phys(ch->rx_skb->data));
                fsm_newstate(fi, CH_STATE_RXIDLE);
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
                rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
                if (rc != 0) {
                        fsm_newstate(fi, CH_STATE_RXINIT);
@@ -1246,7 +1261,7 @@ static void ch_action_rxidle(fsm_instance *fi, int event, void *arg)
                                  DEV_EVENT_RXUP, dev);
        } else {
                printk(KERN_DEBUG "%s: Initial RX count %d not %d\n",
-                      dev->name, ch->dummy_buf, CTC_INITIAL_BLOCKLEN);
+                      dev->name, buflen, CTC_INITIAL_BLOCKLEN);
                ch_action_firstio(fi, event, arg);
        }
 }
@@ -1269,7 +1284,7 @@ static void ch_action_setmode(fsm_instance *fi, int event, void *arg)
        fsm_newstate(fi, CH_STATE_SETUPWAIT);
        if (event == CH_EVENT_TIMER)
                s390irq_spin_lock_irqsave(ch->irq, saveflags);
-       rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0);
+       rc = do_IO(ch->irq, &ch->ccw[6], (intparm_t)ch, 0xff, 0);
        if (event == CH_EVENT_TIMER)
                s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
        if (rc != 0) {
@@ -1303,15 +1318,30 @@ static void ch_action_start(fsm_instance *fi, int event, void *arg)
                       ch->irq);
                return;
        }
-
- dev = ch->netdev;
+       dev = ch->netdev;
 
 #ifdef DEBUG
        printk(KERN_DEBUG "%s: %s channel start\n", dev->name,
               (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
 #endif
 
+       if (ch->trans_skb != NULL) {
+               clear_normalized_cda(&ch->ccw[1]);
+               dev_kfree_skb(ch->trans_skb);
+               ch->trans_skb = NULL;
+       }
+       if (ctc_checkalloc_buffer(ch, 0))
+               printk(KERN_NOTICE
+                      "%s: Could not allocate %s trans_skb, delaying "
+                      "allocation until first transfer\n",
+                      dev->name, 
+                      (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
+
+#if LINUX_VERSION_CODE >= 0x020400
        INIT_LIST_HEAD(&ch->tq.list);
+#else
+       ch->tq.next = NULL;
+#endif
        ch->tq.sync    = 0;
        ch->tq.routine = (void *)(void *)ctc_bh;
        ch->tq.data    = ch;
@@ -1324,17 +1354,18 @@ static void ch_action_start(fsm_instance *fi, int event, void *arg)
                ch->ccw[1].cmd_code = CCW_CMD_READ;
                ch->ccw[1].flags    = CCW_FLAG_SLI;
                ch->ccw[1].count    = 0;
-               ch->ccw[1].cda      = 0;
        } else {
                ch->ccw[1].cmd_code = CCW_CMD_WRITE;
                ch->ccw[1].flags    = CCW_FLAG_SLI | CCW_FLAG_CC;
                ch->ccw[1].count    = 0;
-               ch->ccw[1].cda      = 0;
        }
        ch->ccw[2].cmd_code = CCW_CMD_NOOP;      /* jointed CE + DE */
        ch->ccw[2].flags    = CCW_FLAG_SLI;
        ch->ccw[2].count    = 0;
        ch->ccw[2].cda      = 0;
+       memcpy(&ch->ccw[3], &ch->ccw[0], sizeof(ccw1_t) * 3);
+       ch->ccw[4].cda      = 0;
+
        fsm_newstate(fi, CH_STATE_STARTWAIT);
        fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
        s390irq_spin_lock_irqsave(ch->irq, saveflags);
@@ -1392,26 +1423,62 @@ static void ch_action_stopped(fsm_instance *fi, int event, void *arg)
        channel *ch = (channel *)arg;
        net_device *dev = ch->netdev;
 
-       if (ch->dccw) {
-               printk(KERN_WARNING "ch_action_stopped: dccw !NULL\n");
-               return;
-       }
        fsm_deltimer(&ch->timer);
        fsm_newstate(fi, CH_STATE_STOPPED);
+       if (ch->trans_skb != NULL) {
+               clear_normalized_cda(&ch->ccw[1]);
+               dev_kfree_skb(ch->trans_skb);
+               ch->trans_skb = NULL;
+       }
+       if (CHANNEL_DIRECTION(ch->flags) == READ) {
+               skb_queue_purge(&ch->io_queue);
+               fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
+       } else {
+               ctc_purge_skb_queue(&ch->io_queue);
+               spin_lock(&ch->collect_lock);
+               ctc_purge_skb_queue(&ch->collect_queue);
+               ch->collect_len = 0;
+               spin_unlock(&ch->collect_lock);
+               fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
+       }
+}
+
+/**
+ * A stop command from device statemachine arrived and we are in
+ * not operational mode. Set state to stopped.
+ *
+ * @param fi    An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg   Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_stop(fsm_instance *fi, int event, void *arg)
+{
+       fsm_newstate(fi, CH_STATE_STOPPED);
+}
+
+/**
+ * A machine check for no path, not operational status or gone device has
+ * happened.
+ * Cleanup queue and notify interface statemachine.
+ *
+ * @param fi    An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg   Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_fail(fsm_instance *fi, int event, void *arg)
+{
+       channel *ch = (channel *)arg;
+       net_device *dev = ch->netdev;
+
+       fsm_deltimer(&ch->timer);
+       fsm_newstate(fi, CH_STATE_NOTOP);
        if (CHANNEL_DIRECTION(ch->flags) == READ) {
                skb_queue_purge(&ch->io_queue);
-               if (ch->rx_skb != NULL) {
-                       dev_kfree_skb(ch->rx_skb);
-                       ch->rx_skb = NULL;
-               }
                fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
        } else {
                ctc_purge_skb_queue(&ch->io_queue);
                spin_lock(&ch->collect_lock);
                ctc_purge_skb_queue(&ch->collect_queue);
-               if (ch->dccw)
-                       kfree(ch->dccw);
-               ch->dccw = NULL;
                ch->collect_len = 0;
                spin_unlock(&ch->collect_lock);
                fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
@@ -1629,20 +1696,25 @@ static void ch_action_txretry(fsm_instance *fi, int event, void *arg)
                if ((skb = skb_peek(&ch->io_queue))) {
                        int rc = 0;
 
+                       set_normalized_cda(&ch->ccw[4],
+                                          virt_to_phys(skb->data));
+                       if (ch->ccw[4].cda == 0) {
+                               printk(KERN_DEBUG "%s: IDAL alloc failed, "
+                                      "restarting channel\n", dev->name);
+                               fsm_event(((ctc_priv *)dev->priv)->fsm,
+                                         DEV_EVENT_TXDOWN, dev);
+                               ch_action_restart(fi, event, arg);
+                               return;
+                       }
                        fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
                        if (event == CH_EVENT_TIMER)
                                s390irq_spin_lock_irqsave(ch->irq, saveflags);
-                       if (ch->dccw)
-                               rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch,
-                                          0xff, 0);
-                       else {
-                               clear_normalized_cda(&ch->ccw[1]);
-                               ch->ccw[1].count = skb->len;
-                               set_normalized_cda(&ch->ccw[1],
-                                                  virt_to_phys(skb->data));
-                               rc = do_IO(ch->irq, &ch->ccw[0],
-                                          (intparm_t)ch, 0xff, 0);
-                       }
+                       ch->ccw[4].count = skb->len;
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[4].cda = %08x\n", ch->ccw[4].cda);
+#endif
+                       rc = do_IO(ch->irq, &ch->ccw[3],
+                                  (intparm_t)ch, 0xff, 0);
                        if (event == CH_EVENT_TIMER)
                                s390irq_spin_unlock_irqrestore(ch->irq,
                                                               saveflags);
@@ -1687,6 +1759,13 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_STOPPED,    CH_EVENT_STOP,       fsm_action_nop       },
        { CH_STATE_STOPPED,    CH_EVENT_START,      ch_action_start      },
        { CH_STATE_STOPPED,    CH_EVENT_FINSTAT,    fsm_action_nop       },
+       { CH_STATE_STOPPED,    CH_EVENT_MC_FAIL,    fsm_action_nop       },
+
+       { CH_STATE_NOTOP,      CH_EVENT_STOP,       ch_action_stop       },
+       { CH_STATE_NOTOP,      CH_EVENT_START,      fsm_action_nop       },
+       { CH_STATE_NOTOP,      CH_EVENT_FINSTAT,    fsm_action_nop       },
+       { CH_STATE_NOTOP,      CH_EVENT_MC_FAIL,    fsm_action_nop       },
+       { CH_STATE_NOTOP,      CH_EVENT_MC_GOOD,    ch_action_start      },
 
        { CH_STATE_STARTWAIT,  CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_STARTWAIT,  CH_EVENT_START,      fsm_action_nop       },
@@ -1694,10 +1773,12 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_STARTWAIT,  CH_EVENT_TIMER,      ch_action_setuperr   },
        { CH_STATE_STARTWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_STARTWAIT,  CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_STARTWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_STARTRETRY, CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_STARTRETRY, CH_EVENT_TIMER,      ch_action_setmode    },
        { CH_STATE_STARTRETRY, CH_EVENT_FINSTAT,    fsm_action_nop       },
+       { CH_STATE_STARTRETRY, CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_SETUPWAIT,  CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_SETUPWAIT,  CH_EVENT_START,      fsm_action_nop       },
@@ -1707,6 +1788,7 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_SETUPWAIT,  CH_EVENT_TIMER,      ch_action_setmode    },
        { CH_STATE_SETUPWAIT,  CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_SETUPWAIT,  CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_SETUPWAIT,  CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_RXINIT,     CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_RXINIT,     CH_EVENT_START,      fsm_action_nop       },
@@ -1718,6 +1800,7 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_RXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_RXINIT,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
        { CH_STATE_RXINIT,     CH_EVENT_UC_ZERO,    ch_action_firstio    },
+       { CH_STATE_RXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_RXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_RXIDLE,     CH_EVENT_START,      fsm_action_nop       },
@@ -1726,6 +1809,8 @@ static const fsm_node ch_fsm[] = {
 //     { CH_STATE_RXIDLE,     CH_EVENT_UC_RSRESET, ch_action_rxretry    },
        { CH_STATE_RXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_RXIDLE,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_RXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },
+       { CH_STATE_RXIDLE,     CH_EVENT_UC_ZERO,    ch_action_rx         },
 
        { CH_STATE_TXINIT,     CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_TXINIT,     CH_EVENT_START,      fsm_action_nop       },
@@ -1735,6 +1820,7 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_TXINIT,     CH_EVENT_TIMER,      ch_action_txiniterr  },
        { CH_STATE_TXINIT,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_TXINIT,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_TXINIT,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_TXIDLE,     CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_TXIDLE,     CH_EVENT_START,      fsm_action_nop       },
@@ -1743,18 +1829,21 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_TXIDLE,     CH_EVENT_UC_RSRESET, fsm_action_nop       },
        { CH_STATE_TXIDLE,     CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_TXIDLE,     CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_TXIDLE,     CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_TERM,       CH_EVENT_STOP,       fsm_action_nop       },
        { CH_STATE_TERM,       CH_EVENT_START,      ch_action_restart    },
        { CH_STATE_TERM,       CH_EVENT_FINSTAT,    ch_action_stopped    },
        { CH_STATE_TERM,       CH_EVENT_UC_RCRESET, fsm_action_nop       },
        { CH_STATE_TERM,       CH_EVENT_UC_RSRESET, fsm_action_nop       },
+       { CH_STATE_TERM,       CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_DTERM,      CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_DTERM,      CH_EVENT_START,      ch_action_restart    },
        { CH_STATE_DTERM,      CH_EVENT_FINSTAT,    ch_action_setmode    },
        { CH_STATE_DTERM,      CH_EVENT_UC_RCRESET, fsm_action_nop       },
        { CH_STATE_DTERM,      CH_EVENT_UC_RSRESET, fsm_action_nop       },
+       { CH_STATE_DTERM,      CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_TX,         CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_TX,         CH_EVENT_START,      fsm_action_nop       },
@@ -1764,9 +1853,12 @@ static const fsm_node ch_fsm[] = {
        { CH_STATE_TX,         CH_EVENT_TIMER,      ch_action_txretry    },
        { CH_STATE_TX,         CH_EVENT_IO_ENODEV,  ch_action_iofatal    },
        { CH_STATE_TX,         CH_EVENT_IO_EIO,     ch_action_iofatal    },
+       { CH_STATE_TX,         CH_EVENT_MC_FAIL,    ch_action_fail       },
 
        { CH_STATE_RXERR,      CH_EVENT_STOP,       ch_action_haltio     },
        { CH_STATE_TXERR,      CH_EVENT_STOP,       ch_action_haltio     },
+       { CH_STATE_TXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },
+       { CH_STATE_RXERR,      CH_EVENT_MC_FAIL,    ch_action_fail       },
 };
 
 static const int CH_FSM_LEN = sizeof(ch_fsm) / sizeof(fsm_node);
@@ -1796,7 +1888,7 @@ static int add_channel(int irq, __u16 devno, channel_type_t type)
                return -1;
        }
        memset(ch, 0, sizeof(channel));
-       if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5,
+       if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 8,
                                         GFP_KERNEL|GFP_DMA)) == NULL) {
                kfree(ch);
                printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
@@ -1808,24 +1900,29 @@ static int add_channel(int irq, __u16 devno, channel_type_t type)
         *
         * ccw[0..2] (Channel program for generic I/O):
         *           0: prepare
-        *           1: read or write (depending on direction)
+        *           1: read or write (depending on direction) with fixed
+        *              buffer (idal allocated once when buffer is allocated)
         *           2: nop
-        * ccw[3..4] (Channel program for initial channel setup):
+        * ccw[3..5] (Channel program for direct write of packets)
+        *           3: prepare
+        *           4: write (idal allocated on every write).
+        *           5: nop
+        * ccw[6..7] (Channel program for initial channel setup):
         *           3: set extended mode
         *           4: nop
         *
-        * ch->ccw[0..2] are initialized in ch_action_start because
+        * ch->ccw[0..5] are initialized in ch_action_start because
         * the channel's direction is yet unknown here.
         */
-       ch->ccw[3].cmd_code = CCW_CMD_SET_EXTENDED;
-       ch->ccw[3].flags    = CCW_FLAG_SLI;
-       ch->ccw[3].count    = 0;
-       ch->ccw[3].cda      = 0;
+       ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED;
+       ch->ccw[6].flags    = CCW_FLAG_SLI;
+       ch->ccw[6].count    = 0;
+       ch->ccw[6].cda      = 0;
        
-       ch->ccw[4].cmd_code = CCW_CMD_NOOP;
-       ch->ccw[4].flags    = CCW_FLAG_SLI;
-       ch->ccw[4].count    = 0;
-       ch->ccw[4].cda      = 0;
+       ch->ccw[7].cmd_code = CCW_CMD_NOOP;
+       ch->ccw[7].flags    = CCW_FLAG_SLI;
+       ch->ccw[7].count    = 0;
+       ch->ccw[7].cda      = 0;
 
        ch->irq = irq;
        ch->devno = devno;
@@ -1835,7 +1932,8 @@ static int add_channel(int irq, __u16 devno, channel_type_t type)
                        ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
                        ch_fsm, CH_FSM_LEN, GFP_KERNEL);
        if (ch->fsm == NULL) {
-               printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n");
+               printk(KERN_WARNING
+                      "ctc: Could not create FSM in add_channel\n");
                kfree(ch);
                return -1;
        }
@@ -1852,8 +1950,8 @@ static int add_channel(int irq, __u16 devno, channel_type_t type)
                c = &(*c)->next;
        if ((*c)->devno == devno) {
                printk(KERN_DEBUG
-                      "ctc: add_channel: device %04x already in list\n",
-                      (*c)->devno);
+                      "ctc: add_channel: device %04x already in list, "
+                      "using old entry\n", (*c)->devno);
                kfree(ch->devstat);
                kfree_fsm(ch->fsm);
                kfree(ch);
@@ -1867,14 +1965,14 @@ static int add_channel(int irq, __u16 devno, channel_type_t type)
        return 0;
 }
 
+#ifndef CTC_CHANDEV
 /**
  * scan for all channels and create an entry in the channels list
  * for every supported channel.
- *
- * @param print_result Flag: If !0, print a final result.
  */
-static void channel_scan(int print_result)
+static void channel_scan(void)
 {
+       static int      print_result = 1;
        int             irq;
        int             nr_escon = 0;
        int             nr_ctca  = 0;
@@ -1912,7 +2010,9 @@ static void channel_scan(int print_result)
                else
                        printk(KERN_INFO "ctc: No channel devices found.\n");
        }
+       print_result = 0;
 }
+#endif
 
 /**
  * Release a specific channel in the channel list.
@@ -1925,6 +2025,40 @@ static void channel_free(channel *ch)
        fsm_newstate(ch->fsm, CH_STATE_IDLE);
 }
 
+/**
+ * Remove a specific channel in the channel list.
+ *
+ * @param ch Pointer to channel struct to be released.
+ */
+static void channel_remove(channel *ch)
+{
+       channel **c = &channels;
+
+       if (ch == NULL)
+               return;
+
+#ifndef CTC_CHANDEV
+       if (ch->flags & CHANNEL_FLAGS_INUSE)
+               FREE_IRQ(ch->irq, ch->devstat);
+#endif
+       channel_free(ch);
+       while (*c) {
+               if (*c == ch) {
+                       *c = ch->next;
+                       fsm_deltimer(&ch->timer);
+                       kfree_fsm(ch->fsm);
+                       clear_normalized_cda(&ch->ccw[4]);
+                       if (ch->trans_skb != NULL) {
+                               clear_normalized_cda(&ch->ccw[1]);
+                               dev_kfree_skb(ch->trans_skb);
+                       }
+                       kfree(ch->ccw);
+                       return;
+               }
+               c = &((*c)->next);
+       }
+}
+
 
 /**
  * Get a specific channel from the channel list.
@@ -1977,7 +2111,7 @@ static channel *channel_get(channel_type_t type, int devno, int direction)
        return ch;
 }
 
-
+#ifndef CTC_CHANDEV
 /**
  * Get the next free channel from the channel list
  *
@@ -2001,6 +2135,7 @@ static channel *channel_get_next(channel_type_t type, int direction)
        }
        return ch;
 }
+#endif
 
 /**
  * Return the channel type by name.
@@ -2065,7 +2200,6 @@ static void ctc_irq_handler (int irq, void *intparm, struct pt_regs *regs)
                }
        }
 
-       clear_normalized_cda(&ch->ccw[1]);
        dev = (net_device *)(ch->netdev);
        if (dev == NULL) {
                printk(KERN_CRIT
@@ -2173,6 +2307,7 @@ static void dev_action_stop(fsm_instance *fi, int event, void *arg)
 static void dev_action_chup(fsm_instance *fi, int event, void *arg)
 {
        net_device *dev = (net_device *)arg;
+       ctc_priv   *privptr = dev->priv;
 
        switch (fsm_getstate(fi)) {
                case DEV_STATE_STARTWAIT_RXTX:
@@ -2187,6 +2322,8 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg)
                                printk(KERN_INFO
                                       "%s: connected with remote side\n",
                                       dev->name);
+                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2196,6 +2333,8 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg)
                                printk(KERN_INFO
                                       "%s: connected with remote side\n",
                                       dev->name);
+                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2220,8 +2359,13 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg)
  */
 static void dev_action_chdown(fsm_instance *fi, int event, void *arg)
 {
+       net_device *dev = (net_device *)arg;
+       ctc_priv   *privptr = dev->priv;
+
        switch (fsm_getstate(fi)) {
                case DEV_STATE_RUNNING:
+                       if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                               ctc_tty_setcarrier(dev, 0);
                        if (event == DEV_EVENT_TXDOWN)
                                fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
                        else
@@ -2313,8 +2457,6 @@ static int transmit_skb(channel *ch, struct sk_buff *skb) {
        if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
                int l = skb->len + LL_HEADER_LENGTH;
 
-               if (ch->type == channel_type_escon)
-                       return -EBUSY;
                spin_lock_irqsave(&ch->collect_lock, saveflags);
                if (ch->collect_len + l > ch->max_bufsize - 2)
                        rc = -EBUSY;
@@ -2331,6 +2473,7 @@ static int transmit_skb(channel *ch, struct sk_buff *skb) {
                spin_unlock_irqrestore(&ch->collect_lock, saveflags);
        } else {
                __u16 block_len;
+               int ccw_idx;
 
                /**
                 * Protect skb against beeing free'd by upper
@@ -2345,17 +2488,52 @@ static int transmit_skb(channel *ch, struct sk_buff *skb) {
                       LL_HEADER_LENGTH);
                block_len = skb->len + 2;
                *((__u16 *)skb_push(skb, 2)) = block_len;
-               skb_queue_tail(&ch->io_queue, skb);
+               set_normalized_cda(&ch->ccw[4], virt_to_phys(skb->data));
+               if (ch->ccw[4].cda == 0) {
+                       /**
+                        * idal allocation failed, try via copying to
+                        * trans_skb. trans_skb usually has a pre-allocated
+                        * idal.
+                        */
+                       if (ctc_checkalloc_buffer(ch, 1)) {
+                               /**
+                                * Remove our header. It gets added
+                                * again on retransmit.
+                                */
+                               skb_pull(skb, LL_HEADER_LENGTH + 2);
+                               return -EBUSY;
+                       }
+
+                       ch->trans_skb->tail = ch->trans_skb->data;
+                       ch->trans_skb->len = 0;
+                       ch->ccw[1].count = skb->len;
+                       memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+                              skb->len);
+                       atomic_dec(&skb->users);
+                       dev_kfree_skb_irq(skb);
+                       ccw_idx = 0;
+               } else {
+                       ch->ccw[4].count = block_len;
+                       skb_queue_tail(&ch->io_queue, skb);
+                       ccw_idx = 3;
+               }
                ch->retry = 0;
+#ifdef DEBUG
+               ctc_dump_skb(skb, 0);
+#endif
                fsm_newstate(ch->fsm, CH_STATE_TX);
-               fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
-               ch->ccw[1].count = block_len;
-               set_normalized_cda(&ch->ccw[1], virt_to_phys(skb->data));
+               fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+                            CH_EVENT_TIMER, ch);
                s390irq_spin_lock_irqsave(ch->irq, saveflags);
                ch->prof.send_stamp = xtime;
-               rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+       printk(KERN_DEBUG "ccw[%d].cda = %08x\n", ccw_idx+1,
+              ch->ccw[ccw_idx+1].cda);
+#endif
+               rc = do_IO(ch->irq, &ch->ccw[ccw_idx], (intparm_t)ch, 0xff, 0);
                s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
-               ch->prof.doios_single++;
+               if (ccw_idx == 3)
+                       ch->prof.doios_single++;
                if (rc != 0) {
                        fsm_deltimer(&ch->timer);
                        ccw_check_return_code(ch, rc);
@@ -2365,6 +2543,14 @@ static int transmit_skb(channel *ch, struct sk_buff *skb) {
                         * again on retransmit.
                         */
                        skb_pull(skb, LL_HEADER_LENGTH + 2);
+               } else {
+                       if (ccw_idx == 0) {
+                               net_device *dev = ch->netdev;
+                               ctc_priv   *privptr = dev->priv;
+                               privptr->stats.tx_packets++;
+                               privptr->stats.tx_bytes +=
+                                       skb->len - LL_HEADER_LENGTH;
+                       }
                }
        }
 
@@ -2429,8 +2615,9 @@ static int ctc_tx(struct sk_buff *skb, net_device *dev)
                return 0;
        }
        if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
-               printk(KERN_WARNING "%s: Got sk_buff with head room < %ld bytes\n",
-                               dev->name, LL_HEADER_LENGTH + 2);
+               printk(KERN_WARNING
+                      "%s: Got sk_buff with head room < %ld bytes\n",
+                      dev->name, LL_HEADER_LENGTH + 2);
                dev_kfree_skb(skb);
                privptr->stats.tx_dropped++;
                return 0;
@@ -2443,6 +2630,8 @@ static int ctc_tx(struct sk_buff *skb, net_device *dev)
         */
        if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
                fsm_event(privptr->fsm, DEV_EVENT_START, dev);
+               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                       return -EBUSY;
                dst_link_failure(skb);
                dev_kfree_skb(skb);
                privptr->stats.tx_dropped++;
@@ -2577,12 +2766,23 @@ static ssize_t ctc_ctrl_write(struct file *file, const char *buf, size_t count,
                return -EFAULT;
        tmp[count+1] = '\0';
        bs1 = simple_strtoul(tmp, &e, 0);
+
        if ((bs1 > CTC_BUFSIZE_LIMIT) ||
-           (bs1 < (dev->mtu - LL_HEADER_LENGTH - 2)) ||
            (e && (!isspace(*e))))
                return -EINVAL;
+       if ((dev->flags & IFF_RUNNING) &&
+           (bs1 < (dev->mtu + LL_HEADER_LENGTH + 2)))
+               return -EINVAL;
+       if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+               return -EINVAL;
+
+
        privptr->channel[READ]->max_bufsize =
                privptr->channel[WRITE]->max_bufsize = bs1;
+       if (!(dev->flags & IFF_RUNNING))
+               dev->mtu = bs1 - LL_HEADER_LENGTH - 2;
+       privptr->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
+       privptr->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
 
        return count;
 }
@@ -2685,7 +2885,7 @@ static ssize_t ctc_stat_read(struct file *file, char *buf, size_t count,
                             fsm_getstate_str(privptr->channel[WRITE]->fsm));
                p += sprintf(p, "Max. TX buffer used: %ld\n",
                             privptr->channel[WRITE]->prof.maxmulti);
-               p += sprintf(p, "Max. chained CCWs: %ld\n",
+               p += sprintf(p, "Max. chained SKBs: %ld\n",
                             privptr->channel[WRITE]->prof.maxcqueue);
                p += sprintf(p, "TX single write ops: %ld\n",
                             privptr->channel[WRITE]->prof.doios_single);
@@ -2853,15 +3053,18 @@ static void ctc_proc_create_sub(net_device *dev) {
        proc_register(privptr->proc_dentry, privptr->proc_stat_entry);
        proc_register(privptr->proc_dentry, privptr->proc_ctrl_entry);
 #endif
+       privptr->proc_registered = 1;
 }
 
-#ifdef MODULE
+
 /**
  * Destroy a device specific subdirectory.
  *
  * @param privptr Pointer to device private data.
  */
 static void ctc_proc_destroy_sub(ctc_priv *privptr) {
+       if (!privptr->proc_registered)
+               return;
 #if LINUX_VERSION_CODE > 0x020362
        remove_proc_entry("statistics", privptr->proc_dentry);
        remove_proc_entry("buffersize", privptr->proc_dentry);
@@ -2874,9 +3077,12 @@ static void ctc_proc_destroy_sub(ctc_priv *privptr) {
        proc_unregister(&ctc_dir,
                        privptr->proc_dentry->low_ino);
 #endif
+       privptr->proc_registered = 0;
 }
-#endif MODULE
+
 \f
+
+#ifndef CTC_CHANDEV
 /**
  * Setup related routines
  *****************************************************************************/
@@ -2991,7 +3197,8 @@ static int parse_opts(char **setup, char **dev_name, int *ints, int maxip) {
 #else
 static param parms_array[MAX_STATIC_DEVICES];
 static param *next_param = parms_array;
-#define alloc_param() ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
+#define alloc_param() \
+        ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
 #endif MODULE
 
 /**
@@ -3159,7 +3366,313 @@ static param *find_param(char *name) {
 #if LINUX_VERSION_CODE >= 0x020300
 __setup("ctc=", ctc_setup);
 #endif
+#endif /* !CTC_CHANDEV */
 \f
+
+static void
+ctc_netdev_unregister(net_device *dev)
+{
+       ctc_priv *privptr;
+
+       if (!dev)
+               return;
+       privptr = (ctc_priv *)dev->priv;
+       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+               unregister_netdev(dev);
+       else
+               ctc_tty_unregister_netdev(dev);
+}
+
+static int
+ctc_netdev_register(net_device *dev)
+{
+       ctc_priv *privptr = (ctc_priv *)dev->priv;
+       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+               return register_netdev(dev);
+       else
+               return ctc_tty_register_netdev(dev);
+}
+
+static void
+ctc_free_netdevice(net_device *dev, int free_dev)
+{
+       ctc_priv *privptr;
+       if (!dev)
+               return;
+       privptr = dev->priv;
+       if (privptr) {
+               if (privptr->fsm)
+                       kfree_fsm(privptr->fsm);
+               ctc_proc_destroy_sub(privptr);
+               kfree(privptr);
+       }
+#ifdef MODULE
+       if (free_dev)
+               kfree(dev);
+#endif
+}
+
+#ifdef CTC_CHANDEV
+static int
+ctc_shutdown(net_device *dev)
+{
+       ctc_priv *privptr;
+
+       if (!dev)
+               return 0;
+       privptr = (ctc_priv *)dev->priv;
+       channel_remove(privptr->channel[READ]);
+       channel_remove(privptr->channel[WRITE]);
+       ctc_free_netdevice(dev, 0);
+       return 0;
+}
+#endif
+
+/**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static net_device *
+ctc_init_netdevice(net_device *dev, int alloc_device)
+{
+       ctc_priv *privptr;
+       int      priv_size;
+       if (alloc_device) {
+               dev = kmalloc(sizeof(net_device)
+#if LINUX_VERSION_CODE < 0x020300
+                             + 11 /* name + zero */
+#endif
+                             , GFP_KERNEL);
+               if (!dev)
+                       return NULL;
+               memset(dev, 0, sizeof(net_device));
+       }
+       priv_size = sizeof(ctc_priv) + sizeof(ctc_template) +
+               sizeof(stat_entry) + sizeof(ctrl_entry);
+       dev->priv = kmalloc(priv_size, GFP_KERNEL);
+       if (dev->priv == NULL) {
+               if (alloc_device)
+                       kfree(dev);
+               return NULL;
+       }
+        memset(dev->priv, 0, priv_size);
+        privptr = (ctc_priv *)dev->priv;
+        privptr->proc_dentry = (struct proc_dir_entry *)
+               (((char *)privptr) + sizeof(ctc_priv));
+        privptr->proc_stat_entry = (struct proc_dir_entry *)
+               (((char *)privptr) + sizeof(ctc_priv) +
+                sizeof(ctc_template));
+        privptr->proc_ctrl_entry = (struct proc_dir_entry *)
+               (((char *)privptr) + sizeof(ctc_priv) +
+                sizeof(ctc_template) + sizeof(stat_entry));
+       memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
+       memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
+       memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
+       privptr->fsm = init_fsm("ctcdev", dev_state_names,
+                       dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
+                       dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+       if (privptr->fsm == NULL) {
+               kfree(privptr);
+               if (alloc_device)
+                       kfree(dev);
+               return NULL;
+       }
+       fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+       dev->mtu                 = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+       dev->hard_start_xmit     = ctc_tx;
+       dev->open                = ctc_open;
+       dev->stop                = ctc_close;
+       dev->get_stats           = ctc_stats;
+       dev->change_mtu          = ctc_change_mtu;
+       dev->hard_header_len     = LL_HEADER_LENGTH + 2;
+       dev->addr_len            = 0;
+       dev->type                = ARPHRD_SLIP;
+       dev->tx_queue_len        = 100;
+       SET_DEVICE_START(dev, 1);
+       dev_init_buffers(dev);
+       dev->flags               = IFF_POINTOPOINT | IFF_NOARP;
+       return dev;
+}
+
+#ifdef CTC_CHANDEV
+static void
+ctc_chandev_msck_notify(void *dev, int msck_irq,
+                       chandev_msck_status prevstatus,
+                       chandev_msck_status newstatus)
+{
+       net_device *device = (net_device *)dev;
+       ctc_priv *privptr;
+       int direction;
+
+       if (!dev)
+               return;
+
+       privptr = device->priv;
+       if (prevstatus == chandev_status_revalidate)
+               for (direction = READ; direction <= WRITE; direction++) {
+                       channel *ch = privptr->channel[direction];
+                       if(ch->irq == msck_irq) {
+                               s390_dev_info_t devinfo;
+
+                               if (get_dev_info_by_irq(ch->irq, &devinfo))
+                                       ch->devno = devinfo.devno;
+                               else
+                                       printk(KERN_WARNING
+                                              "ctc_chandev_msck_notify: "
+                                              "get_dev_info_by_irq failed for "
+                                              "irq %d\n", ch->irq);
+                       }
+               }
+       switch (newstatus) {
+               case chandev_status_not_oper:
+               case chandev_status_no_path:
+               case chandev_status_gone:
+                       for (direction = READ; direction <= WRITE; direction++) {
+                               channel *ch = privptr->channel[direction];
+                               fsm_event(ch->fsm, CH_EVENT_MC_FAIL, ch);
+                       }
+                       printk(KERN_WARNING
+                              "ctc: %s channel deactivated\n", device->name);
+                       break;
+               case chandev_status_all_chans_good:
+                       for (direction = READ; direction <= WRITE; direction++) {
+                               channel *ch = privptr->channel[direction];
+                               fsm_event(ch->fsm, CH_EVENT_MC_GOOD, ch);
+                       }
+                       printk(KERN_WARNING
+                              "ctc: %s channel activated\n", device->name);
+                       break;
+               default:
+                       break;
+       }
+}
+
+/**
+ *
+ * Setup an interface.
+ *
+ * Like ctc_setup(), ctc_probe() can be called from two different locations:
+ *  - If built as module, it is called from within init_module().
+ *  - If built in monolithic kernel, it is called from within generic network
+ *    layer during initialization for every corresponding device, declared in
+ *    drivers/net/Space.c
+ *
+ * @param dev Pointer to net_device to be initialized.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int ctc_chandev_probe(chandev_probeinfo *info)
+{
+       int               devno[2];
+       __u16             proto;
+       int               rc;
+       int               direction;
+       channel_type_t    type;
+       ctc_priv          *privptr;
+       net_device        *dev;
+
+       ctc_proc_create_main();
+
+
+       switch (info->chan_type) {
+               case chandev_type_ctc:
+                       type = channel_type_ctca;
+                       break;
+               case chandev_type_escon:
+                       type = channel_type_escon;
+                       break;
+               default:
+                       printk(KERN_WARNING "ctc_chandev_probe called with "
+                              "unsupported channel type %d\n", info->chan_type);
+                       return -ENODEV;
+       }
+       devno[READ]  = info->read.devno;
+       devno[WRITE] = info->write.devno;
+       proto        = info->port_protocol_no;
+
+       if (add_channel(info->read.irq, info->read.devno, type))
+               return -ENOMEM;
+       if (add_channel(info->write.irq, info->write.devno, type))
+               return -ENOMEM;
+
+       dev = ctc_init_netdevice(NULL, 1);
+
+       
+       if (!dev) {
+               printk(KERN_WARNING "ctc_init_netdevice failed\n");
+               return -ENODEV;
+       }
+       
+       if (proto == CTC_PROTO_LINUX_TTY)
+               chandev_build_device_name(info, dev->name, "ctctty", 1);
+       else
+               chandev_build_device_name(info, dev->name, "ctc", 1);
+
+       privptr = (ctc_priv *)dev->priv;
+       privptr->protocol = proto;
+       for (direction = READ; direction <= WRITE; direction++) {
+               privptr->channel[direction] =
+                       channel_get(type, devno[direction], direction);
+               if (privptr->channel[direction] == NULL) {
+                       if (direction == WRITE) {
+                               FREE_IRQ(privptr->channel[READ]->irq,
+                                        privptr->channel[READ]->devstat);
+                               channel_free(privptr->channel[READ]);
+                       }
+                       ctc_free_netdevice(dev, 1);
+                       return -ENODEV;
+               }
+               privptr->channel[direction]->netdev = dev;
+               privptr->channel[direction]->protocol = proto;
+               privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
+               rc = REQUEST_IRQ(privptr->channel[direction]->irq,
+                                (void *)ctc_irq_handler, SA_INTERRUPT,
+                                dev->name,
+                                privptr->channel[direction]->devstat);
+               if (rc) {
+                       printk(KERN_WARNING
+                              "%s: requested irq %d is busy rc=%02x\n",
+                              dev->name, privptr->channel[direction]->irq,
+                              rc);
+                       if (direction == WRITE) {
+                               FREE_IRQ(privptr->channel[READ]->irq,
+                                        privptr->channel[READ]->devstat);
+                               channel_free(privptr->channel[READ]);
+                       }
+                       channel_free(privptr->channel[direction]);
+                       ctc_free_netdevice(dev, 1);
+                       return -EBUSY;
+               }
+       }
+       if (ctc_netdev_register(dev) != 0) {
+               ctc_free_netdevice(dev, 1);
+               return -ENODEV;
+       }
+
+       /**
+        * register subdir in /proc/net/ctc
+        */
+       ctc_proc_create_sub(dev);
+       strncpy(privptr->fsm->name, dev->name, sizeof(privptr->fsm->name));
+       activated++;
+
+       print_banner();
+
+       printk(KERN_INFO
+              "%s: read: ch %04x (irq %04x), "
+              "write: ch %04x (irq %04x) proto: %d\n",
+              dev->name, privptr->channel[READ]->devno,
+              privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
+              privptr->channel[WRITE]->irq, proto);
+
+       chandev_initdevice(info, dev, 0, dev->name,
+                          (proto == CTC_PROTO_LINUX_TTY)
+                          ? chandev_category_serial_device :
+                          chandev_category_network_device,
+                          (chandev_unregfunc)ctc_netdev_unregister);
+       return 0;
+}
+#else /* ! CHANDEV */
 /**
  *
  * Setup an interface.
@@ -3191,7 +3704,7 @@ int ctc_probe(net_device *dev)
         * ctc_probe gets control.
         */
        if (channels == NULL)
-               channel_scan(1);
+               channel_scan();
 
        type = extract_channel_media(dev->name);
        if (type == channel_type_unknown)
@@ -3212,47 +3725,13 @@ int ctc_probe(net_device *dev)
                }
        }
 
-       dev->priv = kmalloc(sizeof(ctc_priv)
-                           + sizeof(ctc_template)
-                           + sizeof(stat_entry)
-                           + sizeof(ctrl_entry)
-                           , GFP_KERNEL);
-       if (dev->priv == NULL)
-               return -ENOMEM;
-       memset(dev->priv, 0, sizeof(ctc_priv));
+#ifndef MODULE
+       if (ctc_init_netdevice(dev, 0) == NULL)
+               return -ENODEV;
+#endif
        privptr = (ctc_priv *)dev->priv;
        privptr->protocol = proto;
-        privptr->proc_dentry = (struct proc_dir_entry *)
-               (((char *)privptr) + sizeof(ctc_priv));
-        privptr->proc_stat_entry = (struct proc_dir_entry *)
-               (((char *)privptr) + sizeof(ctc_priv) +
-                sizeof(ctc_template));
-        privptr->proc_ctrl_entry = (struct proc_dir_entry *)
-               (((char *)privptr) + sizeof(ctc_priv) +
-                sizeof(ctc_template) + sizeof(stat_entry));
-       memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
-       memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
-       memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
-       privptr->fsm = init_fsm(dev->name, dev_state_names,
-                       dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
-                       dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
-       fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
-       if (privptr->fsm == NULL) {
-               kfree(privptr);
-               return -ENOMEM;
-       }
-       dev->mtu                 = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2; 
-       dev->hard_start_xmit     = ctc_tx;
-       dev->open                = ctc_open;
-       dev->stop                = ctc_close;
-       dev->get_stats           = ctc_stats;
-       dev->change_mtu          = ctc_change_mtu;
-       dev->hard_header_len     = LL_HEADER_LENGTH + 2;
-       dev->addr_len            = 0;
-       dev->type                = ARPHRD_SLIP;
-       dev->tx_queue_len        = 100;
-       SET_DEVICE_START(dev, 1);
-       dev->flags               = IFF_POINTOPOINT | IFF_NOARP;
+
        for (direction = READ; direction <= WRITE; direction++) {
                if ((ctc_no_auto == 0) || (devno[direction] == -1))
                        privptr->channel[direction] =
@@ -3262,19 +3741,17 @@ int ctc_probe(net_device *dev)
                                channel_get(type, devno[direction], direction);
                if (privptr->channel[direction] == NULL) {
                        if (direction == WRITE) {
-                               free_irq(privptr->channel[READ]->irq,
+                               FREE_IRQ(privptr->channel[READ]->irq,
                                         privptr->channel[READ]->devstat);
                                channel_free(privptr->channel[READ]);
                        }
-                       kfree_fsm(privptr->fsm);
-                       kfree(dev->priv);
-                       dev->priv = NULL;
+                       ctc_free_netdevice(dev, 1);
                        return -ENODEV;
                }
                privptr->channel[direction]->netdev = dev;
                privptr->channel[direction]->protocol = proto;
                privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
-               rc = request_irq(privptr->channel[direction]->irq,
+               rc = REQUEST_IRQ(privptr->channel[direction]->irq,
                                 (void *)ctc_irq_handler, SA_INTERRUPT,
                                 dev->name,
                                 privptr->channel[direction]->devstat);
@@ -3284,14 +3761,12 @@ int ctc_probe(net_device *dev)
                               dev->name, privptr->channel[direction]->irq,
                               rc);
                        if (direction == WRITE) {
-                               free_irq(privptr->channel[READ]->irq,
+                               FREE_IRQ(privptr->channel[READ]->irq,
                                         privptr->channel[READ]->devstat);
                                channel_free(privptr->channel[READ]);
                        }
                        channel_free(privptr->channel[direction]);
-                       kfree_fsm(privptr->fsm);
-                       kfree(dev->priv);
-                       dev->priv = NULL;
+                       ctc_free_netdevice(dev, 1);
                        return -EBUSY;
                }
        }
@@ -3304,13 +3779,15 @@ int ctc_probe(net_device *dev)
        print_banner();
 
        printk(KERN_INFO
-              "%s: read: ch %04x (irq %04x), write: ch %04x (irq %04x) proto: %d\n",
+              "%s: read: ch %04x (irq %04x), "
+              "write: ch %04x (irq %04x) proto: %d\n",
               dev->name, privptr->channel[READ]->devno,
               privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
               privptr->channel[WRITE]->irq, proto);
 
        return 0;
 }
+#endif
 \f
 /**
  * Module related routines
@@ -3324,46 +3801,35 @@ int ctc_probe(net_device *dev)
  * for that.
  */
 void cleanup_module(void) {
-       channel *c = channels;
 
-       ctc_tty_cleanup();
+       ctc_tty_cleanup(0);
        /* we are called if all interfaces are down only, so no need
         * to bother around with locking stuff
         */
-       channels = NULL;
-       while (c) {
-               channel *oldc = c;
-               if (c->netdev && c->netdev->priv) {
-                       net_device *nd = c->netdev;
-                       ctc_priv *privptr = (ctc_priv *)nd->priv;
-
-                       fsm_deltimer(&privptr->channel[READ]->timer);
-                       fsm_deltimer(&privptr->channel[WRITE]->timer);
-                       free_irq(privptr->channel[READ]->irq,
-                                privptr->channel[READ]->devstat);
-                       free_irq(privptr->channel[WRITE]->irq,
-                                privptr->channel[WRITE]->devstat);
-                       kfree_fsm(privptr->channel[READ]->fsm);
-                       kfree_fsm(privptr->channel[WRITE]->fsm);
-                       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
-                               unregister_netdev(nd);
-                       else
-                               ctc_tty_unregister_netdev(nd);
-                       kfree_fsm(privptr->fsm);
-                       privptr->channel[READ]->netdev = NULL;
-                       privptr->channel[WRITE]->netdev = NULL;
-                       ctc_proc_destroy_sub(privptr);
-                       kfree(privptr);
-                       kfree(nd);
-                       if (c->netdev != NULL)
-                               printk(KERN_EMERG
-                                      "ctc: PANIC: channel list corrupted\n");
+#ifndef CTC_CHANDEV
+       while (channels) {
+               if ((channels->flags & CHANNEL_FLAGS_INUSE) &&
+                   (channels->netdev != NULL)) {
+                       net_device *dev = channels->netdev;
+                       ctc_priv *privptr = dev->priv;
+
+                       if (privptr) {
+                               privptr->channel[READ]->netdev = NULL;
+                               privptr->channel[WRITE]->netdev = NULL;
+                       }
+                       channels->netdev = NULL;
+                       ctc_netdev_unregister(dev);
+                       ctc_free_netdevice(dev, 1);
                }
-               c = c->next;
-               kfree(oldc->ccw);
-               kfree(oldc);
+               channel_remove(channels);
        }
+       channels = NULL;
+#endif
+       ctc_tty_cleanup(1);
        ctc_proc_destroy_main();
+#ifdef CTC_CHANDEV
+       chandev_unregister(ctc_chandev_probe, 1);
+#endif
        printk(KERN_INFO "CTC driver unloaded\n");
 }
 
@@ -3377,41 +3843,48 @@ void cleanup_module(void) {
  * @return 0 on success, !0 on error.
  */
 int ctc_init(void) {
+#ifndef CTC_CHANDEV
        int   cnt[2];
        int   itype;
        int   activated;
-       int   ret = 0;
        param *par;
+#endif
+       int   ret = 0;
+       int   probed = 0;
 
        print_banner();
 
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(CTC_CHANDEV)
        printk(KERN_DEBUG
-              "ctc: init_module(): got string '%s'\n", setup);
+              "ctc: init_module(): got string '%s'\n", ctc);
 #endif
 
+#ifndef CTC_CHANDEV
 #ifdef MODULE
        ctc_setup(ctc);
 #endif
-       activated = 0;
        par = params;
+#endif
+
+       activated = 0;
        ctc_tty_init();
+#ifdef CTC_CHANDEV
+       chandev_register_and_probe(ctc_chandev_probe,
+                                  (chandev_shutdownfunc)ctc_shutdown,
+                                  ctc_chandev_msck_notify,
+                                  chandev_type_ctc|chandev_type_escon);
+#else /* CTC_CHANDEV */
        for (itype = 0; itype < 2; itype++) {
                net_device *dev = NULL;
                char       *bname = (itype) ? "escon" : "ctc";
 
                cnt[itype] = 0;
                do {
-                       dev = kmalloc(sizeof(net_device)
-#if LINUX_VERSION_CODE < 0x020300
-                                     + 11 /* name + zero */
-#endif
-                                     , GFP_KERNEL);
+                       dev = ctc_init_netdevice(NULL, 1);
                        if (!dev) {
                                ret = -ENOMEM;
                                break;
                        }
-                       memset(dev, 0, sizeof(net_device));
 #if LINUX_VERSION_CODE < 0x020300
                        dev->name = (unsigned char *)dev + sizeof(net_device);
 #endif
@@ -3425,7 +3898,9 @@ int ctc_init(void) {
                                        if (isdigit(*p))
                                                break;
                                if (p && *p) {
-                                       int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0;
+                                       int it =
+                                               (strncmp(dev->name, "escon", 5))
+                                               ? 1 : 0;
                                        n = simple_strtoul(p, NULL, 0);
                                        if (n >= cnt[it])
                                                cnt[it] = n + 1;
@@ -3433,7 +3908,7 @@ int ctc_init(void) {
                        } else {
                                if (ctc_no_auto) {
                                        itype = 3;
-                                       kfree(dev);
+                                       ctc_free_netdevice(dev, 1);
                                        dev = NULL;
                                        break;
                                }
@@ -3444,6 +3919,7 @@ int ctc_init(void) {
                        printk(KERN_DEBUG "ctc: %s(): probing for device %s\n",
                                                 __FUNCTION__, dev->name);
 #endif                 
+                       probed = 1;
                        if (ctc_probe(dev) == 0) {
                                ctc_priv *privptr = (ctc_priv *)dev->priv;
 #ifdef DEBUG
@@ -3454,67 +3930,56 @@ int ctc_init(void) {
                                       "ctc: %s(): registering device %s\n",
                                       __FUNCTION__, dev->name);
 #endif
-                               if (privptr->protocol != CTC_PROTO_LINUX_TTY) {
-                                       if (register_netdev(dev) != 0) {
-                                               printk(KERN_WARNING
-                                                      "ctc: Couldn't register netdev %s\n",
-                                                      dev->name);
-                                               free_irq(privptr->channel[READ]->irq,
-                                                        privptr->channel[READ]->devstat);
-                                               free_irq(privptr->channel[WRITE]->irq,
-                                                        privptr->channel[WRITE]->devstat);
-                                               channel_free(privptr->channel[READ]);
-                                               channel_free(privptr->channel[WRITE]);
-                                               kfree(dev->priv);
-                                               kfree(dev);
-                                       } else {
-#ifdef DEBUG
-                                               printk(KERN_DEBUG
-                                                      "ctc: %s(): register succeed\n",
-                                                      __FUNCTION__);
-#endif                 
-                                               activated++;
-                                       }
+                               if (ctc_netdev_register(dev) != 0) {
+                                       printk(KERN_WARNING
+                                              "ctc: Couldn't register %s\n",
+                                              dev->name);
+                                       FREE_IRQ(
+                                               privptr->channel[READ]->irq,
+                                               privptr->channel[READ]->devstat);
+                                       FREE_IRQ(
+                                               privptr->channel[WRITE]->irq,
+                                               privptr->channel[WRITE]->devstat);
+                                       channel_free(privptr->channel[READ]);
+                                       channel_free(privptr->channel[WRITE]);
+                                       ctc_free_netdevice(dev, 1);
+                                       dev = NULL;
                                } else {
-                                       if (ctc_tty_register_netdev(dev) != 0) {
-                                               printk(KERN_WARNING
-                                                      "ctc: Couldn't register ttydev %s\n",
-                                                      dev->name);
-                                               free_irq(privptr->channel[READ]->irq,
-                                                        privptr->channel[READ]->devstat);
-                                               free_irq(privptr->channel[WRITE]->irq,
-                                                        privptr->channel[WRITE]->devstat);
-                                               channel_free(privptr->channel[READ]);
-                                               channel_free(privptr->channel[WRITE]);
-                                               kfree(dev->priv);
-                                               kfree(dev);
-                                       } else {
 #ifdef DEBUG
-                                               printk(KERN_DEBUG
-                                                      "ctc: %s(): register succeed\n",
-                                                      __FUNCTION__);
+                                       printk(KERN_DEBUG
+                                              "ctc: %s(): register succeed\n",
+                                              __FUNCTION__);
 #endif                 
-                                               activated++;
-                                       }
+                                       activated++;
                                }
-                               
                        } else {
 #ifdef DEBUG
                                printk(KERN_DEBUG
                                       "ctc: %s(): probing failed\n",
                                       __FUNCTION__);
 #endif                 
-                               kfree(dev);
                                dev = NULL;
                        }
                } while (dev && (ret == 0));
        }
+#endif /* CHANDEV */
+#if !defined(CTC_CHANDEV) && defined(MODULE)
        if (!activated) {
                printk(KERN_WARNING "ctc: No devices registered\n");
                ret = -ENODEV;
        }
-       if (ret)
-               ctc_tty_cleanup();
+#endif
+       if (ret) {
+               ctc_tty_cleanup(0);
+               ctc_tty_cleanup(1);
+#if defined(CTC_CHANDEV) && defined(MODULE)
+               chandev_unregister(ctc_chandev_probe, 0);
+#endif
+#ifdef MODULE
+               if (probed)
+                       ctc_proc_destroy_main();
+#endif
+       }
        return ret;
 }
 
index 726bda37aeff3fb113aaacbc520132f3cdd840bf..3b9ed0ba1141893ffa6d310921f443d9c284fce1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
 #  include <linux/devfs_fs_kernel.h>
 #endif
 #include "ctctty.h"
-#include <net/dst.h>
+
+#if LINUX_VERSION_CODE < 0x020212
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+       struct wait_queue wait = { current, NULL }
+#define init_waitqueue_head(x) *(x)=NULL
+#define __set_current_state(state_value) \
+       do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value) \
+       do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value) __set_current_state(state_value)
+#endif
+#define init_MUTEX(x) *(x)=MUTEX
+#endif
 
 #define CTC_TTY_MAJOR       43
 #define CTC_TTY_MAX_DEVICES 64
@@ -45,6 +61,8 @@
 #define CTC_ASYNC_CTS_FLOW       0x04000000 /* Do CTS flow control          */
 #define CTC_ASYNC_CHECK_CD       0x02000000 /* i.e., CLOCAL                 */
 #define CTC_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */
+#define CTC_ASYNC_NETDEV_OPEN        0x0002 /* Underlying netdev is open    */
+#define CTC_ASYNC_TX_LINESTAT        0x0004 /* Must send line status        */
 #define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */
 #define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */
 #define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */
 typedef struct {
   int                  magic;
   int                  flags;           /* defined in tty.h               */
-  int                  x_char;          /* xon/xoff character             */
   int                  mcr;             /* Modem control register         */
   int                   msr;             /* Modem status register          */
   int                   lsr;             /* Line status register           */
   int                  line;
   int                  count;           /* # of fd on device              */
   int                  blocked_open;    /* # of blocked opens             */
-       net_device            *netdev;
+  net_device            *netdev;
   struct sk_buff_head   tx_queue;        /* transmit queue                 */
   struct sk_buff_head   rx_queue;        /* receive queue                  */
   struct tty_struct    *tty;            /* Pointer to corresponding tty   */
@@ -69,7 +86,8 @@ typedef struct {
   wait_queue_head_t    open_wait;
   wait_queue_head_t    close_wait;
   struct semaphore      write_sem;
-       struct tq_struct tq;
+  struct tq_struct      tq;
+  struct timer_list     stoptimer;
 } ctc_tty_info;
 
 /* Description of one CTC-tty */
@@ -88,7 +106,7 @@ static ctc_tty_driver *driver;
 #define MODEM_PARANOIA_CHECK
 #define MODEM_DO_RESTART
 
-#define CTC_TTY_NAME "ttyZ"
+#define CTC_TTY_NAME "ctctty"
 
 #ifdef CONFIG_DEVFS_FS
 static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
@@ -96,7 +114,12 @@ static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
 static char *ctc_ttyname = CTC_TTY_NAME;
 #endif
 
-char *ctc_tty_revision = "$Revision: 1.1 $";
+char *ctc_tty_revision = "$Revision: 1.8 $";
+
+static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
+static int ctc_tty_shuttingdown = 0;
+
+static spinlock_t ctc_tty_lock;
 
 /* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
  * to stuff incoming data directly into a tty's flip-buffer. If the
@@ -120,11 +143,11 @@ ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
                        len = skb->len;
                        if (c >= len) {
                                memcpy(tty->flip.char_buf_ptr, skb->data, len);
+                               memset(tty->flip.flag_buf_ptr, 0, len);
                                tty->flip.count += len;
                                tty->flip.char_buf_ptr += len;
-                               memset(tty->flip.flag_buf_ptr, 0, len);
                                tty->flip.flag_buf_ptr += len;
-                               queue_task(&tty->flip.tqueue, &tq_timer);
+                               tty_flip_buffer_push(tty);
                                kfree_skb(skb);
                                return 1;
                        }
@@ -140,7 +163,7 @@ ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
 static int
 ctc_tty_readmodem(ctc_tty_info *info)
 {
-       int ret = 0;
+       int ret = 1;
        struct tty_struct *tty;
 
        if ((tty = info->tty)) {
@@ -152,22 +175,44 @@ ctc_tty_readmodem(ctc_tty_info *info)
                                int len = skb->len;
                                if (len > c)
                                        len = c;
-                               memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len);
-                               tty->flip.count += len;
+                               memcpy(tty->flip.char_buf_ptr, skb->data, len);
+                               skb_pull(skb, len);
                                memset(tty->flip.flag_buf_ptr, 0, len);
+                               tty->flip.count += len;
+                               tty->flip.char_buf_ptr += len;
                                tty->flip.flag_buf_ptr += len;
-                               queue_task(&tty->flip.tqueue, &tq_timer);
-                               if (skb->len) {
+                               tty_flip_buffer_push(tty);
+                               if (skb->len > 0)
                                        skb_queue_head(&info->rx_queue, skb);
-                                       ret = 1;
-                               } else
+                               else {
                                        kfree_skb(skb);
+                                       ret = skb_queue_len(&info->rx_queue);
+                               }
                        }
                }
        }
        return ret;
 }
 
+void
+ctc_tty_setcarrier(net_device *netdev, int on)
+{
+       int i;
+
+       if ((!driver) || ctc_tty_shuttingdown)
+               return;
+       for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+               if (driver->info[i].netdev == netdev) {
+                       ctc_tty_info *info = &driver->info[i];
+                       if (on)
+                               info->msr |= UART_MSR_DCD;
+                       else
+                               info->msr &= ~UART_MSR_DCD;
+                       if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
+                               tty_hangup(info->tty);
+               }
+}
+
 void
 ctc_tty_netif_rx(struct sk_buff *skb)
 {
@@ -176,7 +221,7 @@ ctc_tty_netif_rx(struct sk_buff *skb)
 
        if (!skb)
                return;
-       if (!skb->dev) {
+       if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
                dev_kfree_skb(skb);
                return;
        }
@@ -189,7 +234,35 @@ ctc_tty_netif_rx(struct sk_buff *skb)
                dev_kfree_skb(skb);
                return;
        }
-       skb_pull(skb, sizeof(int));
+       if (skb->len < 6) {
+               dev_kfree_skb(skb);
+               return;
+       }
+       if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
+               dev_kfree_skb(skb);
+               return;
+       }
+       skb_pull(skb, sizeof(__u32));
+
+       i = *((int *)skb->data);
+       skb_pull(skb, sizeof(info->mcr));
+       if (i & UART_MCR_RTS) {
+               info->msr |= UART_MSR_CTS;
+               if (info->flags & CTC_ASYNC_CTS_FLOW)
+                       info->tty->hw_stopped = 0;
+       } else {
+               info->msr &= ~UART_MSR_CTS;
+               if (info->flags & CTC_ASYNC_CTS_FLOW)
+                       info->tty->hw_stopped = 1;
+       }
+       if (i & UART_MCR_DTR)
+               info->msr |= UART_MSR_DSR;
+       else
+               info->msr &= ~UART_MSR_DSR;
+       if (skb->len <= 0) {
+               kfree_skb(skb);
+               return;
+       }
        /* Try to deliver directly via tty-flip-buf if queue is empty */
        if (skb_queue_empty(&info->rx_queue))
                if (ctc_tty_try_read(info, skb))
@@ -203,46 +276,70 @@ ctc_tty_netif_rx(struct sk_buff *skb)
        mark_bh(IMMEDIATE_BH);
 }
 
-static void
-ctc_tty_dstfail(struct sk_buff *skb) {
-       if (!skb)
-               return;
-       dev_kfree_skb(skb);
-       return;
-}
-
-static struct dst_entry dst_e;
-static struct dst_ops   dst_o;
-
 static int
 ctc_tty_tint(ctc_tty_info * info)
 {
        struct sk_buff *skb = skb_dequeue(&info->tx_queue);
+       int stopped = (info->tty->hw_stopped || info->tty->stopped);
+       int wake = 1;
        int rc;
-       int l;
-       char c;
 
-       if (!skb)
-               return 0;
        if (!info->netdev) {
-               kfree(skb);
+               if (skb)
+                       kfree(skb);
                return 0;
        }
-       skb->dst = &dst_e;
-       l = skb->len;
-       c = *(skb->data);
-       rc = info->netdev->hard_start_xmit(skb, info->netdev);
-printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c);
-       if (rc) {
+       if (info->flags & CTC_ASYNC_TX_LINESTAT) {
+               int skb_res = info->netdev->hard_header_len +
+                       sizeof(info->mcr) + sizeof(__u32);
+               /* If we must update line status,
+                * create an empty dummy skb and insert it.
+                */
+               if (skb)
+                       skb_queue_head(&info->tx_queue, skb);
+
+               skb = dev_alloc_skb(skb_res);
+               if (!skb) {
+                       printk(KERN_WARNING
+                              "ctc_tty: Out of memory in %s%d tint\n",
+                              CTC_TTY_NAME, info->line);
+                       return 1;
+               }
+               skb_reserve(skb, skb_res);
+               stopped = 0;
+               wake = 0;
+       }
+       if (!skb)
+               return 0;
+       if (stopped) {
                skb_queue_head(&info->tx_queue, skb);
                return 1;
+       }
+#if 0
+       if (skb->len > 0)
+               printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
+       else
+               printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
+#endif
+       memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
+       memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
+       rc = info->netdev->hard_start_xmit(skb, info->netdev);
+       if (rc) {
+               skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
+               if (skb->len > 0)
+                       skb_queue_head(&info->tx_queue, skb);
+               else
+                       kfree_skb(skb);
        } else {
                struct tty_struct *tty = info->tty;
-               info->lsr |= UART_LSR_TEMT;
-               if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-                   tty->ldisc.write_wakeup)
-                       (tty->ldisc.write_wakeup)(tty);
-               wake_up_interruptible(&tty->write_wait);
+
+               info->flags &= ~CTC_ASYNC_TX_LINESTAT;
+               if (tty) {
+                       if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+                           tty->ldisc.write_wakeup)
+                               (tty->ldisc.write_wakeup)(tty);
+                       wake_up_interruptible(&tty->write_wait);
+               }
        }
        return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
 }
@@ -273,6 +370,40 @@ ctc_tty_paranoia_check(ctc_tty_info * info, kdev_t device, const char *routine)
        return 0;
 }
 
+static void
+ctc_tty_inject(ctc_tty_info *info, char c)
+{
+       int skb_res;
+       struct sk_buff *skb;
+       
+       if (ctc_tty_shuttingdown)
+               return;
+       skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+               sizeof(__u32) + 1;
+       skb = dev_alloc_skb(skb_res);
+       if (!skb) {
+               printk(KERN_WARNING
+                      "ctc_tty: Out of memory in %s%d tx_inject\n",
+                      CTC_TTY_NAME, info->line);
+               return;
+       }
+       skb_reserve(skb, skb_res);
+       *(skb_put(skb, 1)) = c;
+       skb_queue_head(&info->tx_queue, skb);
+       queue_task(&info->tq, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
+static void
+ctc_tty_transmit_status(ctc_tty_info *info)
+{
+       if (ctc_tty_shuttingdown)
+               return;
+       info->flags |= CTC_ASYNC_TX_LINESTAT;
+       queue_task(&info->tq, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
+}
+
 static void
 ctc_tty_change_speed(ctc_tty_info * info)
 {
@@ -294,8 +425,12 @@ ctc_tty_change_speed(ctc_tty_info * info)
        }
        if (quot) {
                info->mcr |= UART_MCR_DTR;
+               info->mcr |= UART_MCR_RTS;
+               ctc_tty_transmit_status(info);
        } else {
                info->mcr &= ~UART_MCR_DTR;
+               info->mcr &= ~UART_MCR_RTS;
+               ctc_tty_transmit_status(info);
                return;
        }
 
@@ -331,11 +466,24 @@ ctc_tty_startup(ctc_tty_info * info)
        ctc_tty_change_speed(info);
 
        info->flags |= CTC_ASYNC_INITIALIZED;
-       info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
-       info->netdev->open(info->netdev);
+       if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
+               info->netdev->open(info->netdev);
+       info->flags |= CTC_ASYNC_NETDEV_OPEN;
        return 0;
 }
 
+static void
+ctc_tty_stopdev(unsigned long data)
+{
+       ctc_tty_info *info = (ctc_tty_info *)data;
+
+       if ((!info) || (!info->netdev) ||
+           (info->flags & CTC_ASYNC_INITIALIZED))
+               return;
+       info->netdev->stop(info->netdev);
+       info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
+}
+
 /*
  * This routine will shutdown a serial port; interrupts are disabled, and
  * DTR is dropped if the hangup on close termio flag is on.
@@ -349,12 +497,11 @@ ctc_tty_shutdown(ctc_tty_info * info)
        printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
 #endif
        info->msr &= ~UART_MSR_RI;
-       if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+       if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
                info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
-       }
        if (info->tty)
                set_bit(TTY_IO_ERROR, &info->tty->flags);
-       info->netdev->stop(info->netdev);
+       mod_timer(&info->stoptimer, jiffies + (10 * HZ));
        skb_queue_purge(&info->tx_queue);
        skb_queue_purge(&info->rx_queue);
        info->flags &= ~CTC_ASYNC_INITIALIZED;
@@ -376,6 +523,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
        int total = 0;
        ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 
+       if (ctc_tty_shuttingdown)
+               return 0;
        if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
                return 0;
        if (!tty)
@@ -392,7 +541,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
                if (c <= 0)
                        break;
                
-               skb_res = info->netdev->hard_header_len + sizeof(int);
+               skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+                       + sizeof(__u32);
                skb = dev_alloc_skb(skb_res + c);
                if (!skb) {
                        printk(KERN_WARNING
@@ -411,6 +561,7 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
                count -= c;
        }
        if (skb_queue_len(&info->tx_queue)) {
+               info->lsr &= ~UART_LSR_TEMT;
                queue_task(&info->tq, &tq_immediate);
                mark_bh(IMMEDIATE_BH);
        }
@@ -457,6 +608,7 @@ ctc_tty_flush_buffer(struct tty_struct *tty)
                return;
        }
        skb_queue_purge(&info->tx_queue);
+       info->lsr |= UART_LSR_TEMT;
        restore_flags(flags);
        wake_up_interruptible(&tty->write_wait);
        if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -469,12 +621,14 @@ ctc_tty_flush_chars(struct tty_struct *tty)
 {
        ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
 
+       if (ctc_tty_shuttingdown)
+               return;
        if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
                return;
-       if (skb_queue_len(&info->tx_queue)) {
-               queue_task(&info->tq, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
-       }
+       if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+               return;
+       queue_task(&info->tq, &tq_immediate);
+       mark_bh(IMMEDIATE_BH);
 }
 
 /*
@@ -492,9 +646,10 @@ ctc_tty_throttle(struct tty_struct *tty)
 
        if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle"))
                return;
-       if (I_IXOFF(tty))
-               info->x_char = STOP_CHAR(tty);
        info->mcr &= ~UART_MCR_RTS;
+       if (I_IXOFF(tty))
+               ctc_tty_inject(info, STOP_CHAR(tty));
+       ctc_tty_transmit_status(info);
 }
 
 static void
@@ -504,13 +659,10 @@ ctc_tty_unthrottle(struct tty_struct *tty)
 
        if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
                return;
-       if (I_IXOFF(tty)) {
-               if (info->x_char)
-                       info->x_char = 0;
-               else
-                       info->x_char = START_CHAR(tty);
-       }
        info->mcr |= UART_MCR_RTS;
+       if (I_IXOFF(tty))
+               ctc_tty_inject(info, START_CHAR(tty));
+       ctc_tty_transmit_status(info);
 }
 
 /*
@@ -573,6 +725,7 @@ static int
 ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
 {
        uint arg;
+       int old_mcr = info->mcr & (UART_MCR_RTS | UART_MCR_DTR);
 
        get_user(arg, (uint *) value);
        switch (cmd) {
@@ -581,24 +734,20 @@ ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
                        printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
                               info->line);
 #endif
-                       if (arg & TIOCM_RTS) {
+                       if (arg & TIOCM_RTS)
                                info->mcr |= UART_MCR_RTS;
-                       }
-                       if (arg & TIOCM_DTR) {
+                       if (arg & TIOCM_DTR)
                                info->mcr |= UART_MCR_DTR;
-                       }
                        break;
                case TIOCMBIC:
 #ifdef CTC_DEBUG_MODEM_IOCTL
                        printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
                               info->line);
 #endif
-                       if (arg & TIOCM_RTS) {
+                       if (arg & TIOCM_RTS)
                                info->mcr &= ~UART_MCR_RTS;
-                       }
-                       if (arg & TIOCM_DTR) {
+                       if (arg & TIOCM_DTR)
                                info->mcr &= ~UART_MCR_DTR;
-                       }
                        break;
                case TIOCMSET:
 #ifdef CTC_DEBUG_MODEM_IOCTL
@@ -612,6 +761,8 @@ ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
                default:
                        return -EINVAL;
        }
+       if ((info->mcr  & (UART_MCR_RTS | UART_MCR_DTR)) != old_mcr)
+               ctc_tty_transmit_status(info);
        return 0;
 }
 
@@ -709,18 +860,30 @@ static void
 ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
 {
        ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+       unsigned int cflag = tty->termios->c_cflag;
 
-       if (!old_termios)
-               ctc_tty_change_speed(info);
-       else {
-               if (tty->termios->c_cflag == old_termios->c_cflag)
-                       return;
-               ctc_tty_change_speed(info);
-               if ((old_termios->c_cflag & CRTSCTS) &&
-                   !(tty->termios->c_cflag & CRTSCTS)) {
-                       tty->hw_stopped = 0;
-               }
+       ctc_tty_change_speed(info);
+
+       /* Handle transition to B0 */
+       if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
+               info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
+               ctc_tty_transmit_status(info);
+       }
+
+       /* Handle transition from B0 to other */
+       if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+               info->mcr |= UART_MCR_DTR;
+               if (!(tty->termios->c_cflag & CRTSCTS) ||
+                    !test_bit(TTY_THROTTLED, &tty->flags)) {
+                        info->mcr |= UART_MCR_RTS;
+                }
+               ctc_tty_transmit_status(info);
        }
+
+       /* Handle turning off CRTSCTS */
+       if ((old_termios->c_cflag & CRTSCTS) &&
+            !(tty->termios->c_cflag & CRTSCTS))
+                tty->hw_stopped = 0;
 }
 
 /*
@@ -836,6 +999,7 @@ static int
 ctc_tty_open(struct tty_struct *tty, struct file *filp)
 {
        ctc_tty_info *info;
+       unsigned long saveflags;
        int retval,
         line;
 
@@ -851,9 +1015,11 @@ ctc_tty_open(struct tty_struct *tty, struct file *filp)
        printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
               info->line, info->count);
 #endif
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
        info->count++;
        tty->driver_data = info;
        info->tty = tty;
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
        /*
         * Start up serial port
         */
@@ -885,6 +1051,7 @@ static void
 ctc_tty_close(struct tty_struct *tty, struct file *filp)
 {
        ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+       unsigned long saveflags;
        ulong flags;
        ulong timeout;
 
@@ -958,7 +1125,9 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
                tty->driver.flush_buffer(tty);
        if (tty->ldisc.flush_buffer)
                tty->ldisc.flush_buffer(tty);
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
        info->tty = 0;
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
        tty->closing = 0;
        if (info->blocked_open) {
                set_current_state(TASK_INTERRUPTIBLE);
@@ -980,13 +1149,16 @@ static void
 ctc_tty_hangup(struct tty_struct *tty)
 {
        ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
+       unsigned long saveflags;
 
        if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
                return;
        ctc_tty_shutdown(info);
        info->count = 0;
        info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
        info->tty = 0;
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
        wake_up_interruptible(&info->open_wait);
 }
 
@@ -998,14 +1170,21 @@ ctc_tty_hangup(struct tty_struct *tty)
 static void
 ctc_tty_task(ctc_tty_info *info)
 {
+       unsigned long saveflags;
        int again;
 
-       again = ctc_tty_tint(info);
-       again |= ctc_tty_readmodem(info);
-       if (again) {
-               queue_task(&info->tq, &tq_immediate);
-               mark_bh(IMMEDIATE_BH);
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
+       if ((!ctc_tty_shuttingdown) && info) {
+               again = ctc_tty_tint(info);
+               if (!again)
+                       info->lsr |= UART_LSR_TEMT;
+               again |= ctc_tty_readmodem(info);
+               if (again) {
+                       queue_task(&info->tq, &tq_immediate);
+                       mark_bh(IMMEDIATE_BH);
+               }
        }
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
 
 int
@@ -1015,8 +1194,6 @@ ctc_tty_init(void)
        ctc_tty_info *info;
        struct tty_driver *device;
 
-       dst_e.ops = &dst_o;
-       dst_o.link_failure = ctc_tty_dstfail;
        driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
        if (driver == NULL) {
                printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
@@ -1064,14 +1241,17 @@ ctc_tty_init(void)
        for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
                info = &driver->info[i];
                init_MUTEX(&info->write_sem);
+#if LINUX_VERSION_CODE >= 0x020400
                INIT_LIST_HEAD(&info->tq.list);
+#else
+               info->tq.next    = NULL;
+#endif
                info->tq.sync    = 0;
                info->tq.routine = (void *)(void *)ctc_tty_task;
                info->tq.data    = info;
                info->magic = CTC_ASYNC_MAGIC;
                info->line = i;
                info->tty = 0;
-               info->x_char = 0;
                info->count = 0;
                info->blocked_open = 0;
                info->normal_termios = device->init_termios;
@@ -1079,6 +1259,10 @@ ctc_tty_init(void)
                init_waitqueue_head(&info->close_wait);
                skb_queue_head_init(&info->tx_queue);
                skb_queue_head_init(&info->rx_queue);
+               init_timer(&info->stoptimer);
+               info->stoptimer.function = ctc_tty_stopdev;
+               info->stoptimer.data = (unsigned long)info;
+               info->mcr = UART_MCR_RTS;
        }
        return 0;
 }
@@ -1118,8 +1302,10 @@ ctc_tty_register_netdev(net_device *dev) {
 void
 ctc_tty_unregister_netdev(net_device *dev) {
        int i;
+       unsigned long saveflags;
        ctc_tty_info *info = NULL;
 
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
        for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
                if (driver->info[i].netdev == dev) {
                        info = &driver->info[i];
@@ -1130,10 +1316,24 @@ ctc_tty_unregister_netdev(net_device *dev) {
                skb_queue_purge(&info->tx_queue);
                skb_queue_purge(&info->rx_queue);
        }
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
 
 void
-ctc_tty_cleanup(void) {
-       tty_unregister_driver(&driver->ctc_tty_device);
-       kfree(driver);
+ctc_tty_cleanup(int final) {
+       unsigned long saveflags;
+       
+       spin_lock_irqsave(&ctc_tty_lock, saveflags);
+       ctc_tty_shuttingdown = 1;
+       if (final) {
+               kfree(driver);
+               driver = NULL;
+       } else {
+               int i;
+
+               for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+                       driver->info[i].tq.routine = NULL;
+               tty_unregister_driver(&driver->ctc_tty_device);
+       }
+       spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
 }
index b2ce33ef1f0ca64f278127d95e7611edb30018d6..55d888100bb2221de3eb786cb3d8e6ae6fdeff90 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $
+ * $Id: ctctty.h,v 1.4 2001/03/22 12:46:01 felfert Exp $
  *
  * CTC / ESCON network driver, tty interface.
  *
@@ -34,10 +34,11 @@ typedef struct device      net_device;
 typedef struct net_device  net_device;
 #endif
 
-extern int  ctc_tty_register_netdev(net_device *dev);
-extern void ctc_tty_unregister_netdev(net_device *dev);
-extern void ctc_tty_netif_rx(struct sk_buff *skb);
+extern int  ctc_tty_register_netdev(net_device *);
+extern void ctc_tty_unregister_netdev(net_device *);
+extern void ctc_tty_netif_rx(struct sk_buff *);
 extern int  ctc_tty_init(void);
-extern void ctc_tty_cleanup(void);
+extern void ctc_tty_cleanup(int);
+extern void ctc_tty_setcarrier(net_device *, int);
 
 #endif
index b519d194b9abd0aa73e98410f8e96e9621c70b8f..8ae653af2d70302569c6a4e320c0c5d19949200a 100644 (file)
@@ -1,23 +1,14 @@
 /**
- * $Id: fsm.c,v 1.1 2000/11/30 11:21:08 bird Exp $
+ * $Id: fsm.c,v 1.3 2001/06/18 16:49:19 felfert Exp $
  *
  * A generic FSM based on fsm used in isdn4linux
  *
- * $Log: fsm.c,v $
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
- *
- * Revision 1.2  2000/11/10 17:25:11  felfert
- * Changes for kernel 2.4
- *
- * Revision 1.1  2000/11/03 16:58:45  felfert
- * Initial import
- *
- *
  */
 
 #include "fsm.h"
 #include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
 
 fsm_instance *
 init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
@@ -228,3 +219,16 @@ fsm_modtimer(fsm_timer *this, int millisec, int event, void *arg)
        this->tl.expires = jiffies + (millisec * HZ) / 1000;
        add_timer(&this->tl);
 }
+
+EXPORT_SYMBOL(init_fsm);
+EXPORT_SYMBOL(kfree_fsm);
+EXPORT_SYMBOL(fsm_settimer);
+EXPORT_SYMBOL(fsm_deltimer);
+EXPORT_SYMBOL(fsm_addtimer);
+EXPORT_SYMBOL(fsm_modtimer);
+EXPORT_SYMBOL(fsm_getstate_str);
+
+#if FSM_DEBUG_HISTORY
+EXPORT_SYMBOL(fsm_print_history);
+EXPORT_SYMBOL(fsm_record_history);
+#endif
index a436eddd7cb922a0e4871a29ebf2da0358c39bdc..c4fa9412f4a9cd524872a04428d967a1f7bc6a97 100644 (file)
@@ -1,13 +1,4 @@
-/* $Id: fsm.h,v 1.1 2000/11/30 11:21:08 bird Exp $
- *
- * $Log: fsm.h,v $
- * Revision 1.1  2000/11/30 11:21:08  bird
- * Support for new ctc driver
- *
- * Revision 1.1  2000/11/03 16:58:45  felfert
- * Initial import
- *
- *
+/* $Id: fsm.h,v 1.3 2001/06/18 16:49:19 felfert Exp $
  */
 #ifndef _FSM_H_
 #define _FSM_H_
@@ -16,7 +7,7 @@
 #include <linux/types.h>
 #include <linux/timer.h>
 #include <linux/time.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <asm/atomic.h>
@@ -115,10 +106,11 @@ typedef struct {
  * @param tmpl_len    Length of the describing array.
  * @param order       Parameter for allocation of the FSM data structs.
  */
-fsm_instance * init_fsm(char *name, const char **state_names,
-                       const char **event_names,
-                       int nr_states, int nr_events, const fsm_node *tmpl,
-                       int tmpl_len, int order);
+extern fsm_instance *
+init_fsm(char *name, const char **state_names,
+        const char **event_names,
+        int nr_states, int nr_events, const fsm_node *tmpl,
+        int tmpl_len, int order);
 
 /**
  * Releases an FSM
index 486cb22384e6a2659569fd612630dae2bcd8404c..4f1caa5210eb0756d5cf0d4e8ec7cf8185ecffe8 100644 (file)
@@ -1,15 +1,30 @@
-/*
- *  drivers/s390/net/iucv.c
+/*                                                                                             
+ *   drivers/s390/net/iucv.c
  *    Support for VM IUCV functions for use by other part of the
  *    kernel or loadable modules.
  *
  *  S390 version
  *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
- *               Alan Altmark (Alan_Altmark@us.ibm.com)
- */
-
+ *    Author(s): Alan Altmark (Alan_Altmark@us.ibm.com)
+ *               Xenia Tkatschow (xenia@us.ibm.com)
+ * Functionality:                                                    
+ * To explore any of the IUCV functions, one must first register     
+ * their program using iucv_register(). Once your program has        
+ * successfully completed a register, it can use the other functions.
+ * For furthur reference on all IUCV functionality, refer to the     
+ * CP Programming Services book, also available on the web            
+ * thru www.ibm.com/s390/vm/pubs , manual # SC24-5760.               
+ *                                                                    
+ *      Definition of Return Codes                                    
+ *      -All positive return codes including zero are reflected back 
+ *       from CP and the definition can be found in CP Programming    
+ *       Services book.                  
+ *      - (-ENOMEM) Out of memory
+ *      - (-EINVAL) Invalid value                             
+*/
+/* #define DEBUG 1 */
 #include <linux/module.h>
+#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/spinlock.h>
 #include <linux/kernel.h>
 #include <asm/atomic.h>
 #include "iucv.h"
 #include <asm/io.h>
+#include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/ebcdic.h>
 
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifdef DEBUG
+#undef KERN_INFO
 #undef KERN_DEBUG
+#define KERN_INFO KERN_EMERG
 #define KERN_DEBUG KERN_EMERG
-//#define DEBUG3
-//#define DEBUG         /* Turns Printk's on                         */
-//#define DEBUG2        /* This prints the parameter list before and */
-                     /* after the b2f0 call to cp                 */
+#endif
+
 #undef NULL
 #define NULL 0
-#define ADDED_STOR 64          /* ADDITIONAL STORAGE FOR PATHID @'S */
-ulong declare_flag = 0;
+
+#define PRRTY_PRMTD    0x01    /* priority permitted */
+#define RPY_RQRD       0x01    /* reply required */
+#define ADDED_STOR  64         /* ADDITIONAL STORAGE FOR PATHID @'S */
+#define BUFFER_SIZE 40         /* Size of 31-bit iparml */
+
+/* FLAGS:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPSRCCLS - Indicates you have specified a source class
+ * IPFGMCL  - Indicates you have specified a target class
+ * IPFGPID  - Indicates you have specified a pathid
+ * IPFGMID  - Indicates you have specified a message ID
+ * IPANSLST - Indicates that you are using an address list for
+ *            reply data
+ * IPBUFLST - Indicates that you are using an address list for
+ *            message data
+ */
+
+#define IPSRCCLS       0x01
+#define IPFGMCL         0x01
+#define IPFGPID         0x02
+#define IPFGMID         0x04
+#define IPANSLST        0x08
+#define IPBUFLST        0x40
+
 static uchar iucv_external_int_buffer[40];
+
+/* Spin Lock declaration */
 struct tq_struct short_task;   /* automatically initialized to zero */
-static iucv_interrupt_ops_t my_ops;
-spinlock_t lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;
 
-static void do_int (iucv_ConnectionPending *);
+/* General IUCV interrupt structure */
+typedef struct {
+       u16 ippathid;
+       uchar res1;
+       uchar iptype;
+       u32 res2;
+       uchar ipvmid[8];
+       uchar res3[24];
+} iucv_GeneralInterrupt;
 
 /***************INTERRUPT HANDLING DEFINITIONS***************/
 typedef struct _iucv_packet {
@@ -46,1984 +103,2323 @@ typedef struct _iucv_packet {
        uchar data[40];
 } iucv_packet;
 struct tq_struct short_task;
+
 static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
+
 iucv_packet *iucv_packets_head, *iucv_packets_tail;
 
 static atomic_t bh_scheduled = ATOMIC_INIT (0);
+
+/* 
+ *Internal function prototypes 
+ */
+
+static ulong iucv_vmsize (void);
+
+int iucv_declare_buffer (void);
+
+int iucv_retrieve_buffer (void);
+
+static int iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data);
+
+static void iucv_remove_pathid (u16 pathid);
+
 void bottom_half_interrupt (void);
 
+static void do_int (iucv_GeneralInterrupt *);
+
+inline void top_half_interrupt (struct pt_regs *regs, __u16 code);
 /************FUNCTION ID'S****************************/
-#define accept          10
-#define connect         11
-#define declare_buffer  12
-#define purge           9
-#define query           0
-#define quiesc          13
-#define receive         5
-#define reject          8
-#define reply           6
-#define resume          14
-#define retrieve_buffer 2
-#define send            4
-#define setmask         16
-#define sever           15
-
-/*****************************************************************/
-/*  Structure: handler                                           */
-/*  members: next - is a pointer to next handler on chain        */
-/*           prev - is a pointer to prev handler on chain        */
-/*           vmid - 8 char array of machine identification       */
-/*           user_data - 16 char array for user identification   */
-/*           mask - 24 char array used to compare the 2 previous */
-/*           interrupt_table - functions for interrupts          */
-/*           start - pointer to start of block of pointers to    */
-/*                   handler_table_entries                       */
-/*           end - pointer to end of block of pointers to        */
-/*                 handler_table_entries                         */
-/*           size - ulong, size of block                         */
-/*           pgm_data - ulong, program data                      */
-/* NOTE: Keep vmid and user_data together in this order          */
-/*****************************************************************/
+
+#define ACCEPT          10
+#define CONNECT         11
+#define DECLARE_BUFFER  12
+#define PURGE           9
+#define QUERY           0
+#define QUIESCE         13
+#define RECEIVE         5
+#define REJECT          8
+#define REPLY           6
+#define RESUME          14
+#define RETRIEVE_BUFFER 2
+#define SEND            4
+#define SETMASK         16
+#define SEVER           15
+
+/*                                                               
+ * Structure: handler                                            
+ * members: next - is a pointer to next handler on chain         
+ *          prev - is a pointer to prev handler on chain         
+ *          structure: id                                        
+ *             vmid - 8 char array of machine identification     
+ *             user_data - 16 char array for user identification 
+ *             mask - 24 char array used to compare the 2 previous  
+ *          interrupt_table - vector of interrupt functions.     
+ *          pathid_head - pointer to start of user_pathid_table  
+ *          pathid_tail - pointer to end of user_pathid_table    
+ *          entries -  ulong, size of user_pathid_table          
+ *          pgm_data -  ulong, application data that is passed   
+ *                      to the interrupt handlers                
+*/
 typedef struct {
        ulong *next;
        ulong *prev;
-       uchar vmid[8];
-       uchar user_data[16];
-       uchar mask[24];
+       struct {
+               uchar userid[8];
+               uchar user_data[16];
+               uchar mask[24];
+       } id;
        iucv_interrupt_ops_t *interrupt_table;
-       ulong *start;
-       ulong *end;
-       ulong size;
-       ulong pgm_data;
+       ulong *pathid_head;
+       ulong *pathid_tail;
+       ulong entries;
+       void *pgm_data;
 } handler;
 
-/*******************************************************************/
-/* Structure: handler_table_entry                                  */
-/* members: addrs - pointer to a handler                           */
-/*          pathid - ushort containing path identification         */
-/*          pgm_data - ulong, program data                         */
-/*******************************************************************/
+/*                                                         
+ * Structure: handler_table_entry                          
+ * members: addrs - pointer to a handler                   
+ *          pathid - ushort containing path identification 
+ *          pgm_data - ulong, application data that is     
+ *                     passed to the interrupt handlers    
+ *          ops - pointer to iucv interrupt vector         
+ */
+
 typedef struct {
        handler *addrs;
-       ushort pathid;
-       ulong pgm_data;
+       u16 pathid;
+       void *pgm_data;
+       iucv_interrupt_ops_t *ops;
 } handler_table_entry;
 
-/* main_table: array of pointers to handler_tables         */
-static handler_table_entry *main_table[128];
-/* handler_anchor: points to first handler on chain        */
-static handler *handler_anchor;
-
-/****************FIVE  STRUCTURES************************************/
-/* Data struct 1: iparml_control                                    */
-/*                Used for iucv_accept                              */
-/*                         iucv_connect                             */
-/*                         iucv_quiesce                             */
-/*                         iucv_resume                              */
-/*                         iucv_sever                               */
-/*                         iucv_retrieve_buffer                     */
-/* Data struct 2: iparml_dpl  (data in parameter list)              */
-/*                Used for iucv_send_prmmsg                         */
-/*                         iucv_send2way_prmmsg                     */
-/*                         iucv_send2way_prmmsg_array               */
-/*                         iucv_reply_prmmsg                        */
-/* Data struct 3: iparml_db    (data in a buffer)                   */
-/*                Used for iucv_receive                             */
-/*                         iucv_receive_array                       */
-/*                         iucv_receive_simple                      */
-/*                         iucv_reject                              */
-/*                         iucv_reply                               */
-/*                         iucv_reply_array                         */
-/*                         iucv_send                                */
-/*                         iucv_send_simple                         */
-/*                         iucv_send_array                          */
-/*                         iucv_send2way                            */
-/*                         iucv_send2way_array                      */
-/*                         iucv_declare_buffer                      */
-/* Data struct 4: iparml_purge                                      */
-/*                Used for iucv_purge                               */
-/*                         iucv_query                               */
-/* Data struct 5: iparml_set_mask                                   */
-/*                Used for iucv_set_mask                            */
-/********************************************************************/
+/* 
+ * Internal function prototypes 
+ */
+
+static int iucv_add_handler (handler * new_handler);
+
+static void iucv_remove_handler (handler * users_handler);
+
+/* handler_anchor: points to first handler on chain */
+/* handler_tail: points to last handler on chain */
+/* handler_table_anchor: points to beginning of handler_table_entries*/
+
+static handler *handler_anchor = NULL;
+
+static handler *handler_tail = NULL;
+
+static handler_table_entry *handler_table_anchor = NULL;
+
+/* declare_flag: is 0 when iucv_declare_buffer has not been called */
+
+static ulong declare_flag = 0;
+
+/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
+/* Data struct 1: iparml_control                                      
+ * Used for iucv_accept                                               
+ *          iucv_connect                                              
+ *          iucv_quiesce                                              
+ *          iucv_resume                                               
+ *          iucv_sever                                                
+ *          iucv_retrieve_buffer                                      
+ * Data struct 2: iparml_dpl     (data in parameter list)             
+ * Used for iucv_send_prmmsg                                          
+ *          iucv_send2way_prmmsg                                      
+ *          iucv_send2way_prmmsg_array                                
+ *          iucv_reply_prmmsg                                         
+ * Data struct 3: iparml_db       (data in a buffer)                  
+ * Used for iucv_receive                                              
+ *          iucv_receive_array                                        
+ *          iucv_reject                                               
+ *          iucv_reply                                                
+ *          iucv_reply_array                
+ *          iucv_send                       
+ *          iucv_send_array                 
+ *          iucv_send2way                   
+ *          iucv_send2way_array             
+ *          iucv_declare_buffer             
+ * Data struct 4: iparml_purge              
+ * Used for iucv_purge                      
+ *          iucv_query                      
+ * Data struct 5: iparml_set_mask           
+ * Used for iucv_set_mask                   
+*/
+
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iprcode;
-       ushort ipmsglim;
-       ushort res1;
+       u16 ipmsglim;
+       u16 res1;
        uchar ipvmid[8];
        uchar ipuser[16];
        uchar iptarget[8];
 } iparml_control;
 
-/******************/
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iprcode;
-       ulong ipmsgid;
-       ulong iptrgcls;
+       u32 ipmsgid;
+       u32 iptrgcls;
        uchar iprmmsg[8];
-       ulong ipsrccls;
-       ulong ipmsgtag;
-       ulong ipbfadr2;
-       ulong ipbfln2f;
-       ulong res;
+       u32 ipsrccls;
+       u32 ipmsgtag;
+       u32 ipbfadr2;
+       u32 ipbfln2f;
+       u32 res;
 } iparml_dpl;
 
-/*******************/
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iprcode;
-       ulong ipmsgid;
-       ulong iptrgcls;
-       ulong ipbfadr1;
-       ulong ipbfln1f;
-       ulong ipsrccls;
-       ulong ipmsgtag;
-       ulong ipbfadr2;
-       ulong ipbfln2f;
-       ulong res;
+       u32 ipmsgid;
+       u32 iptrgcls;
+       u32 ipbfadr1;
+       u32 ipbfln1f;
+       u32 ipsrccls;
+       u32 ipmsgtag;
+       u32 ipbfadr2;
+       u32 ipbfln2f;
+       u32 res;
 } iparml_db;
 
-/********************/
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iprcode;
-       ulong ipmsgid;
-       uchar ipaudit[4];
-       uchar res1[4];
-       ulong res2;
-       ulong ipsrccls;
-       ulong ipmsgtag;
-       ulong res3[3];
+       u32 ipmsgid;
+       uchar ipaudit[3];
+       uchar res1[5];
+       u32 res2;
+       u32 ipsrccls;
+       u32 ipmsgtag;
+       u32 res3[3];
 } iparml_purge;
 
-/*******************/
 typedef struct {
        uchar ipmask;
        uchar res1[2];
        uchar iprcode;
-       ulong res2[9];
+       u32 res2[9];
 } iparml_set_mask;
 
 /*********************INTERNAL FUNCTIONS*****************************/
-/********************************************************************/
-/* Name: b2f0                                                       */
-/* Purpose: this function calls cp to execute iucv commands.        */
-/* Input: code - int, identifier of iucv call to cp.                */
-/*        parm - void *, pointer to 40 byte iparml area passed to cp */
-/* Output: iprcode- return code from iucv call to cp                */
-/********************************************************************/
-/* Assembler code performing iucv call                             */
-/*******************************************************************/
-inline ulong
-b2f0 (int code, void *parm)
+
+static ulong
+iucv_vmsize (void)
+{
+       extern unsigned long memory_size;
+       return memory_size;
+}
+
+/*
+ * Name: dumpit                                                     
+ * Purpose: print to the console buffers of a given length          
+ * Input: buf - (* uchar) - pointer to buffer to be printed         
+ *        len - int - length of buffer being printed                
+ * Output: void                                                     
+ */
+
+#ifdef DEBUG
+
+static void
+iucv_dumpit (uchar * buf, int len)
 {
-       uchar *iprcode;         /* used to extract iprcode */
-#ifdef DEBUG2
        int i;
-       uchar *prt_parm;
-       prt_parm = (uchar *) (parm);
-       printk (KERN_DEBUG "parameter list before b2f0 call\n");
-       for (i = 0; i < 40; i++)
-               printk (KERN_DEBUG "%02x ", prt_parm[i]);
-       printk (KERN_DEBUG "\n");
-#endif
-       asm volatile ("LRA   1,0(%1)\n\t"
-                     "LR    0,%0\n\t"
-                     ".long 0xb2f01000"
-                     : : "d" (code), "a" (parm) : "0", "1");
-#ifdef DEBUG2
-       printk (KERN_DEBUG "parameter list after b2f0 call\n");
-       for (i = 0; i < 40; i++)
-               printk (KERN_DEBUG "%02x ", prt_parm[i]);
-       printk (KERN_DEBUG "\n");
-#endif
-       iprcode = (uchar *) (parm + 3);
-       return (ulong) (*iprcode);
+       for (i = 0; i < len; i++) {
+               if (!(i % 16) && i != 0)
+                       printk ("\n");
+               else if (!(i % 4) && i != 0)
+                       printk (" ");
+               printk ("%02X", buf[i]);
+       }
+       if (len % 16)
+               printk ("\n");
+       return;
 }
 
-/**************************************************************/
-/* Name: iucv_retrieve_buffer                                 */
-/* Purpose: terminates all use of iucv                        */
-/* Input: void                                                */
-/* Output: Return code from CP                                */
-/**************************************************************/
-int
-iucv_retrieve_buffer (void)
+#else
+static void
+iucv_dumpit (uchar * buf, int len)
 {
-       iparml_control parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_retrieve_buffer\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       b2f0_result = b2f0 (retrieve_buffer, &parm);
-       if (b2f0_result == NULL)
-               declare_flag = 0;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n");
-#endif
-       return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_declare_buffer                                  */
-/* Purpose: specifies the guests real address of an external  */
-/*          interrupt.                                        */
-/* Input: bfr - pointer to  buffer                            */
-/* Output: iprcode - return code from b2f0 call               */
-/* Note : See output options for b2f0 call                    */
-/**************************************************************/
+#endif
+
+/*
+ * Name iucv_add_handler
+ * Purpose: Place new handle on handler_anchor chain, if identical handler is not
+ *         found. Handlers are ordered with largest mask integer value first.
+ * Input: new_handler - handle that is being entered into chain
+ * Return: int
+ *        0 - handler added
+ *        1 - identical handler found, handler not added to chain
+*/
 int
-iucv_declare_buffer (uchar * bfr)
+iucv_add_handler (handler * new_handler)
 {
-       iparml_db parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "Entering iucv_declare_buffer\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ipbfadr1 = virt_to_phys (bfr);
-       b2f0_result = b2f0 (declare_buffer, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "Address of EIB = %p\n", bfr);
-       printk (KERN_DEBUG "Exiting iucv_declare_buffer\n");
-#endif
-       return b2f0_result;
+       handler *R = new_handler;
+       int rc = 1, comp = 0;   /* return code (rc = 1 not added) or (rc = 0 added) */
+       ulong flags;
+       pr_debug ("iucv_add_handler: entering\n");
+       iucv_dumpit ((uchar *) new_handler, sizeof (handler));
+       spin_lock_irqsave (&iucv_lock, flags);
+       if (handler_anchor == NULL) {
+               /* add to beginning of chain */
+               handler_anchor = handler_tail = new_handler;
+               rc = 0;
+       } else
+               for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
+                       comp = memcmp ((void *) &(new_handler->id),
+                                      (void *) &(R->id), sizeof (R->id));
+                       pr_debug ("comp = %d\n", comp);
+                       if (comp == 0)  /* identicle handler found */
+                               break;  /* break out of for loop */
+                       else if (comp > 0) {    /* new_handler > R */
+                               pr_debug
+                                   ("iucv_add_handler: Found a place to add,"
+                                    "R is\n");
+                               iucv_dumpit ((uchar *) R, sizeof (handler));
+                               if ((R->prev != NULL)) {
+                                       /* add to middle of chain */
+                                       pr_debug
+                                           ("iucv_add_handler: added to middle\n");
+                                       new_handler->prev = R->prev;
+                                       new_handler->next = (ulong *) R;
+                                       ((handler *) (R->prev))->next =
+                                           (ulong *) new_handler;
+                                       R->prev = (ulong *) new_handler;
+                                       rc = 0;
+                                       break;  /* break out of FOR loop */
+                               } else {        /* R->prev == NULL */
+                                       /* add to start of chain;  */
+                                       pr_debug ("iucv_add_handler:"
+                                                 "added to beginning\n");
+                                       R->prev = (ulong *) new_handler;
+                                       new_handler->next = (ulong *) R;
+                                       handler_anchor = new_handler;
+                                       rc = 0;
+                                       break;  /* break out of FOR loop */
+                               }
+                       }       /* end of else if */
+               }               /* end of for loop */
+       if (R == NULL) {
+               /* add to end of chain */
+               pr_debug ("iucv_add_handler: added to end\n");
+               handler_tail->next = (ulong *) new_handler;
+               new_handler->prev = (ulong *) handler_tail;
+               handler_tail = new_handler;
+               rc = 0;
+       }
+       spin_unlock_irqrestore (&iucv_lock, flags);
+
+       pr_debug ("Current Chain of handlers is\n");
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+       pr_debug ("iucv_add_handler: exiting\n");
+       return rc;
+}
+
+/* 
+ * Name: iucv_remove_handler
+ * Purpose: Remove handler when application unregisters.
+ * Input: users_handler - handler to be removed
+ * Output: void
+*/
+void
+iucv_remove_handler (handler * users_handler)
+{
+       handler *R;             /* used for Debugging */
+       pr_debug ("iucv_remove_handler: entering\n");
+       if ((users_handler->next != NULL) & (users_handler->prev != NULL)) {
+               /* remove from middle of chain */
+               ((handler *) (users_handler->next))->prev =
+                   (ulong *) users_handler->prev;
+               ((handler *) (users_handler->prev))->next =
+                   (ulong *) users_handler->next;
+       } else if ((users_handler->next != NULL) &
+                  (users_handler->prev == NULL)) {
+               /* remove from start of chain */
+               ((handler *) (users_handler->next))->prev = NULL;
+               handler_anchor = (handler *) users_handler->next;
+       } else if ((users_handler->next == NULL) &
+                  (users_handler->prev != NULL)) {
+               /* remove from end of chain */
+               ((handler *) (users_handler->prev))->next = NULL;
+               handler_tail = (handler *) users_handler->prev;
+       } else {
+               handler_anchor = NULL;
+               handler_tail = NULL;
+       }
+
+       pr_debug ("Current Chain of handlers is\n");
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+       pr_debug ("iucv_remove_handler: exiting\n");
+       return;
+}
+
+/*
+ * Name: b2f0
+ * Purpose: This function calls CP to execute IUCV commands.
+ * Input: code -  identifier of IUCV call to CP.
+ *        parm -  pointer to 40 byte iparml area
+ *               passed to CP
+ * Output: iprcode- return code from CP's IUCV call
+ * NOTE: Assembler code performing IUCV call
+*/
+inline ulong
+b2f0 (u32 code, void *parm)
+{
+       uchar *iprcode;
+       pr_debug ("iparml before b2f0 call\n");
+       iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+       asm volatile ("LRA   1,0(%1)\n\t"
+                     "LR    0,%0\n\t"
+                     ".long 0xb2f01000"::"d" (code), "a" (parm):"0", "1");
+       pr_debug ("iparml after b2f0 call\n");
+       iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+       iprcode = (uchar *) (parm + 3);
+       return (ulong) (*iprcode);
 }
 
-/**************************************************************/
-/* Name: add_pathid                                           */
-/* Purpose: adds a path id to the system                      */
-/* Input: pathid - ushort, pathid to enter system             */
-/*        handle - iucv_handle_t, address of handler to add to */
-/*        pgm_data - ulong, pathid identifier.                */
-/* Output: 0: successful addition of pathid                   */
-/**************************************************************/
+/*
+ * Name: iucv_add_pathid                                            
+ * Purpose: Adds a path id to the system.                       
+ * Input: pathid -  pathid that is going to be entered into system              
+ *        handle -  address of handler that the pathid will be associated
+ *                with.
+ *        pgm_data - token passed in by application.                
+ * Output: 0: successful addition of pathid
+ *        - EINVAL - pathid entry is being used by another application
+ *        - ENOMEM - storage allocation for a new pathid table failed      
+*/
 int
-add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data)
+iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data)
 {
-       ulong index1, index2;   /* index1 into main_table */
        ulong add_flag = 0;
        ulong old_size = 0, new_size = 0;
+       ulong flags;
        uchar *to, *from;       /* pointer for copying the table */
-       handler_table_entry *P = 0;     /*P is a pointer to H_T_E */
-       handler *Q = 0;         /*Q is a pointer to handler */
-       ulong *X = 0;           /*Points to array of pointers */
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering add_pathid\n");
-#endif
-       Q = (handler *) handle; /* Q points to a handler    */
-       /*
-        * main_table has 128 entries.
-        * 128*512 = 65536 maximum number of pathid's allowed
-        */
-       index1 = ((ulong) pathid) / 512;
-       index2 = ((ulong) pathid) % 512;
-#ifdef DEBUG
-       printk (KERN_DEBUG "index1 = %d\n ", (int) index1);
-       printk (KERN_DEBUG "index2 = %d\n ", (int) index2);
-       printk (KERN_DEBUG "Q is pointing to %p ", Q);
-#endif
-       spin_lock (&lock);
-       /*
-        * If NULL then handler table does not exist and need to get storage
-        *  and have main_table[index1] point to it
-        * If allocating storage failed, return
-        */
-       if (main_table[index1] == NULL) {
-               main_table[index1] = (handler_table_entry *) kmalloc
-                   (512 * sizeof (handler_table_entry), GFP_KERNEL);
-               if (main_table[index1] == NULL) {
-                       spin_unlock (&lock);
-                       return -ENOBUFS;
-               }
-               memset (main_table[index1], 0,
-                       512 * sizeof (handler_table_entry));
-#ifdef DEBUG
-               printk (KERN_DEBUG "address of table H_T is %p \n",
-                       main_table[index1]);
-#endif
-       }
+       handler_table_entry *P = 0;     /*P is a pointer to the users H_T_E */
+       handler *users_handler = 0;
+       ulong *X = 0;           /* Points to array of pointers to H-T_E */
+
+       pr_debug ("iucv_add_pathid: entering\n");
+
+       users_handler = (handler *) handle;
+
+       pr_debug ("iucv_add_pathid: users_handler is pointing to %p ",
+                 users_handler);
+
+       spin_lock_irqsave (&iucv_lock, flags);
+
        /*
-        * P points to a handler table entry (H_T_E) in which all entries in
+        * P points to the users handler table entry (H_T_E) in which all entries in
         * that structure should be NULL. If they're not NULL, then there
-        * is a bad pointer and it will return(-2) immediately, otherwise
+        * is a bad pointer and it will return(-EINVAL) immediately, otherwise users
         * data will be entered into H_T_E.
         */
-       P = main_table[index1];
-       if ((P + index2)->addrs) {
-#ifdef DEBUG
-               printk (KERN_DEBUG "main_table[index1] = %p \n",
-                       main_table[index1]);
-               printk (KERN_DEBUG "P+index2 = %p \n", P + index2);
-               printk (KERN_DEBUG "(P+index2)->addrs is %p \n",
-                       (P + index2)->addrs);
-#endif
-               spin_unlock (&lock);
-               printk (KERN_DEBUG "bad pointer1\n");
-               return (-2);
+
+       P = handler_table_anchor + pathid;      /* index into users handler table */
+
+       pr_debug ("handler_table_anchor is %p\n", handler_table_anchor);
+       pr_debug ("P=handler_table_anchor+pathid = %p\n", P);
+
+       if (P->addrs) {
+               pr_debug ("iucv_add_pathid: P = %p \n", P);
+               pr_debug ("iucv_add_pathid: P->addrs is %p \n", P->addrs);
+               spin_unlock_irqrestore (&iucv_lock, flags);
+               /* This message should be sent to syslog */
+               printk (KERN_WARNING "iucv_add_pathid: Pathid being used,"
+                       "error.\n");
+               return (-EINVAL);
        }
-       (P + index2)->addrs = handle;
+
+       P->addrs = handle;
+       P->pathid = pathid;
+
        /*
-        * checking if address of handle is valid, if it's not valid,
-        * unlock the lock and return(-2) immediately.
+        * pgm_data provided in iucv_register may be overwritten on a connect, accept. 
         */
-       if ((P + index2)->addrs == NULL) {
-               spin_unlock (&lock);
-               printk (KERN_DEBUG "bad pointer2\n");
-               return (-2);
-       }
-       (P + index2)->pathid = pathid;
+
        if (pgm_data)
-               (P + index2)->pgm_data = pgm_data;
+               P->pgm_data = pgm_data;
        else
-               (P + index2)->pgm_data = Q->pgm_data;
+               P->pgm_data = users_handler->pgm_data;
+
+       /*
+        * Address of pathid's iucv_interrupt_ops is taken from the associated handler
+        * and added here for quicker access to the interrupt tables during interrupt
+        * handling.
+        */
+
+       P->ops = (P->addrs)->interrupt_table;
+
+       pr_debug ("Complete users H_T_E is\n");
+       iucv_dumpit ((uchar *) P, sizeof (handler_table_entry));
+
        /*
         * Step thru the table of addresses of pathid's to find the first
         * available entry (NULL). If an entry is found, add the pathid,
         * unlock and exit. If an available entry is not found, allocate a
-        * new, larger table, copy over the old table and deallocate the
-        * old table and add the pathid.
+        * new, larger table, copy over the old table to the new table. De-allocate the
+        * old table and enter the new pathid.
         */
-#ifdef DEBUG
-       printk (KERN_DEBUG "address of handle is %p\n", handle);
-       printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start));
-       printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end));
-       printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start));
-       printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end));
-       for (X = (Q->start); X < (Q->end); X++)
-               printk (KERN_DEBUG "X = %p ", X);
-       printk (KERN_DEBUG "\n");
-#endif
-       for (X = (Q->start); X < (Q->end); X++) {
+
+       pr_debug ("iucv_add_pathid: address of handle is %p\n", handle);
+       pr_debug ("iucv_add_pathid: &(users_handler->pathid_head) is %p\n",
+                 &(users_handler->pathid_head));
+       pr_debug ("iucv_add_pathid: &(users_handler->pathid_tail) is %p\n",
+                 &(users_handler->pathid_tail));
+       pr_debug ("iucv_add_pathid: start of pathid table is %p\n",
+                 (users_handler->pathid_head));
+       pr_debug ("iucv_add_pathid: end of pathid table is %p\n",
+                 (users_handler->pathid_tail));
+       iucv_dumpit ((uchar *) users_handler->pathid_head,
+                    (int) (users_handler->pathid_tail -
+                           users_handler->pathid_head));
+
+       for (X = (users_handler->pathid_head);
+            X <
+            (users_handler->pathid_head +
+             users_handler->entries * sizeof (ulong)); X++)
                if (*X == NULL) {
-#ifdef DEBUG
-                       printk (KERN_DEBUG "adding pathid, %p = P+index2\n",
-                               (P + index2));
-#endif
-                       *X = (ulong) (P + index2);
+                       pr_debug ("adding pathid, %p = P\n", P);
+                       *X = (ulong) P;
                        add_flag = 1;
+                       break;  /* breaks out of for loop */
                }
-               if (add_flag == 1)
-                       break;
-       }
-       if (add_flag == 0) {    /* element not added to list */
-               X = Q->start;
-               old_size = Q->size;
-               new_size = old_size + ADDED_STOR;       /* size of new table */
-               from = (uchar *) (Q->start);    /* address of old table */
-               (*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL);
-               if ((Q->start) == NULL) {
-                       spin_unlock (&lock);
-                       return -ENOBUFS;
+
+       pr_debug ("Addresses of HTE's are\n");
+       iucv_dumpit ((uchar *) users_handler->pathid_head,
+                    users_handler->entries * sizeof (ulong));
+
+       if (add_flag == 0) {    /* element not added to list: must get a new table */
+               X = users_handler->pathid_head;
+               old_size = users_handler->entries;
+               new_size = old_size + ADDED_STOR;       /*number of entries of new table */
+               from = (uchar *) (users_handler->pathid_head);  /*address of old table */
+               users_handler->pathid_head =
+                   kmalloc (new_size * sizeof (ulong), GFP_ATOMIC);
+
+               if (users_handler->pathid_head == NULL) {
+                       users_handler->pathid_head = X; /*setting old condition */
+                       spin_unlock_irqrestore (&iucv_lock, flags);
+                       printk (KERN_WARNING
+                               "iucv_add_pathid: storage allocation"
+                               "failed for new pathid table \n ");
+                       memset (P, 0, sizeof (handler_table_entry));
+                       return -ENOMEM;
                }
-               memset ((*Q).start, 0, new_size * sizeof (ulong));
-               to = (uchar *) (Q->start);      /* address of new table */
+
+               memset (users_handler->pathid_head, 0,
+                       new_size * sizeof (ulong));
+               to = (uchar *) (users_handler->pathid_head);    /* address of new table */
                /* copy old table to new  */
                memcpy (to, from, old_size * (sizeof (ulong)));
-#ifdef DEBUG
-               printk (KERN_DEBUG "Getting a new pathid table\n");
-               printk (KERN_DEBUG "to is %p \n", to);
-               printk (KERN_DEBUG "from is %p \n", from);
-#endif
-               Q->size = new_size;     /* storing new size of table */
-               Q->end = (Q->start) + (Q->size);
-               X = Q->start + old_size;        /* next blank in table */
-               *X = (ulong) (P + index2);      /* adding element to new table */
-#ifdef DEBUG
-               printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size));
-               printk (KERN_DEBUG "Q->end is %p \n", Q->end);
-               printk (KERN_DEBUG "Q->start is %p \n", Q->start);
-               printk (KERN_DEBUG "X is %p \n", X);
-               printk (KERN_DEBUG "*X is %u \n", (int) (*X));
-#endif
+
+               pr_debug ("iucv: add_pathid: Getting a new pathid table\n");
+               pr_debug ("iucv: add_pathid: to is %p \n", to);
+               pr_debug ("iucv: add_pathid: from is %p \n", from);
+
+               users_handler->entries = new_size;      /* storing new size of table */
+               users_handler->pathid_tail =
+                   (users_handler->pathid_head) + (users_handler->entries);
+               X = users_handler->pathid_head + old_size;
+               *X = (ulong) P; /* adding element to new table */
+
+               pr_debug ("iucv: add_pathid: users_handler->entries is %u \n",
+                         (int) (users_handler->entries));
+               pr_debug
+                   ("iucv: add_pathid: users_handler->pathid_tail is %p\n",
+                    users_handler->pathid_tail);
+               pr_debug ("users_handler->pathid_head is %p \n",
+                         users_handler->pathid_head);
+               pr_debug ("iucv: add_pathid: X is %p \n", X);
+               pr_debug ("iucv: add_pathid: *X is %u \n", (int) (*X));
+               pr_debug ("Addresses of HTE's after getting new table is\n");
+               iucv_dumpit ((uchar *) users_handler->pathid_head,
+                            users_handler->entries * sizeof (ulong));
+               pr_debug ("New handler is\n");
+               iucv_dumpit ((uchar *) users_handler, sizeof (handler));
+
                kfree (from);   /* free old table */
        }
-       spin_unlock (&lock);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting add_pathid\n");
-#endif
+       spin_unlock_irqrestore (&iucv_lock, flags);
+       pr_debug ("iucv_dd_pathid: exiting\n");
        return (0);
 }                              /* end of add_pathid function */
 
-/***********************EXTERNAL FUNCTIONS***************************/
-/**************************************************************/
-/* Name: iucv_query                                           */
-/* Purpose: determines how large an external interrupt buffer */
-/*          IUCV requires to store information                */
-/* Input : bufsize - ulong: size of interrupt buffer          */
-/*         - filled in by function and returned to caller     */
-/*         conmax  - ulong: maximum number of connections that */
-/*           can be outstanding for this VM                   */
-/*         - filled in by function and returned to caller     */
-/* Output: void                                               */
-/**************************************************************/
-void
-iucv_query (ulong * bufsize, ulong * conmax)
-{
-       iparml_purge parm;      /* DOESN'T MATTER WHICH IPARML IS USED    */
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       /*
-        * Assembler instruction calling b2f0  and storing R0 and R1
-        */
-       asm volatile ("LRA   1,0(%3)\n\t"
-                     "LR    0,%2\n\t"
-                     ".long 0xb2f01000\n\t"
-                     "ST    0,%0\n\t"
-                     "ST    1,%1\n\t":"=m" (*bufsize),
-                     "=m" (*conmax):"d" (query), "a" (&parm):"0", "1");
-       return;
-}
-
-/**************************************************************/
-/* Name: iucv_purge                                           */
-/* Purpose: cancels a message you have sent                   */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, mid of message                      */
-/*        srccls - ulong, sourse message class                */
-/*        audit  - uchar[4], info about ansync. error condit. */
-/*                 filled in by function and passed back      */
-/* Output: void                                               */
-/* NOTE: pathid is required, flag is always turned on         */
-/**************************************************************/
+/*
+ * Name: iucv_declare_buffer                                    
+ * Purpose: Specifies the guests real address of an external  
+ *          interrupt.                                        
+ * Input: void                             
+ * Output: iprcode - return code from b2f0 call               
+*/
 int
-iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4])
+iucv_declare_buffer (void)
 {
-       iparml_purge parm;
+       iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ipmsgid = msgid;
-       parm.ippathid = pathid;
-       parm.ipsrccls = srccls;
-       parm.ipflags1 |= specify_pathid;        /* pathid id flag */
-       if (parm.ipmsgid)
-               parm.ipflags1 |= specify_msgid;
-       if (parm.ipsrccls)
-               parm.ipflags1 |= source_class;
-       b2f0_result = b2f0 (purge, &parm);
-       if (b2f0_result != NULL)
-               return b2f0_result;
-       memcpy (audit, parm.ipaudit, 4);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_purge\n");
-#endif
+       pr_debug ("iucv_declare_buffer: entering\n");
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr1 = virt_to_phys ((uchar *) iucv_external_int_buffer);
+       b2f0_result = b2f0 (DECLARE_BUFFER, &parm);
+       pr_debug ("iucv_declare_buffer: Address of EIB = %p\n",
+                 iucv_external_int_buffer);
+       pr_debug ("iucv_declare_buffer: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_quiesce                                         */
-/* Purpose: temporarily suspends incoming messages            */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
+/*
+ * Name: iucv_retrieve_buffer
+ * Purpose: Terminates all use of IUCV.
+ * Input: void
+ * Output:
+ *      b2f0_result: return code from CP
+*/
 int
-iucv_quiesce (ushort pathid, uchar user_data[16])
+iucv_retrieve_buffer (void)
 {
        iparml_control parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_quiesce\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       memcpy (parm.ipuser, user_data, 16);
-       parm.ippathid = pathid;
-       b2f0_result = b2f0 (quiesc, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_quiesce\n");
-#endif
+       ulong b2f0_result = 0;
+       pr_debug ("iucv_retrieve_buffer: entering\n");
+       memset (&parm, 0, sizeof (parm));
+       b2f0_result = b2f0 (RETRIEVE_BUFFER, &parm);
+       if (b2f0_result == NULL) {
+               kfree (handler_table_anchor);
+               handler_table_anchor = NULL;
+               declare_flag = 0;
+       }
+       pr_debug ("iucv_retrieve_buffer: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_resume                                          */
-/* Purpose: restores communication over a quiesced path       */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_resume (ushort pathid, uchar user_data[16])
-{
-       iparml_control parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_resume\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       memcpy (parm.ipuser, user_data, 16);
-       parm.ippathid = pathid;
-       b2f0_result = b2f0 (resume, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_resume\n");
-#endif
-       return b2f0_result;
-}
+/*
+ * Name: iucv_register_program
+ * Purpose: Registers an application with IUCV.   
+ * Input: prmname - user identification
+ *        userid  - machine identification
+ *        pgmmask - indicates which bits in the prmname and userid combined will be used
+ *        to determine who is given control
+ *        ops - address of vector of interrupt handlers
+ *        pgm_data- application data passed to interrupt handlers
+ * Output: NA
+ * Return: type: iucv_handle_t
+ *          address of handler
+ *         (0) - registration failed
+ *            - Machine size > 2GB
+ *            - new_handler kmalloc failed
+ *            - pgmname was not provided
+ *            - pathid_table kmalloc failed
+ *             - application with identical pgmname, userid, and pgmmask is registered
+ *            - iucv_declare_buffer failed
+ * NOTE: pgmmask
+ *     When pgmname, userid, pgmmask is provided, mask is entered into the handler
+ *     as is.
+ *     When pgmname, userid is provided, pgmmask is all 0xff's
+ *     When pgmname, pgmmask is provided, the first 8 bytes = 0x00 and the last 16
+ *      bytes are as provided by pgmmask. 
+ *     When pgmname is provided is provided, the first 8 bytes = 0x00 and the last
+ *     16 bytes are 0xff.   
+*/
 
-/**************************************************************/
-/* Name: iucv_reject                                          */
-/* Purpose: rejects a message                                 */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, mid of message                      */
-/*        trgcls - ulong, target message class                */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid is required field, flag always turned on      */
-/*       RESTRICTION: target class cannot be zero             */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_reject (ushort pathid, ulong msgid, ulong trgcls)
+iucv_handle_t
+iucv_register_program (uchar pgmname[16],
+                      uchar userid[8],
+                      uchar pgmmask[24],
+                      iucv_interrupt_ops_t * ops, void *pgm_data)
 {
-       iparml_db parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_reject\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ipmsgid = msgid;
-       parm.ippathid = pathid;
-       parm.iptrgcls = trgcls;
-       parm.ipflags1 |= specify_pathid;        /* flag for pathid */
-       if (parm.ipmsgid)
-               parm.ipflags1 |= specify_msgid;
-       if (parm.iptrgcls)
-               parm.ipflags1 |= target_class;
-       b2f0_result = b2f0 (reject, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_reject\n");
-#endif
-       return b2f0_result;
-}
+       ulong rc = 0;           /* return code from function calls */
+       ulong machine_size = 0; /* size of virtual machine */
+       static u32 maxconn1;
+       handler *new_handler = NULL;
 
-/**************************************************************/
-/* Name: iucv_setmask                                         */
-/* Purpose: enables or disables certain iucv external interr. */
-/* Input: non_priority_interrupts - uchar                     */
-/*        priority_interrupts - uchar                         */
-/*        non_priority_completion_interrupts - uchar          */
-/*        priority_completion_interrupts) - uchar             */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_setmask (uchar non_priority_interrupts,
-             uchar priority_interrupts,
-             uchar non_priority_completion_interrupts,
-             uchar priority_completion_interrupts)
-{
-       iparml_set_mask parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_setmask\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       if (non_priority_interrupts)
-               parm.ipmask |= 0x80;
-       if (priority_interrupts)
-               parm.ipmask |= 0x40;
-       if (non_priority_completion_interrupts)
-               parm.ipmask |= 0x20;
-       if (priority_completion_interrupts)
-               parm.ipmask |= 0x10;
-       b2f0_result = b2f0 (setmask, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_setmask\n");
-#endif
-       return b2f0_result;
-}
+       pr_debug ("iucv_register_program:entering\n");
 
-/**************************************************************/
-/* Name: iucv_sever                                           */
-/* Purpose: terminates an iucv path to another machine        */
-/* Input: pathid - ushort, pathid                             */
-/*        user_data - uchar[16], user id                      */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: see b2f0 output list                                 */
-/**************************************************************/
-int
-iucv_sever (ushort pathid, uchar user_data[16])
-{
-       ulong index1, index2;
-       ulong b2f0_result;
-       handler_table_entry *P = 0;
-       handler *Q = 0;
-       ulong *X;
-       iparml_control parm;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_sever\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       memcpy (parm.ipuser, user_data, 16);
-       parm.ippathid = pathid;
-       b2f0_result = b2f0 (sever, &parm);
-       if (b2f0_result)
-               return b2f0_result;
-       index1 = ((ulong) pathid) / 512;
-       index2 = ((ulong) pathid) % 512;
-       spin_lock (&lock);
-       P = main_table[index1];
-       if (((P + index2)->addrs) == NULL) {    /* called from interrupt code */
-               spin_unlock (&lock);
-               return (-2);    /* bad pointer */
+       if (ops == NULL) {
+               /* interrupt table is not defined */
+               printk (KERN_WARNING "iucv_register_program:"
+                       "Interrupt table is not defined, exiting\n");
+               return NULL;
        }
-       Q = (*(P + index2)).addrs;
-#ifdef DEBUG
-       printk (KERN_DEBUG "pathid is %d\n", pathid);
-       printk (KERN_DEBUG "index1 is %d\n", (int) index1);
-       printk (KERN_DEBUG "index2 is %d\n", (int) index2);
-       printk (KERN_DEBUG "H_T_E is %p\n", P);
-       printk (KERN_DEBUG "address of handler is %p\n", Q);
-       for (X = ((*Q).start); X < ((*Q).end); X++)
-               printk (KERN_DEBUG " %x ", (int) (*X));
-       printk (KERN_DEBUG "\n above is pathid table\n");
-#endif
-/********************************************************************/
-/* Searching the pathid address table for matching address, once    */
-/* found, NULL the field. Then Null the H_T_E fields.               */
-/********************************************************************/
-       for (X = ((*Q).start); X < ((*Q).end); X++)
-               if (*X == (ulong) (P + index2)) {
-#ifdef DEBUG
-                       printk (KERN_DEBUG "found a path to sever\n");
-                       printk (KERN_DEBUG "severing %d \n", (int) (*X));
-#endif
-                       *X = NULL;
-                       (*(P + index2)).addrs = NULL;   /*clearing the fields */
-                       (*(P + index2)).pathid = 0;
-                       (*(P + index2)).pgm_data = 0;
+
+       if (declare_flag == 0) {
+               /* check size of virtual machine */
+               if ((machine_size = iucv_vmsize ()) > 0x100000000) {    /* 2GB */
+                       printk (KERN_WARNING "iucv_register_progam: Virtual"
+                               "storage = %lx hex," "exiting\n", machine_size);
+                       return NULL;
                }
-       spin_unlock (&lock);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_sever\n");
-#endif
-       return b2f0_result;
+
+               pr_debug ("machine_size is %lx\n", machine_size);
+
+               maxconn1 = iucv_query_maxconn ();
+               handler_table_anchor = kmalloc (maxconn1 * sizeof
+                                               (handler_table_entry),
+                                               GFP_KERNEL);
+
+               if (handler_table_anchor == NULL) {
+                       printk (KERN_WARNING "iucv_register_program:"
+                               "handler_table_anchor"
+                               "storage allocation failed\n");
+                       return NULL;
+               }
+
+               memset (handler_table_anchor, 0,
+                       maxconn1 * sizeof (handler_table_entry));
+
+       }
+       /* Allocate handler table */
+       new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+       if (new_handler == NULL) {
+               printk (KERN_WARNING "iucv_register_program: storage allocation"
+                       "for new handler failed. \n ");
+               return NULL;
+       }
+       memset (new_handler, 0, sizeof (handler));
+       if (pgmname) {
+               memcpy (new_handler->id.user_data, pgmname,
+                       sizeof (new_handler->id.user_data));
+               if (userid) {
+                       memcpy (new_handler->id.userid, userid,
+                               sizeof (new_handler->id.userid));
+                       ASCEBC (new_handler->id.userid,
+                               sizeof (new_handler->id.userid));
+                       EBC_TOUPPER (new_handler->id.userid,
+                                    sizeof (new_handler->id.userid));
+
+                       if (pgmmask) {
+                               memcpy (new_handler->id.mask, pgmmask,
+                                       sizeof (new_handler->id.mask));
+                       } else {
+                               memset (new_handler->id.mask, 0xFF,
+                                       sizeof (new_handler->id.mask));
+                       }
+               } else {
+                       if (pgmmask) {
+                               memcpy (new_handler->id.mask, pgmmask,
+                                       sizeof (new_handler->id.mask));
+                       } else {
+                               memset (new_handler->id.mask, 0xFF,
+                                       sizeof (new_handler->id.mask));
+                       }
+                       memset (new_handler->id.mask, 0x00,
+                               sizeof (new_handler->id.userid));
+               }
+       } else {
+               kfree (new_handler);
+               printk (KERN_WARNING "iucv_register_program: pgmname not"
+                       "provided\n");
+               return NULL;
+       }
+       /* fill in the rest of handler */
+       new_handler->pgm_data = pgm_data;
+       new_handler->interrupt_table = ops;
+       new_handler->entries = ADDED_STOR;
+       /* Allocate storage for pathid table */
+       new_handler->pathid_head =
+           kmalloc (new_handler->entries * sizeof (ulong), GFP_KERNEL);
+       if (new_handler->pathid_head == NULL) {
+               printk (KERN_WARNING "iucv_register_program: storage allocation"
+                       "failed\n");
+               kfree (new_handler);
+               return NULL;
+       }
+
+       memset (new_handler->pathid_head, 0,
+               new_handler->entries * sizeof (ulong));
+       new_handler->pathid_tail =
+           new_handler->pathid_head + new_handler->entries;
+       /* 
+        * Check if someone else is registered with same pgmname, userid, and mask. 
+        * If someone is already registered with same pgmname, userid, and mask 
+        * registration will fail and NULL will be returned to the application. 
+        * If identical handler not found, then handler is added to list.
+        */
+       rc = iucv_add_handler (new_handler);
+       if (rc) {
+               printk (KERN_WARNING "iucv_register_program: Someone already"
+                       "registered with same pgmname, userid, pgmmask\n");
+               kfree (new_handler->pathid_head);
+               kfree (new_handler);
+               return NULL;
+       }
+
+       if (declare_flag == 0) {
+               rc = iucv_declare_buffer ();
+               if (rc) {
+                       kfree (handler_table_anchor);
+                       kfree (new_handler->pathid_head);
+                       kfree (new_handler);
+                       handler_table_anchor = NULL;
+                       printk (KERN_WARNING "iucv_register_program: rc from"
+                               "iucv_declare_buffer is:% ld \n ", rc);
+                       return NULL;
+               }
+               /* request the 0x4000 external interrupt */
+               rc = register_external_interrupt (0x4000, top_half_interrupt);
+               if (rc) {
+                       iucv_retrieve_buffer ();
+                       kfree (new_handler->pathid_head);
+                       kfree (new_handler);
+                       printk (KERN_WARNING "iucv_register_program: rc from"
+                               "register_external_interrupt is:% ld \n ", rc);
+                       return NULL;
+
+               }
+               declare_flag = 1;
+       }
+       pr_debug ("iucv_register_program: exiting\n");
+       return new_handler;
+}                              /* end of register function */
+
+/*
+ * Name: iucv_unregister_program
+ * Purpose: Unregister application with IUCV.
+ * Input: handle address of handler
+ * Output: NA
+ * Return: (0) - Normal return
+ *         (-EINVAL)- Matching handler was not found
+*/
+
+int
+iucv_unregister_program (iucv_handle_t handle)
+{
+       handler *users_handler = 0, *R;
+       handler_table_entry *H_T_E = 0;
+       ulong *S = 0;           /*points to the beginning of block of h_t_e's */
+       ulong flags;
+       u16 pathid_sever = 0;
+       pr_debug ("iucv_unregister_program: entering\n");
+       pr_debug ("iucv_unregister_program: address of handle is %p\n", handle);
+       spin_lock_irqsave (&iucv_lock, flags);
+       users_handler = (handler *) handle;
+       /* 
+        * Checking if handle is still registered: if yes, continue
+        *  if not registered, return.
+        */
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               if (users_handler == R) {
+                       pr_debug ("iucv_unregister_program: found a matching"
+                                 "handler\n");
+                       break;
+               }
+       if (!R) {
+               pr_debug ("You are not registered\n");
+               spin_unlock_irqrestore (&iucv_lock, flags);
+               return (0);
+       }
+       S = users_handler->pathid_head;
+       while (S < (users_handler->pathid_tail)) {      /* index thru table */
+               if (*S) {
+                       H_T_E = (handler_table_entry *) (*S);
+
+                       pr_debug ("iucv_unregister_program: pointer to H_T_E is"
+                                 "%p\n", H_T_E);
+                       pr_debug
+                           ("iucv_unregister_program: address of handle in"
+                            "H_T_E is %p", (H_T_E->addrs));
+                       pathid_sever = H_T_E->pathid;
+                       spin_unlock_irqrestore (&iucv_lock, flags);
+                       iucv_sever (pathid_sever, users_handler->id.user_data);
+                       spin_lock_irqsave (&iucv_lock, flags);
+               }
+
+               S++;            /* index by address */
+       }
+
+       kfree (users_handler->pathid_head);
+       iucv_remove_handler (users_handler);
+       spin_unlock_irqrestore (&iucv_lock, flags);
+       kfree (handle);
+       pr_debug ("iucv_unregister_program: exiting\n");
+       return 0;
 }
 
-/**************************************************************/
-/* Name: iucv_receive                                         */
-/* Purpose: receives incoming message                         */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - *ulong, mid of message                     */
-/*        trgcls - *ulong, target message class               */
-/*        buffer - pointer of buffer                          */
-/*        buflen - length of buffer                           */
-/*        adds_curr_buffer - pointer to updated buffer address*/
-/*                           to write to                      */
-/*        adds_curr_length - pointer to updated length in     */
-/*                           buffer available to write to     */
-/*        reply_required - uchar *, flag                      */
-/*        priority_msg - uchar *, flag                        */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid must be specified, flag being turned on       */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if  */
-/* target class = zero, flag will not be turned on.           */
-/**************************************************************/
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ *          interrupt and now wishes to complete the IUCV communication path.
+ * Input:  pathid - u16 , path identification number   
+ *         msglim_reqstd - u16, The number of outstanding messages requested.
+ *         user_data - uchar[16], Data specified by the iucv_connect function.
+ *        flags1 - int, Contains options for this path.
+ *           -IPPRTY - 0x20- Specifies if you want to send priority message.
+ *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *             in  the parameter list.
+ *           -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ *             established.
+ *         handle - iucv_handle_t, Address of handler.
+ *         pgm_data - ulong, Application data passed to interrupt handlers.
+ *        flags1_out - int *, Options for path.
+ *           IPPRTY - 0x20 - Indicates you may send a priority message.
+ *         priority_permitted -uchar *, Indicates you may send priority messages.
+ *         msglim - *u16, Number of outstanding messages.
+ * Output: b2f0_result - return code from CP
+*/
 int
-iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls,
-             void *buffer, ulong buflen,
-             uchar * reply_required,
-             uchar * priority_msg,
-             ulong * adds_curr_buffer, ulong * adds_curr_length)
+iucv_accept (u16 pathid, u16 msglim_reqstd,
+            uchar user_data[16], int flags1,
+            iucv_handle_t handle, void *pgm_data,
+            int *flags1_out, u16 * msglim)
 {
-       iparml_db parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_receive\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ipmsgid = *msgid;
+       iparml_control parm;
+       ulong b2f0_result = 0;
+       ulong flags;
+       handler *R = NULL;
+       pr_debug ("iucv_accept: entering \n");
+       pr_debug ("iucv_accept: pathid = %d\n", pathid);
+
+       /* Checking if handle is valid  */
+       spin_lock_irqsave (&iucv_lock, flags);
+
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               if (R == handle)
+                       break;
+
+       spin_unlock_irqrestore (&iucv_lock, flags);
+       if (R == NULL) {
+               printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+                       "application\n");
+               return -EINVAL;
+       }
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
-       parm.iptrgcls = *trgcls;
-       parm.ipflags1 |= specify_pathid;        /* turning pathid flag */
-       if (parm.ipmsgid)
-               parm.ipflags1 |= 0x05;
-       if (parm.iptrgcls)
-               parm.ipflags1 |= target_class;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen;
-       b2f0_result = b2f0 (receive, &parm);
+       parm.ipmsglim = msglim_reqstd;
+       if (user_data)
+               memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+       parm.ipflags1 = (uchar) flags1;
+       b2f0_result = b2f0 (ACCEPT, &parm);
+
+       if (b2f0_result == 0) {
+               if (pgm_data)
+                       (handler_table_anchor + pathid)->pgm_data = pgm_data;
+               if (parm.ipflags1 & IPPRTY)
+                       if (flags1_out) {
+                               pr_debug ("*flags1_out = %d\n", *flags1_out);
+                               *flags1_out = 0;
+                               *flags1_out |= IPPRTY;
+                               pr_debug (" *flags1_out = %d\n", *flags1_out);
+                       }
+       }
+
+       pr_debug ("iucv_accept: exiting\n");
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_connect                                         
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ *         successfully, you are not able to use the path until you receive an IUCV 
+ *          Connection Complete external interrupt.            
+ * Input: pathid - u16 *, path identification number          
+ *        msglim_reqstd - u16, number of outstanding messages requested       
+ *        user_data - uchar[16], 16-byte user data                    
+ *        userid - uchar[8], 8-byte of user identification                        
+ *        system_name - uchar[8], 8-byte identifying the system name 
+ *        flags1 - int, Contains options for this path.
+ *          -IPPRTY - 0x20- Specifies if you want to send priority message.
+ *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *               in  the parameter list.
+ *          -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ *              established.
+ *          -IPLOCAL - 0X01, allows an application to force the partner to be on the
+ *              local system. If local is specified then target class cannot be
+ *              specified.  
+ *         flags1_out - int *, Options for path. 
+ *           IPPRTY - 0x20 - Indicates you may send a priority message.
+ *        msglim - * u16, number of outstanding messages
+ *        handle - iucv_handle_t, address of handler                         
+ *        pgm_data - *void, application data passed to interrupt handlers                  
+ * Output: b2f0_result - return code from CP
+ *         -ENOMEM
+ *         rc - return code from iucv_declare_buffer
+ *         -EINVAL - invalid handle passed by application 
+ *         -EINVAL - pathid address is NULL 
+ *        -ENOMEM - pathid table storage allocation failed
+ *         add_pathid_result - return code from internal function add_pathid             
+*/
+int
+iucv_connect (u16 * pathid, u16 msglim_reqstd,
+             uchar user_data[16], uchar userid[8],
+             uchar system_name[8], int flags1,
+             int *flags1_out, u16 * msglim,
+             iucv_handle_t handle, void *pgm_data)
+{
+       iparml_control parm;
+       ulong b2f0_result = 0;
+       ulong flags;
+       int add_pathid_result = 0;
+       handler *R = NULL;
+       uchar no_memory[16] = "NO MEMORY";
+
+       pr_debug ("iucv_connect: entering \n");
+
+       /* Checking if handle is valid  */
+       spin_lock_irqsave (&iucv_lock, flags);
+
+       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+               if (R == handle)
+                       break;
+
+       spin_unlock_irqrestore (&iucv_lock, flags);
+
+       if (R == NULL) {
+               printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+                       "application\n");
+               return -EINVAL;
+       }
+
+       if (pathid == NULL) {
+               printk (KERN_WARNING "iucv_connect: NULL pathid pointer\n");
+               return -EINVAL;
+       }
+       memset (&parm, 0, sizeof (iparml_control));
+       parm.ipmsglim = msglim_reqstd;
+
+       if (user_data)
+               memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+
+       if (userid) {
+               memcpy (parm.ipvmid, userid, sizeof (parm.ipvmid));
+               ASCEBC (parm.ipvmid, sizeof (parm.ipvmid));
+               EBC_TOUPPER (parm.ipvmid, sizeof (parm.ipvmid));
+       }
+
+       if (system_name) {
+               memcpy (parm.iptarget, system_name, sizeof (parm.iptarget));
+               ASCEBC (parm.iptarget, sizeof (parm.iptarget));
+               EBC_TOUPPER (parm.iptarget, sizeof (parm.iptarget));
+       }
+
+       parm.ipflags1 = (uchar) flags1;
+       b2f0_result = b2f0 (CONNECT, &parm);
        if (b2f0_result)
                return b2f0_result;
-       if (msgid)
-               *msgid = parm.ipmsgid;
-       if (trgcls)
-               *trgcls = parm.iptrgcls;
-       if (parm.ipflags1 & prior_msg)
-               if (priority_msg)
-                       *priority_msg = 0x01;   /*yes, priority msg */
-       if (!(parm.ipflags1 & 0x10))    /*& with X'10'     */
-               if (reply_required)
-                       *reply_required = 0x01; /*yes, reply required */
-       if (!(parm.ipflags1 & parm_data)) {     /*msg not in parmlist */
-               if (adds_curr_length)
-                       *adds_curr_length = parm.ipbfln1f;
-               if (adds_curr_buffer)
-                       *adds_curr_buffer = parm.ipbfadr1;
-       } else {
-               if ((buflen) >= 8) {
-                       if (buffer)
-                               memcpy ((char *) buffer,
-                                       (char *) parm.ipbfadr1, 8);
-                       if (adds_curr_length)
-                               *adds_curr_length = ((buflen) - 8);
-                       if (adds_curr_buffer)
-                               *adds_curr_buffer = (ulong) buffer + 8;
-               } else {
-                       parm.iprcode |= 0x05;
-                       b2f0_result = (ulong) parm.iprcode;
-               }
+
+       add_pathid_result = iucv_add_pathid (parm.ippathid, handle, pgm_data);
+       if (add_pathid_result) {
+
+               iucv_sever (parm.ippathid, no_memory);
+               printk (KERN_WARNING "iucv_connect: add_pathid failed with rc ="
+                       "%d\n", add_pathid_result);
+               return (add_pathid_result);
        }
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+       *pathid = parm.ippathid;
+
+       if (msglim)
+               *msglim = parm.ipmsglim;
+
+       if (parm.ipflags1 & IPPRTY)
+               if (flags1_out) {
+                       *flags1_out = 0;
+                       *flags1_out |= IPPRTY;
+               }
+
+       pr_debug ("iucv_connect: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_receive_simple                                  */
-/* Purpose: receives fully-qualified message                  */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        buffer - pointer of buffer                          */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_purge                                           
+ * Purpose: Cancels a message you have sent.                   
+ * Input: pathid -   address of pathid                                  
+ *        msgid  -   address of message identification             
+ *        srccls -   address of source message class                     
+ *        audit  -  contains information about                              
+ *                 asynchronous error that may have affected                           
+ *                 the normal completion of this message.                  
+ * Output:b2f0_result - return code from CP                   
+*/
 int
-iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls,
-                    void *buffer, ulong buflen)
+iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3])
+{
+       iparml_purge parm;
+       ulong b2f0_result = 0;
+       pr_debug ("iucv_purge: entering\n");
+       pr_debug ("iucv_purge: pathid = %d \n", pathid);
+       memset (&parm, 0, sizeof (parm));
+       parm.ipmsgid = msgid;
+       parm.ippathid = pathid;
+       parm.ipsrccls = srccls;
+       parm.ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
+       b2f0_result = b2f0 (PURGE, &parm);
+
+       if ((b2f0_result == 0) && (audit))
+               memcpy (audit, parm.ipaudit, sizeof (parm.ipaudit));
+
+       pr_debug ("iucv_purge: b2f0_result = %ld \n", b2f0_result);
+       pr_debug ("iucv_purge: exiting\n");
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_query_maxconn                                            
+ * Purpose: Determines the maximum number of connections thay may be established.
+ * Output: maxconn - ulong: Maximum number of connections that can be.     
+*/
+ulong
+iucv_query_maxconn (void)
+{
+       iparml_purge parm;      /* DOESN'T MATTER WHICH IPARML IS USED    */
+       static u32 maxconn1, bufsize1;
+
+       pr_debug ("iucv_query_maxconn: entering\n");
+
+       memset (&parm, 0, sizeof (parm));
+
+       /* Assembler instruction calling b2f0  and storing R0 and R1 */
+       asm volatile ("LRA   1,0(%3)\n\t"
+                     "LR    0,%2\n\t"
+                     ".long 0xb2f01000\n\t"
+                     "ST    0,%0\n\t"
+                     "ST    1,%1\n\t":"=m" (bufsize1),
+                     "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+       pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+       pr_debug ("iucv_query_maxconn: exiting\n");
+
+       return maxconn1;
+}
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: Determines the size of the external interrupt buffer.
+ * Output: bufsize - ulong: Size of external interrupt buffer.
+ */
+ulong
+iucv_query_bufsize (void)
+{
+       iparml_purge parm;      /* DOESN'T MATTER WHICH IPARML IS USED    */
+       static u32 maxconn1, bufsize1;
+
+       pr_debug ("iucv_query_bufsize: entering\n");
+       pr_debug ("iucv_query_maxconn: entering\n");
+
+       memset (&parm, 0, sizeof (parm));
+
+       /* Assembler instruction calling b2f0  and storing R0 and R1 */
+       asm volatile ("LRA   1,0(%3)\n\t"
+                     "LR    0,%2\n\t"
+                     ".long 0xb2f01000\n\t"
+                     "ST    0,%0\n\t"
+                     "ST    1,%1\n\t":"=m" (bufsize1),
+                     "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+       pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+       pr_debug ("iucv_query_bufsize: exiting\n");
+
+       return bufsize1;
+}
+
+/*
+ * Name: iucv_quiesce                                         
+ * Purpose: temporarily suspends incoming messages on an IUCV path.
+ *          You can later reactivate the path by invoking the iucv_resume function        
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte user data                      
+ * Output: b2f0_result - return code from CP               
+ */
+int
+iucv_quiesce (u16 pathid, uchar user_data[16])
+{
+       iparml_control parm;
+       ulong b2f0_result = 0;
+
+       pr_debug ("iucv_quiesce: entering \n");
+       pr_debug ("iucv_quiesce: pathid = %d\n", pathid);
+
+       memset (&parm, 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+       parm.ippathid = pathid;
+
+       b2f0_result = b2f0 (QUIESCE, &parm);
+
+       pr_debug ("iucv_quiesce: b2f0_result = %ld\n", b2f0_result);
+       pr_debug ("iucv_quiesce: exiting\n");
+
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_receive
+ * Purpose: This function receives messages that are being sent to you
+ *          over established paths. 
+ * Input:
+ *        pathid - path identification number
+ *        buffer - address of buffer to receive
+ *        buflen - length of buffer to receive
+ *        msgid - specifies the message ID.
+ *        trgcls - specifies target class
+ * Output:
+ *      flags1_out: Options for path.
+ *         IPNORPY - 0x10 specifies whether a reply is required
+ *         IPPRTY - 0x20 specifies if you want to send priority message
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address of buffer updated by the number
+ *                         of bytes you have received.
+ *       residual_length - 
+ *             Contains one of the following values, if the receive buffer is:
+ *              The same length as the message, this field is zero.
+ *              Longer than the message, this field contains the number of
+ *               bytes remaining in the buffer.
+ *              Shorter than the message, this field contains the residual
+ *               count (that is, the number of bytes remaining in the
+ *               message that does not fit into the buffer. In this
+ *               case b2f0_result = 5. 
+ * Return: b2f0_result - return code from CP IUCV call.
+ *         (-EINVAL) - buffer address is pointing to NULL
+ */
+int
+iucv_receive (u16 pathid, u32 msgid, u32 trgcls,
+             void *buffer, ulong buflen,
+             int *flags1_out, ulong * residual_buffer, ulong * residual_length)
 {
        iparml_db parm;
        ulong b2f0_result;
-       pr_debug ("entering iucv_receive_simple\n");
+       int moved = 0;          /* number of bytes moved from parmlist to buffer */
+       pr_debug ("iucv_receive: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
 
-       memset (&(parm), 0, sizeof (parm));
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr1 = (u32) buffer;
+       parm.ipbfln1f = (u32) ((ulong) buflen);
        parm.ipmsgid = msgid;
        parm.ippathid = pathid;
        parm.iptrgcls = trgcls;
-       parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen;
+       parm.ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
 
-       b2f0_result = b2f0 (receive, &parm);
-       if (b2f0_result)
-               return b2f0_result;
+       b2f0_result = b2f0 (RECEIVE, &parm);
+
+       if (b2f0_result == 0 || b2f0_result == 5) {
+               if (flags1_out) {
+                       pr_debug ("*flags1_out = %d\n", *flags1_out);
+                       *flags1_out = (parm.ipflags1 & (~0x07));
+                       pr_debug ("*flags1_out = %d\n", *flags1_out);
+               }
+
+               if (!(parm.ipflags1 & IPRMDATA)) {      /*msg not in parmlist */
+                       if (residual_length)
+                               *residual_length = parm.ipbfln1f;
+
+                       if (residual_buffer)
+                               *residual_buffer = parm.ipbfadr1;
+               } else {
+                       moved = min (buflen, 8);
 
-       if (parm.ipflags1 & IPRMDATA) { /*msg in parmlist */
-               if ((buflen) >= 8)
-                       memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8);
-               else
-                       b2f0_result = 5;
+                       memcpy ((char *) buffer,
+                               (char *) &parm.ipbfadr1, moved);
+
+                       if (buflen < 8)
+                               b2f0_result = 5;
+
+                       if (residual_length)
+                               *residual_length = abs (buflen - 8);
+
+                       if (residual_buffer)
+                               *residual_buffer = (ulong) (buffer + moved);
+               }
        }
-       pr_debug ("exiting iucv_receive_simple\n");
+       pr_debug ("iucv_receive: exiting \n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_receive_array                                   */
-/* Purpose: receives incoming message                         */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  -* ulong, mid of message                     */
-/*        trgcls -* ulong, target message class               */
-/*        buffer - pointer of iucv_array_t                    */
-/*        buflen - ulong , length of buffer                   */
-/*        reply_required - uchar *, flag returned to caller   */
-/*        priority_msg - uchar *, flag returned to caller     */
-/*        adds_curr_buffer - pointer to updated buffer array  */
-/*                   to write to                              */
-/*        adds_curr_length - pointer to updated length in     */
-/*                   buffer available to write to             */
-/* Output: iprcode - return code from b2f0 call               */
-/* NOTE: pathid must be specified, flag being turned on       */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if  */
-/* target class = if target class = zero flag will not be     */
-/* turned on, therefore if target class is specified it cannot */
-/* be zero.                                                   */
-/**************************************************************/
+/*
+ * Name: iucv_receive_array
+ * Purpose: This function receives messages that are being sent to you
+ *          over established paths. 
+ * Input: pathid - path identification number
+ *        buffer - address of array of buffers
+ *        buflen - total length of buffers
+ *        msgid - specifies the message ID.
+ *        trgcls - specifies target class
+ * Output:
+ *        flags1_out: Options for path.
+ *          IPNORPY - 0x10 specifies whether a reply is required
+ *          IPPRTY - 0x20 specifies if you want to send priority message
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address points to the current list entry IUCV
+ *                         is working on.
+ *       residual_length -
+ *              Contains one of the following values, if the receive buffer is:
+ *               The same length as the message, this field is zero.
+ *               Longer than the message, this field contains the number of
+ *                bytes remaining in the buffer.
+ *               Shorter than the message, this field contains the residual
+ *                count (that is, the number of bytes remaining in the
+ *                message that does not fit into the buffer. In this case
+ *               b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
 int
-iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls,
-                   iucv_array_t * buffer, ulong * buflen,
-                   uchar * reply_required,
-                   uchar * priority_msg,
-                   ulong * adds_curr_buffer, ulong * adds_curr_length)
+iucv_receive_array (u16 pathid,
+                   u32 msgid, u32 trgcls,
+                   iucv_array_t * buffer, ulong buflen,
+                   int *flags1_out,
+                   ulong * residual_buffer, ulong * residual_length)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_receive_array\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ipmsgid = *msgid;
+       int i = 0, moved = 0, need_to_move = 8, dyn_len;
+       pr_debug ("iucv_receive_array: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr1 = (u32) ((ulong) buffer);
+       parm.ipbfln1f = (u32) buflen;
+       parm.ipmsgid = msgid;
        parm.ippathid = pathid;
-       parm.iptrgcls = *trgcls;
-       parm.ipflags1 |= array; /* using an address list  */
-       parm.ipflags1 |= specify_pathid;        /*turning on pathid flag */
-       if (parm.ipmsgid)
-               parm.ipflags1 |= 0x05;
-       if (parm.iptrgcls)
-               parm.ipflags1 |= target_class;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = *buflen;
-       b2f0_result = b2f0 (receive, &parm);
-       if (b2f0_result)
-               return b2f0_result;
-       if (msgid)
-               *msgid = parm.ipmsgid;
-       if (trgcls)
-               *trgcls = parm.iptrgcls;
-       if (parm.ipflags1 & prior_msg)
-               if (priority_msg)
-                       *priority_msg = 0x01;   /*yes, priority msg */
-       if (!(parm.ipflags1 & 0x10))    /*& with X'10'     */
-               if (reply_required)
-                       *reply_required = 0x01; /*yes, reply required */
-       if (!(parm.ipflags1 & parm_data)) {     /*msg not in parmlist */
-               if (adds_curr_length)
-                       *adds_curr_length = parm.ipbfln1f;
-               if (adds_curr_buffer)
-                       *adds_curr_buffer = parm.ipbfadr1;
-       } else {
-               if ((buffer->length) >= 8) {
-                       memcpy ((char *) buffer->address,
-                               (char *) parm.ipbfadr1, 8);
-                       if (adds_curr_buffer)
-                               *adds_curr_buffer =
-                                   (ulong) ((buffer->address) + 8);
-                       if (adds_curr_length)
-                               *adds_curr_length = ((buffer->length) - 8);
+       parm.iptrgcls = trgcls;
+       parm.ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
+
+       b2f0_result = b2f0 (RECEIVE, &parm);
+
+       if (b2f0_result == 0 || b2f0_result == 5) {
+
+               if (flags1_out) {
+                       pr_debug ("*flags1_out = %d\n", *flags1_out);
+                       *flags1_out = (parm.ipflags1 & (~0x07));
+                       pr_debug ("*flags1_out = %d\n", *flags1_out);
+               }
+
+               if (!(parm.ipflags1 & IPRMDATA)) {      /*msg not in parmlist */
+
+                       if (residual_length)
+                               *residual_length = parm.ipbfln1f;
+
+                       if (residual_buffer)
+                               *residual_buffer = parm.ipbfadr1;
 
                } else {
-                       parm.iprcode |= 0x05;
-                       b2f0_result = (ulong) parm.iprcode;
+                       /* copy msg from parmlist to users array. */
+
+                       while ((moved < 8) && (moved < buflen)) {
+                               dyn_len =
+                                   min ((buffer + i)->length, need_to_move);
+
+                               memcpy ((char *)((ulong)((buffer + i)->address)),
+                                       ((char *) &parm.ipbfadr1) + moved,
+                                       dyn_len);
+
+                               moved += dyn_len;
+                               need_to_move -= dyn_len;
+
+                               (buffer + i)->address =
+                                       (u32)  
+                               ((ulong)(uchar *) ((ulong)(buffer + i)->address) 
+                                               + dyn_len);
+
+                               (buffer + i)->length -= dyn_len;
+                               i++;
+                       }
+
+                       if (need_to_move)       /* buflen < 8 bytes */
+                               b2f0_result = 5;
+
+                       if (residual_length)
+                               *residual_length = abs (buflen - 8);
+
+                       if (residual_buffer) {
+                               if (moved == 0)
+                                       *residual_buffer = (ulong) buffer;
+                               else
+                                       *residual_buffer =
+                                           (ulong) (buffer + (i - 1));
+                       }
+
                }
        }
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+       pr_debug ("iucv_receive_array: exiting\n");
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_reject                                          
+ * Purpose: Refuses a specified message. Between the time you are notified of a 
+ *          message and the time that you complete the message, the message may
+ *          be rejected.                                 
+ * Input: pathid - u16, path identification number.                            
+ *        msgid  - u32, specifies the message ID.
+ *        trgcls - u32, specifies target class.                
+ * Output: b2f0_result - return code from CP
+ * NOTE: see b2f0 output list                                 
+*/
+int
+iucv_reject (u16 pathid, u32 msgid, u32 trgcls)
+{
+       iparml_db parm;
+       ulong b2f0_result = 0;
+
+       pr_debug ("iucv_reject: entering \n");
+       pr_debug ("iucv_reject: pathid = %d\n", pathid);
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
+       parm.iptrgcls = trgcls;
+       parm.ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
+
+       b2f0_result = b2f0 (REJECT, &parm);
+
+       pr_debug ("iucv_reject: b2f0_result = %ld\n", b2f0_result);
+       pr_debug ("iucv_reject: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send                                            */
-/* Purpose: sends messages                                    */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to buffer                          */
-/*        buflen - ulong, length of buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/* 
+ * Name: iucv_reply
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class
+ *        flags1 - option for path
+ *                 IPPRTY- 0x20 - specifies if you want to send priority message
+ *        buffer - address of reply buffer
+ *        buflen - length of reply buffer
+ * Output: ipbfadr2 - Address of buffer updated by the number
+ *                    of bytes you have moved.
+ *         ipbfln2f - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *                case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
 int
-iucv_send (ushort pathid, ulong * msgid,
-          ulong trgcls, ulong srccls,
-          ulong msgtag, uchar priority_msg, void *buffer, ulong buflen)
+iucv_reply (u16 pathid,
+           u32 msgid, u32 trgcls,
+           int flags1,
+           void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_reply: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr2 = (u32) ((ulong) buffer);
+       parm.ipbfln2f = (u32) buflen;   /* length of message */
        parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen; /* length of message */
-       parm.ipsrccls = srccls;
-       parm.ipmsgtag = msgtag;
-       parm.ipflags1 |= one_way_msg;   /* one way message */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (send, &parm);
-       if (b2f0_result)
-               return b2f0_result;
-       if (msgid)
-               *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send\n");
-#endif
+       parm.ipflags1 = (uchar) flags1; /* priority message */
+
+       b2f0_result = b2f0 (REPLY, &parm);
+
+       if ((b2f0_result == 0) || (b2f0_result == 5)) {
+               if (ipbfadr2)
+                       *ipbfadr2 = parm.ipbfadr2;
+               if (ipbfln2f)
+                       *ipbfln2f = parm.ipbfln2f;
+       }
+
+       pr_debug ("iucv_reply: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send_array                                      */
-/* Purpose: sends messages in buffer array                    */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to iucv_array_t                    */
-/*        buflen - ulong, length of buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/*
+ * Name: iucv_reply_array
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to   
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ *          The array identifies a list of addresses and lengths of
+ *          discontiguous buffers that contains the reply data.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class 
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of reply buffers
+ *        buflen - total length of reply buffers
+ * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
+ *         ipbfln2f - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ *             (-EINVAL) - buffer address is NULL
+*/
 int
-iucv_send_array (ushort pathid, ulong * msgid,
-                ulong trgcls, ulong srccls,
-                ulong msgtag, uchar priority_msg,
-                iucv_array_t * buffer, ulong buflen)
+iucv_reply_array (u16 pathid,
+                 u32 msgid, u32 trgcls,
+                 int flags1,
+                 iucv_array_t * buffer,
+                 ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send_array\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_reply_array: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr2 = (u32) ((ulong) buffer);
+       parm.ipbfln2f = buflen; /* length of message */
        parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen; /* length of message */
-       parm.ipsrccls = srccls;
-       parm.ipmsgtag = msgtag;
-       parm.ipflags1 |= one_way_msg;   /* one way message */
-       parm.ipflags1 |= array; /* one way w/ array */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
-               *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send_array\n");
-#endif
+       parm.ipflags1 = (IPANSLST | flags1);
+
+       b2f0_result = b2f0 (REPLY, &parm);
+
+       if ((b2f0_result == 0) || (b2f0_result == 5)) {
+
+               if (ipbfadr2)
+                       *ipbfadr2 = parm.ipbfadr2;
+               if (ipbfln2f)
+                       *ipbfln2f = parm.ipbfln2f;
+       }
+
+       pr_debug ("iucv_reply_array: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send_prmmsg                                     */
-/* Purpose: sends messages in parameter list                  */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent               */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/*
+ * Name: iucv_reply_prmmsg
+ * Purpose: This function responds to the two-way messages that you
+ *          receive. You must identify completely the message to
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.
+ *          Prmmsg signifies the data is moved into the
+ *          parameter list.
+ * Input: pathid - path identification number
+ *        msgid - specifies the message ID. 
+ *        trgcls - specifies target class
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into the parameter
+ *                 list.
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
 int
-iucv_send_prmmsg (ushort pathid, ulong * msgid,
-                 ulong trgcls, ulong srccls,
-                 ulong msgtag, uchar priority_msg, uchar prmmsg[8])
+iucv_reply_prmmsg (u16 pathid,
+                  u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8])
 {
        iparml_dpl parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send_prmmsg\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_reply_prmmsg: entering\n");
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
+       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       parm.ipsrccls = srccls;
-       parm.ipmsgtag = msgtag;
-       parm.ipflags1 |= parm_data;     /* message in prmlist */
-       parm.ipflags1 |= one_way_msg;   /* one way message */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       memcpy (parm.iprmmsg, prmmsg, 8);
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
-               *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send_prmmsg\n");
-#endif
+       memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+       parm.ipflags1 = (IPRMDATA | flags1);
+
+       b2f0_result = b2f0 (REPLY, &parm);
+
+       pr_debug ("iucv_reply_prmmsg: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way                                        */
-/* Purpose: sends messages in both directions                 */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to buffer                          */
-/*        buflen - ulong, length of buffer                    */
-/*        ansbuf - pointer to buffer on reply                 */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/*
+ * Name: iucv_resume                                          
+ * Purpose: This function restores communication over a quiesced path.       
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte of user data                     
+ * Output: b2f0_result - return code from CP               
+ */
 int
-iucv_send2way (ushort pathid, ulong * msgid,
-              ulong trgcls, ulong srccls,
-              ulong msgtag, uchar priority_msg,
-              void *buffer, ulong buflen, void *ansbuf, ulong anslen)
+iucv_resume (u16 pathid, uchar user_data[16])
+{
+       iparml_control parm;
+       ulong b2f0_result = 0;
+
+       pr_debug ("iucv_resume: entering\n");
+       pr_debug ("iucv_resume: pathid = %d\n", pathid);
+
+       memset (&parm, 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, sizeof (*user_data));
+       parm.ippathid = pathid;
+
+       b2f0_result = b2f0 (RESUME, &parm);
+
+       pr_debug ("iucv_resume: exiting \n");
+
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_send                                             
+ * Purpose: sends messages                                    
+ * Input: pathid - ushort, pathid                            
+ *        msgid  - ulong *, id of message returned to caller   
+ *        trgcls - ulong, target message class              
+ *        srccls - ulong, source message class              
+ *        msgtag - ulong, message tag                    
+ *       flags1  - Contains options for this path.
+ *             IPPRTY - Ox20 - specifies if you want to send a priority message.
+ *        buffer - pointer to buffer                           
+ *        buflen - ulong, length of buffer                     
+ * Output: b2f0_result - return code from b2f0 call               
+ *         msgid - returns message id                         
+ */
+int
+iucv_send (u16 pathid, u32 * msgid,
+          u32 trgcls, u32 srccls,
+          u32 msgtag, int flags1, void *buffer, ulong buflen)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send2way\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_send: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ipbfadr1 = (u32) ((ulong) buffer);
        parm.ippathid = pathid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen; /* length of message */
-       parm.ipbfadr2 = (ulong) ansbuf;
-       parm.ipbfln2f = anslen;
+       parm.ipbfln1f = (u32) buflen;   /* length of message */
        parm.ipsrccls = srccls;
        parm.ipmsgtag = msgtag;
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
+       parm.ipflags1 = (IPNORPY | flags1);     /* one way priority message */
+
+       b2f0_result = b2f0 (SEND, &parm);
+
+       if ((b2f0_result == 0) && (msgid))
                *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send2way\n");
-#endif
+
+       pr_debug ("iucv_send: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_array                                  */
-/* Purpose: sends messages in both directions in arrays       */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        buffer - pointer to iucv_array_t                    */
-/*        buflen - ulong, length of buffer                    */
-/*        ansbuf - pointer to iucv_array_t on reply           */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/*
+ * Name: iucv_send_array
+ * Purpose: This function transmits data to another application.
+ *          The contents of buffer is the address of the array of
+ *          addresses and lengths of discontiguous buffers that hold
+ *          the message text. This is a one-way message and the
+ *          receiver will not reply to the message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated witht the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of send buffers
+ *        buflen - total length of send buffers
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP 
+ *         (-EINVAL) - buffer address is NULL
+ */
 int
-iucv_send2way_array (ushort pathid, ulong * msgid,
-                    ulong trgcls, ulong srccls,
-                    ulong msgtag, uchar priority_msg,
-                    iucv_array_t * buffer, ulong buflen,
-                    iucv_array_t * ansbuf, ulong anslen)
+iucv_send_array (u16 pathid,
+                u32 * msgid,
+                u32 trgcls,
+                u32 srccls,
+                u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send2way_array\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_send_array: entering\n");
+
+       if (!buffer)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr1 = (ulong) buffer;
-       parm.ipbfln1f = buflen; /* length of message */
-       parm.ipbfadr2 = (ulong) ansbuf;
-       parm.ipbfln2f = anslen;
+       parm.ipbfadr1 = (u32) ((ulong) buffer);
+       parm.ipbfln1f = (u32) buflen;   /* length of message */
        parm.ipsrccls = srccls;
        parm.ipmsgtag = msgtag;
-       parm.ipflags1 |= array; /* send  w/ array  */
-       parm.ipflags1 |= reply_array;   /* reply w/ array  */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
+       parm.ipflags1 = (IPNORPY | IPBUFLST | flags1);
+       b2f0_result = b2f0 (SEND, &parm);
+
+       if ((b2f0_result == 0) && (msgid))
                *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send2way_array\n");
-#endif
+       pr_debug ("iucv_send_array: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg                                 */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message                     */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent in parameter  */
-/*        ansbuf - pointer to buffer                          */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
+/*
+ * Name: iucv_send_prmmsg
+ * Purpose: This function transmits data to another application. 
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a one-way message and the
+ *          receiver will not reply to the message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into parameter list
+ * Output: msgid - specifies the message ID.   
+ * Return: b2f0_result - return code from CP
+*/
 int
-iucv_send2way_prmmsg (ushort pathid, ulong * msgid,
-                     ulong trgcls, ulong srccls,
-                     ulong msgtag, uchar priority_msg,
-                     uchar prmmsg[8], void *ansbuf, ulong anslen)
+iucv_send_prmmsg (u16 pathid,
+                 u32 * msgid,
+                 u32 trgcls,
+                 u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8])
 {
        iparml_dpl parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_send_prmmsg: entering\n");
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
        parm.iptrgcls = trgcls;
        parm.ipsrccls = srccls;
        parm.ipmsgtag = msgtag;
-       parm.ipbfadr2 = (ulong) ansbuf;
-       parm.ipbfln2f = anslen;
-       parm.ipflags1 |= parm_data;     /* message in prmlist */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       memcpy (parm.iprmmsg, prmmsg, 8);
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
+       parm.ipflags1 = (IPRMDATA | IPNORPY | flags1);
+       memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+       b2f0_result = b2f0 (SEND, &parm);
+
+       if ((b2f0_result == 0) && (msgid))
                *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
+
+       pr_debug ("iucv_send_prmmsg: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply                                           */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        buf    - pointer, address of buffer                 */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way
+ * Purpose: This function transmits data to another application.
+ *          Data to be transmitted is in a buffer. The receiver
+ *          of the send is expected to reply to the message and
+ *          a buffer is provided into which IUCV moves the reply 
+ *          to this message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of send buffer
+ *        buflen - length of send buffer
+ *        ansbuf - address of buffer to reply with
+ *        anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer or ansbuf address is NULL
+ */
 int
-iucv_reply (ushort pathid, ulong msgid, ulong trgcls,
-           uchar priority_msg, void *buf, ulong buflen)
+iucv_send2way (u16 pathid,
+              u32 * msgid,
+              u32 trgcls,
+              u32 srccls,
+              u32 msgtag,
+              int flags1,
+              void *buffer, ulong buflen, void *ansbuf, ulong anslen)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_reply\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+       pr_debug ("iucv_send2way: entering\n");
+
+       if (!buffer || !ansbuf)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
-       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr2 = (ulong) buf;
-       parm.ipbfln2f = buflen; /* length of message */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_reply\n");
-#endif
+       parm.ipbfadr1 = (u32) ((ulong) buffer);
+       parm.ipbfln1f = (u32) buflen;   /* length of message */
+       parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+       parm.ipbfln2f = (u32) anslen;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 = flags1; /* priority message */
+
+       b2f0_result = b2f0 (SEND, &parm);
+
+       if ((b2f0_result == 0) && (msgid))
+               *msgid = parm.ipmsgid;
+
+       pr_debug ("iucv_send2way: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply_array                                     */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        buf    - pointer, address of array                  */
-/*        buflen - length of buffer                           */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_array
+ * Purpose: This function transmits data to another application.
+ *          The contents of buffer is the address of the array of
+ *          addresses and lengths of discontiguous buffers that hold
+ *          the message text. The receiver of the send is expected to
+ *          reply to the message and a buffer is provided into which
+ *          IUCV moves the reply to this message.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - spcifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        buffer - address of array of send buffers
+ *        buflen - total length of send buffers
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+ */
 int
-iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls,
-                 uchar priority_msg, iucv_array_t * buffer, ulong buflen)
+iucv_send2way_array (u16 pathid,
+                    u32 * msgid,
+                    u32 trgcls,
+                    u32 srccls,
+                    u32 msgtag,
+                    int flags1,
+                    iucv_array_t * buffer,
+                    ulong buflen, iucv_array_t * ansbuf, ulong anslen)
 {
        iparml_db parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_reply_array\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_send2way_array: entering\n");
+
+       if (!buffer || !ansbuf)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
-       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       parm.ipbfadr2 = (ulong) buffer;
-       parm.ipbfln2f = buflen; /* length of message */
-       parm.ipflags1 |= reply_array;   /* reply w/ array  */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_reply_array\n");
-#endif
+       parm.ipbfadr1 = (u32) ((ulong) buffer);
+       parm.ipbfln1f = (u32) buflen;   /* length of message */
+       parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+       parm.ipbfln2f = (u32) anslen;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipflags1 = (IPBUFLST | IPANSLST | flags1);
+       b2f0_result = b2f0 (SEND, &parm);
+       if ((b2f0_result == 0) && (msgid))
+               *msgid = parm.ipmsgid;
+       pr_debug ("iucv_send2way_array: exiting\n");
+       return b2f0_result;
+}
+
+/*
+ * Name: iucv_send2way_prmmsg
+ * Purpose: This function transmits data to another application.
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a two-way message and the
+ *          receiver of the message is expected to reply. A buffer
+ *          is provided into which IUCV moves the reply to this
+ *          message.
+ * Input: pathid - path identification number  
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed in parameter list
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - buffer address is NULL
+*/
+int
+iucv_send2way_prmmsg (u16 pathid,
+                     u32 * msgid,
+                     u32 trgcls,
+                     u32 srccls,
+                     u32 msgtag,
+                     ulong flags1, uchar prmmsg[8], void *ansbuf, ulong anslen)
+{
+       iparml_dpl parm;
+       ulong b2f0_result;
+       pr_debug ("iucv_send2way_prmmsg: entering\n");
+
+       if (!ansbuf)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
+       parm.ippathid = pathid;
+       parm.iptrgcls = trgcls;
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+       parm.ipbfln2f = (u32) anslen;
+       parm.ipflags1 = (IPRMDATA | flags1);    /* message in prmlist */
+       memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+       b2f0_result = b2f0 (SEND, &parm);
+
+       if ((b2f0_result == 0) && (msgid))
+               *msgid = parm.ipmsgid;
+
+       pr_debug ("iucv_send2way_prmmsg: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_reply_prmmsg                                    */
-/* Purpose: responds to the two-way messages in parameter list */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong, id of message                       */
-/*        trgcls - ulong, target message class                */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message in parameter list        */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_prmmsg_array
+ * Purpose: This function transmits data to another application.
+ *          Prmmsg specifies that the 8-bytes of data are to be moved
+ *          into the parameter list. This is a two-way message and the
+ *          receiver of the message is expected to reply. A buffer
+ *          is provided into which IUCV moves the reply to this
+ *          message. The contents of ansbuf is the address of the
+ *          array of addresses and lengths of discontiguous buffers
+ *          that contain the reply.
+ * Input: pathid - path identification number
+ *        trgcls - specifies target class
+ *        srccls - specifies the source message class   
+ *        msgtag - specifies a tag to be associated with the message
+ *        flags1 - option for path
+ *                 IPPRTY- specifies if you want to send priority message
+ *        prmmsg - 8-bytes of data to be placed into the parameter list
+ *        ansbuf - address of buffer to reply with                       
+ *        anslen - length of buffer to reply with     
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ *         (-EINVAL) - ansbuf address is NULL
+ */
 int
-iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls,
-                  uchar priority_msg, uchar prmmsg[8])
+iucv_send2way_prmmsg_array (u16 pathid,
+                           u32 * msgid,
+                           u32 trgcls,
+                           u32 srccls,
+                           u32 msgtag,
+                           int flags1,
+                           uchar prmmsg[8],
+                           iucv_array_t * ansbuf, ulong anslen)
 {
        iparml_dpl parm;
        ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+
+       pr_debug ("iucv_send2way_prmmsg_array: entering\n");
+
+       if (!ansbuf)
+               return -EINVAL;
+
+       memset (&parm, 0, sizeof (parm));
        parm.ippathid = pathid;
-       parm.ipmsgid = msgid;
        parm.iptrgcls = trgcls;
-       memcpy (parm.iprmmsg, prmmsg, 8);
-       parm.ipflags1 |= parm_data;
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
-#endif
+       parm.ipsrccls = srccls;
+       parm.ipmsgtag = msgtag;
+       parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+       parm.ipbfln2f = (u32) anslen;
+       parm.ipflags1 = (IPRMDATA | IPANSLST | flags1);
+       memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+       b2f0_result = b2f0 (SEND, &parm);
+       if ((b2f0_result == 0) && (msgid))
+               *msgid = parm.ipmsgid;
+       pr_debug ("iucv_send2way_prmmsg_array: exiting\n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_connect                                         */
-/* Purpose: establishes an IUCV path to another vm            */
-/* Input: pathid - ushort *, pathid returned to user          */
-/*        msglim - ushort, limit of outstanding messages      */
-/*        user_data - uchar[16], user data                    */
-/*        userid - uchar[8], user's id                        */
-/*        system_name - uchar[8], system identification       */
-/*        priority_requested - uchar- flag                    */
-/*        prmdata - uchar, flag prgrm can handler messages    */
-/*                  in parameter list                         */
-/*        quiesce - uchar, flag to quiesce a path being establ */
-/*        control - uchar, flag, option not used              */
-/*        local   - uchar, flag, establish connection only on */
-/*                  local system                              */
-/*        priority_permitted - uchar *, flag returned to user */
-/*        handle - address of handler                         */
-/*        pgm_data - ulong                                    */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_setmask
+ * Purpose: This function enables or disables the following IUCV   
+ *          external interruptions: Nonpriority and priority message
+ *          interrupts, nonpriority and priority reply interrupts.
+ * Input: SetMaskFlag - options for interrupts
+ *           0x80 - Nonpriority_MessagePendingInterruptsFlag
+ *           0x40 - Priority_MessagePendingInterruptsFlag
+ *           0x20 - Nonpriority_MessageCompletionInterruptsFlag
+ *           0x10 - Priority_MessageCompletionInterruptsFlag
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
 int
-iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16],
-             uchar userid[8], uchar system_name[8],
-             uchar priority_requested, uchar prmdata,
-             uchar quiesce, uchar control,
-             uchar local, uchar * priority_permitted,
-             iucv_handle_t handle, ulong pgm_data)
+iucv_setmask (int SetMaskFlag)
 {
-       iparml_control parm;
-       ulong b2f0_result;
-       int add_pathid_result, rc;
-       handler *R;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_connect\n");
-#endif
+       iparml_set_mask parm;
+       ulong b2f0_result = 0;
+       pr_debug ("iucv_setmask: entering \n");
+
        memset (&parm, 0, sizeof (parm));
-       if (declare_flag == NULL) {
-               rc = iucv_declare_buffer (iucv_external_int_buffer);
-               if (rc) {
-                       printk (KERN_DEBUG "IUCV: registration failed\n");
-#ifdef DEBUG
-                       printk (KERN_DEBUG "rc from declare buffer is: %i\n",
-                               rc);
-#endif
-                       return rc;
-               } else
-                       declare_flag = 1;
-       }
-       /* Checking if handle is valid  */
-       spin_lock (&lock);
-       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
-               if (R == handle)
-                       break;
-       if (R == NULL) {
-               spin_unlock (&lock);
-#ifdef DEBUG
-               printk (KERN_DEBUG "iucv_connect: Invalid Handle\n");
-#endif
-               return (-2);
-       }
-       if (pathid == NULL) {
-               spin_unlock (&lock);
-#ifdef DEBUG
-               printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n");
-#endif
-               return (-3);
-       }
-       spin_unlock (&lock);
-       parm.ipmsglim = msglim;
-       memcpy (parm.ipuser, user_data, 16);
-       memcpy (parm.ipvmid, userid, 8);
-       memcpy (parm.iptarget, system_name, 8);
-       if (parm.iptarget)
-               ASCEBC (parm.iptarget, 8);
-       if (parm.ipvmid) {
-               ASCEBC (parm.ipvmid, 8);
-               EBC_TOUPPER(parm.ipvmid, 8);
-       }
-       if (priority_requested)
-               parm.ipflags1 |= prior_msg;
-       if (prmdata)
-               parm.ipflags1 |= parm_data;     /*data in parameter list */
-       if (quiesce)
-               parm.ipflags1 |= quiesce_msg;
-       if (control) {
-               /* do nothing at the time being  */
-               /*control not provided yet */
-       }
-       if (local)
-               parm.ipflags1 |= local_conn;    /*connect on local system */
-       b2f0_result = b2f0 (connect, &parm);
-       if (b2f0_result)
-               return b2f0_result;
-       add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
-       if (add_pathid_result) {
-#ifdef DEBUG
-               printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
-#endif
-               return (add_pathid_result);
-       }
-       *pathid = parm.ippathid;
-       if (parm.ipflags1 & prior_msg)
-               if (priority_permitted)
-                       *priority_permitted = 0x01;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_connect\n");
-#endif
+       parm.ipmask = (uchar) SetMaskFlag;
+
+       b2f0_result = b2f0 (SETMASK, &parm);
+
+       pr_debug ("iucv_setmask: b2f0_result = %ld\n", b2f0_result);
+       pr_debug ("iucv_setmask: exiting\n");
+
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_accept                                          */
-/* Purpose: completes the iucv communication path             */
-/* Input: pathid - ushort , pathid                            */
-/*        msglim - ushort, limit of outstanding messages      */
-/*        user_data - uchar[16], user data                    */
-/*        priority_requested - uchar- flag                    */
-/*        prmdata - uchar, flag prgrm can handler messages    */
-/*                  in parameter list                         */
-/*        quiesce - uchar, flag to quiesce a path being establ*/
-/*        control - uchar, flag, option not used              */
-/*        priority_permitted -uchar *, flag returned to caller*/
-/*        handle - address of handler                         */
-/*        pgm_data - ulong                                    */
-/* Output: iprcode - return code from b2f0 call               */
-/**************************************************************/
+/*
+ * Name: iucv_sever                                           
+ * Purpose: This function terminates an iucv path         
+ * Input: pathid - u16, path identification number                             
+ *        user_data - uchar[16], 16-byte of user data                     
+ * Output: b2f0_result - return code from CP          
+ *         -EINVAL - NULL address found for handler                                 
+ */
 int
-iucv_accept (ushort pathid, ushort msglim, uchar user_data[16],
-            uchar priority_requested,
-            uchar prmdata, uchar quiesce, uchar control,
-            uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data)
+iucv_sever (u16 pathid, uchar user_data[16])
 {
-       ulong index1, index2;
-       handler_table_entry *P = 0;
        iparml_control parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_accept\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
+       ulong b2f0_result = 0;
+       pr_debug ("iucv_sever: entering\n");
+       memset (&parm, 0, sizeof (parm));
+       memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
        parm.ippathid = pathid;
-       parm.ipmsglim = msglim;
-       memcpy (parm.ipuser, user_data, 16);
-       if (priority_requested)
-               parm.ipflags1 |= prior_msg;
-       if (prmdata)
-               parm.ipflags1 |= parm_data;     /*data in parameter list */
-       if (quiesce)
-               parm.ipflags1 |= quiesce_msg;
-       if (control) {
-               /* do nothing at the time being  */
-               /*control not provided yet */
-       }
-       b2f0_result = b2f0 (accept, &parm);
-       if (b2f0_result)
-               return b2f0_result;
-       index1 = ((ulong) pathid) / 512;
-       index2 = ((ulong) pathid) % 512;
-       spin_lock (&lock);
-       if (pgm_data) {
-               P = main_table[index1];
-               (P + index2)->pgm_data = pgm_data;
-       }
-       spin_unlock (&lock);
-       if (parm.ipflags1 & prior_msg)
-               if (priority_permitted)
-                       *priority_permitted = 0x01;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_accept\n");
-#endif
+
+       b2f0_result = b2f0 (SEVER, &parm);
+
+       if (!b2f0_result)
+               iucv_remove_pathid (pathid);
+
+       pr_debug ("iucv_sever: exiting \n");
        return b2f0_result;
 }
 
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg_array                           */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid                             */
-/*        msgid  - ulong *, id of message returned to caller  */
-/*        trgcls - ulong, target message class                */
-/*        srccls - ulong, source message class                */
-/*        msgtag - ulong, message tag                         */
-/*        priority_msg - uchar, flag                          */
-/*        prmmsg - uchar[8], message being sent in parameter  */
-/*        ansbuf - pointer to array of buffers                */
-/*        anslen - length of ansbuf buffer                    */
-/* Output: iprcode - return code from b2f0 call               */
-/*         msgid - returns message id                         */
-/**************************************************************/
-int
-iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid,
-                           ulong trgcls, ulong srccls,
-                           ulong msgtag, uchar priority_msg,
-                           uchar prmmsg[8],
-                           iucv_array_t * ansbuf, ulong anslen)
+static void
+iucv_remove_pathid (u16 pathid)
 {
-       iparml_dpl parm;
-       ulong b2f0_result;
-#ifdef DEBUG
-       printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
-       memset (&(parm), 0, sizeof (parm));
-       parm.ippathid = pathid;
-       parm.iptrgcls = trgcls;
-       parm.ipsrccls = srccls;
-       parm.ipmsgtag = msgtag;
-       parm.ipbfadr2 = (ulong) ansbuf;
-       parm.ipbfln2f = anslen;
-       parm.ipflags1 |= 0x88;  /* message in prmlist */
-       if (priority_msg)
-               parm.ipflags1 |= prior_msg;     /* priority message */
-       memcpy (parm.iprmmsg, prmmsg, 8);
-       b2f0_result = b2f0 (send, &parm);
-       if (msgid)
-               *msgid = parm.ipmsgid;
-#ifdef DEBUG
-       printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
-       return b2f0_result;
+       handler_table_entry *users_hte = NULL;  /*users handler_table_entry */
+       handler *users_handler = NULL;
+       ulong *users_pathid = NULL;
+       ulong flags;
+       spin_lock_irqsave (&iucv_lock, flags);
+       users_hte = handler_table_anchor + (int) pathid;
+
+       if ((users_hte->addrs) == NULL) {
+               spin_unlock_irqrestore (&iucv_lock, flags);
+               return;         /* wild pointer has been found */
+       }
+
+       users_handler = users_hte->addrs;
+
+       pr_debug ("iucv_sever: pathid is %d\n", pathid);
+       pr_debug ("iucv_sever: H_T_E is %p\n", users_hte);
+       pr_debug ("iucv_sever: address of handler is %p\n", users_handler);
+       pr_debug ("iucv_sever: below is pathid table\n");
+       iucv_dumpit ((uchar *) users_handler->pathid_head,
+                    (int) users_handler->entries * sizeof (ulong));
+
+/*
+ * Searching the pathid address table for matching address, once    
+ * found, NULL the handler_table_entry field and then zero the H_T_E fields.               
+ */
+
+       for (users_pathid = (users_handler->pathid_head);
+            users_pathid < (users_handler->pathid_tail); users_pathid++)
+
+               if (*users_pathid == (ulong) users_hte) {
+                       pr_debug ("iucv_sever: found a path to remove from"
+                                 "table\n");
+                       pr_debug ("iucv_sever: removing %d \n",
+                                 (int) (*users_pathid)); *users_pathid = NULL;
+
+                       memset (users_hte, 0, sizeof (handler_table_entry));
+               }
+       spin_unlock_irqrestore (&iucv_lock, flags);
+       return;
 }
 
-/******************************************************************/
-/* Name: top_half_handler                                         */
-/* Purpose: handle minimum amount of interrupt in fastest time    */
-/*  possible and then pass interrupt to bottom half handler.      */
-/* Input: external interrupt buffer                               */
-/* Output: void                                                   */
-/******************************************************************/
+/*
+ * Interrupt Handling Functions
+ *     top_half_interrupt
+ *     bottom_half_interrupt
+ *     do_int
+ */
+
+/*
+ * Name: top_half_interrupt                                         
+ * Purpose: Handles interrupts coming in from CP.  Places the interrupt on a queue and  
+ *         calls bottom_half_interrupt          
+ * Input: external interrupt buffer                                
+ * Output: void                                                    
+ */
 
 inline void
 top_half_interrupt (struct pt_regs *regs, __u16 code)
 {
        iucv_packet *pkt;
-       pkt = (iucv_packet *) kmalloc
-           (sizeof (iucv_packet), GFP_ATOMIC);
+       int cpu = smp_processor_id();
+
+       irq_enter(cpu, 0x4000);
+
+       pkt = (iucv_packet *) kmalloc (sizeof (iucv_packet), GFP_ATOMIC);
        if (pkt == NULL) {
-               printk (KERN_DEBUG "out of memory\n");
+               printk (KERN_WARNING
+                       "iucv:top_half_interrupt: out of memory\n");
+               irq_exit(cpu, 0x4000);
                return;
        }
-       memcpy (pkt->data, iucv_external_int_buffer, 40);
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4));
-#endif
+
+       memcpy (pkt->data, iucv_external_int_buffer, BUFFER_SIZE);
+
+       pr_debug ("TH: Got INT: %08x\n", *(int *) (pkt->data + 4));
+
        /* put new packet on the list */
        spin_lock (&iucv_packets_lock);
        pkt->next = NULL;
+
        if (iucv_packets_tail != NULL)
                iucv_packets_tail->next = pkt;
        else
                iucv_packets_head = pkt;
+
        iucv_packets_tail = pkt;
        spin_unlock (&iucv_packets_lock);
 
        if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Queuing BH\n");
-#endif
-               INIT_LIST_HEAD(&short_task.list);
-               short_task.sync = 0;
                short_task.routine = (void *) bottom_half_interrupt;
                queue_task (&short_task, &tq_immediate);
                mark_bh (IMMEDIATE_BH);
        }
+       irq_exit(cpu, 0x4000);
        return;
 }
 
-/*******************************************************************/
-/* Name: bottom_half_interrupt                                     */
-/* Purpose: Handle interrupt at a more safer time                  */
-/* Input: void                                                     */
-/* Output: void                                                    */
-/*******************************************************************/
+/*
+ * Name: bottom_half_interrupt                                      
+ * Purpose: Handle interrupt at a more safer time                  
+ * Input: void                                                     
+ * Output: void                                                    
+ */
 void
 bottom_half_interrupt (void)
 {
        iucv_packet *iucv_packet_list;
        iucv_packet *tmp;
        ulong flags;
-
        atomic_set (&bh_scheduled, 0);
+
        spin_lock_irqsave (&iucv_packets_lock, flags);
        iucv_packet_list = iucv_packets_head;
        iucv_packets_head = iucv_packets_tail = NULL;
        spin_unlock_irqrestore (&iucv_packets_lock, flags);
 
        /* now process all the request in the iucv_packet_list */
-#ifdef DEBUG3
-       printk (KERN_EMERG "BH: Process all packets\n");
-#endif
+       pr_debug ("BH: Process all packets\n");
        while (iucv_packet_list != NULL) {
-#ifdef DEBUG3
-               printk( KERN_EMERG "BH:>  %08x\n", 
-                       *(int *)(iucv_packet_list->data+4));
-#endif
-               do_int ((iucv_ConnectionPending *) iucv_packet_list->data);
-#ifdef DEBUG3
-               printk( KERN_EMERG "BH:<  %08x\n",
-                       *(int *)(iucv_packet_list->data+4));
-#endif
+               pr_debug ("BH:>  %08x\n",
+                         *(int *) (iucv_packet_list->data + 4));
+
+               do_int ((iucv_GeneralInterrupt *) iucv_packet_list->data);
+
+               pr_debug ("BH:<  %08x\n",
+                         *(int *) (iucv_packet_list->data + 4));
                tmp = iucv_packet_list;
                iucv_packet_list = iucv_packet_list->next;
                kfree (tmp);
        }
-#ifdef DEBUG3
-       printk (KERN_EMERG "BH: Done\n");
-#endif
+       pr_debug ("BH: Done\n");
        return;
 }
-/*******************************************************************/
-/* Name: do_int                                                    */
-/* Purpose: Handle interrupt in a more safe environment            */
-/* Inuput: int_buf - pointer to copy of external interrupt buffer  */
-/* Output: void                                                    */
-/*******************************************************************/
+
+/*
+ * Name: do_int                                                     
+ * Purpose: Handles the interrupts in a more safe environment             
+ * Input: int_buf - pointer to copy of external interrupt buffer  
+ * Output: void                                                     
+ */
 void
-do_int (iucv_ConnectionPending * int_buf)
+do_int (iucv_GeneralInterrupt * int_buf)
 {
-       ulong index1 = 0, index2 = 0;
-       handler_table_entry *P = 0;     /* P is a pointer */
-       handler *Q = 0, *R;     /* Q and R are pointers */
+       handler_table_entry *P = 0;
+       ulong flags;
+       handler *Q = 0, *R;
        iucv_interrupt_ops_t *interrupt = 0;    /* interrupt addresses */
        uchar temp_buff1[24], temp_buff2[24];   /* masked handler id. */
        int add_pathid_result = 0, j = 0;
        uchar no_listener[16] = "NO LISTENER";
-#ifdef DEBUG
-       int i;
-       uchar *prt_parm;
-#endif
-#ifdef DEBUG3
-       printk (KERN_DEBUG "BH:-  Entered do_int "
-                          "pathid %d, type %02X\n",
-               int_buf->ippathid, int_buf->iptype);
-#endif
-#ifdef DEBUG
-       prt_parm = (uchar *) (int_buf);
-       printk (KERN_DEBUG "External Interrupt Buffer\n");
-       for (i = 0; i < 40; i++)
-               printk (KERN_DEBUG "%02x ", prt_parm[i]);
-       printk (KERN_DEBUG "\n");
-#endif
+
+       pr_debug ("IUCV: BHI: -  Entered do_int "
+                 "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
+       pr_debug ("BHI:External Interrupt Buffer\n");
+       iucv_dumpit ((uchar *) int_buf, sizeof (iucv_GeneralInterrupt));
+
        ASCEBC (no_listener, 16);
        if (int_buf->iptype != 01) {
-               index1 = ((ulong) (int_buf->ippathid)) / 512;
-               index2 = ((ulong) (int_buf->ippathid)) % 512;
-               spin_lock (&lock);
-
-               P = main_table[index1];
-               Q = (P + index2)->addrs;
-               interrupt = Q->interrupt_table; /* interrupt functions */
-               spin_unlock (&lock);
-#ifdef DEBUG
-               printk (KERN_DEBUG "Handler is: \n");
-               prt_parm = (uchar *) Q;
-               for (i = 0; i < sizeof (handler); i++)
-                       printk (KERN_DEBUG " %02x ", prt_parm[i]);
-               printk (KERN_DEBUG "\n");
-#endif
-       }                       /* end of if statement */
+               spin_lock_irqsave (&iucv_lock, flags);
+               P = handler_table_anchor + int_buf->ippathid;
+               Q = P->addrs;
+               interrupt = P->ops;     /* interrupt functions */
+
+               pr_debug ("iucv: do_int: Handler\n");
+               iucv_dumpit ((uchar *) Q, sizeof (handler));
+               spin_unlock_irqrestore (&iucv_lock, flags);
+       }
+       /* end of if statement */
        switch (int_buf->iptype) {
        case 0x01:              /* connection pending */
-               spin_lock (&lock);
+               spin_lock_irqsave (&iucv_lock, flags);
                for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
                        memcpy (temp_buff1, &(int_buf->ipvmid), 24);
-                       memcpy (temp_buff2, &(R->vmid), 24);
+                       memcpy (temp_buff2, &(R->id.userid), 24);
                        for (j = 0; j < 24; j++) {
-                               temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j];
-                               temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j];
+                               temp_buff1[j] =
+                                   (temp_buff1[j]) & (R->id.mask)[j];
+                               temp_buff2[j] =
+                                   (temp_buff2[j]) & (R->id.mask)[j];
                        }
-#ifdef DEBUG
-                       for (i = 0; i < sizeof (temp_buff1); i++)
-                               printk (KERN_DEBUG " %c ", temp_buff1[i]);
-                       printk (KERN_DEBUG "\n");
-                       for (i = 0; i < sizeof (temp_buff2); i++)
-                               printk (KERN_DEBUG " %c ", temp_buff2[i]);
-                       printk (KERN_DEBUG "\n");
-#endif
-                       if (memcmp((void *) temp_buff1,
-                                  (void *) temp_buff2, 24) == 0) {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "found a matching handler\n");
-#endif
+
+                       pr_debug ("iucv:do_int: temp_buff1\n");
+                       iucv_dumpit (temp_buff1, sizeof (temp_buff1));
+                       pr_debug ("iucv:do_int: temp_buff2\n");
+                       iucv_dumpit (temp_buff2, sizeof (temp_buff2));
+
+                       if (memcmp ((void *) temp_buff1,
+                                   (void *) temp_buff2, 24) == 0) {
+
+                               pr_debug
+                                   ("iucv:do_int: found a matching handler\n");
                                break;
                        }
                }
-               spin_unlock (&lock);
+               spin_unlock_irqrestore (&iucv_lock, flags);
+
                if (R) {
                        /* ADD PATH TO PATHID TABLE */
-                       add_pathid_result =
-                           add_pathid (int_buf->ippathid, R, R->pgm_data);
+                       add_pathid_result = iucv_add_pathid (int_buf->ippathid,
+                                                            R, R->pgm_data);
                        if (add_pathid_result == NULL) {
                                interrupt = R->interrupt_table;
-                               if ((*interrupt).ConnectionPending) {
+                               if (interrupt->ConnectionPending) {
+
                                        EBCASC (int_buf->ipvmid, 8);
-                                       
-                                           ((*interrupt).
-                                        ConnectionPending) (int_buf,
-                                                            R->pgm_data);
+
+                                       (interrupt->ConnectionPending)
+                                           ((iucv_ConnectionPending *) int_buf,
+                                            (R->pgm_data));
                                } else {
                                        iucv_sever (int_buf->ippathid,
                                                    no_listener);
                                }
-                       } /* end if if(add_p...... */
+                       } /* end of if(add_p...... */
                        else {
                                iucv_sever (int_buf->ippathid, no_listener);
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "add_pathid failed with rc = %d\n",
-                                       (int) add_pathid_result);
-#endif
+                               pr_debug ("iucv:do_int:add_pathid failed"
+                                         "with rc = %d\n",
+                                         (int) add_pathid_result);
                        }
                } else
                        iucv_sever (int_buf->ippathid, no_listener);
                break;
+
        case 0x02:              /*connection complete */
                if (Q) {
-                       if ((*interrupt).ConnectionComplete)
-                               ((*interrupt).ConnectionComplete)
-                                   
-                                   ((iucv_ConnectionComplete *) int_buf,
-                                    (P + index2)->pgm_data);
-                       else {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "ConnectionComplete not called\n");
-                               printk (KERN_DEBUG "routine@ is %p\n",
-                                       (*interrupt).ConnectionComplete);
-#endif
-                       }
+                       if (interrupt->ConnectionComplete)
+                               (interrupt->ConnectionComplete)
+                                   ((iucv_ConnectionComplete *) int_buf, (P->pgm_data));
+                       else
+                               pr_debug ("iucv:do_int:"
+                                         "ConnectionComplete not called\n");
                }
+               
                break;
+
        case 0x03:              /* connection severed */
                if (Q) {
-                       if ((*interrupt).ConnectionSevered)
-                               ((*interrupt).ConnectionSevered)
-                                   
+                       if (interrupt->ConnectionSevered)
+                               (interrupt->ConnectionSevered)
                                    ((iucv_ConnectionSevered *) int_buf,
-                                    (P + index2)->pgm_data);
+                                    (P->pgm_data));
+
                        else
                                iucv_sever (int_buf->ippathid, no_listener);
                } else
                        iucv_sever (int_buf->ippathid, no_listener);
                break;
+
        case 0x04:              /* connection quiesced */
                if (Q) {
-                       if ((*interrupt).ConnectionQuiesced)
-                               ((*interrupt).ConnectionQuiesced)
-                                   
+                       if (interrupt->ConnectionQuiesced)
+                               (interrupt->ConnectionQuiesced)
                                    ((iucv_ConnectionQuiesced *) int_buf,
-                                    (P + index2)->pgm_data);
-                       else {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "ConnectionQuiesced not called\n");
-                               printk (KERN_DEBUG "routine@ is %p\n",
-                                       (*interrupt).ConnectionQuiesced);
-#endif
-                       }
+                                    (P->pgm_data));
+                       else
+                               pr_debug ("iucv:do_int:"
+                                         "ConnectionQuiesced not called\n");
                }
                break;
+
        case 0x05:              /* connection resumed */
                if (Q) {
-                       if ((*interrupt).ConnectionResumed)
-                               ((*interrupt).ConnectionResumed)
-                                   
-                                   ((iucv_ConnectionResumed *) int_buf,
-                                    (P + index2)->pgm_data);
-                       else {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "ConnectionResumed not called\n");
-                               printk (KERN_DEBUG "routine@ is %p\n",
-                                       (*interrupt).ConnectionResumed);
-#endif
-                       }
+                       if (interrupt->ConnectionResumed)
+                               (interrupt->ConnectionResumed)
+                                   ((iucv_ConnectionResumed *) int_buf, (P->pgm_data));
+                       else
+                               pr_debug ("iucv:do_int:"
+                                         "ConnectionResumed not called\n");
                }
                break;
+
        case 0x06:              /* priority message complete */
        case 0x07:              /* nonpriority message complete */
                if (Q) {
-                       if ((*interrupt).MessageComplete)
-                               ((*interrupt).MessageComplete)
-                                   
-                                   ((iucv_MessageComplete *) int_buf,
-                                    (P + index2)->pgm_data);
-                       else {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "MessageComplete not called\n");
-                               printk (KERN_DEBUG "routine@ is %p\n",
-                                       (*interrupt).MessageComplete);
-#endif
-                       }
+                       if (interrupt->MessageComplete)
+                               (interrupt->MessageComplete)
+                                   ((iucv_MessageComplete *) int_buf, (P->pgm_data));
+                       else
+                               pr_debug ("iucv:do_int:"
+                                         "MessageComplete not called\n");
                }
                break;
+
        case 0x08:              /* priority message pending  */
        case 0x09:              /* nonpriority message pending  */
                if (Q) {
-                       if ((*interrupt).MessagePending)
-                               ((*interrupt).MessagePending)
-                                   
-                                   ((iucv_MessagePending *) int_buf,
-                                    (P + index2)->pgm_data);
-                       else {
-#ifdef DEBUG
-                               printk (KERN_DEBUG
-                                       "MessagePending not called\n");
-                               printk (KERN_DEBUG "routine@ is %p\n",
-                                       (*interrupt).MessagePending);
-#endif
-                       }
+                       if (interrupt->MessagePending)
+                               (interrupt->MessagePending)
+                                   ((iucv_MessagePending *) int_buf, (P->pgm_data));
+                       else
+                               pr_debug ("iucv:do_int:"
+                                         "MessagePending not called\n");
                }
                break;
        default:                /* unknown iucv type */
-               printk (KERN_DEBUG "unknown iucv interrupt \n");
+               printk (KERN_WARNING "iucv:do_int: unknown iucv interrupt \n");
                break;
        }                       /* end switch */
-#ifdef DEBUG3
-       printk (KERN_DEBUG "BH:-  Exiting do_int "
-                          "pathid %d, type %02X\n",
-               int_buf->ippathid, int_buf->iptype);
-#endif
-       return;
-}                              /* end of function call */
-
-/**************************************************************/
-/* Name: iucv_register_program                                */
-/* Purpose: registers a new handler                           */
-/* Input: pgmname- uchar[16], user id                         */
-/*        userid - uchar[8], machine id                       */
-/*        prmmask- mask                                       */
-/*        ops    - pointer to iucv_interrupt_ops buffer       */
-/* Output: new_handler - address of new handler               */
-/**************************************************************/
-iucv_handle_t
-iucv_register_program (uchar pgmname[16],
-                      uchar userid[8],
-                      uchar pgmmask[24],
-                      iucv_interrupt_ops_t * ops, ulong pgm_data)
-{
-       int rc;
-       handler *new_handler = 0;
-#ifdef DEBUG
-       int i;
-       uchar *prt_parm;
-       printk (KERN_DEBUG "enter iucv_register_program\n");
-#endif
-       my_ops = *ops;
-       /* Allocate handler table */
-       new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
-       if (new_handler == NULL) {
-#ifdef DEBUG
-               printk (KERN_DEBUG
-                       "IUCV: returned NULL address for new handle \n");
-#endif
-               return NULL;
-       }
-       /* fill in handler table */
-       memcpy (new_handler->user_data, pgmname, 16);
-       memcpy (new_handler->vmid, userid, 8);
-       memcpy (new_handler->mask, pgmmask, 24);
-       new_handler->pgm_data = pgm_data;
-       /* Convert from ASCII to EBCDIC */
-       if (new_handler->vmid) {
-               ASCEBC (new_handler->vmid, 8);
-               EBC_TOUPPER(new_handler->vmid, 8);
-       }
-       /* fill in handler table */
-       new_handler->interrupt_table = ops;
-       new_handler->size = ADDED_STOR;
-       /* Allocate storage for pathid table */
-       new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
-       if (new_handler->start == NULL) {
-#ifdef DEBUG
-               printk (KERN_DEBUG
-                       "IUCV: returned NULL address for pathid table,"
-                       " exiting\n");
-#endif
-               kfree(new_handler);
-               return NULL;
-       }
-       memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
-       new_handler->end = (*new_handler).start + ADDED_STOR;
-       new_handler->next = 0;
-       new_handler->prev = 0;
-       /* Place handler at beginning of chain */
-       spin_lock (&lock);
-       if (handler_anchor == NULL)
-               handler_anchor = new_handler;
-       else {
-               handler_anchor->prev = (ulong *) new_handler;
-               new_handler->next = (ulong *) handler_anchor;
-               handler_anchor = new_handler;
-#ifdef DEBUG
-               printk (KERN_DEBUG "adding a another handler to list\n");
-               printk (KERN_DEBUG "handler_anchor->prev is %p \n",
-                       handler_anchor->prev);
-               printk (KERN_DEBUG "new_handler->next is %p \n",
-                       new_handler->next);
-               printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
-#endif
-       }
-       spin_unlock (&lock);
-       if (declare_flag == NULL) {
-               rc = iucv_declare_buffer (iucv_external_int_buffer);
-               if (rc == 0) {
-                       declare_flag = 1;
-                       /* request the 0x4000 external interrupt */
-                       rc =
-                           register_external_interrupt (0x4000,
-                                                        top_half_interrupt);
-               } else {
-                       panic ("Registration failed");
-#ifdef DEBUG
-                       printk (KERN_DEBUG "rc from declare buffer is: %i\n",
-                               rc);
-#endif
-               }
-       }
-#ifdef DEBUG
-       printk (KERN_DEBUG "address of handle is %p ", new_handler);
-       printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler)));
-       printk (KERN_DEBUG "exit iucv_register_program\n");
-       printk (KERN_DEBUG "main_table is %p \n", main_table);
-       printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
-       printk (KERN_DEBUG "Handler is: \n");
-       prt_parm = (uchar *) new_handler;
-       for (i = 0; i < sizeof (handler); i++)
-               printk (KERN_DEBUG " %02x ", prt_parm[i]);
-       printk (KERN_DEBUG "\n");
-#endif
-       return new_handler;     /* send buffer address back */
-}                              /* end of register function */
 
-/**************************************************************/
-/* Name: iucv_unregister                                      */
-/* Purpose: remove handler from chain and sever all paths     */
-/* Input: handle - address of handler to be severed           */
-/* Output: returns 0                                          */
-/**************************************************************/
-int
-iucv_unregister (iucv_handle_t handle)
-{
-       handler *temp_next = 0, *temp_prev = 0;
-       handler *Q = 0, *R;
-       handler_table_entry *H_T_E = 0;
-       ulong *S = 0;           /*points to the beginning of block of h_t_e's*/
-#ifdef DEBUG
-       printk (KERN_DEBUG "enter iucv_unregister\n");
-       printk (KERN_DEBUG "address of handle is %p ", handle);
-       printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle)));
-#endif
-       spin_lock (&lock);
-       Q = (handler *) handle;
-       /*
-        * Checking if handle is still registered: if yes, continue
-        *  if not registered, return.
-        */
-       for (R = handler_anchor; R != NULL; R = (handler *) R->next)
-               if (Q == R) {
-#ifdef DEBUG
-                       printk (KERN_DEBUG "found a matching handler\n");
-#endif
-                       break;
-               }
-       if (!R) {
-               spin_unlock (&lock);
-               return (0);
-       }
-       S = Q->start;
-#ifdef DEBUG
-       printk (KERN_DEBUG "Q is handle? %p ", Q);
-       printk (KERN_DEBUG "Q->start is %p ", Q->start);
-       printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start));
-       printk (KERN_DEBUG "Q->end is %p ", Q->end);
-       printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end));
-#endif
-       while (S < (Q->end)) {  /* index thru table */
-               if (*S) {
-                       H_T_E = (handler_table_entry *) (*S);
-#ifdef DEBUG
-                       printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E);
-                       printk (KERN_DEBUG "Address of handle in H_T_E is %p",
-                               (H_T_E->addrs));
-#endif
-                       if ((H_T_E->addrs) != handle) {
-                               spin_unlock (&lock);
-                               return (-2);    /*handler addresses don't match */
-                       } else {
-                               spin_unlock (&lock);
-                               iucv_sever (H_T_E->pathid, Q->user_data);
-                               spin_lock (&lock);
-                       }
-               }
-               S++;            /* index by size of ulong */
-       }
-       kfree (Q->start);
-       temp_next = (handler *) Q->next;        /* address of next handler on list */
-       temp_prev = (handler *) Q->prev;        /* address of prev handler on list */
-       if ((temp_next != NULL) & (temp_prev != NULL)) {
-               (*temp_next).prev = (ulong *) temp_prev;
-               (*temp_prev).next = (ulong *) temp_next;
-       } else if ((temp_next != NULL) & (temp_prev == NULL)) {
-               (*temp_next).prev = NULL;
-               handler_anchor = temp_next;
-       } else if ((temp_next == NULL) & (temp_prev != NULL))
-               (*temp_prev).next = NULL;
-       else
-               handler_anchor = NULL;
-       if (handler_anchor == NULL)
-               iucv_retrieve_buffer ();
-       kfree (handle);
-       spin_unlock (&lock);
-#ifdef DEBUG
-       printk (KERN_DEBUG "exit iucv_unregister\n");
-#endif
-       return 0;
+       pr_debug ("BH:-  Exiting do_int "
+                 "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
+
+       return;
 }
+/* end of function call */
 
 EXPORT_SYMBOL (iucv_accept);
 EXPORT_SYMBOL (iucv_connect);
 EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query);
+EXPORT_SYMBOL (iucv_query_maxconn);
+EXPORT_SYMBOL (iucv_query_bufsize);
 EXPORT_SYMBOL (iucv_quiesce);
 EXPORT_SYMBOL (iucv_receive);
-EXPORT_SYMBOL (iucv_receive_simple);
 EXPORT_SYMBOL (iucv_receive_array);
 EXPORT_SYMBOL (iucv_reject);
 EXPORT_SYMBOL (iucv_reply);
@@ -2040,5 +2436,4 @@ EXPORT_SYMBOL (iucv_send_prmmsg);
 EXPORT_SYMBOL (iucv_setmask);
 EXPORT_SYMBOL (iucv_sever);
 EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister);
-
+EXPORT_SYMBOL (iucv_unregister_program);
index 82c5115657e26f0eb11503efbd6da44a0bfce4c3..5ab30c4ad630ca207b287808be6d1baf75e42447 100644 (file)
 /*
- *  drivers/s390/net/netiucv.h
+ *  drivers/s390/net/iucv.h
  *    IUCV base support.
  *
  *  S390 version
  *    Copyright (C) 2000 IBM Corporation
- *    Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ *    Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) 
+ *             Xenia Tkatschow (xenia@us.ibm.com)
  *
  *
+ * Linux Kernel IUCV will not support a machine with storage > 2 GB. 
+ *
  * Functionality:
  * To explore any of the IUCV functions, one must first register
- * their program using iucv_register(). Once your program has
- * successfully completed a register, it can use the other functions.
+ * their program using iucv_register_program(). Once your program has
+ * successfully completed a register, it can exploit the other functions.
  * For furthur reference on all IUCV functionality, refer to the
  * CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm.
+ * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ *
+ *      Definition of Return Codes                                    
+ *      -All positive return codes including zero are reflected back  
+ *       from CP except for iucv_register_program. The definition of each 
+ *       return code can be found in CP Programming Services book.    
+ *       Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760          
+ *      - Return Code of:         
+ *             (-EINVAL) Invalid value       
+ *             (-ENOMEM) storage allocation failed              
+ *     pgmask defined in iucv_register_program will be set depending on input
+ *     paramters. 
+ *     
  */
-#ifndef _IUCV_H
-#define _IUCV_H
+
+#include <linux/types.h>
 #define uchar  unsigned char
 #define ushort unsigned short
 #define ulong  unsigned long
 #define iucv_handle_t void *
-/***********************FLAGS*************************************/
-#define  source_class   0x01
-#define  target_class   0x01
-#define  local_conn     0x01
-#define  specify_pathid 0x02
-#define  specify_msgid  0x04
-#define  reply_array    0x08
-#define  one_way_msg    0x10
-#define  prior_msg      0x20
-#define  array          0x40
-#define  quiesce_msg    0x40
-#define  parm_data      0x80
-#define  IPRMDATA       0x80
-#define  IPBUFLST       0x40
-#define  IPPRTY         0x20
-#define  IPNORPY        0x10
-#define  IPANSLST       0x08
-#define  IPFGMID        0x04
-#define  IPFGPID        0x02
-#define  IPFGMCL        0x01
-
-/*---------------------------------------------------------*/
-/* Mapping of external interrupt buffers                   */
-/* Names: iucv_ConnectionPending    ->  connection pending */
-/*        iucv_ConnectionComplete   ->  connection complete */
-/*        iucv_ConnectionSevered    ->  connection severed */
-/*        iucv_ConnectionQuiesced   ->  connection quiesced */
-/*        iucv_ConnectionResumed    ->  connection resumed */
-/*        iucv_MessagePending       ->  message pending    */
-/*        iucv_MessageComplete      ->  message complete   */
-/*---------------------------------------------------------*/
+
+/* flags1:
+ * All flags are defined in the field IPFLAGS1 of each function   
+ * and can be found in CP Programming Services.                  
+ * IPLOCAL  - Indicates the connect can only be satisfied on the 
+ *            local system                                       
+ * IPPRTY   - Indicates a priority message                       
+ * IPQUSCE  - Indicates you do not want to receive messages on a 
+ *            path until an iucv_resume is issued                
+ * IPRMDATA - Indicates that the message is in the parameter list
+ */
+#define IPLOCAL        0x01
+#define IPPRTY                 0x20
+#define IPQUSCE                0x40
+#define IPRMDATA               0x80
+
+/* flags1_out:
+ * All flags are defined in the output field of IPFLAGS1 for each function
+ * and can be found in CP Programming Services.
+ * IPNORPY - Specifies this is a one-way message and no reply is expected.
+ * IPPRTY   - Indicates a priority message is permitted. Defined in flags1.
+ */
+#define IPNORPY         0x10
+
+#define Nonpriority_MessagePendingInterruptsFlag         0x80
+#define Priority_MessagePendingInterruptsFlag            0x40
+#define Nonpriority_MessageCompletionInterruptsFlag      0x20
+#define Priority_MessageCompletionInterruptsFlag         0x10
+/*
+ * Mapping of external interrupt buffers should be used with the corresponding
+ * interrupt types.                  
+ * Names: iucv_ConnectionPending    ->  connection pending 
+ *        iucv_ConnectionComplete   ->  connection complete
+ *        iucv_ConnectionSevered    ->  connection severed 
+ *        iucv_ConnectionQuiesced   ->  connection quiesced 
+ *        iucv_ConnectionResumed    ->  connection resumed 
+ *        iucv_MessagePending       ->  message pending    
+ *        iucv_MessageComplete      ->  message complete   
+ */
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iptype;
-       ushort ipmsglim;
-       ushort res1;
+       u16 ipmsglim;
+       u16 res1;
        uchar ipvmid[8];
        uchar ipuser[16];
-       ulong res3;
+       u32 res3;
        uchar ippollfg;
        uchar res4[3];
 } iucv_ConnectionPending;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iptype;
-       ushort ipmsglim;
-       ushort res1;
+       u16 ipmsglim;
+       u16 res1;
        uchar res2[8];
        uchar ipuser[16];
-       ulong res3;
+       u32 res3;
        uchar ippollfg;
        uchar res4[3];
 } iucv_ConnectionComplete;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar res1;
        uchar iptype;
-       ulong res2;
+       u32 res2;
        uchar res3[8];
        uchar ipuser[16];
-       ulong res4;
+       u32 res4;
        uchar ippollfg;
        uchar res5[3];
 } iucv_ConnectionSevered;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar res1;
        uchar iptype;
-       ulong res2;
+       u32 res2;
        uchar res3[8];
        uchar ipuser[16];
-       ulong res4;
+       u32 res4;
        uchar ippollfg;
        uchar res5[3];
 } iucv_ConnectionQuiesced;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar res1;
        uchar iptype;
-       ulong res2;
+       u32 res2;
        uchar res3[8];
        uchar ipuser[16];
-       ulong res4;
+       u32 res4;
        uchar ippollfg;
        uchar res5[3];
 } iucv_ConnectionResumed;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iptype;
-       ulong ipmsgid;
-       ulong iptrgcls;
-       ulong iprmmsg1;
+       u32 ipmsgid;
+       u32 iptrgcls;
+       uchar iprmmsg1[4];
        union u1 {
-               ulong ipbfln1f;
-               ulong iprmmsg2;
+               u32 ipbfln1f;
+               uchar iprmmsg2[4];
        } ln1msg2;
-       ulong res1[3];
-       ulong ipbfln2f;
+       u32 res1[3];
+       u32 ipbfln2f;
        uchar ippollfg;
        uchar res2[3];
 } iucv_MessagePending;
 
 typedef struct {
-       ushort ippathid;
+       u16 ippathid;
        uchar ipflags1;
        uchar iptype;
-       ulong ipmsgid;
-       ulong ipaudit;
-       ulong iprmmsg1;
-       ulong iprmmsg2;
-       ulong ipsrccls;
-       ulong ipmsgtag;
-       ulong res;
-       ulong ipbfln2f;
+       u32 ipmsgid;
+       u32 ipaudit;
+       uchar iprmmsg[8];
+       u32 ipsrccls;
+       u32 ipmsgtag;
+       u32 res;
+       u32 ipbfln2f;
        uchar ippollfg;
        uchar res2[3];
 } iucv_MessageComplete;
 
-/************************structures*************************/
-/*---------------------------------------------------------*/
-/*iucv_interrupt_ops_t: List of functions for interrupt    */
-/* handling.                                               */
-/*---------------------------------------------------------*/
-
+/* 
+ * iucv_interrupt_ops_t: Is a vector of functions that handle 
+ * IUCV interrupts.                                          
+ * Parameter list:                                           
+ *         eib - is a pointer to a 40-byte area described    
+ *               with one of the structures above.           
+ *         pgm_data - this data is strictly for the          
+ *                    interrupt handler that is passed by    
+ *                    the application. This may be an address 
+ *                    or token.                              
+*/
 typedef struct {
        void (*ConnectionPending) (iucv_ConnectionPending * eib,
-                                  ulong pgm_data);
+                                  void *pgm_data);
        void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
-                                   ulong pgm_data);
+                                   void *pgm_data);
        void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
-                                  ulong pgm_data);
+                                  void *pgm_data);
        void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
-                                   ulong pgm_data);
+                                   void *pgm_data);
        void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
-                                  ulong pgm_data);
-       void (*MessagePending) (iucv_MessagePending * eib,
-                               ulong pgm_data);
-       void (*MessageComplete) (iucv_MessageComplete * eib,
-                                ulong pgm_data);
+                                  void *pgm_data);
+       void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
+       void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
 } iucv_interrupt_ops_t;
 
-/*---------------------------------------------------------*/
-/*iucv_array_t : Defines buffer array                      */
-/*---------------------------------------------------------*/
-
+/*
+ *iucv_array_t : Defines buffer array.                      
+ * Inside the array may be 31- bit addresses and 31-bit lengths. 
+*/
 typedef struct {
-       void *address;
-       int length;
+       u32 address;
+       u32 length;
 } iucv_array_t __attribute__ ((aligned (8)));
 
-/*************************-prototypes-******************************/
-
+/*   -prototypes-    */
+/*                                                                
+ * Name: iucv_register_program                                    
+ * Purpose: Registers an application with IUCV                    
+ * Input: prmname - user identification                           
+ *        userid  - machine identification
+ *        pgmmask - indicates which bits in the prmname and userid combined will be
+ *                 used to determine who is given control
+ *        ops     - address of vector of interrupt handlers       
+ *        pgm_data- application data passed to interrupt handlers 
+ * Output: NA                                                     
+ * Return: address of handler                                     
+ *         (0) - Error occured, registration not completed.
+ * NOTE: Exact cause of failure will be recorded in syslog.                        
+*/
 iucv_handle_t iucv_register_program (uchar pgmname[16],
                                     uchar userid[8],
                                     uchar pgmmask[24],
                                     iucv_interrupt_ops_t * ops,
-                                    ulong pgm_data);
-
-int iucv_unregister (iucv_handle_t handle);
-
-int iucv_purge (ulong msgid,
-               ushort pathid,
-               ulong srccls,
-               uchar audit[4]);
-
-void iucv_query (ulong * bufsize,
-                ulong * conmax);
-
-int iucv_quiesce (ushort pathid,
-                 uchar user_data[16]);
+                                    void *pgm_data);
+
+/*                                                
+ * Name: iucv_unregister_program                  
+ * Purpose: Unregister application with IUCV      
+ * Input: address of handler                      
+ * Output: NA                                     
+ * Return: (0) - Normal return                    
+ *         (-EINVAL) - Internal error, wild pointer     
+*/
+int iucv_unregister_program (iucv_handle_t handle);
 
-int iucv_resume (ushort pathid,
-                uchar user_data[16]);
-
-int iucv_reject (ushort pathid,
-                ulong msgid,
-                ulong trgcls);
-
-int iucv_setmask (uchar non_priority_interrupts,
-                 uchar priority_interrupts,
-                 uchar non_priority_completion_interrupts,
-                 uchar priority_completion_interrupts);
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ *          interrupt and now wishes to complete the IUCV communication path.
+ * Input:  pathid - u16 , Path identification number   
+ *         msglim_reqstd - u16, The number of outstanding messages requested.
+ *         user_data - uchar[16], Data specified by the iucv_connect function.
+ *        flags1 - int, Contains options for this path.
+ *           -IPPRTY   - 0x20- Specifies if you want to send priority message.
+ *           -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *             in  the parameter list.
+ *           -IPQUSCE  - 0x40, Specifies whether you want to quiesce the path being
+ *             established.
+ *         handle - iucv_handle_t, Address of handler.
+ *         pgm_data - void *, Application data passed to interrupt handlers.
+ *         flags1_out - int * Contains information about the path
+ *           - IPPRTY - 0x20, Indicates you may send priority messages.
+ *         msglim - *u16, Number of outstanding messages.
+ * Output: return code from CP IUCV call.
+*/
+
+int iucv_accept (u16 pathid,
+                u16 msglim_reqstd,
+                uchar user_data[16],
+                int flags1,
+                iucv_handle_t handle,
+                void *pgm_data, int *flags1_out, u16 * msglim);
 
-int iucv_connect (ushort * pathid,
-                 ushort msglim,
+/*
+ * Name: iucv_connect                                         
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ *         successfully, you are not able to use the path until you receive an IUCV 
+ *          Connection Complete external interrupt.            
+ * Input: pathid - u16 *, Path identification number          
+ *        msglim_reqstd - u16, Number of outstanding messages requested       
+ *        user_data - uchar[16], 16-byte user data                    
+ *       userid - uchar[8], User identification
+ *        system_name - uchar[8], 8-byte identifying the system name 
+ *       flags1 - int, Contains options for this path.
+ *          -IPPRTY -   0x20, Specifies if you want to send priority message.
+ *          -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ *              in  the parameter list.
+ *          -IPQUSCE -  0x40, Specifies whether you want to quiesce the path being      
+ *             established.
+ *          -IPLOCAL -  0X01, Allows an application to force the partner to be on 
+ *             the local system. If local is specified then target class cannot be
+ *             specified.                       
+ *        flags1_out - int * Contains information about the path
+ *           - IPPRTY - 0x20, Indicates you may send priority messages.
+ *        msglim - * u16, Number of outstanding messages
+ *        handle - iucv_handle_t, Address of handler                         
+ *        pgm_data - void *, Application data passed to interrupt handlers              
+ * Output: return code from CP IUCV call
+ *         rc - return code from iucv_declare_buffer
+ *         -EINVAL - Invalid handle passed by application 
+ *         -EINVAL - Pathid address is NULL 
+ *         add_pathid_result - Return code from internal function add_pathid         
+*/
+int
+    iucv_connect (u16 * pathid,
+                 u16 msglim_reqstd,
                  uchar user_data[16],
                  uchar userid[8],
                  uchar system_name[8],
-                 uchar priority_requested,
-                 uchar prmdata,
-                 uchar quiesce,
-                 uchar control,
-                 uchar local,
-                 uchar * priority_permitted,
-                 iucv_handle_t handle,
-                 ulong pgm_data);
-
-int iucv_accept (ushort pathid,
-                ushort msglim,
-                uchar user_data[16],
-                uchar priority_requested,
-                uchar prmdata,
-                uchar quiesce,
-                uchar control,
-                uchar * priority_permitted,
-                iucv_handle_t handle,
-                ulong pgm_data);
-
-int iucv_sever (ushort pathid,
-               uchar user_data[16]);
-
-int iucv_receive (ushort pathid,
-                 ulong * msgid,
-                 ulong * trgcls,
-                 void *buffer, ulong buflen,
-                 uchar * reply_required,
-                 uchar * priority_msg,
-                 ulong * adds_curr_buffer,
-                 ulong * adds_curr_length);
-
-int iucv_receive_simple (ushort pathid,
-                        ulong msgid,
-                        ulong trgcls,
-                        void *buffer, ulong buflen);
-
-int iucv_receive_array (ushort pathid,
-                       ulong * msgid,
-                       ulong * trgcls,
+                 int flags1,
+                 int *flags1_out,
+                 u16 * msglim, iucv_handle_t handle, void *pgm_data);
+
+/*                                                                     
+ * Name: iucv_purge                                                    
+ * Purpose: This function cancels a message that you have sent.        
+ * Input: pathid - Path identification number.                          
+ *        msgid - Specifies the message ID of the message to be purged.
+ *        srccls - Specifies the source message class.                  
+ * Output: audit - Contains information about asynchronous error       
+ *                 that may have affected the normal completion        
+ *                 of this message.                                    
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3]);
+/*
+ * Name: iucv_query_maxconn
+ * Purpose: This function determines the maximum number of communication paths you
+ *         may establish.
+ * Return:  maxconn - ulong, Maximum number of connection the virtual machine may
+ *          establish.
+*/
+ulong iucv_query_maxconn (void);
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: This function determines how large an external interrupt
+ *          buffer IUCV requires to store information.
+ * Return:  bufsize - ulong, Size of external interrupt buffer.
+ */
+ulong iucv_query_bufsize (void);
+
+/*                                                                     
+ * Name: iucv_quiesce                                                  
+ * Purpose: This function temporarily suspends incoming messages on an 
+ *          IUCV path. You can later reactivate the path by invoking   
+ *          the iucv_resume function.                                  
+ * Input: pathid - Path identification number                          
+ *        user_data  - 16-bytes of user data                           
+ * Output: NA                                                          
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_quiesce (u16 pathid, uchar user_data[16]);
+
+/*                                                                     
+ * Name: iucv_receive                                                  
+ * Purpose: This function receives messages that are being sent to you 
+ *          over established paths. Data will be returned in buffer for length of
+ *          buflen.
+ * Input: 
+ *       pathid - Path identification number.                          
+ *       buffer - Address of buffer to receive.                        
+ *       buflen - Length of buffer to receive.                         
+ *       msgid - Specifies the message ID.          
+ *       trgcls - Specifies target class.                       
+ * Output: 
+ *      flags1_out: int *, Contains information about this path.
+ *         IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+ *        expected.      
+ *         IPPRTY  - 0x20 Specifies if you want to send priority message.       
+ *         IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ *       residual_buffer - address of buffer updated by the number
+ *                         of bytes you have received.
+ *       residual_length -      
+ *              Contains one of the following values, if the receive buffer is:
+ *               The same length as the message, this field is zero.
+ *               Longer than the message, this field contains the number of
+ *                bytes remaining in the buffer.
+ *               Shorter than the message, this field contains the residual
+ *                count (that is, the number of bytes remaining in the
+ *                message that does not fit into the buffer. In this
+ *                case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - buffer address is pointing to NULL                   
+*/
+int iucv_receive (u16 pathid,
+                 u32 msgid,
+                 u32 trgcls,
+                 void *buffer,
+                 ulong buflen,
+                 int *flags1_out,
+                 ulong * residual_buffer, ulong * residual_length);
+
+ /*                                                                     
+  * Name: iucv_receive_array                                            
+  * Purpose: This function receives messages that are being sent to you 
+  *          over established paths. Data will be returned in first buffer for
+  *          length of first buffer.
+  * Input: pathid - Path identification number.                          
+  *        msgid - specifies the message ID.
+  *        trgcls - Specifies target class.
+  *        buffer - Address of array of buffers.                         
+  *        buflen - Total length of buffers.                             
+  * Output:
+  *        flags1_out: int *, Contains information about this path.
+  *          IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+  *          expected.
+  *          IPPRTY  - 0x20 Specifies if you want to send priority message.
+  *          IPRMDATA - 0x80 specifies the data is contained in the parameter list
+  *       residual_buffer - address points to the current list entry IUCV
+  *                         is working on.
+  *       residual_length -
+  *              Contains one of the following values, if the receive buffer is:
+  *               The same length as the message, this field is zero.
+  *               Longer than the message, this field contains the number of
+  *                bytes remaining in the buffer.
+  *               Shorter than the message, this field contains the residual
+  *                count (that is, the number of bytes remaining in the
+  *                message that does not fit into the buffer. In this
+  *                case b2f0_result = 5.
+  * Return: Return code from CP IUCV call.                           
+  *         (-EINVAL) - Buffer address is NULL.       
+  */
+int iucv_receive_array (u16 pathid,
+                       u32 msgid,
+                       u32 trgcls,
                        iucv_array_t * buffer,
-                       ulong * buflen,
-                       uchar * reply_required,
-                       uchar * priority_msg,
-                       ulong * adds_curr_buffer,
-                       ulong * adds_curr_length);
-
-int iucv_send (ushort pathid,
-              ulong * msgid,
-              ulong trgcls,
-              ulong srccls,
-              ulong msgtag,
-              uchar priority_msg,
-              void *buffer,
-              ulong buflen);
-
-int iucv_send_array (ushort pathid,
-                    ulong * msgid,
-                    ulong trgcls,
-                    ulong srccls,
-                    ulong msgtag,
-                    uchar priority_msg,
-                    iucv_array_t * buffer,
-                    ulong buflen);
-
-int iucv_send_prmmsg (ushort pathid,
-                     ulong * msgid,
-                     ulong trgcls,
-                     ulong srccls,
-                     ulong msgtag,
-                     uchar priority_msg,
-                     uchar prmmsg[8]);
-
-int iucv_send2way (ushort pathid,
-                  ulong * msgid,
-                  ulong trgcls,
-                  ulong srccls,
-                  ulong msgtag,
-                  uchar priority_msg,
-                  void *buffer,
-                  ulong buflen,
-                  void *ansbuf,
-                  ulong anslen);
-
-int iucv_send2way_array (ushort pathid,
-                        ulong * msgid,
-                        ulong trgcls,
-                        ulong srccls,
-                        ulong msgtag,
-                        uchar priority_msg,
+                       ulong buflen,
+                       int *flags1_out,
+                       ulong * residual_buffer, ulong * residual_length);
+
+/*                                                                       
+ * Name: iucv_reject                                                     
+ * Purpose: The reject function refuses a specified message. Between the 
+ *          time you are notified of a message and the time that you     
+ *          complete the message, the message may be rejected.           
+ * Input: pathid - Path identification number.                            
+ *        msgid - Specifies the message ID.                   
+ *        trgcls - Specifies target class.                                
+ * Output: NA                                                            
+ * Return: Return code from CP IUCV call.                             
+*/
+int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
+
+/*                                                                     
+ * Name: iucv_reply                                                    
+ * Purpose: This function responds to the two-way messages that you    
+ *          receive. You must identify completely the message to       
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.    
+ * Input: pathid - Path identification number.                          
+ *        msgid - Specifies the message ID.                
+ *        trgcls - Specifies target class.                              
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20, Specifies if you want to send priority message.        
+ *        buffer - Address of reply buffer.                             
+ *        buflen - Length of reply buffer.                              
+ * Output: residual_buffer - Address of buffer updated by the number 
+ *                    of bytes you have moved.              
+ *         residual_length - Contains on the the following values
+ *             If the answer buffer is the same length as the reply, this field
+ *              contains zero.
+ *             If the answer buffer is longer than the reply, this field contains
+ *              the number of bytes remaining in the buffer.  
+ *             If the answer buffer is shorter than the reply, this field contains
+ *              a residual count (that is, the number of bytes remianing in the
+ *              reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - Buffer address is NULL.                               
+*/
+int iucv_reply (u16 pathid,
+               u32 msgid,
+               u32 trgcls,
+               int flags1,
+               void *buffer, ulong buflen, ulong * residual_buffer,
+               ulong * residual_length);
+
+/*                                                                       
+ * Name: iucv_reply_array                                                
+ * Purpose: This function responds to the two-way messages that you      
+ *          receive. You must identify completely the message to         
+ *          which you wish to reply. ie, pathid, msgid, and trgcls.      
+ *          The array identifies a list of addresses and lengths of      
+ *          discontiguous buffers that contains the reply data.          
+ * Input: pathid - Path identification number                            
+ *        msgid - Specifies the message ID. 
+ *        trgcls - Specifies target class.                                
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20, Specifies if you want to send priority message.
+ *        buffer - Address of array of reply buffers.                     
+ *        buflen - Total length of reply buffers.                         
+ * Output: residual_buffer - Address of buffer which IUCV is currently working on.
+ *         residual_length - Contains on the the following values
+ *              If the answer buffer is the same length as the reply, this field
+ *               contains zero.
+ *              If the answer buffer is longer than the reply, this field contains
+ *               the number of bytes remaining in the buffer.
+ *              If the answer buffer is shorter than the reply, this field contains
+ *               a residual count (that is, the number of bytes remianing in the
+ *               reply that does not fit into the buffer. In this
+ *               case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.                             
+ *         (-EINVAL) - Buffer address is NULL.              
+*/
+int iucv_reply_array (u16 pathid,
+                     u32 msgid,
+                     u32 trgcls,
+                     int flags1,
+                     iucv_array_t * buffer,
+                     ulong buflen, ulong * residual_address,
+                     ulong * residual_length);
+
+/*                                                                  
+ * Name: iucv_reply_prmmsg                                          
+ * Purpose: This function responds to the two-way messages that you 
+ *          receive. You must identify completely the message to    
+ *          which you wish to reply. ie, pathid, msgid, and trgcls. 
+ *          Prmmsg signifies the data is moved into the             
+ *          parameter list.                                         
+ * Input: pathid - Path identification number.                       
+ *        msgid - Specifies the message ID.              
+ *        trgcls - Specifies target class.                           
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into the parameter.  
+ *                 list.                                            
+ * Output: NA                                                       
+ * Return: Return code from CP IUCV call.                        
+*/
+int iucv_reply_prmmsg (u16 pathid,
+                      u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
+
+/*                                                                     
+ * Name: iucv_resume                                                   
+ * Purpose: This function restores communications over a quiesced path 
+ * Input: pathid - Path identification number.                          
+ *        user_data  - 16-bytes of user data.                           
+ * Output: NA                                                          
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_resume (u16 pathid, uchar user_data[16]);
+
+/*                                                                   
+ * Name: iucv_send                                                   
+ * Purpose: This function transmits data to another application.     
+ *          Data to be transmitted is in a buffer and this is a      
+ *          one-way message and the receiver will not reply to the   
+ *          message.                                                 
+ * Input: pathid - Path identification number.                        
+ *        trgcls - Specifies target class.                            
+ *        srccls - Specifies the source message class.                
+ *        msgtag - Specifies a tag to be associated with the message. 
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Address of send buffer.                            
+ *        buflen - Length of send buffer.                             
+ * Output: msgid - Specifies the message ID.                         
+ * Return: Return code from CP IUCV call.                         
+ *         (-EINVAL) - Buffer address is NULL.                             
+*/
+int iucv_send (u16 pathid,
+              u32 * msgid,
+              u32 trgcls,
+              u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
+
+/*                                                                   
+ * Name: iucv_send_array                                             
+ * Purpose: This function transmits data to another application.     
+ *          The contents of buffer is the address of the array of    
+ *          addresses and lengths of discontiguous buffers that hold 
+ *          the message text. This is a one-way message and the      
+ *          receiver will not reply to the message.                  
+ * Input: pathid - Path identification number.                        
+ *        trgcls - Specifies target class.                            
+ *        srccls - Specifies the source message class.                
+ *        msgtag - Specifies a tag to be associated witht the message.
+ *        flags1 - Option for path.
+ *          IPPRTY- specifies if you want to send priority message. 
+ *        buffer - Address of array of send buffers.                  
+ *        buflen - Total length of send buffers.                      
+ * Output: msgid - Specifies the message ID.                         
+ * Return: Return code from CP IUCV call.                         
+ *         (-EINVAL) - Buffer address is NULL.                             
+*/
+int iucv_send_array (u16 pathid,
+                    u32 * msgid,
+                    u32 trgcls,
+                    u32 srccls,
+                    u32 msgtag,
+                    int flags1, iucv_array_t * buffer, ulong buflen);
+
+/*                                                                     
+ * Name: iucv_send_prmmsg                                              
+ * Purpose: This function transmits data to another application.       
+ *          Prmmsg specifies that the 8-bytes of data are to be moved  
+ *          into the parameter list. This is a one-way message and the 
+ *          receiver will not reply to the message.                    
+ * Input: pathid - Path identification number.                          
+ *        trgcls - Specifies target class.                              
+ *        srccls - Specifies the source message class.                  
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into parameter list.    
+ * Output: msgid - Specifies the message ID.                           
+ * Return: Return code from CP IUCV call.                           
+*/
+int iucv_send_prmmsg (u16 pathid,
+                     u32 * msgid,
+                     u32 trgcls,
+                     u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
+
+/*                                                                
+ * Name: iucv_send2way                                            
+ * Purpose: This function transmits data to another application.  
+ *          Data to be transmitted is in a buffer. The receiver   
+ *          of the send is expected to reply to the message and   
+ *          a buffer is provided into which IUCV moves the reply  
+ *          to this message.                                      
+ * Input: pathid - Path identification number.                     
+ *        trgcls - Specifies target class.                         
+ *        srccls - Specifies the source message class.             
+ *        msgtag - Specifies a tag associated with the message.    
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Address of send buffer.                         
+ *        buflen - Length of send buffer.                          
+ *        ansbuf - Address of buffer into which IUCV moves the reply of 
+ *                 this message.        
+ *        anslen - Address of length of buffer.          
+ * Output: msgid - Specifies the message ID.                      
+ * Return: Return code from CP IUCV call.                      
+ *         (-EINVAL) - Buffer or ansbuf address is NULL.    
+*/
+int iucv_send2way (u16 pathid,
+                  u32 * msgid,
+                  u32 trgcls,
+                  u32 srccls,
+                  u32 msgtag,
+                  int flags1,
+                  void *buffer, ulong buflen, void *ansbuf, ulong anslen);
+
+/*                                                                    
+ * Name: iucv_send2way_array                                          
+ * Purpose: This function transmits data to another application.      
+ *          The contents of buffer is the address of the array of     
+ *          addresses and lengths of discontiguous buffers that hold  
+ *          the message text. The receiver of the send is expected to 
+ *          reply to the message and a buffer is provided into which  
+ *          IUCV moves the reply to this message.                     
+ * Input: pathid - Path identification number.                         
+ *        trgcls - Specifies target class.                             
+ *        srccls - Specifies the source message class.                 
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        buffer - Sddress of array of send buffers.                   
+ *        buflen - Total length of send buffers.                       
+ *        ansbuf - Address of array of buffer into which IUCV moves the reply            
+ *                 of this message.                         
+ *        anslen - Address of length reply buffers.              
+ * Output: msgid - Specifies the message ID.                          
+ * Return: Return code from CP IUCV call.                          
+ *         (-EINVAL) - Buffer address is NULL.                              
+*/
+int iucv_send2way_array (u16 pathid,
+                        u32 * msgid,
+                        u32 trgcls,
+                        u32 srccls,
+                        u32 msgtag,
+                        int flags1,
                         iucv_array_t * buffer,
-                        ulong buflen,
-                        iucv_array_t * ansbuf,
-                        ulong anslen);
-
-int iucv_send2way_prmmsg (ushort pathid,
-                         ulong * msgid,
-                         ulong trgcls,
-                         ulong srccls,
-                         ulong msgtag,
-                         uchar priority_msg,
-                         uchar prmmsg[8],
-                         void *ansbuf,
-                         ulong anslen);
-
-int iucv_send2way_prmmsg_array (ushort pathid,
-                               ulong * msgid,
-                               ulong trgcls, ulong srccls,
-                               ulong msgtag,
-                               uchar priority_msg,
+                        ulong buflen, iucv_array_t * ansbuf, ulong anslen);
+
+/*                                                                     
+ * Name: iucv_send2way_prmmsg                                          
+ * Purpose: This function transmits data to another application.       
+ *          Prmmsg specifies that the 8-bytes of data are to be moved  
+ *          into the parameter list. This is a two-way message and the 
+ *          receiver of the message is expected to reply. A buffer     
+ *          is provided into which IUCV moves the reply to this        
+ *          message.                                                   
+ * Input: pathid - Rath identification number.                          
+ *        trgcls - Specifies target class.                              
+ *        srccls - Specifies the source message class.                  
+ *        msgtag - Specifies a tag to be associated with the message.   
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 Specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed in parameter list.      
+ *        ansbuf - Address of buffer into which IUCV moves the reply of    
+ *                 this message.
+ *        anslen - Address of length of buffer.               
+ * Output: msgid - Specifies the message ID.                           
+ * Return: Return code from CP IUCV call.                           
+ *         (-EINVAL) - Buffer address is NULL.         
+*/
+int iucv_send2way_prmmsg (u16 pathid,
+                         u32 * msgid,
+                         u32 trgcls,
+                         u32 srccls,
+                         u32 msgtag,
+                         ulong flags1,
+                         uchar prmmsg[8], void *ansbuf, ulong anslen);
+
+/*                                                                      
+ * Name: iucv_send2way_prmmsg_array                                     
+ * Purpose: This function transmits data to another application.        
+ *          Prmmsg specifies that the 8-bytes of data are to be moved   
+ *          into the parameter list. This is a two-way message and the  
+ *          receiver of the message is expected to reply. A buffer      
+ *          is provided into which IUCV moves the reply to this         
+ *          message. The contents of ansbuf is the address of the       
+ *          array of addresses and lengths of discontiguous buffers     
+ *          that contain the reply.                                     
+ * Input: pathid - Path identification number.                           
+ *        trgcls - Specifies target class.                               
+ *        srccls - Specifies the source message class.                   
+ *        msgtag - Specifies a tag to be associated with the message.    
+ *        flags1 - Option for path.
+ *          IPPRTY- 0x20 specifies if you want to send priority message.
+ *        prmmsg - 8-bytes of data to be placed into the parameter list. 
+ *        ansbuf - Address of array of buffer into which IUCV moves the reply
+ *                 of this message.  
+ *        anslen - Address of length of reply buffers.                
+ * Output: msgid - Specifies the message ID.      
+ * Return: Return code from CP IUCV call.      
+ *         (-EINVAL) - Ansbuf address is NULL.          
+*/
+int iucv_send2way_prmmsg_array (u16 pathid,
+                               u32 * msgid,
+                               u32 trgcls,
+                               u32 srccls,
+                               u32 msgtag,
+                               int flags1,
                                uchar prmmsg[8],
-                               iucv_array_t * ansbuf,
-                               ulong anslen);
-int iucv_reply (ushort pathid,
-               ulong msgid,
-               ulong trgcls,
-               uchar priority_msg,
-               void *buf,
-               ulong buflen);
-
-int iucv_reply_array (ushort pathid,
-                     ulong msgid,
-                     ulong trgcls,
-                     uchar priority_msg,
-                     iucv_array_t * buffer,
-                     ulong buflen);
-
-int iucv_reply_prmmsg (ushort pathid,
-                      ulong msgid,
-                      ulong trgcls,
-                      uchar priority_msg,
-                      uchar prmmsg[8]);
-
-#endif
+                               iucv_array_t * ansbuf, ulong anslen);
+
+/*                                                                   
+ * Name: iucv_setmask                                                
+ * Purpose: This function enables or disables the following IUCV     
+ *          external interruptions: Nonpriority and priority message 
+ *          interrupts, nonpriority and priority reply interrupts.   
+ * Input: SetMaskFlag - options for interrupts
+ *           0x80 - Nonpriority_MessagePendingInterruptsFlag         
+ *           0x40 - Priority_MessagePendingInterruptsFlag            
+ *           0x20 - Nonpriority_MessageCompletionInterruptsFlag      
+ *           0x10 - Priority_MessageCompletionInterruptsFlag         
+ * Output: NA                                                        
+ * Return: Return code from CP IUCV call.                         
+*/
+int iucv_setmask (int SetMaskFlag);
+
+/*                                                  
+ * Name: iucv_sever                                 
+ * Purpose: This function terminates an IUCV path.  
+ * Input: pathid - Path identification number.       
+ *        user_data - 16-bytes of user data.         
+ * Output: NA       
+ * Return: Return code from CP IUCV call.                                
+ *         (-EINVAL) - Interal error, wild pointer.       
+*/
+int iucv_sever (u16 pathid, uchar user_data[16]);
index 7bc3b491ae0bda025649c75746bd8d93267ecd82..da068f42a5177df89480a77a9b2e0afeab6722ae 100644 (file)
  *    Re-write:   Alan Altmark (Alan_Altmark@us.ibm.com)  Sept. 2000
  *                Uses iucv.c kernel module for IUCV services. 
  *
+ *    2.4 Updates Alan Altmark (Alan_Altmark@us.ibm.com)  June 2001
+ *                Update to use changed IUCV (iucv.c) interface.
+ *
  * -------------------------------------------------------------------------- 
  *  An IUCV frame consists of one or more packets preceded by a 16-bit
  *  header.   The header contains the offset to the next packet header,
  *  measured from the beginning of the _frame_.  If zero, there are no more
  *  packets in the frame.  Consider a frame which contains a 10-byte packet
  *  followed by a 20-byte packet:
- *        +-----+----------------+-----+----------------------------+-----+
- *        |h'12'| 10-byte packet |h'34'|  20-byte packet            |h'00'|
- *        +-----+----------------+-----+----------------------------+-----+
- * Offset: 0     2                12    14                           34  
+ *        +-----+----------------+--------------------------------+-----+
+ *        |h'12'| 10-byte packet |h'34'|  20-byte packet          |h'00'|
+ *        +-----+----------------+-----+--------------------------+-----+
+ * Offset: 0     2                12    14                         34  
  *
  *  This means that each header will always have a larger value than the
  *  previous one (except for the final zero header, of course).
  * --------------------------------------------------------------------------
 */
 //#define DEBUG 1
+//#define DEBUG2 1
+//#define IPDEBUG 1
+#define LEVEL "1.1"
 
 /* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */
 /* (See bottom of program.)                                                */
-#define MAX_DEVICES 10         /* Allows "iucv0" to "iucv9"    */
+#define MAX_DEVICES 20         /* Allows "iucv0" to "iucv19"   */
 #define MAX_VM_MTU 32764       /* 32K IUCV buffer, minus 4     */
 #define MAX_TX_Q 50            /* Maximum pending TX           */
 
 #include <linux/module.h>
 MODULE_AUTHOR
     ("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)");
-MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver " LEVEL);
 MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s");
 MODULE_PARM_DESC (iucv,
                  "Specify the userids associated with iucv0-iucv9:\n"
                  "iucv=userid1,userid2,...,userid10\n");
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #else
 #define MOD_INC_USE_COUNT
 #define MOD_DEC_USE_COUNT
@@ -77,18 +86,22 @@ MODULE_PARM_DESC (iucv,
 #include <linux/interrupt.h>   /* mark_bh                      */
 #include <linux/netdevice.h>   /* struct net_device, etc.      */
 #include <linux/if_arp.h>      /* ARPHRD_SLIP                  */
+#include <linux/ip.h>          /* IP header                    */
 #include <linux/skbuff.h>      /* skb                          */
 #include <linux/init.h>                /* __setup()                    */
-#include <asm/io.h>            /* virt_to_phys()               */
 #include <asm/string.h>                /* memset, memcpy, etc.         */
 #include "iucv.h"
 #define min(a,b) (a < b) ? a : b
 
-#ifdef DEBUG
+#if defined( DEBUG )
 #undef KERN_INFO
 #undef KERN_DEBUG
+#undef KERN_NOTICE
+#undef KERN_ERR
 #define KERN_INFO    KERN_EMERG
 #define KERN_DEBUG   KERN_EMERG
+#define KERN_NOTICE  KERN_EMERG
+#define KERN_ERR     KERN_EMERG
 #endif
 
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
@@ -145,14 +158,14 @@ static int iucv_start (net_device *);
 static int iucv_stop (net_device *);
 static int iucv_change_mtu (net_device *, int);
 static int iucv_init (net_device *);
-static void iucv_rx (net_device *, uchar *, int);
+static void iucv_rx (net_device *, u32, uchar *, int);
 static int iucv_tx (struct sk_buff *, net_device *);
 
-static void connection_severed (iucv_ConnectionSevered *, ulong);
-static void connection_pending (iucv_ConnectionPending *, ulong);
-static void connection_complete (iucv_ConnectionComplete *, ulong);
-static void message_pending (iucv_MessagePending *, ulong);
-static void send_complete (iucv_MessageComplete *, ulong);
+static void connection_severed (iucv_ConnectionSevered *, void *);
+static void connection_pending (iucv_ConnectionPending *, void *);
+static void connection_complete (iucv_ConnectionComplete *, void *);
+static void message_pending (iucv_MessagePending *, void *);
+static void send_complete (iucv_MessageComplete *, void *);
 
 void register_iucv_dev (int, char *);
 
@@ -168,7 +181,6 @@ static iucv_interrupt_ops_t netiucv_ops = {
 
 static char iucv_userid[MAX_DEVICES][8];
 net_device iucv_netdev[MAX_DEVICES];
-static char eodata[2] = { '\0', '\0' };
 
 /* This structure is private to each device. It contains the    */
 /* information necessary to do IUCV operations.                 */
@@ -188,12 +200,6 @@ struct iucv_priv {
        u16 pathid;
 };
 
-struct iucvtag {
-       iucv_array_t iucvvec[3];
-       u16 framelen;
-       struct sk_buff *skb;
-};
-
 uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
        0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
@@ -207,7 +213,7 @@ const char mask[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
        0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 };
 
-#ifdef DEBUG
+#if defined( DEBUG2 ) || defined( IPDEBUG )
 /*--------------------------*/
 /* Dump buffer formatted    */
 /*--------------------------*/
@@ -260,8 +266,6 @@ static int
 iucv_start (net_device * dev)
 {
        int rc, i;
-       uchar pri;
-       uchar unused = '\0';
        struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 
        pr_debug ("iucv_start(%s)\n", dev->name);
@@ -269,7 +273,7 @@ iucv_start (net_device * dev)
        if (p == NULL) {
                /* Allocate priv data */
                p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv),
-                                                 GFP_KERNEL);
+                                                 GFP_ATOMIC);
                if (p == NULL) {
                        printk (KERN_CRIT "%s: no memory for dev->priv.\n",
                                dev->name);
@@ -292,11 +296,11 @@ iucv_start (net_device * dev)
                atomic_set (&p->state, FREE);
                p->handle =
                    iucv_register_program (iucvMagic, p->userid2, (char *) mask,
-                                          &netiucv_ops, (ulong) dev);
+                                          &netiucv_ops, (void *) dev);
                if (p->handle <= 0) {
                        printk (KERN_ERR
-                               "%s: iucv_register_program error, rc=%i\n",
-                               dev->name, (int) p->handle);
+                               "%s: iucv_register_program error, rc=%p\n",
+                               dev->name, p->handle);
                        dev->priv = NULL;
                        kfree (p);
                        return -ENODEV;
@@ -312,8 +316,7 @@ iucv_start (net_device * dev)
 
        rc =
            iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2,
-                         iucv_host, unused, unused, unused, unused, unused,
-                         &pri, p->handle, (ulong) p);
+                         iucv_host, 0, NULL, NULL, p->handle, p);
 
        /* Some errors are not fatal.  In these cases we will report "OK". */
        switch (rc) {
@@ -321,30 +324,30 @@ iucv_start (net_device * dev)
                pr_debug ("...waiting for connection to complete...");
                return 0;
        case 11:                /* Wait for parter to connect */
-               printk (KERN_NOTICE "Device %s: "
+               printk (KERN_NOTICE "%s: "
                        "User %s is not available now.\n",
                        dev->name, p->userid);
                atomic_set (&p->state, FREE);
                return 0;
        case 12:                /* Wait for partner to connect */
-               printk (KERN_NOTICE "Device %s: "
+               printk (KERN_NOTICE "%s: "
                        "User %s is not ready to talk now.\n",
                        dev->name, p->userid);
                atomic_set (&p->state, FREE);
                return 0;
        case 13:                /* Fatal */
-               printk (KERN_ERR "Device %s: "
+               printk (KERN_ERR "%s: "
                        "You have too many IUCV connections."
                        "Check MAXCONN in CP directory.\n", dev->name);
                break;
        case 14:                /* Fatal */
-               printk (KERN_ERR "Device %s: "
+               printk (KERN_ERR "%s: "
                        "User %s has too many IUCV connections."
                        "Check MAXCONN in CP directory.\n",
                        dev->name, p->userid);
                break;
        case 15:                /* Fatal */
-               printk (KERN_ERR "Device %s: "
+               printk (KERN_ERR "%s: "
                        "No IUCV authorization found in CP directory.\n",
                        dev->name);
                break;
@@ -353,7 +356,7 @@ iucv_start (net_device * dev)
                        "return code %i from iucv_connect()\n", dev->name, rc);
        }
 
-       rc = iucv_unregister (p->handle);
+       rc = iucv_unregister_program (p->handle);
        dev->priv = NULL;
        kfree (p);
        MOD_DEC_USE_COUNT;
@@ -364,7 +367,7 @@ iucv_start (net_device * dev)
 /* Our connection TO another stack has been accepted.                */
 /*********************************************************************/
 static void
-connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
+connection_complete (iucv_ConnectionComplete * cci, void *pgm_data)
 {
        struct iucv_priv *p = (struct iucv_priv *) pgm_data;
        pr_debug ("...%s connection complete... txq=%u\n",
@@ -374,7 +377,7 @@ connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
        p->dev->tx_queue_len = cci->ipmsglim;
        netif_start (p->dev);
        netif_start_queue (p->dev);
-       printk (KERN_INFO "%s: Connection to user %s is up\n",
+       printk (KERN_NOTICE "%s: Connection to user %s is up\n",
                p->dev->name, p->userid);
 }                              /* end connection_complete() */
 
@@ -386,7 +389,7 @@ connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
 /* the remote user is the correct user.                              */
 /*********************************************************************/
 static void
-connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
+connection_pending (iucv_ConnectionPending * cpi, void *pgm_data)
 {
        /* Only get this far if handler is set up, so we know userid is ok. */
        /* and the device is started.                                       */
@@ -394,9 +397,8 @@ connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
        net_device *dev = (net_device *) pgm_data;
        struct iucv_priv *p = (struct iucv_priv *) dev->priv;
        int rc;
+       u16 msglimit;
        uchar udata[16];
-       uchar no = '\0';
-       uchar na;
 
        /* If we're not waiting on a connect, reject the connection */
        if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
@@ -404,27 +406,25 @@ connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
                return;
        }
 
-       rc = iucv_accept (cpi->ippathid,        /* Path id              */
-                         MAX_TX_Q,     /* msglimit                     */
+       rc = iucv_accept (cpi->ippathid,        /* Path id                      */
+                         MAX_TX_Q,     /* desired IUCV msg limit       */
                          udata,        /* user_Data                    */
-                         no,   /* will we send priority msgs?  */
-                         no,   /* do we accept prmdata?        */
-                         no,   /* quiece immediately?          */
-                         no,   /* control path?                */
-                         &na,  /* other side accept prmdata?   */
-                         p->handle,    /* registration handle  */
-                         (ulong) p);   /* private data         */
+                         0,    /* No flags                     */
+                         p->handle,    /* registration handle          */
+                         p,    /* private data                 */
+                         NULL, /* don't care about output flags */
+                         &msglimit);   /* Actual IUCV msg limit        */
        if (rc != 0) {
                atomic_set (&p->state, FREE);
                printk (KERN_ERR "%s: iucv accept failed rc=%i\n",
                        p->dev->name, rc);
        } else {
+               atomic_set (&p->state, CONNECTED);
                p->pathid = cpi->ippathid;
-               p->dev->tx_queue_len = cpi->ipmsglim;
+               p->dev->tx_queue_len = (u32) msglimit;
                netif_start (p->dev);
                netif_start_queue (p->dev);
-               atomic_set (&p->state, CONNECTED);
-               printk (KERN_INFO "Device %s: Connection to user %s is up\n",
+               printk (KERN_NOTICE "%s: Connection to user %s is up\n",
                        p->dev->name, p->userid);
        }
 }                              /* end connection_pending() */
@@ -433,15 +433,21 @@ connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
 /* Our connection to another stack has been severed.                 */
 /*********************************************************************/
 static void
-connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data)
+connection_severed (iucv_ConnectionSevered * eib, void *pgm_data)
 {
        struct iucv_priv *p = (struct iucv_priv *) pgm_data;
 
        printk (KERN_INFO "%s: Connection to user %s is down\n",
                p->dev->name, p->userid);
 
+       /* FIXME: We can also get a severed interrupt while in
+                 state CONNECTING!  Fix the state machine ... */
+#if 0
        if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0)
                return;         /* In case reconnect in progress already */
+#else
+       atomic_set (&p->state, FREE);
+#endif
 
        netif_stop_queue (p->dev);
        netif_stop (p->dev);
@@ -464,7 +470,8 @@ iucv_stop (net_device * dev)
        if (p == NULL)
                return 0;
 
-       rc = iucv_unregister (p->handle);       /* Will sever connections */
+       /* Unregister will sever associated connections */
+       rc = iucv_unregister_program (p->handle);
        dev->priv = NULL;
        kfree (p);
        MOD_DEC_USE_COUNT;
@@ -477,7 +484,7 @@ iucv_stop (net_device * dev)
 /* separate packets, and send them to the "generic" packet processor.  */
 /*---------------------------------------------------------------------*/
 static void
-message_pending (iucv_MessagePending * mpi, ulong pgm_data)
+message_pending (iucv_MessagePending * mpi, void *pgm_data)
 {
        struct iucv_priv *p = (struct iucv_priv *) pgm_data;
        int rc;
@@ -486,22 +493,21 @@ message_pending (iucv_MessagePending * mpi, ulong pgm_data)
        void *buffer;
 
        buffer_length = mpi->ln1msg2.ipbfln1f;
-       pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
-                 buffer_length);
+       pr_debug ("%s: MP id=%i Length=%u\n",
+                 p->dev->name, mpi->ipmsgid, buffer_length);
 
        buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA);
        if (buffer == NULL) {
                p->stats.rx_dropped++;
                return;
        }
-
-       rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
-                                 buffer, buffer_length);
+       rc = iucv_receive (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
+                          buffer, buffer_length, NULL, NULL, NULL);
 
        if (rc != 0 || buffer_length < 5) {
                printk (KERN_INFO
-                       "%s: iucv_receive error. rc=%X, length=%u\n",
-                       p->dev->name, rc, buffer_length);
+                       "%s: IUCV rcv error. rc=%X ID=%i length=%u\n",
+                       p->dev->name, rc, mpi->ipmsgid, buffer_length);
                p->stats.rx_errors++;
                kfree (buffer);
                return;
@@ -519,7 +525,7 @@ message_pending (iucv_MessagePending * mpi, ulong pgm_data)
                        break;
                } else {
                        /* Kick the packet upstairs */
-                       iucv_rx (p->dev,
+                       iucv_rx (p->dev, mpi->ipmsgid,
                                 buffer + prev_offset + 2,
                                 packet_offset - prev_offset - 2);
                        prev_offset = packet_offset;
@@ -535,20 +541,23 @@ message_pending (iucv_MessagePending * mpi, ulong pgm_data)
 /* Add meta-data to packet and send upstairs.                  */
 /*-------------------------------------------------------------*/
 static void
-iucv_rx (net_device * dev, uchar * buf, int len)
+iucv_rx (net_device * dev, u32 msgid, uchar * buf, int len)
 {
        struct iucv_priv *p = (struct iucv_priv *) dev->priv;
        struct sk_buff *skb;
 
-       pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len);
-#ifdef DEBUG
+#ifdef IPDEBUG
+       printk (KERN_DEBUG "RX id=%i\n", msgid);
        dumpit (buf, 20);
+       dumpit (buf + 20, 20);
 #endif
 
+       pr_debug ("%s: RX len=%u\n", p->dev->name, len);
+
        if (len > p->dev->mtu) {
                printk (KERN_INFO
-                       "%s: inbound packet length %u exceeds MTU %i\n",
-                       p->dev->name, len, p->dev->mtu);
+                       "%s: inbound packet id# %i length %u exceeds MTU %i\n",
+                       p->dev->name, msgid, len, p->dev->mtu);
                p->stats.rx_errors++;
                return;
        }
@@ -585,81 +594,86 @@ static int
 iucv_tx (struct sk_buff *skb, net_device * dev)
 {
        int rc, pktlen;
-       struct iucvtag *tag;
+       u32 framelen, msgid;
+       void *frame;
        struct iucv_priv *p = (struct iucv_priv *) dev->priv;
 
-       if (skb == NULL)        /* Nothing to do */
-               return 0;
-
-       if (netif_is_busy (dev)) {
-               p->stats.tx_dropped++;
-               dev_kfree_skb (skb);
-               printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n",
+       if (skb == NULL) {      /* Nothing to do */
+               printk (KERN_WARNING "%s: TX Kernel passed null sk_buffer\n",
                        dev->name);
-               return -EBUSY;
+               p->stats.tx_dropped++;
+               return -EIO;
        }
 
-       netif_stop_queue (dev); /* transmission is busy */
+       if (netif_is_busy (dev))
+               return -EBUSY;
 
        dev->trans_start = jiffies;     /* save the timestamp */
 
-       /* Tag contains data that must survive exit from this */
-       /* routine.  MessageComplete exit will free the tag   */
-       /* and any structures it points to.                   */
-       tag =
-           (struct iucvtag *) kmalloc (sizeof (struct iucvtag),
-                                       GFP_DMA | GFP_KERNEL);
-       if (!tag) {
+       /* IUCV frame will be released when MessageComplete   */
+       /* interrupt is received.                             */
+       pktlen = skb->len;
+       framelen = pktlen + 4;
+
+       frame = kmalloc (framelen, GFP_ATOMIC | GFP_DMA);
+       if (!frame) {
                p->stats.tx_dropped++;
                dev_kfree_skb (skb);
-               return -ENOMEM;
+               return 0;
        }
 
-       pktlen = skb->len;
-       tag->framelen = (u16) pktlen + 2;
-       tag->skb = skb;
-       tag->iucvvec[0].address = &tag->framelen;
-       tag->iucvvec[0].length = 2;
-       tag->iucvvec[1].address = (void *) virt_to_phys (skb->data);
-       tag->iucvvec[1].length = pktlen;
-       tag->iucvvec[2].address = (void *) virt_to_phys (eodata);
-       tag->iucvvec[2].length = 2;
-       pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag);
-
-       /* Ok, now the packet is ready for transmission: send it. */
-       rc =
-           iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0,
-                            tag->iucvvec, pktlen + 4);
-       if (rc == 0)
+       netif_stop_queue (dev); /* transmission is busy */
+
+       *(u16 *) frame = pktlen + 2;    /* Set header   */
+       memcpy (frame + 2, skb->data, pktlen);  /* Copy data    */
+       memset (frame + pktlen + 2, 0, 2);      /* Set trailer  */
+
+       /* Ok, now the frame is ready for transmission: send it. */
+       rc = iucv_send (p->pathid, &msgid, 0, 0,
+                       (u32) frame,    /* Msg tag      */
+                       0,      /* No flags     */
+                       frame, framelen);
+       if (rc == 0) {
+#ifdef IPDEBUG
+               printk (KERN_DEBUG "TX id=%i\n", msgid);
+               dumpit (skb->data, 20);
+               dumpit (skb->data + 20, 20);
+#endif
+               pr_debug ("%s: tx START %i.%i @=%p len=%i\n",
+                         p->dev->name, p->pathid, msgid, frame, framelen);
                p->stats.tx_packets++;
-       else {
+       else {
                if (rc == 3)    /* Exceeded MSGLIMIT */
                        p->stats.tx_dropped++;
                else {
                        p->stats.tx_errors++;
-                       printk (KERN_INFO "%s: iucv send failed, rc=%i\n",
-                               p->dev->name, rc);
+                       printk (KERN_INFO "%s: tx ERROR id=%i.%i rc=%i\n",
+                               p->dev->name, p->pathid, msgid, rc);
                }
-               dev_kfree_skb (skb);
-               kfree (tag);
+               /* We won't get interrupt.  Free frame now. */
+               kfree (frame);
        }
+       dev_kfree_skb (skb);    /* Finished with skb            */
 
        netif_wake_queue (p->dev);
-       return rc;              /* zero == done; nonzero == fail */
+       return 0;
 }                              /* end iucv_tx() */
 
 /*-----------------------------------------------------------*/
 /* SEND COMPLETE                    Called by IUCV handler.  */
-/* Free SKB associated with this transmission and free       */
-/* the IUCV buffer list and SKB pointer.                     */
+/* Free the IUCV frame that was used for this transmission.  */
 /*-----------------------------------------------------------*/
 static void
-send_complete (iucv_MessageComplete * mci, ulong pgm_data)
+send_complete (iucv_MessageComplete * mci, void *pgm_data)
 {
-       struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag;
-       pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb);
-       dev_kfree_skb (tag->skb);
-       kfree (tag);
+       void *frame;
+#ifdef DEBUG
+       struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+#endif
+       frame = (void *) (ulong) mci->ipmsgtag;
+       kfree (frame);
+       pr_debug ("%s: TX DONE %i.%i @=%p\n",
+                 p->dev->name, mci->ippathid, mci->ipmsgid, frame);
 }                              /* end send_complete() */
 
 /*-----------------------------------------------------------*/
@@ -704,9 +718,10 @@ iucv_init (net_device * dev)
        dev->type = ARPHRD_SLIP;
        dev->tx_queue_len = MAX_TX_Q;   /* Default - updated based on IUCV */
        /* keep the default flags, just add NOARP and POINTOPOINT */
-       dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+       dev->flags |= IFF_NOARP | IFF_POINTOPOINT;
        dev->mtu = 9216;
 
+       dev_init_buffers (dev);
        pr_debug ("%s: iucv_init  dev@=%p\n", dev->name, dev);
        return 0;
 }
@@ -734,6 +749,7 @@ __initfunc (void iucv_setup (char *iucv, int *ints))
        i = devnumber = 0;
        memset (temp_userid, ' ', 8);
        temp_userid[8] = '\0';
+       printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
 
        if (!iucv)
                init_return (0);
@@ -784,6 +800,7 @@ int
 init_module (void)
 {
        int i;
+       printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
        for (i = 0; i < MAX_DEVICES; i++) {
                if (iucv[i] == NULL)
                        break;
@@ -838,60 +855,120 @@ net_device iucv_netdev[MAX_DEVICES] = {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[0][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[1][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[2][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[3][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[4][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[5][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[6][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[7][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[8][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
        },
        {
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
                name: &iucv_names[9][0],  /* Name filled in at load time  */
 #endif
-               init: iucv_init           /* probe function               */
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[10][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[11][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[12][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[13][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[14][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[15][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[16][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[17][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[18][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
+       },
+       {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+               name: &iucv_names[19][0], /* Name filled in at load time  */
+#endif
+               init: iucv_init           /* probe function               */
        },
 };
index 7febc6ac003dbd894a1e506c5cea0e679a70956d..0fb89baf41824e573454996e9d4747475b91a851 100644 (file)
@@ -112,32 +112,23 @@ static inline devreg_t *s390_search_devreg_internal(ioinfo_t *ioinfo)
                         if (ioinfo->ui.flags.dval != 1 ||
                            ioinfo->devno != pdevreg->ci.devno)
                                continue;
-                } else if ((flag & DEVREG_TYPE_DEVCHARS) &&
-                          (flag & DEVREG_EXACT_MATCH)) {
-                       if (pdevreg->ci.hc.ctype != sid->cu_type ||
-                           pdevreg->ci.hc.cmode != sid->cu_model ||
-                           pdevreg->ci.hc.dtype != sid->dev_type ||
-                           pdevreg->ci.hc.dmode != sid->dev_model)
-                               continue;
                } else if (flag & DEVREG_TYPE_DEVCHARS) {
-                       if (!(flag & DEVREG_NO_CU_INFO) &&
-                           pdevreg->ci.hc.ctype != sid->cu_type)
+                       if ( (flag & DEVREG_MATCH_CU_TYPE) &&
+                            pdevreg->ci.hc.ctype != sid->cu_type )
                                continue;
-
-                        if (!(flag & DEVREG_NO_CU_INFO) &&
-                           !(flag & DEVREG_MATCH_CU_TYPE) &&
-                            pdevreg->ci.hc.cmode != sid->cu_model)
-                                continue;
-
-                        if (!(flag & DEVREG_NO_DEV_INFO) &&
-                            pdevreg->ci.hc.dtype != sid->dev_type)
-                                continue;
-
-                        if (!(flag & DEVREG_NO_DEV_INFO) &&
-                            !(flag & DEVREG_MATCH_DEV_TYPE) &&
-                            pdevreg->ci.hc.dmode != sid->dev_model)
-                                continue;
+                       if ( (flag & DEVREG_MATCH_CU_MODEL) &&
+                            pdevreg->ci.hc.cmode != sid->cu_model )
+                               continue;
+                       if ( (flag & DEVREG_MATCH_DEV_TYPE) &&
+                            pdevreg->ci.hc.dtype != sid->dev_type )
+                               continue;
+                       if ( (flag & DEVREG_MATCH_DEV_MODEL) &&
+                            pdevreg->ci.hc.dmode != sid->dev_model )
+                               continue;
+               } else {
+                       continue;
                }
+               
                return pdevreg;
        }
        return NULL;
index 63c39c08e9c1081f8149aa5da156f004ac125452..cfd2e3cd2500f19aa560e2edd017788302a29441 100644 (file)
  *                                       decrease retry2 on busy while 
  *                                        disabling sync_isc; reset isc_cnt
  *                                        on io error during sync_isc enablement
+ *               05/09/2001 Cornelia Huck added exploitation of debug feature
+ *               05/16/2001 Cornelia Huck added /proc/deviceinfo/<devno>/
+ *               05/22/2001 Cornelia Huck added /proc/cio_ignore
+ *                                        un-ignore blacklisted devices by piping 
+ *                                        to /proc/cio_ignore
  */
 
 #include <linux/module.h>
@@ -24,7 +29,7 @@
 #include <linux/signal.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
@@ -49,6 +54,7 @@
 #include <asm/s390io.h>
 #include <asm/s390dyn.h>
 #include <asm/s390mach.h>
+#include <asm/debug.h>
 
 #ifndef TRUE
 #define TRUE  1
@@ -79,10 +85,17 @@ static irb_t     *p_init_irb        = NULL;
 static __u64      irq_IPL_TOD;
 static adapter_int_handler_t adapter_handler   = NULL;
 
+/* for use of debug feature */
+debug_info_t *cio_debug_msg_id = NULL;  
+debug_info_t *cio_debug_trace_id = NULL;
+debug_info_t *cio_debug_crw_id = NULL;
+int cio_debug_initialized = 0;
+
 static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
 static void s390_process_subchannels( void);
 static void s390_device_recognition_all( void);
 static void s390_device_recognition_irq( int irq);
+static void s390_redo_validation(void);
 static int  s390_validate_subchannel( int irq, int enable);
 static int  s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
 static int  s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
@@ -91,7 +104,7 @@ static int  s390_process_IRQ( unsigned int irq );
 static int  enable_subchannel( unsigned int irq);
 static int  disable_subchannel( unsigned int irq);
 
-void chan_proc_init( void );
+static int chan_proc_init( void );
 
 static inline void do_adapter_IO( __u32 intparm );
 
@@ -105,6 +118,16 @@ extern int  disable_none(unsigned int irq);
 
 asmlinkage void do_IRQ( struct pt_regs regs );
 
+#define MAX_CIO_PROCFS_ENTRIES 0x300
+/* magic number; we want to have some room to spare */
+
+int cio_procfs_device_create(int devno);
+int cio_procfs_device_remove(int devno);
+int cio_procfs_device_purge(void);
+
+int cio_notoper_msg = 1;
+int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
+                            until problems are dealt with */
 
 /* 
  * "Blacklisting" of certain devices:
@@ -123,6 +146,7 @@ typedef struct dev_blacklist_range_t {
 
 static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
 static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+static int nr_blacklisted_ranges = 0;
 
 /* Handling of the blacklist ranges */
 
@@ -133,7 +157,16 @@ static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
 static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
 {
      dev_blacklist_range_t *range = NULL;
-     range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+
+     if (to && (from>to)) {
+            printk("Invalid blacklist range %x to %x, skipping\n", from, to);
+            return NULL;
+     }
+     if (init_IRQ_complete) {
+            range = ( dev_blacklist_range_t *) kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL);
+     } else {
+            range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+     }
      if (range == NULL)
          return NULL;
      memset( range, 0, sizeof( dev_blacklist_range_t ));
@@ -143,6 +176,7 @@ static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
      } else {
          range->to = to;
      }
+     nr_blacklisted_ranges++;
      return range;
 }
 
@@ -153,7 +187,12 @@ static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
 
 static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
 {
-     kfree( range );
+       nr_blacklisted_ranges--;
+       /*
+        * FIXME: the memory was allocated as bootmem, 
+        * how to get it free again ?! 
+        */
+       /* kfree( range ); */
 }
 
 /*
@@ -207,7 +246,7 @@ static inline void blacklist_range_dechain( dev_blacklist_range_t *range )
 /* 
  * Function: blacklist_range_add
  * Creates a range from the specified arguments and appends it to the list of
- * blacklisted devices 
+ * blacklisted devices
  */
 
 static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
@@ -342,6 +381,9 @@ void __init blacklist_init( void )
 #ifdef CONFIG_DEBUG_IO     
      printk( "Reading blacklist...\n");
 #endif
+     if (cio_debug_initialized)
+            debug_sprintf_event(cio_debug_msg_id, 6,
+                                "Reading blacklist\n");
      blacklist_split_parm_string( blacklist_parm_string );
      blacklist_parse( blacklist );
 }
@@ -366,6 +408,9 @@ int __init blacklist_call_setup (char *str)
 #ifdef CONFIG_DEBUG_IO
        printk( "Reading blacklist parameters...\n" );
 #endif
+       if (cio_debug_initialized)
+               debug_sprintf_event(cio_debug_msg_id, 6,
+                                   "Reading blacklist parameters\n");
         blacklist_setup(str,&dummy);
        
        blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
@@ -401,10 +446,107 @@ static inline int is_blacklisted( int devno )
      return 0;
 }
 
+/*
+ * Function: blacklist_free_all_ranges
+ * set all blacklisted devices free...
+ */
+
+void blacklist_free_all_ranges(void) 
+{
+       dev_blacklist_range_t *tmp = dev_blacklist_range_head;
+
+       while (tmp) {
+               blacklist_range_dechain(tmp);
+               blacklist_range_destroy(tmp);
+               tmp = dev_blacklist_range_head;
+       }
+}
+
+/*
+ * Function: blacklist_parse_proc_parameters
+ * parse the stuff which is piped to /proc/cio_ignore
+ */
+void blacklist_parse_proc_parameters(char *buf)
+{
+       char *tmp;
+       int i;
+       char *end;
+       int len = -1;
+       char *param;
+       int from = 0;
+       int to = 0;
+       int changed = 0;
+       dev_blacklist_range_t *range, *temp;
+
+       tmp = buf;
+       if (strstr(tmp, "free ")) {
+               for (i=0; i<5; i++) {
+                       tmp++;
+               }
+               if (strstr(tmp, "all")) {
+                       blacklist_free_all_ranges();
+                       s390_redo_validation();
+               } else {
+                       while (tmp != NULL) {
+                               end = strchr(tmp, ',');
+                               if (end == NULL) {
+                                       len = strlen(tmp) + 1;
+                               } else {
+                                       len = (long)end - (long) tmp + 1;
+                                       *end = '\0';
+                                       end++;
+                               }
+                               param =  (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
+                               strncpy(param, (const char *) tmp, len);
+                               tmp = end;
+                               from = blacklist_strtoul(param, &param);
+                               if (*param == '-') {
+                                       param++;
+                                       to = blacklist_strtoul(param, &param);
+                               } else {
+                                       to = from;
+                               }
+                               range = dev_blacklist_range_head;
+                               while (range != NULL) {
+                                       temp = range->next;
+                                       if ((from <= range->from) && (to >= range->to)) {
+                                               blacklist_range_dechain(range);
+                                               blacklist_range_destroy(range);
+                                               changed = 1;
+                                       } else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
+                                               blacklist_range_add(to+1, range->to);
+                                               blacklist_range_dechain(range);
+                                               blacklist_range_destroy(range);
+                                               changed = 1;
+                                       } else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
+                                               blacklist_range_add(range->from, from-1);
+                                               blacklist_range_dechain(range);
+                                               blacklist_range_destroy(range);
+                                               changed = 1;
+                                       } else if ((from > range->from) && (to < range->to)) {
+                                               blacklist_range_add(range->from, from-1);
+                                               blacklist_range_add(to+1, range->to);
+                                               blacklist_range_dechain(range);
+                                               blacklist_range_destroy(range);
+                                               changed = 1;
+                                       }
+                                       range = temp;
+                               }
+                               kfree(param);
+                       }
+                       if (changed)
+                               s390_redo_validation();
+               }
+       } else {
+               printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
+       }
+}
+
 /* End of blacklist handling */
 
 
 void s390_displayhex(char *str,void *ptr,s32 cnt);
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
 
 void s390_displayhex(char *str,void *ptr,s32 cnt)
 {
@@ -425,6 +567,23 @@ void s390_displayhex(char *str,void *ptr,s32 cnt)
        }
 }
 
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+{
+       s32 cnt1, cnt2, maxcnt2;
+       u32 *currptr = (__u32 *)ptr;
+
+       debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+
+       for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
+               debug_sprintf_event(cio_debug_msg_id, level, "%08lX ", (unsigned long)currptr);
+               maxcnt2 = cnt - cnt1;
+               if (maxcnt2 > 16)
+                       maxcnt2 = 16;
+               for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+                       debug_sprintf_event(cio_debug_msg_id, level, "%08X ", *currptr++);
+       }
+}
+
 static int __init cio_setup( char *parm )
 {
        if ( !strcmp( parm, "yes") )
@@ -446,6 +605,35 @@ static int __init cio_setup( char *parm )
 
 __setup("cio_msg=", cio_setup);
 
+static int __init cio_notoper_setup(char *parm)
+{
+       if (!strcmp(parm, "yes")) {
+               cio_notoper_msg = 1;
+       } else if (!strcmp(parm, "no")) {
+               cio_notoper_msg = 0;
+       } else {
+               printk("cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+       }
+
+       return 1;
+}
+       
+__setup("cio_notoper_msg=", cio_notoper_setup);
+
+static int __init cio_proc_devinfo_setup(char *parm)
+{
+       if (!strcmp(parm, "yes")) {
+               cio_proc_devinfo = 1;
+       } else if (!strcmp(parm, "no")) {
+               cio_proc_devinfo = 0;
+       } else {
+               printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+       }
+
+       return 1;
+}
+
+__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
 
 /*
  * register for adapter interrupts
@@ -461,6 +649,9 @@ __setup("cio_msg=", cio_setup);
 int  s390_register_adapter_interrupt( adapter_int_handler_t handler )
 {
        int ret = 0;
+       
+       if (cio_debug_initialized)
+               debug_text_event(cio_debug_trace_id, 4, "rgaint");
 
        spin_lock( &adapter_lock );
 
@@ -480,6 +671,9 @@ int  s390_register_adapter_interrupt( adapter_int_handler_t handler )
 int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
 {
        int ret = 0;
+       
+       if (cio_debug_initialized)
+               debug_text_event(cio_debug_trace_id, 4, "urgaint");
 
        spin_lock( &adapter_lock );     
 
@@ -497,6 +691,9 @@ int  s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
 
 static inline void do_adapter_IO( __u32 intparm )
 {
+       if (cio_debug_initialized)
+               debug_text_event(cio_debug_trace_id, 4, "doaio");
+       
        spin_lock( &adapter_lock );     
 
        if ( adapter_handler )
@@ -507,7 +704,6 @@ static inline void do_adapter_IO( __u32 intparm )
        return;         
 }
 
-
 int s390_request_irq_special( int                      irq,
                               io_handler_func_t        io_handler,
                               not_oper_handler_func_t  not_oper_handler,
@@ -517,6 +713,7 @@ int s390_request_irq_special( int                      irq,
 {
        int             retval = 0;
        unsigned long   flags;
+       char            dbf_txt[15];
 
        if (irq >= __MAX_SUBCHANNELS)
                return -EINVAL;
@@ -528,6 +725,12 @@ int s390_request_irq_special( int                      irq,
                return -ENODEV;
 
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "reqsp");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * The following block of code has to be executed atomically
         */
@@ -598,6 +801,7 @@ void s390_free_irq(unsigned int irq, void *dev_id)
        int          ret;
 
        unsigned int count = 0;
+       char dbf_txt[15];
 
        if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
        {
@@ -605,6 +809,12 @@ void s390_free_irq(unsigned int irq, void *dev_id)
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 2, "free");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+       }
+
        s390irq_spin_lock_irqsave( irq, flags);
 
 #ifdef  CONFIG_KERNEL_DEBUG
@@ -614,6 +824,8 @@ void s390_free_irq(unsigned int irq, void *dev_id)
 
        } /* endif */
 #endif
+       if (cio_debug_initialized)
+               debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
 
        /*
         * disable the device and reset all IRQ info if
@@ -687,6 +899,10 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                                                               "count exceeded\n",
                                                            irq,
                                                         ioinfo[irq]->devstat.devno);
+                                                       if (cio_debug_initialized)
+                                                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                                   "free_irq(%04X) - device %04X busy, retry count exceeded\n",
+                                                                                   irq, ioinfo[irq]->devstat.devno);
 
                   } /* endif */
                                                
@@ -710,7 +926,10 @@ void s390_free_irq(unsigned int irq, void *dev_id)
                        s390irq_spin_unlock_irqrestore( irq, flags);
 
                        printk( "free_irq(%04X) : error, "
-                               "dev_id does not match !", irq);
+                               "dev_id does not match !\n", irq);
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_msg_id, 0, 
+                                                   "free_irq(%04X) : error, dev_id does not match !\n", irq);
 
                } /* endif */
 
@@ -721,6 +940,9 @@ void s390_free_irq(unsigned int irq, void *dev_id)
 
                printk( "free_irq(%04X) : error, "
                        "no action block ... !\n", irq);
+               if (cio_debug_initialized)
+                       debug_sprintf_event(cio_debug_msg_id, 0,
+                                           "free_irq(%04X) : error, no action block ... !\n", irq);
 
        } /* endif */
 
@@ -733,6 +955,7 @@ int disable_irq(unsigned int irq)
 {
        unsigned long flags;
        int           ret;
+       char dbf_txt[15];
 
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
                return( -ENODEV);
@@ -740,6 +963,12 @@ int disable_irq(unsigned int irq)
        if ( !ioinfo[irq]->ui.flags.ready )
                return -ENODEV;
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "disirq");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        s390irq_spin_lock_irqsave(irq, flags);
        ret = disable_subchannel(irq);
        s390irq_spin_unlock_irqrestore(irq, flags);
@@ -753,6 +982,7 @@ int enable_irq(unsigned int irq)
 {
        unsigned long flags;
        int           ret;
+       char dbf_txt[15];
 
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
                return( -ENODEV);
@@ -760,6 +990,12 @@ int enable_irq(unsigned int irq)
        if ( !ioinfo[irq]->ui.flags.ready )
                return -ENODEV;
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "enirq");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        s390irq_spin_lock_irqsave(irq, flags);
        ret = enable_subchannel(irq);
        s390irq_spin_unlock_irqrestore(irq, flags);
@@ -775,6 +1011,7 @@ static int enable_subchannel( unsigned int irq)
        int   ret;
        int   ccode;
        int   retry = 5;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel || irq < 0 )
        {
@@ -785,6 +1022,12 @@ static int enable_subchannel( unsigned int irq)
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
                return( -ENODEV);
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 2, "ensch");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+       }
+
        /*
         * If a previous disable request is pending we reset it. However, this
         *  status implies that the device may (still) be not-operational.
@@ -862,6 +1105,10 @@ static int enable_subchannel( unsigned int irq)
                                                "%04X received !\n",
                                                irq,
                                                ioinfo[irq]->devstat.devno);
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                   "enable_subchannel(%04X) : ccode 2 on msch() for device %04X received !\n",
+                                                                   irq, ioinfo[irq]->devstat.devno);
 
                                        ret = -ENODEV; // never reached
                                }
@@ -884,6 +1131,7 @@ static int disable_subchannel( unsigned int irq)
        int  cc;          /* condition code */
        int  ret;         /* function return value */
        int  retry = 5;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel )
        {
@@ -903,6 +1151,12 @@ static int disable_subchannel( unsigned int irq)
        }
        else
        {
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 2, "dissch");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+               }
+               
                /*
                 * If device isn't operational we have to perform delayed
                 *  disabling when the next interrupt occurs - unless the
@@ -962,6 +1216,10 @@ static int disable_subchannel( unsigned int irq)
                                                          "device %04X received !\n",
                                                irq,
                                                ioinfo[irq]->devstat.devno);
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 0, 
+                                                                   "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
+                                                                   irq, ioinfo[irq]->devstat.devno);
                                        ret = -EBUSY;
                                        break;
 
@@ -998,14 +1256,6 @@ void s390_init_IRQ( void )
        unsigned long flags;     /* PSW flags */
        long          cr6 __attribute__ ((aligned (8)));
 
-       // Hopefully bh_count's will get set when we copy the prefix lowcore
-       // structure to other CPI's ( DJB )
-       softirq_active(smp_processor_id()) = 0;
-       softirq_mask(smp_processor_id()) = 0;
-       local_bh_count(smp_processor_id()) = 0;
-       local_irq_count(smp_processor_id()) = 0;
-       syscall_count(smp_processor_id()) = 0;
-
        asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
 
        p_init_schib = alloc_bootmem_low( sizeof(schib_t));
@@ -1065,6 +1315,8 @@ int s390_start_IO( int            irq,      /* IRQ */
 {
        int            ccode;
        int            ret = 0;
+       char buffer[80];
+       char dbf_txt[15];
 
        /*
         * The flag usage is mutal exclusive ...
@@ -1076,6 +1328,12 @@ int s390_start_IO( int            irq,      /* IRQ */
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "stIO");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * setup ORB
         */
@@ -1367,18 +1625,17 @@ io_wakeup:
                        {
                                ret                         = -ENODEV;
                                ioinfo[irq]->ui.flags.oper  = 0;
-         }
+                       }
                        else
                        {
                                ret = -EIO;
 
-         } /* endif */
+                       } /* endif */
 
                        ioinfo[irq]->devstat.flag  |= DEVSTAT_NOT_OPER;
 
 #ifdef CONFIG_DEBUG_IO
                        {
-                       char buffer[80];
 
                        stsch(irq, &(ioinfo[irq]->schib) );
 
@@ -1416,6 +1673,41 @@ io_wakeup:
                        } /* endif */
                        }
 #endif
+                       if (cio_debug_initialized) {
+                               stsch(irq, &(ioinfo[irq]->schib) );
+                               
+                               sprintf( buffer, "s390_start_IO(%04X) - irb for "
+                                        "device %04X, after status pending\n",
+                                        irq,
+                                        ioinfo[irq]->devstat.devno );
+                               
+                               s390_displayhex2( buffer,
+                                                &(ioinfo[irq]->devstat.ii.irb) ,
+                                                sizeof(irb_t), 2);
+                               
+                               sprintf( buffer, "s390_start_IO(%04X) - schib for "
+                                        "device %04X, after status pending\n",
+                                        irq,
+                                        ioinfo[irq]->devstat.devno );
+                               
+                               s390_displayhex2( buffer,
+                                                &(ioinfo[irq]->schib) ,
+                                                sizeof(schib_t), 2);
+                               
+                               
+                               if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+                                       sprintf( buffer, "s390_start_IO(%04X) - sense "
+                                                "data for "
+                                                "device %04X, after status pending\n",
+                                                irq,
+                                                ioinfo[irq]->devstat.devno );
+                                       
+                                       s390_displayhex2( buffer,
+                                                         ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
+                                                         ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
+                                       
+                               } /* endif */
+                       }
                }
                else
                {
@@ -1457,9 +1749,8 @@ io_wakeup:
                        &(ioinfo[irq]->devstat),
                        sizeof( devstat_t) );
 
+
 #ifdef CONFIG_DEBUG_IO
-               {
-                       char buffer[80];
 
                        stsch(irq, &(ioinfo[irq]->schib) );
 
@@ -1471,8 +1762,20 @@ io_wakeup:
                        s390_displayhex( buffer,
                                         &(ioinfo[irq]->schib),
                                         sizeof(schib_t));
-       }
 #endif
+               if (cio_debug_initialized) {
+                       stsch(irq, &(ioinfo[irq]->schib) );
+
+                       sprintf( buffer, "s390_start_IO(%04X) - schib for "
+                                "device %04X, after 'not oper' status\n",
+                                irq,
+                                ioinfo[irq]->devstat.devno );
+
+                       s390_displayhex2( buffer,
+                                        &(ioinfo[irq]->schib),
+                                        sizeof(schib_t), 2);
+               }
+                       
                break;
 
        } /* endswitch */
@@ -1499,6 +1802,7 @@ int do_IO( int            irq,          /* IRQ */
            unsigned long  flag)         /* flags : see above */
 {
        int ret = 0;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel || irq < 0 )
        {
@@ -1518,6 +1822,12 @@ int do_IO( int            irq,          /* IRQ */
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "doIO");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * Note: We ignore the device operational status - if not operational,
         *        the SSCH will lead to an -ENODEV condition ...
@@ -1567,6 +1877,7 @@ int do_IO( int            irq,          /* IRQ */
 int resume_IO( int irq)
 {
        int ret = 0;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel || irq < 0 )
        {
@@ -1579,6 +1890,12 @@ int resume_IO( int irq)
                return( -ENODEV);
        }
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "resIO");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * We allow for 'resume' requests only for active I/O operations
         */
@@ -1635,16 +1952,17 @@ int halt_IO( int           irq,
 {
        int            ret;
        int            ccode;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel || irq < 0 )
        {
-               ret = -ENODEV;
+               return -ENODEV;
        }
 
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
        {
                return( -ENODEV);
-   }
+       }
 
        /*
         * we only allow for halt_IO if the device has an I/O handler associated
@@ -1671,6 +1989,11 @@ int halt_IO( int           irq,
        }
        else
        {
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 2, "haltIO");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+               }
                /*
                 * If sync processing was requested we lock the sync ISC,
                 *  modify the device to present interrupts for this ISC only
@@ -1895,10 +2218,11 @@ int clear_IO( int           irq,
 {
        int            ret;
        int            ccode;
+       char dbf_txt[15];
 
        if ( irq > highest_subchannel || irq < 0 )
        {
-               ret = -ENODEV;
+               return -ENODEV;
        }
 
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -1932,6 +2256,11 @@ int clear_IO( int           irq,
        }
        else
        {
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 2, "clearIO");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+               }
                /*
                 * If sync processing was requested we lock the sync ISC,
                 *  modify the device to present interrupts for this ISC only
@@ -2066,7 +2395,7 @@ cio_wakeup:
                        break;
 
                case 1 :            /* status pending */
-       
+
                        ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
 
                        /*
@@ -2117,7 +2446,7 @@ cio_wakeup:
                                ioinfo[irq]->devstat.flag  &= ~DEVSTAT_NOT_OPER;
                                ioinfo[irq]->ui.flags.oper  = 1;
 
-                       } /* endif */
+                       } /* endif */ 
 
                        break;
 
@@ -2172,7 +2501,6 @@ asmlinkage void do_IRQ( struct pt_regs regs )
                return;
        } /* endif */
 
-       
 #ifdef CONFIG_FAST_IRQ
        do {
 #endif /*  CONFIG_FAST_IRQ */
@@ -2252,12 +2580,20 @@ int s390_process_IRQ( unsigned int irq )
        int               chnchk          = 0;
        devstat_t        *dp;
        devstat_t        *udp;
+
+       char dbf_txt[15];
 #if 0
        int               cpu             = smp_processor_id();
 
        kstat.irqs[cpu][irq]++;
 #endif
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 3, "procIRQ");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+       }
+
        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
        {
                /* we can't properly process the interrupt ... */
@@ -2270,7 +2606,6 @@ int s390_process_IRQ( unsigned int irq )
        udp = ioinfo[irq]->irq_desc.dev_id;
        
 
-#ifdef CONFIG_DEBUG_IO
        /*
         * It might be possible that a device was not-oper. at the time
         *  of free_irq() processing. This means the handler is no longer
@@ -2281,16 +2616,20 @@ int s390_process_IRQ( unsigned int irq )
        {
                if ( !ioinfo[irq]->ui.flags.d_disable )
                {
+#ifdef CONFIG_DEBUG_IO
                        printk( KERN_CRIT"s390_process_IRQ(%04X) "
                                "- no interrupt handler registered "
                                          "for device %04X !\n",
                                irq,
                                ioinfo[irq]->devstat.devno);
-
+#endif /* CONFIG_DEBUG_IO */
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                   "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
+                                                   irq, ioinfo[irq]->devstat.devno);
                } /* endif */
 
        } /* endif */
-#endif
 
        /*
         * retrieve the i/o interrupt information (irb),
@@ -2360,6 +2699,10 @@ int s390_process_IRQ( unsigned int irq )
                                "residual count from irb after tsch() %d\n",
                                irq, dp->rescnt );
 #endif
+               if (cio_debug_initialized)
+                       debug_sprintf_event(cio_debug_msg_id, 6,
+                                           "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
+                                           irq, dp->rescnt);
 
        } /* endif */
 
@@ -2372,17 +2715,24 @@ int s390_process_IRQ( unsigned int irq )
        if (    (dp->ii.irb.scsw.cstat
                    & (  SCHN_STAT_CHN_DATA_CHK
                       | SCHN_STAT_CHN_CTRL_CHK
-                      | SCHN_STAT_INTF_CTRL_CHK )       )
-            && (irq != cons_dev                         ) )
-       {
-               printk( "Channel-Check or Interface-Control-Check "
-                       "received\n"
-                       " ... device %04X on subchannel %04X, dev_stat "
-                       ": %02X sch_stat : %02X\n",
-                       ioinfo[irq]->devstat.devno,
-                       irq,
-                       dp->dstat,
-                       dp->cstat);
+                        | SCHN_STAT_INTF_CTRL_CHK )))
+       {
+               if (irq != cons_dev)
+                       printk( "Channel-Check or Interface-Control-Check "
+                               "received\n"
+                               " ... device %04X on subchannel %04X, dev_stat "
+                               ": %02X sch_stat : %02X\n",
+                               ioinfo[irq]->devstat.devno,
+                               irq,
+                               dp->dstat,
+                               dp->cstat);
+               if (cio_debug_initialized) {
+                       debug_sprintf_event(cio_debug_msg_id, 0,
+                                           "Channel-Check or Interface-Control-Check received\n");
+                       debug_sprintf_event(cio_debug_msg_id, 0,
+                                           "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
+                                           ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
+               }
 
                chnchk = 1;
 
@@ -2422,6 +2772,10 @@ int s390_process_IRQ( unsigned int irq )
                                "concurrent sense bytes avail %d\n",
                                irq, dp->scnt );
 #endif
+               if (cio_debug_initialized)
+                       debug_sprintf_event(cio_debug_msg_id, 4,
+                                           "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
+                                           irq, dp->scnt);
        }
        else
        {
@@ -2453,6 +2807,17 @@ int s390_process_IRQ( unsigned int irq )
                        s390_displayhex( buffer,
                                         &(dp->ii.irb) ,
                                         sizeof(irb_t));
+                       if (cio_debug_initialized) {
+                               
+                               sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+                                "device %04X after channel check\n",
+                                irq,
+                                dp->devno );
+
+                               s390_displayhex2( buffer,
+                                                 &(dp->ii.irb) ,
+                                                 sizeof(irb_t), 0);
+                       }
                } /* endif */
                        
                ioinfo[irq]->stctl |= stctl;
@@ -2473,20 +2838,19 @@ int s390_process_IRQ( unsigned int irq )
                 *       unsolicited interrupt applies to the console device
                 *       itself !
                 */
-#ifdef CONFIG_DEBUG_IO
-               if (     ( irq != cons_dev                 )
-                        && !( stctl & SCSW_STCTL_ALERT_STATUS )
-                        &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )
+               if ( !( stctl & SCSW_STCTL_ALERT_STATUS )
+                    &&  ( ioinfo[irq]->ui.flags.busy == 0  ) )
                {
                        char buffer[80];
-
-                       printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
-                               " ... device status : %02X subchannel status : %02X\n",
-                               dp->devno,
-                               irq,
-                               dp->dstat,
-                               dp->cstat);
-
+#ifdef CONFIG_DEBUG_IO
+                       if (irq != cons_dev)
+                               printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+                                       " ... device status : %02X subchannel status : %02X\n",
+                                       dp->devno,
+                                       irq,
+                                       dp->dstat,
+                                       dp->cstat);
+                       
                        sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
                                 "device %04X, ending_status %d\n",
                                 irq,
@@ -2496,10 +2860,27 @@ int s390_process_IRQ( unsigned int irq )
                        s390_displayhex( buffer,
                                         &(dp->ii.irb) ,
                                         sizeof(irb_t));
-
+#endif
+                       if (cio_debug_initialized) {
+                               debug_sprintf_event(cio_debug_msg_id, 2, 
+                                                   "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+                                                   " ... device status : %02X subchannel status : %02X\n",
+                                                   dp->devno,
+                                                   irq,
+                                                   dp->dstat,
+                                                   dp->cstat);
+                               sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+                                        "device %04X, ending_status %d\n",
+                                        irq,
+                                        dp->devno,
+                                        ending_status);
+                               
+                               s390_displayhex2( buffer,
+                                                &(dp->ii.irb) ,
+                                                sizeof(irb_t), 2);     
+                       }
                } /* endif */
 
-#endif
                /*
                 * take fast exit if no handler is available
                 */
@@ -2639,11 +3020,15 @@ int s390_process_IRQ( unsigned int irq )
                                int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
 
 #ifdef CONFIG_DEBUG_IO
-      if ( irq != cons_dev )
-         printk( "s390_process_IRQ( %04X ) : "
-                 "BASIC SENSE bytes avail %d\n",
-                 irq, sense_count );
+                               if ( irq != cons_dev )
+                                       printk( "s390_process_IRQ( %04X ) : "
+                                               "BASIC SENSE bytes avail %d\n",
+                                               irq, sense_count );
 #endif
+                               if (cio_debug_initialized)
+                                       debug_sprintf_event(cio_debug_msg_id, 4,
+                                                           "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
+                                                           irq, sense_count);
                                ioinfo[irq]->ui.flags.w4sense = 0;
                                udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
                                udp->scnt  = sense_count;
@@ -2664,6 +3049,11 @@ int s390_process_IRQ( unsigned int irq )
                                        printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
                                                "negative sense count\n",
                                                irq);
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                   "s390_process_IRQ(%04x) encountered "
+                                                                   "negative sense count\n",
+                                                                   irq);                   
 #endif
                                } /* endif */
                        }
@@ -2906,6 +3296,7 @@ int set_cons_dev( int irq )
        int           ccode;
        unsigned long cr6 __attribute__ ((aligned (8)));
        int           rc = 0;
+       char dbf_txt[15];
 
        if ( cons_dev != -1  )
        {
@@ -2921,6 +3312,12 @@ int set_cons_dev( int irq )
    }
        else
        {
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 4, "scons");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+               }
+               
                /*
                 * modify the indicated console device to operate
                 *  on special console interrupt sublass 7
@@ -2967,6 +3364,7 @@ int reset_cons_dev( int irq)
        int     rc = 0;
        int     ccode;
        long    cr6 __attribute__ ((aligned (8)));
+       char dbf_txt[15];
 
        if ( cons_dev != -1  )
        {
@@ -2982,6 +3380,12 @@ int reset_cons_dev( int irq)
    }
        else
        {
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 4, "rcons");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+               }
+
                /*
                 * reset the indicated console device to operate
                 *  on default console interrupt sublass 3
@@ -3028,10 +3432,17 @@ int wait_cons_dev( int irq )
 {
        int              rc = 0;
        long             save_cr6;
+       char dbf_txt[15];
 
        if ( irq == cons_dev )
        {
 
+               if (cio_debug_initialized) {
+                       debug_text_event(cio_debug_trace_id, 4, "wcons");
+                       sprintf(dbf_txt, "%x", irq);
+                       debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+               }
+
                /*
                 * before entering the spinlock we may already have
                 *  processed the interrupt on a different CPU ...
@@ -3087,6 +3498,13 @@ int enable_cpu_sync_isc( int irq )
 
        int             count = 0;
        int             rc    = 0;
+       char dbf_txt[15];
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "enisc");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
 
        /* This one spins until it can get the sync_isc lock for irq# irq */
 
@@ -3171,6 +3589,7 @@ int enable_cpu_sync_isc( int irq )
 
                } /* endif */
 
+
                if ( rc )       /* can only happen if stsch/msch fails */
                {
                        sync_isc_cnt = 0;
@@ -3200,6 +3619,14 @@ int disable_cpu_sync_isc( int irq)
        int     ccode;
        long    cr6 __attribute__ ((aligned (8)));
 
+       char dbf_txt[15];
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "disisc");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
        {
                /*
@@ -3311,6 +3738,9 @@ void VM_virtual_device_info( __u16      devno,
 
        int        error = 0;
 
+       if (cio_debug_initialized) 
+               debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+
        if ( init_IRQ_complete )
        {
                p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
@@ -3596,6 +4026,19 @@ void VM_virtual_device_info( __u16      devno,
                        p_diag_data->vrdcrccl,
                        p_diag_data->vrdccrty,
                        p_diag_data->vrdccrmd );
+               if (cio_debug_initialized)
+                       debug_sprintf_event( cio_debug_msg_id, 0,
+                                            "DIAG X'210' for "
+                                            "device %04X returned "
+                                            "(cc = %d): vdev class : %02X, "
+                                            "vdev type : %04X \n ...  rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+                                            devno,
+                                            ccode,
+                                            p_diag_data->vrdcvcla,
+                                            p_diag_data->vrdcvtyp,
+                                            p_diag_data->vrdcrccl,
+                                            p_diag_data->vrdccrty,
+                                            p_diag_data->vrdccrmd );
 
        } /* endif */
 
@@ -3636,6 +4079,8 @@ int read_dev_chars( int irq, void **buffer, int length )
        int           emulated = 0;
        int           retry    = 5;
 
+       char dbf_txt[15];
+
        if ( !buffer || !length )
        {
                return( -EINVAL );
@@ -3650,7 +4095,7 @@ int read_dev_chars( int irq, void **buffer, int length )
        else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
        {
                return( -ENODEV);
-   }
+       }
 
        if ( ioinfo[irq]->ui.flags.oper == 0 )
        {
@@ -3658,6 +4103,12 @@ int read_dev_chars( int irq, void **buffer, int length )
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "rddevch");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * Before playing around with irq locks we should assure
         *   running disabled on (just) our CPU. Sync. I/O requests
@@ -3769,6 +4220,8 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
        int           found  = 0; // RCD CIW found
        int           ret    = 0; // return code
 
+       char dbf_txt[15];
+
        if ( (irq > highest_subchannel) || (irq < 0 ) )
        {
                return( -ENODEV );
@@ -3791,6 +4244,12 @@ int read_conf_data( int irq, void **buffer, int *length, __u8 lpm )
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "rdconf");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        /*
         * scan for RCD command in extended SenseID data
         */
@@ -4262,6 +4721,13 @@ unsigned int get_devno_by_irq( int irq )
 void s390_device_recognition_irq( int irq )
 {
        int           ret;
+       char dbf_txt[15];
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "devrec");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
 
        /*
         * We issue the SenseID command on I/O subchannels we think are
@@ -4274,7 +4740,7 @@ void s390_device_recognition_irq( int irq )
                int       irq_ret;
                devstat_t devstat;
 
-          irq_ret = request_irq( irq,
+               irq_ret = request_irq( irq,
                                       init_IRQ_handler,
                                       0,
                                       "INIT",
@@ -4284,7 +4750,7 @@ void s390_device_recognition_irq( int irq )
                {
                        ret = enable_cpu_sync_isc( irq );
 
-                       if ( !ret )
+                       if ( !ret ) 
                        {
                                ioinfo[irq]->ui.flags.unknown = 0;
 
@@ -4305,9 +4771,8 @@ void s390_device_recognition_irq( int irq )
 
                                        if ( !ret )     // on success only ...
                                        {
-#ifdef CONFIG_DEBUG_IO
                                                char buffer[80];
-
+#ifdef CONFIG_DEBUG_IO
                                                sprintf( buffer,
                                                         "RCD for device(%04X)/"
                                                         "subchannel(%04X) returns :\n",
@@ -4316,6 +4781,15 @@ void s390_device_recognition_irq( int irq )
 
                                                s390_displayhex( buffer, prcd, lrcd );
 #endif                                 
+                                               if (cio_debug_initialized) {
+                                                       sprintf( buffer,
+                                                                "RCD for device(%04X)/"
+                                                                "subchannel(%04X) returns :\n",
+                                                                ioinfo[irq]->schib.pmcw.dev,
+                                                                irq );
+                                                       
+                                                       s390_displayhex2( buffer, prcd, lrcd, 2);
+                                               }
                                                if ( init_IRQ_complete )
                                                {
                                                        kfree( prcd );
@@ -4326,9 +4800,9 @@ void s390_device_recognition_irq( int irq )
 
                                                } /* endif */
 
-                               } /* endif */
-
-             } /* endif */
+                                       } /* endif */
+                                       
+                               } /* endif */
 #endif
                                s390_DevicePathVerification( irq, 0 );
 
@@ -4364,6 +4838,44 @@ void s390_device_recognition_all( void)
 
 }
 
+/*
+ * Function: s390_redo_validation
+ * Look for no longer blacklisted devices
+ * FIXME: there must be a better way to do this...
+ */
+
+void s390_redo_validation(void) 
+{
+       int irq = 0;
+       int ret;
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 0, "redoval");
+       }
+       do {
+               if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+                       ret = s390_validate_subchannel(irq, 0);
+                       if (!ret) {
+                               s390_device_recognition_irq(irq);
+                               if (ioinfo[irq]->ui.flags.oper) {
+                                       devreg_t *pdevreg;
+                                       
+                                       pdevreg = s390_search_devreg( ioinfo[irq] );
+                                       if ( pdevreg != NULL ) {
+                                               if ( pdevreg->oper_func != NULL )
+                                                       pdevreg->oper_func( irq, pdevreg );
+                                               
+                                       } 
+                               }
+                               if (cio_proc_devinfo) 
+                                       if (irq < MAX_CIO_PROCFS_ENTRIES) {
+                                               cio_procfs_device_create(ioinfo[irq]->devno);
+                               }
+                       }
+               }
+               irq++;
+       } while (irq<=highest_subchannel);
+}
 
 /*
  * s390_search_devices
@@ -4389,6 +4901,10 @@ void s390_process_subchannels( void)
 
        printk( "Highest subchannel number detected (hex) : %04X\n",
                highest_subchannel);
+       if (cio_debug_initialized)
+               debug_sprintf_event(cio_debug_msg_id, 0, 
+                                   "Highest subchannel number detected (hex) : %04X\n",
+                                   highest_subchannel);        
 }
 
 /*
@@ -4405,6 +4921,14 @@ int s390_validate_subchannel( int irq, int enable )
        int      ccode2;    /* condition code for other I/O routines */
        schib_t *p_schib;
        int      ret;
+       
+       char dbf_txt[15];
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "valsch");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
 
        /*
         * The first subchannel that is not-operational (ccode==3)
@@ -4444,6 +4968,10 @@ int s390_validate_subchannel( int irq, int enable )
                                "non-I/O subchannel type %04X\n",
                                irq,
                                p_schib->pmcw.st);
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                   "Subchannel %04X reports non-I/O subchannel type %04X\n",
+                                                   irq, p_schib->pmcw.st);
 
                        if ( ioinfo[irq] != INVALID_STORAGE_AREA )
                                ioinfo[irq]->ui.flags.oper = 0;
@@ -4460,6 +4988,10 @@ int s390_validate_subchannel( int irq, int enable )
 #ifdef CONFIG_DEBUG_IO
                          printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
 #endif
+                         if (cio_debug_initialized)
+                                 debug_sprintf_event(cio_debug_msg_id, 0,
+                                                     "Blacklisted device detected at devno %04X\n",
+                                                     p_schib->pmcw.dev);
                          ret = -ENODEV;
                     } else {
                        if ( ioinfo[irq] == INVALID_STORAGE_AREA )
@@ -4547,6 +5079,16 @@ int s390_validate_subchannel( int irq, int enable )
                                       ioinfo[irq]->schib.pmcw.pom);
 
                        } /* endif */
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                   "Detected device %04X "
+                                                   "on subchannel %04X"
+                                                   " - PIM = %02X, PAM = %02X, POM = %02X\n",
+                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                   irq,
+                                                   ioinfo[irq]->schib.pmcw.pim,
+                                                   ioinfo[irq]->schib.pmcw.pam,
+                                                   ioinfo[irq]->schib.pmcw.pom);
 
                        /*
                         * initialize ioinfo structure
@@ -4661,6 +5203,10 @@ int s390_validate_subchannel( int irq, int enable )
                                                        {
                                                                printk( " ... msch() (2) failed with CC = %X\n",
                                                                        ccode2 );
+                                                               if (cio_debug_initialized)
+                                                                       debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                                           "msch() (2) failed with CC=%X\n",
+                                                                                           ccode2);
                                                                ioinfo[irq]->ui.flags.oper = 0;
                                                                ret                        = -EIO;
                                                        }
@@ -4676,6 +5222,10 @@ int s390_validate_subchannel( int irq, int enable )
                                                {
                                                        printk( " ... msch() (1) failed with CC = %X\n",
                                                                ccode2);
+                                                       if (cio_debug_initialized)
+                                                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                                   "msch() (1) failed with CC = %X\n",
+                                                                                   ccode2);
                                                        ioinfo[irq]->ui.flags.oper = 0;
                                                        ret                        = -EIO;
 
@@ -4694,6 +5244,11 @@ int s390_validate_subchannel( int irq, int enable )
                                                "subchannel %04X exceeded, CC = %d\n",
                                                irq,
                                                ccode2);
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 0,
+                                                                   " ... msch() retry count for "
+                                                                   "subchannel %04X exceeded, CC = %d\n",
+                                                                   irq, ccode2);                   
 
                                } /* endif */
                        }
@@ -4750,6 +5305,8 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
        senseid_t *psid     = sid;/* start with the external buffer */  
        int        sbuffer  = 0; /* switch SID data buffer */
 
+       char dbf_txt[15];
+
        if ( (irq > highest_subchannel) || (irq < 0 ) )
        {
                return( -ENODEV );
@@ -4767,6 +5324,12 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
 
        } /* endif */
 
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "snsID");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        if ( !ioinfo[irq]->ui.flags.ready )
        {
 
@@ -4792,8 +5355,8 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
        } /* endif */
 
        if ( irq_ret == 0 )
-   {
-      int i;
+       {
+               int i;
 
                s390irq_spin_lock( irq);
 
@@ -4888,6 +5451,15 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                             irq,
                                                                retry);
 #endif
+                                                       if (cio_debug_initialized)
+                                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                                   "SenseID : device %04X on "
+                                                                                   "Subchannel %04X "
+                                                                                   "reports pending status, "
+                                                                                   "retry : %d\n",
+                                                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                                                   irq,
+                                                                                   retry);                 
                                                } /* endif */
 
                                                if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
@@ -4907,11 +5479,20 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                        ioinfo[irq]->schib.pmcw.dev,
                                                                        irq);
 #endif
+                                                               if (cio_debug_initialized)
+                                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                                           "SenseID : device %04X on "
+                                                                                           "Subchannel %04X "
+                                                                                           "reports cmd reject or "
+                                                                                           "intervention required\n",
+                                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                                           irq);                   
                                                                io_retry = 1;
                                                        }
-#ifdef CONFIG_DEBUG_IO
+
                                                        else
                                                        {
+#ifdef CONFIG_DEBUG_IO                                                 
                                                                printk( "SenseID : UC on "
                                                                        "dev %04X, "
                                                                        "retry %d, "
@@ -4932,9 +5513,31 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                        pdevstat->ii.sense.data[5],
                                                                        pdevstat->ii.sense.data[6],
                                                                        pdevstat->ii.sense.data[7]);
-
-                                                       } /* endif */
 #endif
+                                                               if (cio_debug_initialized)
+                                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                                           "SenseID : UC on "
+                                                                                           "dev %04X, "
+                                                                                           "retry %d, "
+                                                                                           "lpum %02X, "
+                                                                                           "cnt %02d, "
+                                                                                           "sns :"
+                                                                                           " %02X%02X%02X%02X "
+                                                                                           "%02X%02X%02X%02X ...\n",
+                                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                                           retry,
+                                                                                           pdevstat->lpum,
+                                                                                           pdevstat->scnt,
+                                                                                           pdevstat->ii.sense.data[0],
+                                                                                           pdevstat->ii.sense.data[1],
+                                                                                           pdevstat->ii.sense.data[2],
+                                                                                           pdevstat->ii.sense.data[3],
+                                                                                           pdevstat->ii.sense.data[4],
+                                                                                           pdevstat->ii.sense.data[5],
+                                                                                           pdevstat->ii.sense.data[6],
+                                                                                           pdevstat->ii.sense.data[7]);            
+                                                       } /* endif */
+
                                                }
                                                else if (    ( pdevstat->flag & DEVSTAT_NOT_OPER )
                                                     || ( irq_ret        == -ENODEV         ) )
@@ -4948,18 +5551,28 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                ioinfo[irq]->schib.pmcw.dev,
                                                                irq);
 #endif
+                                                       if (cio_debug_initialized)
+                                                               debug_sprintf_event(cio_debug_msg_id, 2, 
+                                                                                   "SenseID : path %02X for "
+                                                                                   "device %04X on "
+                                                                                   "subchannel %04X "
+                                                                                   "is 'not operational'\n",
+                                                                                   domask,
+                                                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                                                   irq);                   
 
                                                        io_retry          = 0;
                                                        ioinfo[irq]->opm &= ~domask;
        
                                                }
-#ifdef CONFIG_DEBUG_IO
+
                                                else if (     (pdevstat->flag !=
                                                                    (   DEVSTAT_START_FUNCTION
                                                                      | DEVSTAT_FINAL_STATUS    ) )
                                                           && !(pdevstat->flag &
                                                                    DEVSTAT_STATUS_PENDING        ) )
                                                {
+#ifdef CONFIG_DEBUG_IO
                                                        printk( "SenseID : start_IO() for "
                                                                "device %04X on "
                                                                "subchannel %04X "
@@ -4970,9 +5583,22 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                                                irq_ret,
                                                                retry,
                                                                pdevstat->flag);
+#endif
+                                                       if (cio_debug_initialized)
+                                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                                   "SenseID : start_IO() for "
+                                                                                   "device %04X on "
+                                                                                   "subchannel %04X "
+                                                                                   "returns %d, retry %d, "
+                                                                                   "status %04X\n",
+                                                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                                                   irq,
+                                                                                   irq_ret,
+                                                                                   retry,
+                                                                                   pdevstat->flag);                
 
                                                } /* endif */
-#endif
+
                                        }
                                        else   // we got it ...
                                        {
@@ -5079,38 +5705,54 @@ int s390_SenseID( int irq, senseid_t *sid, __u8 lpm )
                                ioinfo[irq]->schib.pmcw.dev,
                                irq);
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                   "SenseID : unknown device %04X on subchannel %04X\n",
+                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                   irq);                   
                        ioinfo[irq]->ui.flags.unknown = 1;
 
                } /* endif */
 
-               if ( cio_show_msg )
-               {
+       
                        /*
                         * Issue device info message if unit was operational .
                         */
-                       if ( !ioinfo[irq]->ui.flags.unknown )
-                       {
-                               if ( sid->dev_type != 0 )
-                               {
+               if ( !ioinfo[irq]->ui.flags.unknown ) {
+                       if ( sid->dev_type != 0 ) {
+                               if ( cio_show_msg ) 
                                        printk( KERN_INFO"SenseID : device %04X reports: "
-                                               "CU  Type/Mod = %04X/%02X,"
-                                         " Dev Type/Mod = %04X/%02X\n",
-                                            ioinfo[irq]->schib.pmcw.dev,
-                                               sid->cu_type,
-                                               sid->cu_model,
-                                               sid->dev_type,
-                                               sid->dev_model);
-                               }
-                               else
-                               {
+                                               "CU  Type/Mod = %04X/%02X,"
+                                               " Dev Type/Mod = %04X/%02X\n",
+                                               ioinfo[irq]->schib.pmcw.dev,
+                                               sid->cu_type,
+                                               sid->cu_model,
+                                               sid->dev_type,
+                                               sid->dev_model);
+                               if (cio_debug_initialized)
+                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                           "SenseID : device %04X reports: "
+                                                           "CU  Type/Mod = %04X/%02X,"
+                                                           " Dev Type/Mod = %04X/%02X\n",
+                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                           sid->cu_type,
+                                                           sid->cu_model,
+                                                           sid->dev_type,
+                                                           sid->dev_model);
+                       } else {
+                               if ( cio_show_msg ) 
                                        printk( KERN_INFO"SenseID : device %04X reports:"
-                                            " Dev Type/Mod = %04X/%02X\n",
-                                               ioinfo[irq]->schib.pmcw.dev,
-                                               sid->cu_type,
-                                               sid->cu_model);
-
-                               } /* endif */
-
+                                               " Dev Type/Mod = %04X/%02X\n",
+                                               ioinfo[irq]->schib.pmcw.dev,
+                                               sid->cu_type,
+                                               sid->cu_model);
+                               if (cio_debug_initialized)
+                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                           "SenseID : device %04X reports:"
+                                                           " Dev Type/Mod = %04X/%02X\n",
+                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                           sid->cu_type,
+                                                           sid->cu_model);                 
                        } /* endif */
 
                } /* endif */
@@ -5159,6 +5801,14 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
 
        int ret = 0;
 
+       char dbf_txt[15];
+
+       if (cio_debug_initialized) {
+               debug_text_event(cio_debug_trace_id, 4, "dpver");
+               sprintf(dbf_txt, "%x", irq);
+               debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+       }
+
        if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
        {
                return( 0);     // just exit ...
@@ -5270,16 +5920,30 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                                                        irq,
                                                        ioinfo[irq]->schib.pmcw.dev);
 #endif
+                                               if (cio_debug_initialized)
+                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                           "PathVerification(%04X) "
+                                                                           "- Device %04X doesn't "
+                                                                           " support path grouping\n",
+                                                                           irq,
+                                                                           ioinfo[irq]->schib.pmcw.dev);                   
 
                                        } /* endif */
                                }
-                               else if ( ret == -EIO )
+                               else if ( ret == -EIO ) 
                                {
 #ifdef CONFIG_DEBUG_IO
                                        printk("PathVerification(%04X) - I/O error "
                                               "on device %04X\n", irq,
                                               ioinfo[irq]->schib.pmcw.dev);
 #endif
+
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                   "PathVerification(%04X) - I/O error "
+                                                                   "on device %04X\n", irq,
+                                                                   ioinfo[irq]->schib.pmcw.dev);
+
                                        ioinfo[irq]->ui.flags.pgid_supp = 0;
                    
                                } else {
@@ -5289,6 +5953,13 @@ int s390_DevicePathVerification( int irq, __u8 usermask )
                                                irq,
                                                ioinfo[irq]->schib.pmcw.dev);
 #endif
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                   "PathVerification(%04X) - "
+                                                                   "Unexpected error on device %04X\n",
+                                                                   irq,
+                                                                   ioinfo[irq]->schib.pmcw.dev);                   
+                                       
                                        ioinfo[irq]->ui.flags.pgid_supp = 0;
                                        
                                } /* endif */
@@ -5357,7 +6028,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
 
                if ( irq_ret == 0 )
                        inlreq = 1;
-   }
+       }
        else
        {
                pdevstat = ioinfo[irq]->irq_desc.dev_id;
@@ -5419,6 +6090,15 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
                                                irq,
                                                retry);
 #endif
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                   "SPID - Device %04X "
+                                                                   "on Subchannel %04X "
+                                                                   "reports pending status, "
+                                                                   "retry : %d\n",
+                                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                                   irq,
+                                                                   retry);         
                                } /* endif */
 
                                if ( pdevstat->flag == (   DEVSTAT_START_FUNCTION
@@ -5468,19 +6148,50 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
                                                        pdevstat->ii.sense.data[5],
                                                        pdevstat->ii.sense.data[6],
                                                        pdevstat->ii.sense.data[7]);
-
 #endif
-                                               retry--;
 
+                                               if (cio_debug_initialized)
+                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                           "SPID - device %04X,"
+                                                                           " unit check,"
+                                                                           " retry %d, cnt %02d,"
+                                                                           " sns :"
+                                                                           " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                           retry,
+                                                                           pdevstat->scnt,
+                                                                           pdevstat->ii.sense.data[0],
+                                                                           pdevstat->ii.sense.data[1],
+                                                                           pdevstat->ii.sense.data[2],
+                                                                           pdevstat->ii.sense.data[3],
+                                                                           pdevstat->ii.sense.data[4],
+                                                                           pdevstat->ii.sense.data[5],
+                                                                           pdevstat->ii.sense.data[6],
+                                                                           pdevstat->ii.sense.data[7]);
+
+                                               retry--;
+                   
                                        } /* endif */
+
                                }
                                else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
                                {
-                                       printk( "SPID - Device %04X "
-                                               "on Subchannel %04X "
-                                               "became 'not operational'\n",
-                                               ioinfo[irq]->schib.pmcw.dev,
-                                               irq);
+                                       /* don't issue warnings during startup unless requested*/
+                                       if (init_IRQ_complete || cio_notoper_msg) {   
+                                               
+                                               printk( "SPID - Device %04X "
+                                                       "on Subchannel %04X "
+                                                       "became 'not operational'\n",
+                                                       ioinfo[irq]->schib.pmcw.dev,
+                                                       irq);
+                                               if (cio_debug_initialized)
+                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                           "SPID - Device %04X "
+                                                                           "on Subchannel %04X "
+                                                                           "became 'not operational'\n",
+                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                           irq);                   
+                                       }
 
                                        retry = 0;
                                        irq_ret = -EIO;
@@ -5503,7 +6214,7 @@ int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
                {
                        irq_ret = -EIO;
 
-               } /* endif */           
+               } /* endif */
 
                if ( init_IRQ_complete )
                {
@@ -5659,17 +6370,47 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                                                        pdevstat->ii.sense.data[7]);
 
 #endif
+                                               if (cio_debug_initialized)
+                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                           "SNID - device %04X,"
+                                                                           " unit check,"
+                                                                           " flag %04X, "
+                                                                           " retry %d, cnt %02d,"
+                                                                           " sns :"
+                                                                           " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                           pdevstat->flag,
+                                                                           retry,
+                                                                           pdevstat->scnt,
+                                                                           pdevstat->ii.sense.data[0],
+                                                                           pdevstat->ii.sense.data[1],
+                                                                           pdevstat->ii.sense.data[2],
+                                                                           pdevstat->ii.sense.data[3],
+                                                                           pdevstat->ii.sense.data[4],
+                                                                           pdevstat->ii.sense.data[5],
+                                                                           pdevstat->ii.sense.data[6],
+                                                                           pdevstat->ii.sense.data[7]);                    
                                                retry--;
 
                                        } /* endif */
                                }
                                else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
                                {
-                                       printk( "SNID - Device %04X "
-                                               "on Subchannel %04X "
-                                               "became 'not operational'\n",
-                                               ioinfo[irq]->schib.pmcw.dev,
-                                               irq);
+                                       /* don't issue warnings during startup unless requested*/
+                                       if (init_IRQ_complete || cio_notoper_msg) {  
+                                               printk( "SNID - Device %04X "
+                                                       "on Subchannel %04X "
+                                                       "became 'not operational'\n",
+                                                       ioinfo[irq]->schib.pmcw.dev,
+                                                       irq);
+                                               if (cio_debug_initialized)
+                                                       debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                           "SNID - Device %04X "
+                                                                           "on Subchannel %04X "
+                                                                           "became 'not operational'\n",
+                                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                                           irq);                   
+                                       }
 
                                        retry = 0;
 
@@ -5682,9 +6423,10 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                        }
                        else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
                        {
-#ifdef CONFIG_DEBUG_IO
+
                                if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
                                {
+#ifdef CONFIG_DEBUG_IO
                                        printk( "SNID - Device %04X "
                                                "on Subchannel %04X "
                                                "reports pending status, "
@@ -5692,13 +6434,29 @@ int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
                                                ioinfo[irq]->schib.pmcw.dev,
                                                irq,
                                                retry);
-                               } /* endif */
 #endif
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_msg_id, 2,
+                                                                   "SNID - Device %04X "
+                                                                   "on Subchannel %04X "
+                                                                   "reports pending status, "
+                                                                   "retry : %d\n",
+                                                                   ioinfo[irq]->schib.pmcw.dev,
+                                                                   irq,
+                                                                   retry);                 
+                               } /* endif */
+
 
                                printk( "SNID - device %04X,"
                                        " start_io() reports rc : %d, retrying ...\n",
                                        ioinfo[irq]->schib.pmcw.dev,
                                        irq_ret);
+                               if (cio_debug_initialized)
+                                       debug_sprintf_event(cio_debug_msg_id, 2, 
+                                                           "SNID - device %04X,"
+                                                           " start_io() reports rc : %d, retrying ...\n",
+                                                           ioinfo[irq]->schib.pmcw.dev,
+                                                           irq_ret);
                                retry--;
                        }
                        else    // -ENODEV ...
@@ -5758,7 +6516,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #ifdef CONFIG_DEBUG_CRW
        printk( "do_crw_pending : starting ...\n");
 #endif
-
+       if (cio_debug_initialized) 
+               debug_sprintf_event(cio_debug_crw_id, 2, 
+                                   "do_crw_pending: starting\n");
        while ( pcrwe != NULL )
        {
                int is_owned = 0;
@@ -5772,7 +6532,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        printk( KERN_INFO"do_crw_pending : source is "
                                "subchannel %04X\n", irq);
 #endif
-
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "source is subchannel %04X\n", irq);
                        /*
                         * If the device isn't known yet
                         *   we can't lock it ...
@@ -5794,6 +6556,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #ifdef CONFIG_DEBUG_CRW
                        printk( "do_crw_pending : subchannel validation - start ...\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 4,
+                                                   "subchannel validation - start\n");
                        s390_validate_subchannel( irq, is_owned );
 
                        if ( irq > highest_subchannel )
@@ -5802,6 +6567,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #ifdef CONFIG_DEBUG_CRW
                        printk( "do_crw_pending : subchannel validation - done\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 4,
+                                                   "subchannel validation - done\n");
                        /*
                         * After the validate processing
                         *   the ioinfo control block
@@ -5813,26 +6581,34 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 
                        } /* endif */
 
-#ifdef CONFIG_DEBUG_CRW
+
                        if ( ioinfo[irq] != INVALID_STORAGE_AREA )
                        {
+#ifdef CONFIG_DEBUG_CRW
                                printk( "do_crw_pending : ioinfo at %08X\n",
                                        (unsigned)ioinfo[irq]);
-
-                       } /* endif */
 #endif
+                               if (cio_debug_initialized)
+                                       debug_sprintf_event(cio_debug_crw_id, 4,
+                                                           "ioinfo at %08X\n");
+                       } /* endif */
+
 
                        if ( ioinfo[irq] != INVALID_STORAGE_AREA )
                        {
                                if ( ioinfo[irq]->ui.flags.oper == 0 )
                                {
                                         not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+                                        
+                                        /* remove procfs entry */
+                                        if (cio_proc_devinfo)
+                                                cio_procfs_device_remove(dev_no);
                                        /*
                                         * If the device has gone
                                         *  call not oper handler               
                                         */             
-                                       if (    (             dev_oper == 1    )
-                                            && ( nopfunc != NULL ) )
+                                        if (( dev_oper == 1 )
+                                            && ( nopfunc != NULL))
                                        {
                                                
                                                free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
@@ -5846,13 +6622,18 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                        printk( "do_crw_pending : device "
                                                "recognition - start ...\n");
 #endif
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_crw_id, 4,
+                                                                   "device recognition - start\n");
                                        s390_device_recognition_irq( irq );
 
 #ifdef CONFIG_DEBUG_CRW
                                        printk( "do_crw_pending : device "
                                                "recognition - done\n");
 #endif
-               
+                                       if (cio_debug_initialized)
+                                               debug_sprintf_event(cio_debug_crw_id, 4,
+                                                                   "device recognition - done\n");
                                        /*
                                         * the device became operational
                                         */
@@ -5868,6 +6649,12 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                                                pdevreg->oper_func( irq, pdevreg );
 
                                                } /* endif */
+
+                                               /* add new procfs entry */
+                                               if (cio_proc_devinfo) 
+                                                       if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+                                                               cio_procfs_device_create(ioinfo[irq]->devno);
+                                                       }
                                        }
                                        /*
                                         * ... it is and was operational, but
@@ -5875,13 +6662,23 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                                         */
                                        else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))                                    
                                        {
+                                               int devno_old = ioinfo[irq]->devno;
                                                ioinfo[irq]->nopfunc( irq,
                                                                      DEVSTAT_REVALIDATE );                             
 
+                                               /* remove old entry, add new */
+                                               if (cio_proc_devinfo) {
+                                                       cio_procfs_device_remove(devno_old);
+                                                       cio_procfs_device_create(ioinfo[irq]->devno);
+                                               }
                                        } /* endif */
 
                                } /* endif */
 
+                               /* get rid of dead procfs entries */
+                               if (cio_proc_devinfo) 
+                                       cio_procfs_device_purge();
+
                        } /* endif */
 
                        break;
@@ -5892,6 +6689,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        printk( "do_crw_pending : source is "
                                "monitoring facility\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "source is monitoring facility\n");
                        break;
 
                case CRW_RSC_CPATH :    
@@ -5902,6 +6702,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        printk( "do_crw_pending : source is "
                                "channel path %02X\n", chpid);
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "source is channel path %02X\n");
                        break;
 
                case CRW_RSC_CONFIG :   
@@ -5910,6 +6713,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        printk( "do_crw_pending : source is "
                                "configuration-alert facility\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "source is configuration-alert facility\n");
                        break;
 
                case CRW_RSC_CSS :
@@ -5918,6 +6724,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
                        printk( "do_crw_pending : source is "
                                "channel subsystem\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "source is channel subsystem\n");
                        break;
 
                default :
@@ -5925,6 +6734,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #ifdef CONFIG_DEBUG_CRW
                        printk( "do_crw_pending : unknown source\n");
 #endif
+                       if (cio_debug_initialized)
+                               debug_sprintf_event(cio_debug_crw_id, 2,
+                                                   "unknown source\n");
                        break;          
 
                } /* endswitch */
@@ -5936,7 +6748,9 @@ void s390_do_crw_pending( crwe_t *pcrwe )
 #ifdef CONFIG_DEBUG_CRW
        printk( "do_crw_pending : done\n");
 #endif
-
+       if (cio_debug_initialized)
+               debug_sprintf_event(cio_debug_crw_id, 2,
+                                   "do_crw_pending: done\n");
    return;
 }
 
@@ -5964,8 +6778,64 @@ reipl ( int sch )
                do_reipl( 0x10000 | sch );
 }
 
-/* Display info on subchannels in /proc/subchannels. *
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      */
+
+/*
+ * Function: cio_debug_init
+ * Initializes three debug logs (under /proc/s390dbf) for common I/O:
+ * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * - cio_trace logs the calling of different functions
+ * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
+ * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ */
+int cio_debug_init( void )
+{
+       int ret = 0;
+
+       cio_debug_msg_id = debug_register("cio_msg",2,4,16*sizeof(long));
+       if (cio_debug_msg_id != NULL) {
+               debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_IO
+               debug_set_level(cio_debug_msg_id, 6);
+#else /* CONFIG_DEBUG_IO */
+               debug_set_level(cio_debug_msg_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+       } else {
+               ret = -1;
+       }
+       cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+       if (cio_debug_trace_id != NULL) {
+               debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+#ifdef CONFIG_DEBUG_IO
+               debug_set_level(cio_debug_trace_id, 6);
+#else /* CONFIG_DEBUG_IO */
+               debug_set_level(cio_debug_trace_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+       } else {
+               ret = -1;
+       }
+       cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+       if (cio_debug_crw_id != NULL) {
+               debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_CRW
+               debug_set_level(cio_debug_crw_id, 6);
+#else /* CONFIG_DEBUG_CRW */
+               debug_set_level(cio_debug_crw_id, 2);
+#endif /* CONFIG_DEBUG_CRW */
+       } else {
+               ret = -1;
+       }
+       if (ret)
+               return ret;
+       cio_debug_initialized = 1;
+       return 0;
+}
+
+__initcall(cio_debug_init);
+
+/* 
+ * Display info on subchannels in /proc/subchannels. 
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.      
+ */
 
 typedef struct {
      char *data;
@@ -6090,10 +6960,12 @@ static struct file_operations chan_subch_file_ops =
      release:chan_subch_close,
 };
 
-void chan_proc_init( void )
+static int chan_proc_init( void )
 {
      chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
      chan_subch_entry->proc_fops = &chan_subch_file_ops;
+
+     return 1;
 }
 
 __initcall(chan_proc_init);
@@ -6103,6 +6975,531 @@ void chan_proc_cleanup( void )
      remove_proc_entry( "subchannels", &proc_root);
 }
 
+/* 
+ * Display device specific information under /proc/deviceinfo/<devno>
+ */
+
+static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+
+/* 
+ * cio_procfs_device_list holds all devno-specific procfs directories
+ */
+
+typedef struct {
+       int devno;
+       struct proc_dir_entry *cio_device_entry;
+       struct proc_dir_entry *cio_sensedata_entry;
+       struct proc_dir_entry *cio_in_use_entry;
+       struct proc_dir_entry *cio_chpid_entry;
+} cio_procfs_entry_t;
+
+typedef struct _cio_procfs_device{
+       struct _cio_procfs_device *next;
+       cio_procfs_entry_t *entry;
+} cio_procfs_device_t;
+
+cio_procfs_device_t *cio_procfs_device_list = NULL;
+
+/*
+ * File operations
+ */
+
+static int cio_device_entry_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;
+}
+
+static ssize_t cio_device_entry_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;
+     } else {
+         len = MIN(user_len, (p_info->len - *offset));
+         if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+              return -EFAULT; 
+         (* offset) += len;
+         return len;
+     }
+}
+
+int cio_search_devno_by_inode(struct inode *inode)
+{
+       int devno = -1;
+       struct proc_dir_entry *pde;
+       cio_procfs_device_t *tmp;
+       
+       pde = (struct proc_dir_entry *)inode->u.generic_ip;
+       tmp = cio_procfs_device_list;
+
+       while (tmp) {
+               if ((tmp->entry->cio_device_entry == pde) ||
+                   (tmp->entry->cio_sensedata_entry == pde) ||
+                   (tmp->entry->cio_in_use_entry == pde) ||
+                   (tmp->entry->cio_chpid_entry == pde))
+                       break;
+               tmp = tmp->next;
+       }
+
+       if (tmp)
+               devno = tmp->entry->devno;
+               
+       return devno;
+}
+
+
+static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+{
+       int rc = 0;
+       int size = 1;
+       int len = 0;
+       tempinfo_t *info;
+       int irq;
+       int devno;
+
+       info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+       if (info == NULL) {
+               printk( KERN_WARNING "No memory available for data\n");
+               rc = -ENOMEM;
+       } else {
+               file->private_data = (void *) info;
+               size += 2 * 32;
+               info->data = (char *) vmalloc(size);
+               if (size && info->data == NULL) {
+                       printk(KERN_WARNING "No memory available for data\n");
+                       vfree(info);
+                       rc = -ENOMEM;
+               } else {
+                       devno = cio_search_devno_by_inode(inode);
+                       if (devno != 0xFFFF) {
+                               irq = get_irq_by_devno(devno);
+                               if (irq != -1) {
+                                       len += sprintf(info->data+len, "Dev Type/Mod: ");
+                                       if (ioinfo[irq]->senseid.dev_type == 0) {
+                                               len += sprintf(info->data+len, "%04X/%02X\n",
+                                                              ioinfo[irq]->senseid.cu_type,
+                                                              ioinfo[irq]->senseid.cu_model);
+                                       } else {
+                                               len += sprintf(info->data+len, "%04X/%02X\n",
+                                                              ioinfo[irq]->senseid.dev_type,
+                                                              ioinfo[irq]->senseid.dev_model);
+                                               len+= sprintf(info->data+len, "CU Type/Mod:  %04X/%02X\n",
+                                                             ioinfo[irq]->senseid.cu_type,
+                                                             ioinfo[irq]->senseid.cu_model);
+                                       }
+                               }
+                       }
+                       info->len = len;
+               }
+       }
+       
+       return rc;
+}
+
+static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+{
+       int rc = 0;
+       int size = 1;
+       int len = 0;
+       tempinfo_t *info;
+       int irq;
+       int devno;
+
+       info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+       if (info == NULL) {
+               printk( KERN_WARNING "No memory available for data\n");
+               rc = -ENOMEM;
+       } else {
+               file->private_data = (void *) info;
+               size += 8;
+               info->data = (char *) vmalloc(size);
+               if (size && info->data == NULL) {
+                       printk(KERN_WARNING "No memory available for data\n");
+                       vfree(info);
+                       rc = -ENOMEM;
+               } else {
+                       devno = cio_search_devno_by_inode(inode);
+                       if (devno != -1) {
+                               irq = get_irq_by_devno(devno);
+                               if (irq != -1) {
+                                       len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+                               }
+                       }
+                       info->len = len;
+               }
+       }
+       
+       return rc;
+}
+
+static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+{
+       int rc = 0;
+       int size = 1;
+       int len = 0;
+       tempinfo_t *info;
+       int irq;
+       int devno;
+       int i;
+
+       info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+       if (info == NULL) {
+               printk( KERN_WARNING "No memory available for data\n");
+               rc = -ENOMEM;
+       } else {
+               file->private_data = (void *) info;
+               size += 8*16;
+               info->data = (char *) vmalloc(size);
+               if (size && info->data == NULL) {
+                       printk(KERN_WARNING "No memory available for data\n");
+                       vfree(info);
+                       rc = -ENOMEM;
+               } else {
+                       devno = cio_search_devno_by_inode(inode);
+                       if (devno != -1) {
+                               irq = get_irq_by_devno(devno);
+                               if (irq != -1) {
+                                       for (i=0; i<8; i++) {
+                                               len += sprintf(info->data+len, "CHPID[%d]: ", i);
+                                               len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+                                       }
+                               }
+                       }
+                       info->len = len;
+               }
+       }
+
+       return rc;
+}
+
+static struct file_operations cio_sensedata_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_sensedata_entry_open,
+     release:cio_device_entry_close,
+};
+
+static struct file_operations cio_in_use_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_in_use_entry_open,
+     release:cio_device_entry_close,
+};
+
+static struct file_operations cio_chpid_entry_file_ops =
+{
+     read:cio_device_entry_read,
+     open:cio_chpid_entry_open,
+     release:cio_device_entry_close,
+};
+
+/*
+ * Function: cio_procfs_device_create
+ * create procfs entry for given device number
+ * and insert it into list
+ */
+int cio_procfs_device_create(int devno)
+{
+       cio_procfs_entry_t *entry;
+       cio_procfs_device_t *tmp;
+       cio_procfs_device_t *where;
+       char buf[8];
+       int i;
+       int rc = 0;
+
+
+       /* create the directory entry */
+       entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+       if (entry) {
+               entry->devno = devno;
+               sprintf(buf, "%x", devno);
+               entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
+               
+               if (entry->cio_device_entry) {
+                       tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+                       if (tmp) {
+                               tmp->entry = entry;
+                               
+                               if (cio_procfs_device_list == NULL) {
+                                       cio_procfs_device_list = tmp;
+                                       tmp->next = NULL;
+                               } else {
+                                       where = cio_procfs_device_list;
+                                       i = where->entry->devno;
+                                       while ((devno>i) && (where->next != NULL)) {
+                                               where = where->next;
+                                               i = where->entry->devno;
+                                       }
+                                       if (where->next == NULL) {
+                                               where->next = tmp;
+                                               tmp->next = NULL;
+                                       } else {
+                                               tmp->next = where->next;
+                                               where->next = tmp;
+                                       }
+                               }
+                               /* create the different entries */
+                               entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
+                               entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
+                               entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
+                               entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
+                               entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
+                               entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+                       } else {
+                               printk("Error, could not allocate procfs structure!\n");
+                               remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+                               kfree(entry);
+                               rc = -ENOMEM;
+                       }
+               } else {
+                       printk("Error, could not allocate procfs structure!\n");
+                       kfree(entry);
+                       rc = -ENOMEM;
+               }
+
+       } else {
+               printk("Error, could not allocate procfs structure!\n");
+               rc = -ENOMEM;
+       }
+       return rc;
+}
+
+/*
+ * Function: cio_procfs_device_remove
+ * remove procfs entry for given device number
+ */
+int cio_procfs_device_remove(int devno)
+{
+       int rc = 0;
+       cio_procfs_device_t *tmp;
+       cio_procfs_device_t *prev = NULL;
+
+       tmp=cio_procfs_device_list;
+       while (tmp) {
+               if (tmp->entry->devno == devno)
+                       break;
+               prev = tmp;
+               tmp = tmp->next;
+       }
+
+       if (tmp) {
+               char buf[8];
+               
+               remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
+               remove_proc_entry("in_use", tmp->entry->cio_device_entry);
+               remove_proc_entry("chpid", tmp->entry->cio_device_entry);
+               sprintf(buf, "%x", devno);
+               remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+               
+               if (tmp == cio_procfs_device_list) {
+                       cio_procfs_device_list = tmp->next;
+               } else {
+                       prev->next = tmp->next;
+               }
+               kfree(tmp->entry);
+               kfree(tmp);
+       } else {
+               rc = -ENODEV;
+       }
+
+       return rc;
+}
+
+/*
+ * Function: cio_procfs_purge
+ * purge /proc/deviceinfo of entries for gone devices
+ */
+
+int cio_procfs_device_purge(void) 
+{
+       int i;
+
+       for (i=0; i<=highest_subchannel; i++) {
+               if (ioinfo[i] != INVALID_STORAGE_AREA) {
+                       if (!ioinfo[i]->ui.flags.oper) 
+                               cio_procfs_device_remove(ioinfo[i]->devno);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Function: cio_procfs_create
+ * create /proc/deviceinfo/ and subdirs for the devices
+ */
+static int cio_procfs_create( void )
+{
+       int irq;
+
+       if (cio_proc_devinfo) {
+
+               cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
+               
+               if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
+                       printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
+                              "Not every device will get an entry.\n");
+               }
+               
+               for (irq=0; irq<=highest_subchannel; irq++) {
+                       if (irq >= MAX_CIO_PROCFS_ENTRIES)
+                               break;
+                       if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+                               if (ioinfo[irq]->ui.flags.oper) 
+                                       if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
+                                               printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
+                                                      "not all devices might show up\n");
+                                       break;
+                                       }
+                       }
+               }
+       
+       }
+       
+       return 1;
+}
+
+__initcall(cio_procfs_create);
+
+/*
+ * Entry /proc/cio_ignore to display blacklisted ranges of devices.
+ * un-ignore devices by piping to /proc/cio_ignore:
+ * free all frees all blacklisted devices, free <range>,<range>,...
+ * frees specified ranges of devnos
+ */
+
+static struct proc_dir_entry *cio_ignore_proc_entry;
+
+static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+{
+       int rc = 0;
+       int size = 1;
+       int len = 0;
+       tempinfo_t *info;
+       dev_blacklist_range_t *tmp;
+
+       info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+       if (info == NULL) {
+               printk( KERN_WARNING "No memory available for data\n");
+               rc = -ENOMEM;
+       } else {
+               file->private_data = (void *) info;
+               size += nr_blacklisted_ranges * 32;
+               info->data = (char *) vmalloc(size);
+               if (size && info->data == NULL) {
+                       printk( KERN_WARNING "No memory available for data\n");
+                       vfree (info);
+                       rc = -ENOMEM;
+               } else {
+                       tmp = dev_blacklist_range_head;
+                       while (tmp) {
+                               len += sprintf(info->data+len, "%04x ", tmp->from);
+                               if (tmp->to != tmp->from) 
+                                       len += sprintf(info->data+len, "- %04x", tmp->to);
+                               len += sprintf(info->data+len, "\n");
+                               tmp = tmp->next;
+                       }
+                       info->len = len;
+               }
+       }
+       return rc;
+}
+
+static int cio_ignore_proc_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;
+}
+
+static ssize_t cio_ignore_proc_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;
+     } else {
+         len = MIN(user_len, (p_info->len - *offset));
+         if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+              return -EFAULT; 
+         (* offset) += len;
+         return len;
+     }
+}
+
+static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
+                                     size_t user_len, loff_t * offset)
+{
+       char *buffer = vmalloc (user_len);
+
+       if (buffer == NULL)
+               return -ENOMEM;
+       if (copy_from_user (buffer, user_buf, user_len)) {
+               vfree (buffer);
+               return -EFAULT;
+       }
+       buffer[user_len]='\0';
+#ifdef CIO_DEBUG_IO
+       printk ("/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+       if (cio_debug_initialized)
+               debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+
+       blacklist_parse_proc_parameters(buffer);
+
+       return user_len;
+}
+
+static struct file_operations cio_ignore_proc_file_ops =
+{
+       read:cio_ignore_proc_read,
+       open:cio_ignore_proc_open,
+       write:cio_ignore_proc_write,
+       release:cio_ignore_proc_close,
+};
+
+static int cio_ignore_proc_init(void)
+{
+       cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+       cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
+
+       return 1;
+}
+
+__initcall(cio_ignore_proc_init);
+
+/* end of procfs stuff */
+
+schib_t *s390_get_schib( int irq )
+{
+       if ( (irq > highest_subchannel) || (irq < 0) )
+               return NULL;
+       if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+               return NULL;
+       return &ioinfo[irq]->schib;
+
+}
+
+
 EXPORT_SYMBOL(halt_IO);
 EXPORT_SYMBOL(clear_IO);
 EXPORT_SYMBOL(do_IO);
@@ -6117,3 +7514,6 @@ EXPORT_SYMBOL(get_irq_next);
 EXPORT_SYMBOL(read_conf_data);
 EXPORT_SYMBOL(read_dev_chars);
 EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_get_schib);
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
index b9f5eb9b5eb6a474b2781c0f7f5b4c1b00fede88..b38b6e96b7595ee1648d7305c09f4f0e8a88da8b 100644 (file)
@@ -11,7 +11,7 @@
 #include <linux/config.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #ifdef CONFIG_SMP
 #include <linux/smp.h>
 #endif
index e1a00e94af888ccc7c4ac39b9f66e844fb21536a..8776f56d3c323074356010dd40c274b88422daa8 100644 (file)
@@ -2646,7 +2646,7 @@ find_adp:
                {
                    printk(" %2x ",workrequ->cmnd[k]);
                }
-               printk(" last_lenu= %x ",dev->id[j].last_lenu);
+               printk(" last_lenu= %lx ",dev->id[j].last_lenu);
           }
        }
        return (SCSI_ABORT_SNOOZE);
index 6023cae9b3ea443dedc28f8006c9703dbd6b9ab2..f8a816744f61429e46fafeef7dcafe94694d5e50 100644 (file)
@@ -399,6 +399,7 @@ int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt){
                release_mem_region(overrides[current_override].NCR5380_map_name,
                                                NCR5380_region_size);
 #endif
+               continue;
        }
        
        instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
index bc39562827b84cd540d03161cc4e9880d9365e0b..cb61a628d2f69b5aa925f912a3065131b6d3708b 100644 (file)
@@ -47,6 +47,8 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
 #if LINUX_VERSION_CODE >= 0x020322
     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
     scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+           return -ENOMEM;
     scp->cmd_len = 12;
     scp->use_sg = 0;
 #else
index 38b08106551526d78c4881a218d35033f648a872..9b937910aca798aa59cf6fb726d9696c2ed2aa28 100644 (file)
@@ -9,7 +9,7 @@
  *              as published by the Free Software Foundation; either version
  *              2 of the License, or (at your option) any later version.
  *
- * Version : v1.15d(May 30, 2001)
+ * Version : v1.17a (July 13, 2001)
  *
  * Description: Linux device driver for AMI MegaRAID controller
  *
@@ -21,7 +21,7 @@
  *     Original source contributed by Dell; integrated it into the kernel and
  *     cleaned up some things.  Added support for 438/466 controllers.
  * Version 0.91:
- *     Aligned mailbox area on 16-byte boundry.
+ *     Aligned mailbox area on 16-byte boundary.
  *     Added schedule() at the end to properly clean up.
  *     Made improvements for conformity to linux driver standards.
  *
  *    Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
  *      data area greater than 4 KB, which is the upper bound for data
  *      tranfer through scsi_ioctl interface.
- *    The addtional 32 bit field for 64bit address in the newly defined
+ *    The additional 32 bit field for 64bit address in the newly defined
  *      mailbox64 structure is set to 0 at this point.
  *
  * Version 1.05
  *    Changed the queing implementation for handling SCBs and completed
  *      commands.
- *    Added spinlocks in the interrupt service routine to enable the dirver
+ *    Added spinlocks in the interrupt service routine to enable the driver
  *      function in the SMP environment.
  *    Fixed the problem of unnecessary aborts in the abort entry point, which
  *      also enables the driver to handle large amount of I/O requests for
  *                 MEGA_HP_FIX)
  *
  *      Version 1a12
- *      I.      reboot notifer and new ioctl changes ported from 1c09
+ *      I.      reboot notifier and new ioctl changes ported from 1c09
  *
- *      Veriosn 1b12
+ *      Version 1b12
  *      I.      Changes in new ioctl interface routines ( Nov 06, 2000 )
  *
- *      Veriosn 1c12
+ *      Version 1c12
  *      I.      Changes in new ioctl interface routines ( Nov 07, 2000 )
  *
- *      Veriosn 1d12
+ *      Version 1d12
  *      I.      Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
  *
- *      Veriosn 1e12, 1f12
+ *      Version 1e12, 1f12
  *      1.  Fixes for pci_map_single, pci_alloc_consistent along with mailbox
  *          alignment
  *
  *     
  *     Version 1.13j
  *     Moved some code to megaraid.h file, replaced some hard coded values 
- *      with respective macros. Chaged some funtions to static
+ *      with respective macros. Changed some functions to static
  *
  *     Version 1.13k
  *     Only some idendation correction to 1.13j 
  *     Assorted changes to remove compilation error in 1.14k when compiled
  *     with kernel < 2.4.0
  *
+ *     Version 1.14m
+ *     Tue Mar 27 12:09:22 EST 2001 - AM
+ *
+ *     Added support for extended CDBs ( > 10 bytes ) and OBDR ( One Button
+ *     Disaster Recovery ) feature.
+ *
+ *
+ *     Version 1.14n
+ *     Tue Apr 10 14:28:13 EDT 2001 - AM
+ *
+ *     "modeversions.h" is no longer included in the code.
+ *     2.4.xx style mutex initialization used for older kernels also
+ *
+ *     Version 1.14o
+ *     Wed Apr 18 17:47:26 EDT 2001 - PJ
+ *
+ *     Before returning status for 'inquiry', we first check if request buffer
+ *     is SG list, and then return appropriate status
+ *
+ *     Version 1.14p
+ *     Wed Apr 25 13:44:48 EDT 2001 - PJ
+ *
+ *     SCSI result made appropriate in case of check conditions for extended
+ *     passthru commands
+ *
+ *     Do not support lun >7 for physically accessed devices 
+ *
+ *     
  *     Version 1.15
  *     Thu Apr 19 09:38:38 EDT 2001 - AM
  *
- *     1.14l rollover to 1.15
+ *     1.14l rollover to 1.15 - merged with main trunk after 1.15d
  *
  *     Version 1.15b
  *  Wed May 16 20:10:01 EDT 2001 - AM
  *     "modeversions.h" is no longer included in the code.
  *     2.4.xx style mutex initialization used for older kernels also
  *     Brought in-sync with Alan's changes in 2.4.4
- *     Note: 1.15a is on OBDR brabch(main trunk), and is not merged with yet.
+ *     Note: 1.15a is on OBDR branch(main trunk), and is not merged with yet.
  *
  * Version 1.15c
  * Mon May 21 23:10:42 EDT 2001 - AM
  * NULL is not a valid first argument for pci_alloc_consistent() on
  * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
  * "pci_dev" before making calls to pci interface routines.
-
+ *
+ * Version 1.16pre
+ * Fri Jun  1 19:40:48 EDT 2001 - AM
+ *
+ * 1.14p and 1.15d merged
+ * ROMB support added
+ *
+ * Version 1.16-pre1
+ * Mon Jun  4 15:01:01 EDT 2001 - AM
+ *
+ * Non-ROMB firmware do no DMA support 0xA9 command. Value 0xFF
+ * (all channels are raid ) is chosen for those firmware.
+ *
+ * Version 1.16-pre2
+ * Mon Jun 11 18:15:31 EDT 2001 - AM
+ *
+ * Changes for boot from any logical drive
+ *
+ * Version 1.16
+ * Tue Jun 26 18:07:02 EDT 2001 - AM
+ *
+ * branched at 1.14p
+ *
+ * Check added for HP 1M/2M controllers if having firmware H.01.07 or
+ * H.01.08. If found, disable 64 bit support since these firmware have
+ * limitations for 64 bit addressing
+ *
+ *
+ * Version 1.17
+ * Thu Jul 12 11:14:09 EDT 2001 - AM
+ *
+ * 1.16pre2 and 1.16 merged.
+ *
+ * init_MUTEX and init_MUTEX_LOCKED are defined in 2.2.19. Pre-processor
+ * statements are added for them
+ *
+ * Linus's 2.4.7pre3 kernel introduces a new field 'max_sectors' in Scsi_Host
+ * structure, to improve IO performance.
+ *
+ *
+ * Version 1.17a
+ * Fri Jul 13 18:44:01 EDT 2001 - AM
+ *
+ * Starting from kernel 2.4.x, LUN is not < 8 - following SCSI-III. So to have
+ * our current formula working to calculate logical drive number, return
+ * failure for LUN > 7
+ *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
  *     fails to detect the controller as a pci device on the system.
@@ -509,16 +583,17 @@ MODULE_DESCRIPTION ("AMI MegaRAID driver");
 
 #define pci_free_consistent(a,b,c,d)
 #define pci_unmap_single(a,b,c,d)
-
-#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
-#define init_MUTEX(x)           (*(x)=MUTEX)
-
 #define pci_enable_device(x) (0)
-
 #define queue_task_irq(a,b)     queue_task(a,b)
 #define queue_task_irq_off(a,b) queue_task(a,b)
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)        /* 0x020219 */
+#define init_MUTEX_LOCKED(x)    (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x)           (*(x)=MUTEX)
 #define DECLARE_WAIT_QUEUE_HEAD(x)     struct wait_queue *x = NULL
+#endif
+
+
 #else
 
 /*
@@ -577,7 +652,9 @@ typedef struct {
 #define dma_alloc_consistent pci_alloc_consistent
 #define dma_free_consistent pci_free_consistent
 #else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19)        /* 0x020219 */
 typedef unsigned long dma_addr_t;
+#endif
 void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
 void dma_free_consistent(void *, size_t, void *, dma_addr_t);
 int mega_get_order(int);
@@ -661,7 +738,7 @@ static struct file_operations megadev_fops = {
 static struct mcontroller mcontroller[MAX_CONTROLLERS];
 
 /* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 117;
 
 /* major number used by the device for character interface */
 static int major;
@@ -684,6 +761,8 @@ static struct proc_dir_entry proc_scsi_megaraid = {
 extern struct proc_dir_entry proc_root;
 #endif
 
+static char mega_ch_class;     /* channels are raid or scsi */
+#define        IS_RAID_CH(ch)  ( (mega_ch_class >> (ch)) & 0x01 )
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -782,6 +861,11 @@ static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb)
                                  pScb->pthru->dataxferlen,
                                  pScb->dma_direction);
                break;
+       case M_RD_EPTHRU_WITH_BULK_DATA:
+               pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+                                 pScb->epthru->dataxferlen,
+                                 pScb->dma_direction);
+               break;
        case M_RD_PTHRU_WITH_SGLIST:
        {
                int count;
@@ -928,7 +1012,10 @@ static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int stat
        int islogical;
        Scsi_Cmnd *SCpnt;
        mega_passthru *pthru;
+       mega_ext_passthru *epthru;
        mega_mailbox *mbox;
+       struct scatterlist *sgList;
+       u8      c;
 
        if (pScb == NULL) {
                TRACE (("NULL pScb in mega_cmd_done!"));
@@ -939,8 +1026,10 @@ static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int stat
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        pthru = pScb->pthru;
+       epthru = pScb->epthru;
 #else
        pthru = &pScb->pthru;
+       epthru = &pScb->epthru;
 #endif
 
        mbox = (mega_mailbox *) & pScb->mboxData;
@@ -968,9 +1057,33 @@ static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int stat
 
        mega_freeSCB (megaCfg, pScb);
 
+       /*
+        * Do not return the presence of hard disk on the channel so, inquiry
+        * sent, and returned data==hard disk or removable hard disk and not
+        * logical, request should return failure! - PJ
+        */
+#if 0
        if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
                status = 0xF0;
        }
+#endif
+       if (SCpnt->cmnd[0] == INQUIRY && !islogical) {
+               if ( SCpnt->use_sg ) {
+                       sgList = (struct scatterlist *)SCpnt->request_buffer;
+                       memcpy(&c, sgList[0].address, 0x1);
+               } else {
+                       memcpy(&c, SCpnt->request_buffer, 0x1);
+               }
+#if 0
+               if( (c & 0x1F ) == TYPE_DISK ) {
+                       status = 0xF0;
+               }
+#endif
+               if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+                       status = 0xF0;
+               }
+       }
+
 
        /* clear result; otherwise, success returns corrupt value */
        SCpnt->result = 0;
@@ -997,7 +1110,16 @@ static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int stat
                        /*set sense_buffer and result fields */
                        if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
                                memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
-                               SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;
+                       } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
+                               SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+                               memcpy(
+                                       SCpnt->sense_buffer,
+                                       epthru->reqsensearea, 14
+                               );
+                               SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+                               /*SCpnt->result =
+                                       (DRIVER_SENSE << 24) |
+                                       (DID_ERROR << 16) | status;*/
                        } else {
                                SCpnt->sense_buffer[0] = 0x70;
                                SCpnt->sense_buffer[2] = ABORTED_COMMAND;
@@ -1041,6 +1163,7 @@ static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
        mega_scb *pScb;
        mega_mailbox *mbox;
        mega_passthru *pthru;
+       mega_ext_passthru *epthru;
        long seg;
        char islogical;
        char lun = SCpnt->lun;
@@ -1060,27 +1183,56 @@ static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
        }
 #endif
 
-       islogical = (SCpnt->channel == megaCfg->host->max_channel);
+       islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
+                                               (SCpnt->channel == megaCfg->host->max_channel));
 
-       if (!islogical && lun != 0) {
+       if ( ! megaCfg->support_ext_cdb ) {
+               if (!islogical && lun != 0) {
+                       SCpnt->result = (DID_BAD_TARGET << 16);
+                       callDone (SCpnt);
+                       return NULL;
+               }
+       }
+
+       if (!islogical && SCpnt->target == skip_id) {
                SCpnt->result = (DID_BAD_TARGET << 16);
                callDone (SCpnt);
                return NULL;
        }
 
-       if (!islogical && SCpnt->target == skip_id) {
+       /*
+        * Return error for LUN > 7. The way we calculate logical drive number
+        * requires it to be so.
+        */
+       if( lun > 7 ) {
                SCpnt->result = (DID_BAD_TARGET << 16);
                callDone (SCpnt);
                return NULL;
        }
 
        if (islogical) {
+
                lun = (SCpnt->target * 8) + lun;
-               if (lun > FC_MAX_LOGICAL_DRIVES) {
+
+               if(lun >= megaCfg->numldrv ) {
                        SCpnt->result = (DID_BAD_TARGET << 16);
                        callDone (SCpnt);
                        return NULL;
                }
+
+               /*
+                * If we have a logical drive with boot enabled, project it first
+                */
+               if( megaCfg->boot_ldrv_enabled ) {
+                       if( lun == 0 ) {
+                               lun = megaCfg->boot_ldrv;
+                       }
+                       else {
+                               if( lun <= megaCfg->boot_ldrv ) {
+                                       lun--;
+                               }
+                       }
+               }
        }
        /*-----------------------------------------------------
         *
@@ -1232,8 +1384,35 @@ static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
                                            mbox->numsectors;
                                }
                        }
+
+                       /* 12-byte */
+                       if (*SCpnt->cmnd == READ_12 || *SCpnt->cmnd == WRITE_12) {
+                               mbox->lba =
+                                   ((u32) SCpnt->cmnd[2] << 24) |
+                                   ((u32) SCpnt->cmnd[3] << 16) |
+                                   ((u32) SCpnt->cmnd[4] << 8) |
+                                   (u32) SCpnt->cmnd[5];
+
+                               mbox->numsectors =
+                                   ((u32) SCpnt->cmnd[6] << 24) |
+                                   ((u32) SCpnt->cmnd[7] << 16) |
+                                   ((u32) SCpnt->cmnd[8] << 8) |
+                                   (u32) SCpnt->cmnd[9];
+
+                               if (*SCpnt->cmnd == READ_12) {
+                                       megaCfg->nReads[(int) lun]++;
+                                       megaCfg->nReadBlocks[(int) lun] +=
+                                           mbox->numsectors;
+                               } else {
+                                       megaCfg->nWrites[(int) lun]++;
+                                       megaCfg->nWriteBlocks[(int) lun] +=
+                                           mbox->numsectors;
+                               }
+                       }
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-                       if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) {
+                       if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10
+                                       || *SCpnt->cmnd == READ_12) {
                                pScb->dma_direction = PCI_DMA_FROMDEVICE;
                        } else {        /*WRITE_6 or WRITE_10 */
                                pScb->dma_direction = PCI_DMA_TODEVICE;
@@ -1242,9 +1421,7 @@ static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
 
                        /* Calculate Scatter-Gather info */
                        mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
-                                                                (u32 *) &
-                                                                mbox->xferaddr,
-                                                                (u32 *) & seg);
+                                                                (u32 *)&mbox->xferaddr, (u32 *)&seg);
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                        pScb->iDataSize = seg;
@@ -1277,80 +1454,157 @@ static mega_scb *mega_build_cmd (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
                        callDone (SCpnt);
                        return NULL;
                }
+
+               mbox = (mega_mailbox *) pScb->mboxData;
+               memset (mbox, 0, sizeof (pScb->mboxData));
+
+               if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
+                       epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+                       mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-               pthru = pScb->pthru;
+                       mbox->xferaddr = pScb->dma_ext_passthruhandle64;
+
+                       if(epthru->numsgelements) {
+                               pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+                       } else {
+                               pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA;
+                       }
 #else
-               pthru = &pScb->pthru;
+                       mbox->xferaddr = virt_to_bus(epthru);
 #endif
-               mbox = (mega_mailbox *) pScb->mboxData;
+               }
+               else {
+                       pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
 
-               memset (mbox, 0, sizeof (pScb->mboxData));
-               memset (pthru, 0, sizeof (mega_passthru));
+                       /* Initialize mailbox */
+                       mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+                       mbox->xferaddr = pScb->dma_passthruhandle64;
 
-               /* set adapter timeout value to 10 min. for tape drive  */
-               /* 0=6sec/1=60sec/2=10min/3=3hrs                        */
-               pthru->timeout = 2;
-               pthru->ars = 1;
-               pthru->reqsenselen = 14;
-               pthru->islogical = 0;
-               pthru->channel =
-                   (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
-               pthru->target = (megaCfg->flag & BOARD_40LD) ?  /*BOARD_40LD */
-                   (SCpnt->channel << 4) | SCpnt->target : SCpnt->target;
-               pthru->cdblen = SCpnt->cmd_len;
+                       if (pthru->numsgelements) {
+                               pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+                       } else {
+                               pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+                       }
+#else
+                       mbox->xferaddr = virt_to_bus(pthru);
+#endif
+               }
+               return pScb;
+       }
+       return NULL;
+}
 
-               memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+static mega_passthru *
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+       mega_passthru *pthru;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-               /* Not sure about the direction */
-               pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+       pthru = scb->pthru;
+#else
+       pthru = &scb->pthru;
+#endif
+       memset (pthru, 0, sizeof (mega_passthru));
+
+       /* set adapter timeout value to 10 min. for tape drive  */
+       /* 0=6sec/1=60sec/2=10min/3=3hrs                        */
+       pthru->timeout = 2;
+       pthru->ars = 1;
+       pthru->reqsenselen = 14;
+       pthru->islogical = 0;
+       pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+       pthru->target = (megacfg->flag & BOARD_40LD) ?
+           (sc->channel << 4) | sc->target : sc->target;
+       pthru->cdblen = sc->cmd_len;
+       pthru->logdrv = sc->lun;
+
+       memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);
 
-               /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
-               switch (SCpnt->cmnd[0]) {
-               case INQUIRY:
-               case READ_CAPACITY:
-                       pthru->numsgelements = 0;
-                       pthru->dataxferaddr = pScb->dma_bounce_buffer;
-                       pthru->dataxferlen = SCpnt->request_bufflen;
-                       break;
-               default:
-                       pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-                                                                 (u32 *) &
-                                                                 pthru->
-                                                                 dataxferaddr,
-                                                                 (u32 *) &
-                                                                 pthru->
-                                                                 dataxferlen);
-                       break;
-               }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Not sure about the direction */
+       scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+       /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+       switch (sc->cmnd[0]) {
+       case INQUIRY:
+       case READ_CAPACITY:
+               pthru->numsgelements = 0;
+               pthru->dataxferaddr = scb->dma_bounce_buffer;
+               pthru->dataxferlen = sc->request_bufflen;
+               break;
+       default:
+               pthru->numsgelements =
+                       mega_build_sglist(
+                               megacfg, scb, (u32 *)&pthru->dataxferaddr,
+                               (u32 *)&pthru->dataxferlen
+                       );
+               break;
+       }
 #else
-               pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
-                                                         (u32 *) & pthru->
-                                                         dataxferaddr,
-                                                         (u32 *) & pthru->
-                                                         dataxferlen);
+       pthru->numsgelements =
+               mega_build_sglist(
+                       megacfg, scb, (u32 *)&pthru->dataxferaddr,
+                       (u32 *)&pthru->dataxferlen
+               );
 #endif
+       return pthru;
+}
 
-               /* Initialize mailbox */
-               mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+static mega_ext_passthru *
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+       mega_ext_passthru *epthru;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-               mbox->xferaddr = pScb->dma_passthruhandle64;
-
-               if (pthru->numsgelements) {
-                       pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
-                       TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n"));
-               } else {
-                       pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA
-                           TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
-               }
+       epthru = scb->epthru;
 #else
-               mbox->xferaddr = virt_to_bus (pthru);
+       epthru = &scb->epthru;
 #endif
+       memset(epthru, 0, sizeof(mega_ext_passthru));
+
+       /* set adapter timeout value to 10 min. for tape drive  */
+       /* 0=6sec/1=60sec/2=10min/3=3hrs                        */
+       epthru->timeout = 2;
+       epthru->ars = 1;
+       epthru->reqsenselen = 14;
+       epthru->islogical = 0;
+       epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+       epthru->target = (megacfg->flag & BOARD_40LD) ?
+           (sc->channel << 4) | sc->target : sc->target;
+       epthru->cdblen = sc->cmd_len;
+       epthru->logdrv = sc->lun;
+
+       memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);
 
-               return pScb;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       /* Not sure about the direction */
+       scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+       /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+       switch (sc->cmnd[0]) {
+       case INQUIRY:
+       case READ_CAPACITY:
+               epthru->numsgelements = 0;
+               epthru->dataxferaddr = scb->dma_bounce_buffer;
+               epthru->dataxferlen = sc->request_bufflen;
+               break;
+       default:
+               epthru->numsgelements =
+                       mega_build_sglist(
+                               megacfg, scb, (u32 *)&epthru->dataxferaddr,
+                               (u32 *)&epthru->dataxferlen
+                       );
+               break;
        }
-       return NULL;
+#else
+       epthru->numsgelements =
+               mega_build_sglist(
+                       megacfg, scb, (u32 *)&epthru->dataxferaddr,
+                       (u32 *)&epthru->dataxferlen
+               );
+#endif
+       return epthru;
 }
 
 /* Handle Driver Level IOCTLs
@@ -1906,7 +2160,7 @@ static int mega_busyWaitMbox (mega_host_config * megaCfg)
  *   int intr         - if 1, interrupt, 0 is blocking
  * Return Value: (added on 7/26 for 40ld/64bit)
  *   -1: the command was not actually issued out
- *   othercases:
+ *   other cases:
  *     intr==0, return ScsiStatus, i.e. mbox->status
  *     intr==1, return 0
  *=====================================================
@@ -2082,7 +2336,7 @@ mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
                                      scb->SCpnt->request_bufflen,
                                      scb->dma_direction);
                /* We need to handle special commands like READ64, WRITE64
-                  as they need a minimum of 1 SG irrespective of actaully SG
+                  as they need a minimum of 1 SG irrespective of actually SG
                 */
                if ((megaCfg->flag & BOARD_64BIT) &&
                    ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
@@ -2183,7 +2437,7 @@ mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 }
 
 /*--------------------------------------------------------------------
- * Initializes the adress of the controller's mailbox register
+ * Initializes the address of the controller's mailbox register
  *  The mailbox register is used to issue commands to the card.
  *  Format of the mailbox area:
  *   00 01 command
@@ -2201,7 +2455,7 @@ mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
 static int
 mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
 {
-       /* align on 16-byte boundry */
+       /* align on 16-byte boundary */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
 #else
@@ -2303,7 +2557,7 @@ static int mega_i_query_adapter (mega_host_config * megaCfg)
 
 /*
  * Try to issue Enquiry3 command
- * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+ * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
  * update enquiry3 structure
  */
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -2428,9 +2682,15 @@ static int mega_i_query_adapter (mega_host_config * megaCfg)
        memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
        megaCfg->biosVer[4] = 0;
 #endif
+       megaCfg->support_ext_cdb = mega_support_ext_cdb(megaCfg);
 
        printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
                megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+
+       if ( megaCfg->support_ext_cdb ) {
+               printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
+       }
+
        /*
         * I hope that I can unmap here, reason DMA transaction is not required any more
         * after this
@@ -2506,16 +2766,11 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
                                continue;       /* not an AMI board */
                        }
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#if 0
-/*
- *     This leads to corruption on some HP boards so disable it
- */
                        pcibios_read_config_dword (pciBus, pciDevFun,
                                                   PCI_CONF_AMISIG64, &magic64);
 
                        if (magic64 == AMI_64BIT_SIGNATURE)
                                flag |= BOARD_64BIT;
-#endif                         
 #endif
                }
 
@@ -2537,17 +2792,14 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
                        pci_read_config_word (pdev,
                                              PCI_SUBSYSTEM_ID, &subsysid);
 #endif
-                       if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
-                               printk (KERN_WARNING
-                                       "megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
-                                       "megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
-                                       "megaraid: with those firmware versions on this specific card.  In order\n"
-                                       "megaraid: to protect your data, please upgrade your firmware to version\n"
-                                       "megaraid: 3.10 or later, available from the Dell Technical Support web\n"
-                                       "megaraid: site at\n"
-                                       "http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
-                               continue;
-                       }
+
+#if 0
+                       /*
+                        * This routine is called with well know values and we
+                        * should not be getting what we have not asked.
+                        * Also, the check is not right. It should have been for
+                        * pci_vendor_id not subsysvid - AM
+                        */
 
                        /* If we dont detect this valid subsystem vendor id's 
                           we refuse to load the driver 
@@ -2558,6 +2810,7 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
                            && (subsysvid != DELL_SUBSYS_ID)
                            && (subsysvid != HP_SUBSYS_ID))
                                continue;
+#endif
                }
 
                printk (KERN_NOTICE
@@ -2597,6 +2850,14 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
                if (!host)
                        goto err_unmap;
 
+               /*
+                * Comment the following initialization if you know 'max_sectors' is
+                * not defined for this kernel.
+                * This field was introduced in Linus's kernel 2.4.7pre3 and it
+                * greatly increases the IO performance - AM
+                */
+               host->max_sectors = 1024;
+
                scsi_set_pci_device(host, pdev);
                megaCfg = (mega_host_config *) host->hostdata;
                memset (megaCfg, 0, sizeof (mega_host_config));
@@ -2667,7 +2928,6 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
                                       virt_to_bus ((void *) megaCfg->
                                                    mailbox64ptr));
 #else
-               /*Taken care */
                mega_register_mailbox (megaCfg,
                                       virt_to_bus ((void *) &megaCfg->
                                                    mailbox64));
@@ -2675,9 +2935,74 @@ static int mega_findCard (Scsi_Host_Template * pHostTmpl,
 
                mega_i_query_adapter (megaCfg);
 
+               if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
+
+                       /*
+                        * Which firmware
+                        */
+                       if( strcmp(megaCfg->fwVer, "3.00") == 0 ||
+                                       strcmp(megaCfg->fwVer, "3.01") == 0 ) {
+
+                               printk( KERN_WARNING
+                                       "megaraid: Your  card is a Dell PERC 2/SC RAID controller "
+                                       "with  firmware\nmegaraid: 3.00 or 3.01.  This driver is "
+                                       "known to have corruption issues\nmegaraid: with those "
+                                       "firmware versions on this specific card.  In order\n"
+                                       "megaraid: to protect your data, please upgrade your "
+                                       "firmware to version\nmegaraid: 3.10 or later, available "
+                                       "from the Dell Technical Support web\nmegaraid: site at\n"
+                                       "http://support.dell.com/us/en/filelib/download/"
+                                       "index.asp?fileid=2940\n"
+                               );
+                       }
+               }
+
+#ifdef MEGA_HP_FIX
+               /*
+                * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
+                * firmware H.01.07 or H.01.08, disable 64 bit support,
+                * since this firmware cannot handle 64 bit addressing
+                */
+
+               if( (subsysvid == HP_SUBSYS_ID) &&
+                               ((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) {
+
+                       /*
+                        * which firmware
+                        */
+                       if( strcmp(megaCfg->fwVer, "H01.07") == 0 ||
+                                       strcmp(megaCfg->fwVer, "H01.08") == 0 ) {
+                               printk(KERN_WARNING
+                                               "megaraid: Firmware H.01.07 or H.01.08 on 1M/2M "
+                                               "controllers\nmegaraid: do not support 64 bit "
+                                               "addressing.\n"
+                                               "megaraid: DISABLING 64 bit support.\n");
+                               megaCfg->flag &= ~BOARD_64BIT;
+                       }
+               }
+#endif
+
                if (mega_is_bios_enabled (megaCfg)) {
                        mega_hbas[numCtlrs].is_bios_enabled = 1;
                }
+
+               /*
+                * Find out which channel is raid and which is scsi
+                */
+               mega_enum_raid_scsi(megaCfg);
+               for( i = 0; i < megaCfg->host->max_channel; i++ ) {
+                       if(IS_RAID_CH(i))
+                               printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+                       else
+                               printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
+               }
+
+               /*
+                * Find out if a logical drive is set as the boot drive. If there is
+                * one, will make that as the first logical drive.
+                */
+               mega_get_boot_ldrv(megaCfg);
+
                mega_hbas[numCtlrs].hostdata_addr = megaCfg;
 
                /* Initialize SCBs */
@@ -2800,7 +3125,7 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
 #endif
 
        /*
-        * Register the driver as a character device, for appliactions to access
+        * Register the driver as a character device, for applications to access
         * it for ioctls.
         * Ideally, this should go in the init_module() routine, but since it is
         * hidden in the file "scsi_module.c" ( included in the end ), we define
@@ -2816,6 +3141,7 @@ int megaraid_detect (Scsi_Host_Template * pHostTmpl)
        if (register_reboot_notifier (&mega_notifier)) {
                printk ("MegaRAID Shutdown routine not registered!!\n");
        }
+
        init_MUTEX (&mimd_entry_mtx);
 
        return count;
@@ -2910,7 +3236,7 @@ static int mega_is_bios_enabled (mega_host_config * megacfg)
                0, sizeof (megacfg->mega_buffer));
 
        /*
-        * issue command to find out if the BIOS is enbled for this controller
+        * issue command to find out if the BIOS is enabled for this controller
         */
        mbox[0] = IS_BIOS_ENABLED;
        mbox[2] = GET_BIOS;
@@ -2922,6 +3248,123 @@ static int mega_is_bios_enabled (mega_host_config * megacfg)
        return (*(char *) megacfg->mega_buffer);
 }
 
+/*
+ * Find out what channels are RAID/SCSI
+ */
+void
+mega_enum_raid_scsi(mega_host_config *megacfg)
+{
+       mega_mailbox *mboxp;
+       unsigned char mbox[16];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t      dma_handle;
+#endif
+
+       mboxp = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+       /*
+        * issue command to find out what channels are raid/scsi
+        */
+       mbox[0] = CHNL_CLASS;
+       mbox[2] = GET_CHNL_CLASS;
+
+       memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+                             (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+       mboxp->xferaddr = dma_handle;
+#else
+       mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+       /*
+        * Non-ROMB firware fail this command, so all channels
+        * must be shown RAID
+        */
+       if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+               mega_ch_class = *((char *)megacfg->mega_buffer);
+
+               /* logical drives channel is RAID */
+               mega_ch_class |= (0x01 << megacfg->host->max_channel);
+       }
+       else {
+               mega_ch_class = 0xFF;
+       }
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pci_unmap_single(megacfg->dev, dma_handle,
+                                 (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
+/*
+ * get the boot logical drive number if enabled
+ */
+void
+mega_get_boot_ldrv(mega_host_config *megacfg)
+{
+       mega_mailbox *mboxp;
+       unsigned char mbox[16];
+       struct private_bios_data *prv_bios_data;
+       u16             cksum = 0;
+       char    *cksum_p;
+       int             i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_addr_t      dma_handle;
+#endif
+
+       mboxp = (mega_mailbox *)mbox;
+
+       memset(mbox, 0, sizeof(mbox));
+
+       mbox[0] = BIOS_PVT_DATA;
+       mbox[2] = GET_BIOS_PVT_DATA;
+
+       memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+                             (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+       mboxp->xferaddr = dma_handle;
+#else
+       mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+       megacfg->boot_ldrv_enabled = 0;
+       megacfg->boot_ldrv = 0;
+       if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+
+               prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
+
+               cksum = 0;
+               cksum_p = (char *)prv_bios_data;
+               for( i = 0; i < 14; i++ ) {
+                       cksum += (u16)(*cksum_p++);
+               }
+
+               if( prv_bios_data->cksum == (u16)(0-cksum) ) {
+                       megacfg->boot_ldrv_enabled = 1;
+                       megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+               }
+       }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+       pci_unmap_single(megacfg->dev, dma_handle,
+                                 (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
 static void mega_reorder_hosts (void)
 {
        struct Scsi_Host *shpnt;
@@ -3492,36 +3935,19 @@ static int proc_read_stat (char *page, char **start, off_t offset,
        *start = page;
 
        proc_printf (megaCfg, "Statistical Information for this controller\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /* 0x020400 */
-       proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
+       proc_printf (megaCfg, "Interrupts Collected = %lu\n",
                     megaCfg->nInterrupts);
-#else
-       proc_printf (megaCfg, "Interrupts Collected = %u\n",
-                    (u32) megaCfg->nInterrupts);
-#endif
 
        for (i = 0; i < megaCfg->numldrv; i++) {
                proc_printf (megaCfg, "Logical Drive %d:\n", i);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
                proc_printf (megaCfg,
-                            "\tReads Issued = %Lu, Writes Issued = %Lu\n",
+                            "\tReads Issued = %lu, Writes Issued = %lu\n",
                             megaCfg->nReads[i], megaCfg->nWrites[i]);
 
                proc_printf (megaCfg,
-                            "\tSectors Read = %Lu, Sectors Written = %Lu\n\n",
+                            "\tSectors Read = %lu, Sectors Written = %lu\n\n",
                             megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
-#else
-               proc_printf (megaCfg,
-                            "\tReads Issued = %10u, Writes Issued = %10u\n",
-                            (u32) megaCfg->nReads[i],
-                            (u32) megaCfg->nWrites[i]);
-
-               proc_printf (megaCfg,
-                            "\tSectors Read = %10u, Sectors Written = %10u\n\n",
-                            (u32) megaCfg->nReadBlocks[i],
-                            (u32) megaCfg->nWriteBlocks[i]);
-#endif
 
        }
 
@@ -3670,26 +4096,120 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom)
        /* Get pointer to host config structure */
        megaCfg = (mega_host_config *) disk->device->host->hostdata;
 
-       /* Default heads (64) & sectors (32) */
-       heads = 64;
-       sectors = 32;
-       cylinders = disk->capacity / (heads * sectors);
+       if( IS_RAID_CH(disk->device->channel)) {
+                       /* Default heads (64) & sectors (32) */
+                       heads = 64;
+                       sectors = 32;
+                       cylinders = disk->capacity / (heads * sectors);
+
+                       /* Handle extended translation size for logical drives > 1Gb */
+                       if (disk->capacity >= 0x200000) {
+                               heads = 255;
+                               sectors = 63;
+                               cylinders = disk->capacity / (heads * sectors);
+                       }
 
-       /* Handle extended translation size for logical drives > 1Gb */
-       if (disk->capacity >= 0x200000) {
-               heads = 255;
-               sectors = 63;
-               cylinders = disk->capacity / (heads * sectors);
+                       /* return result */
+                       geom[0] = heads;
+                       geom[1] = sectors;
+                       geom[2] = cylinders;
        }
+       else {
+               if( mega_partsize(disk, dev, geom) == 0 ) return 0;
+
+               printk(KERN_WARNING
+                               "megaraid: invalid partition on this disk on channel %d\n",
+                               disk->device->channel);
 
-       /* return result */
-       geom[0] = heads;
-       geom[1] = sectors;
-       geom[2] = cylinders;
+               /* Default heads (64) & sectors (32) */
+               heads = 64;
+               sectors = 32;
+               cylinders = disk->capacity / (heads * sectors);
+
+               /* Handle extended translation size for logical drives > 1Gb */
+               if (disk->capacity >= 0x200000) {
+                       heads = 255;
+                       sectors = 63;
+                       cylinders = disk->capacity / (heads * sectors);
+               }
+
+               /* return result */
+               geom[0] = heads;
+               geom[1] = sectors;
+               geom[2] = cylinders;
+       }
 
        return 0;
 }
 
+/*
+ * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *                     table, storing the results (cyls, hds, and secs) in geom
+ *
+ * Note:       Code is picked from scsicam.h
+ *
+ * Returns : -1 on failure, 0 on success.
+ */
+static int
+mega_partsize(Disk * disk, kdev_t dev, int *geom)
+{
+       struct buffer_head *bh;
+       struct partition *p, *largest = NULL;
+       int i, largest_cyl;
+       int heads, cyls, sectors;
+       int capacity = disk->capacity;
+
+       int ma = MAJOR(dev);
+       int mi = (MINOR(dev) & ~0xf);
+
+       int block = 1024; 
+
+       if(blksize_size[ma])
+               block = blksize_size[ma][mi];
+               
+       if(!(bh = bread(MKDEV(ma,mi), 0, block)))
+               return -1;
+
+       if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
+               for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
+                               i = 0; i < 4; ++i, ++p) {
+
+                       if (!p->sys_ind) continue;
+
+                       cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
+
+                       if(cyls >= largest_cyl) {
+                               largest_cyl = cyls;
+                               largest = p;
+                       }
+               }
+       }
+       if (largest) {
+               heads = largest->end_head + 1;
+               sectors = largest->end_sector & 0x3f;
+
+               if (heads == 0 || sectors == 0) {
+                       brelse(bh);
+                       return -1;
+               }
+
+               cyls = capacity/(heads * sectors);
+
+               geom[0] = heads;
+               geom[1] = sectors;
+               geom[2] = cyls;
+
+               brelse(bh);
+               return 0;
+       }
+
+       brelse(bh);
+       return -1;
+}
+
+
 /*
  * This routine will be called when the use has done a forced shutdown on the
  * system. Flush the Adapter cache, that's the most we can do.
@@ -3779,6 +4299,17 @@ static int mega_init_scb (mega_host_config * megacfg)
                        printk (KERN_WARNING
                                "Can't allocate passthru for id %d\n", idx);
                }
+
+               megacfg->scbList[idx].epthru =
+                       pci_alloc_consistent(
+                               megacfg->dev, sizeof(mega_ext_passthru),
+                               &(megacfg->scbList[idx].dma_ext_passthruhandle64)
+                       );
+
+               if (megacfg->scbList[idx].epthru == NULL) {
+                       printk (KERN_WARNING
+                               "Can't allocate extended passthru for id %d\n", idx);
+               }
                /* 
                 * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA 
                 */
@@ -3888,7 +4419,7 @@ static int megadev_ioctl (struct inode *inode, struct file *filep,
        struct uioctl_t *uioc;
        dma_addr_t      dma_addr;
        u32             length;
-       mega_host_config *megacfg;
+       mega_host_config *megacfg = NULL;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)        /* 0x020400 */
        struct pci_dev pdev;
        struct pci_dev *pdevp = &pdev;
@@ -4355,6 +4886,28 @@ megadev_close (struct inode *inode, struct file *filep)
 }
 
 
+static int
+mega_support_ext_cdb(mega_host_config *this_hba)
+{
+       mega_mailbox *mboxpnt;
+       unsigned char mbox[16];
+       int ret;
+
+       mboxpnt = (mega_mailbox *) mbox;
+
+       memset(mbox, 0, sizeof (mbox));
+       /*
+        * issue command to find out if controller supports extended CDBs.
+        */
+       mbox[0] = 0xA4;
+       mbox[2] = 0x16;
+
+       ret = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+       return !ret;
+}
+
+
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
 void *
 dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
@@ -4450,3 +5003,5 @@ Scsi_Host_Template driver_template = MEGARAID;
 
 #include "scsi_module.c"
 #endif                         /* LINUX VERSION 2.4.XX || MODULE */
+
+/* vi: set ts=4: */
index dd679a7b703c68d1e45c7594c2153ed2be730706..8d8bc9507169c02604aadd51c11f900e61e54572 100644 (file)
@@ -10,7 +10,7 @@
 #define IN_RESET               0x20000000L
 #define IN_QUEUE               0x10000000L
 
-#define BOARD_QUARTZ           0x08000000L
+#define BOARD_QUARTZ   0x08000000L
 #define BOARD_40LD             0x04000000L
 #define BOARD_64BIT            0x02000000L
 
@@ -27,7 +27,7 @@
 #define M_RD_IOCTL_CMD_NEW             0x81
 #define M_RD_DRIVER_IOCTL_INTERFACE    0x82
 
-#define MEGARAID_VERSION "v1.15d (Release Date: Wed May 30 17:30:41 EDT 2001)"
+#define MEGARAID_VERSION "v1.17a (Release Date: Fri Jul 13 18:44:01 EDT 2001)"
 
 #define MEGARAID_IOCTL_VERSION         114
 
 #define FROMTO_DEVICE          0x2
 
 /* Mailbox commands */
-#define MEGA_MBOXCMD_LREAD      0x01
-#define MEGA_MBOXCMD_LWRITE     0x02
-#define MEGA_MBOXCMD_LREAD64    0xA7
-#define MEGA_MBOXCMD_LWRITE64   0xA8
-#define MEGA_MBOXCMD_PASSTHRU   0x03
-#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+#define MEGA_MBOXCMD_LREAD             0x01
+#define MEGA_MBOXCMD_LWRITE            0x02
+#define MEGA_MBOXCMD_LREAD64           0xA7
+#define MEGA_MBOXCMD_LWRITE64          0xA8
+#define MEGA_MBOXCMD_PASSTHRU          0x03
+#define MEGA_MBOXCMD_EXTPASSTHRU       0xE3
+#define MEGA_MBOXCMD_ADAPTERINQ                0x05
+
 
 /* Offsets into Mailbox */
 #define COMMAND_PORT           0x00
@@ -472,6 +474,7 @@ struct MegaRAID_Notify {
 #define M_RD_PTHRU_WITH_SGLIST         0x0002
 #define M_RD_BULK_DATA_ONLY            0x0004
 #define M_RD_SGLIST_ONLY               0x0008
+#define M_RD_EPTHRU_WITH_BULK_DATA     0x0010
 #endif
 /********************************************
  * ENQUIRY3
@@ -564,6 +567,38 @@ typedef struct mega_passthru {
        u32 dataxferlen;
 } mega_passthru;
 
+/*
+ * Extended passthru: support CDB > 10 bytes
+ */
+typedef struct {
+       u8 timeout:3;           /* 0=6sec/1=60sec/2=10min/3=3hrs */
+       u8 ars:1;
+       u8 rsvd1:1;
+       u8 cd_rom:1;
+       u8 rsvd2:1;
+       u8 islogical:1;
+
+       u8 logdrv;              /* if islogical == 1 */
+       u8 channel;             /* if islogical == 0 */
+       u8 target;              /* if islogical == 0 */
+
+       u8 queuetag;            /* unused */
+       u8 queueaction;         /* unused */
+
+       u8 cdblen;
+       u8 rsvd3;
+       u8 cdb[16];
+
+       u8 numsgelements;
+       u8 status;
+       u8 reqsenselen;
+       u8 reqsensearea[MAX_REQ_SENSE_LEN];
+       u8 rsvd4;
+
+       u32 dataxferaddr;
+       u32 dataxferlen;
+}mega_ext_passthru;
+
 struct _mega_mailbox {
        /* 0x0 */ u8 cmd;
        /* 0x1 */ u8 cmdid;
@@ -635,14 +670,17 @@ struct _mega_scb {
        u8 sglist_count;
        dma_addr_t dma_sghandle64;
        dma_addr_t dma_passthruhandle64;
+       dma_addr_t dma_ext_passthruhandle64;
        dma_addr_t dma_bounce_buffer;
        u8 *bounce_buffer;
 #endif
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
        mega_passthru *pthru;
+       mega_ext_passthru *epthru;
 #else
        mega_passthru pthru;
+       mega_ext_passthru epthru;
 #endif
 
        Scsi_Cmnd *SCpnt;
@@ -726,6 +764,9 @@ typedef struct _mega_host_config {
        int procidx;
        struct proc_dir_entry *controller_proc_dir_entry;
        struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
+       int             support_ext_cdb;
+       int             boot_ldrv_enabled;
+       int             boot_ldrv;
 } mega_host_config;
 
 typedef struct _driver_info {
@@ -840,6 +881,36 @@ struct mega_hbas {
 
 #define                IS_BIOS_ENABLED         0x62
 #define                GET_BIOS                0x01
+#define                CHNL_CLASS              0xA9
+#define                GET_CHNL_CLASS  0x00
+#define                SET_CHNL_CLASS  0x01
+#define                CH_RAID                 0x01
+#define                CH_SCSI                 0x00
+
+
+#define BIOS_PVT_DATA          0x40
+#define GET_BIOS_PVT_DATA      0x00
+
+#pragma pack(1)
+struct private_bios_data {
+       u8              geometry:4;             /*
+                                                        * bits 0-3 - BIOS geometry
+                                                        * 0x0001 - 1GB
+                                                        * 0x0010 - 2GB
+                                                        * 0x1000 - 8GB
+                                                        * Others values are invalid
+                                                        */
+       u8              unused:4;               /* bits 4-7 are unused */
+       u8              boot_ldrv;              /*
+                                                        * logical drive set as boot drive
+                                                        * 0..7 - for 8LD cards
+                                                        * 0..39 - for 40LD cards
+                                                        */
+       u8              rsvd[12];
+       u16             cksum;                  /* 0-(sum of first 13 bytes of this structure) */
+};
+#pragma pack()
+
 
 /*================================================================
  *
@@ -896,5 +967,15 @@ static void mega_reorder_hosts (void);
 static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
 
 static void mega_create_proc_entry (int index, struct proc_dir_entry *);
+static int mega_support_ext_cdb(mega_host_config *);
+static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
+               Scsi_Cmnd *);
+static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
+               mega_scb *, Scsi_Cmnd *);
+static void mega_enum_raid_scsi(mega_host_config *);
+static int mega_partsize(Disk *, kdev_t, int *);
+static void mega_get_boot_ldrv(mega_host_config *);
 
 #endif
+
+/* vi: set ts=4: */
index afb1c358f117d258d9e5b404df189a0216a78027..b2437a1a1fac66e8030bccc0b33caf3cd89ae222 100644 (file)
@@ -602,6 +602,12 @@ static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
       tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
 
       shpnt = scsi_register(tpnt, 0);
+      if (!shpnt) {
+             printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");
+             free_irq(config.interrupt, do_ultrastor_interrupt);
+             return FALSE;
+      }
+
       shpnt->irq = config.interrupt;
       shpnt->dma_channel = config.dma_channel;
       shpnt->io_port = config.port_address;
index 66ba17df77f01e0865ae73ff9929511df78ee597..4388f7f34c967e11d8e64644ccb99c734dae7ceb 100644 (file)
@@ -298,11 +298,21 @@ static struct {
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
                0,0,0,0,
                0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+               0,0,0,0,
+               0,1,1,-1},
        {"Sound Blaster 16", 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
                0,0,0,0,
                0,1,1,-1},
+       {"Sound Blaster 16", 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+               0,0,0,0,
+               0,1,1,-1},
        {"Sound Blaster Vibra16S", 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
@@ -524,9 +534,15 @@ static struct isapnp_device_id id_table[] __devinitdata = {
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
 
+       {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
 
+       {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086), 
+               ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+
        {       ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051), 
                ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
 
index 6745cac220ce7bd2868e597d914ecf032c734a56..6eca75faecf73a5388f8d618cd89341ee36e115e 100644 (file)
@@ -748,6 +748,7 @@ int sb_mixer_init(sb_devc * devc, struct module *owner)
 
 void sb_mixer_unload(sb_devc *devc)
 {
+       kfree(mixer_devs[devc->my_mixerdev]);
        sound_unload_mixerdev(devc->my_mixerdev);
        sbmixnum--;
 }
index ddbc04a08649aa0bbfea6d0c1c75a0a7f402635b..4e6f45fa4edc99bcc601bd1ba93336f1efdc72aa 100644 (file)
@@ -1640,7 +1640,8 @@ static void via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
        if (!(status32 & VIA_INTR_MASK))
         {
 #ifdef CONFIG_MIDI_VIA82CXXX
-                uart401intr(irq, card->midi_devc, regs);
+                if (card->midi_devc)
+                       uart401intr(irq, card->midi_devc, regs);
 #endif
                return;
        }           
index 952fa0c728847acc1e9357bb790dd06377ddfc1a..822536e33d2040763bcde4f8534795242d89dc2c 100644 (file)
@@ -2591,11 +2591,11 @@ static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                {
                        struct video_window vw;
 
+                       memset(&vw, 0, sizeof(vw));
                        vw.x = 0;
                        vw.y = 0;
                        vw.width = imgwidth;
                        vw.height = imgheight;
-                       vw.chromakey = 0;
                        vw.flags = usb_ibmcam_calculate_fps();
 
                        if (copy_to_user(arg, &vw, sizeof(vw)))
@@ -2658,6 +2658,11 @@ static int ibmcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        if (copy_from_user((void *)&frame, arg, sizeof(int)))
                                return -EFAULT;
 
+                       if ((unsigned)frame >= IBMCAM_NUMFRAMES) {
+                               err("VIDIOCSYNC: invalid frame %d.", frame);
+                               return -EINVAL;
+                       }
+
                        if (debug >= 1)
                                printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
 
@@ -3161,5 +3166,3 @@ module_exit(usb_ibmcam_cleanup);
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
-
-
index bb49dfd9f822e4f6933abd4d75473a46b49ec24a..5e67eed5ee599c421dfc532f39f719270d3336d0 100644 (file)
@@ -2254,6 +2254,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 
                PDEBUG (4, "VIDIOCGCAP");
 
+               memset(&b, 0, sizeof(b));
                strcpy(b.name, "OV511 USB Camera");
                b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
                b.channels = 1;
@@ -2305,9 +2306,11 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
 
                PDEBUG (4, "VIDIOCGPICT");
 
+               memset(&p, 0, sizeof(p));
+
                if (ov7610_get_picture(ov511, &p))
                        return -EIO;
-                                                       
+
                if (copy_to_user(arg, &p, sizeof(p)))
                        return -EFAULT;
 
@@ -2422,11 +2425,11 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
        {
                struct video_window vw;
 
+               memset(&vw, 0, sizeof(vw));
                vw.x = 0;               /* FIXME */
                vw.y = 0;
                vw.width = ov511->frame[0].width;
                vw.height = ov511->frame[0].height;
-               vw.chromakey = 0;
                vw.flags = 30;
 
                PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
@@ -2439,12 +2442,16 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
        case VIDIOCGMBUF:
        {
                struct video_mbuf vm;
-
+               int i;
+               
                memset(&vm, 0, sizeof(vm));
                vm.size = OV511_NUMFRAMES * MAX_DATA_SIZE;
                vm.frames = OV511_NUMFRAMES;
                vm.offsets[0] = 0;
-               vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+               for (i = 1; i < OV511_NUMFRAMES; i++) {
+                       vm.offsets[i] = vm.offsets[i-1] + MAX_FRAME_SIZE
+                               + sizeof (struct timeval);
+               }
 
                if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
                        return -EFAULT;
@@ -2469,7 +2476,7 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                        return -EINVAL;
                }
 
-               if ((vm.frame != 0) && (vm.frame != 1)) {
+               if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
                        err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
                        return -EINVAL;
                }
@@ -2519,6 +2526,11 @@ static int ov511_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
                if (copy_from_user((void *)&frame, arg, sizeof(int)))
                        return -EFAULT;
 
+               if ((unsigned)frame >= OV511_NUMFRAMES) {
+                       err("VIDIOCSYNC: invalid frame (%d)", frame);
+                       return -EINVAL;
+               }
+
                PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
                       ov511->frame[frame].grabstate);
 
index 75cf1ece364d21b27ed385502d70c12b84a5d793..1dda98f0cc30cbdf2a815d92304c116077c05afe 100644 (file)
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
 
 #include "rio500_usb.h"
 
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
 #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
 #define DRIVER_DESC "USB Rio 500 driver"
 
@@ -60,6 +61,7 @@
 
 struct rio_usb_data {
         struct usb_device *rio_dev;     /* init: probe_rio */
+        devfs_handle_t devfs;           /* devfs device */
         unsigned int ifnum;             /* Interface number of the USB device */
         int isopen;                     /* nz if open */
         int present;                    /* Device is present on the bus */
@@ -69,6 +71,8 @@ struct rio_usb_data {
        struct semaphore lock;          /* general race avoidance */
 };
 
+extern devfs_handle_t usb_devfs_handle;        /* /dev/usb dir. */
+
 static struct rio_usb_data rio_instance;
 
 static int open_rio(struct inode *inode, struct file *file)
@@ -350,7 +354,7 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
        int this_read;
        int result;
        int maxretry = 10;
-       char *ibuf = rio->ibuf;
+       char *ibuf;
 
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
@@ -358,6 +362,8 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
              rio->rio_dev == NULL )
           return -1;
 
+       ibuf = rio->ibuf;
+
        read_count = 0;
 
        down(&(rio->lock));
@@ -416,6 +422,15 @@ read_rio(struct file *file, char *buffer, size_t count, loff_t * ppos)
        return read_count;
 }
 
+static struct
+file_operations usb_rio_fops = {
+       read:           read_rio,
+       write:          write_rio,
+       ioctl:          ioctl_rio,
+       open:           open_rio,
+       release:        close_rio,
+};
+
 static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
                       const struct usb_device_id *id)
 {
@@ -439,6 +454,14 @@ static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
        }
        dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
+       rio->devfs = devfs_register(usb_devfs_handle, "rio500",
+                                   DEVFS_FL_DEFAULT, USB_MAJOR,
+                                   RIO_MINOR,
+                                   S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+                                   S_IWGRP, &usb_rio_fops, NULL);
+       if (rio->devfs == NULL)
+               dbg("probe_rio: device node registration failed");
+       
        init_MUTEX(&(rio->lock));
 
        return rio;
@@ -448,6 +471,8 @@ static void disconnect_rio(struct usb_device *dev, void *ptr)
 {
        struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
 
+       devfs_unregister(rio->devfs);
+
        if (rio->isopen) {
                rio->isopen = 0;
                /* better let it finish - the release will do whats needed */
@@ -462,15 +487,6 @@ static void disconnect_rio(struct usb_device *dev, void *ptr)
        rio->present = 0;
 }
 
-static struct
-file_operations usb_rio_fops = {
-       read:           read_rio,
-       write:          write_rio,
-       ioctl:          ioctl_rio,
-       open:           open_rio,
-       release:        close_rio,
-};
-
 static struct usb_device_id rio_table [] = {
        { USB_DEVICE(0x0841, 1) },              /* Rio 500 */
        { }                                     /* Terminating entry */
index 95f36da88159ae0c0b46dcc42ae2224ae144488a..194fd0fca361ec96f97457d1614e2757fbde65b2 100644 (file)
@@ -858,6 +858,10 @@ ioctl_scanner(struct inode *inode, struct file *file,
 
        switch (cmd)
        {
+       case IOCTL_SCANNER_VENDOR :
+               return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+       case IOCTL_SCANNER_PRODUCT :
+               return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
        case PV8630_IOCTL_INREQUEST :
        {
                struct {
index 73b96eef3938c71a638a3cc609df4f64c39dc6a0..d1e1908ea6856c2ad7a47cc8108f3e033585c4f1 100644 (file)
@@ -53,7 +53,7 @@ MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
 
 /* Enable to activate the ioctl interface.  This is mainly meant for */
 /* development purposes until an ioctl number is officially registered */
-// #define SCN_IOCTL
+#define SCN_IOCTL
 
 /* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
 // #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
@@ -123,6 +123,7 @@ static struct usb_device_id scanner_device_ids [] = {
        { USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
        { USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
        { USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
+       { USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
        /* Umax */
        { USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
        { USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
@@ -164,6 +165,10 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids);
 #define PV8630_IOCTL_INREQUEST 69
 #define PV8630_IOCTL_OUTREQUEST 70
 
+/* read vendor and product IDs */
+#define IOCTL_SCANNER_VENDOR _IOR('u', 0xa0, int)
+#define IOCTL_SCANNER_PRODUCT _IOR('u', 0xa1, int)
+
 #define SCN_MAX_MNR 16         /* We're allocated 16 minors */
 #define SCN_BASE_MNR 48                /* USB Scanners start at minor 48 */
 
index f326bef419901f9efba8327bc96a30174f9a3a7b..322064a11eb14569879bb9cb49ec856c0067132a 100644 (file)
@@ -486,12 +486,8 @@ static void se401_auto_resetlevel(struct usb_se401 *se401)
 /* irq handler for snapshot button */
 static void se401_button_irq(struct urb *urb)
 {
-       struct usb_se401 *se401=urb->context;
+       struct usb_se401 *se401 = urb->context;
        
-       if (!urb) {
-               info("ohoh: null urb");
-               return;
-       }
        if (!se401->dev) {
                info("ohoh: device vapourished");
                return;
@@ -505,17 +501,13 @@ static void se401_button_irq(struct urb *urb)
 
 static void se401_video_irq(struct urb *urb)
 {
-       struct usb_se401 *se401=urb->context;
-       int length=urb->actual_length;
+       struct usb_se401 *se401 = urb->context;
+       int length = urb->actual_length;
 
        /* ohoh... */
-       if (!se401->streaming) {
-               return;
-       }
-       if (!urb) {
-               info ("ohoh: null urb");
+       if (!se401->streaming)
                return;
-       }
+
        if (!se401->dev) {
                info ("ohoh: device vapourished");
                return;
index de9c744d14f72eb1e28cf03af4b367aaebc0852f..1caca5943ec921936ae6d2052a7b06c790454728 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (07/16/2001) gb
+ *     remove unused code in empeg_close() (thanks to Oliver Neukum for pointing this
+ *     out) and rewrote empeg_set_termios().
+ * 
  * (05/30/2001) gkh
  *     switched from using spinlock to a semaphore, which fixes lots of problems.
  *
@@ -74,7 +78,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
 #define DRIVER_DESC "USB Empeg Mark I/II Driver"
 
@@ -164,55 +168,8 @@ static int empeg_open (struct usb_serial_port *port, struct file *filp)
 
        if (!port->active) {
 
-               /* gb - 2000/11/05
-                * personally, I think these termios should be set in
-                * empeg_startup(), but it appears doing so leads to one
-                * of those chicken/egg problems. :)
-                */
-               port->tty->termios->c_iflag
-                       &= ~(IGNBRK
-                       | BRKINT
-                       | PARMRK
-                       | ISTRIP
-                       | INLCR
-                       | IGNCR
-                       | ICRNL
-                       | IXON);
-
-               port->tty->termios->c_oflag
-                       &= ~OPOST;
-
-               port->tty->termios->c_lflag
-                       &= ~(ECHO
-                       | ECHONL
-                       | ICANON
-                       | ISIG
-                       | IEXTEN);
-
-               port->tty->termios->c_cflag
-                       &= ~(CSIZE
-                       | PARENB);
-
-               port->tty->termios->c_cflag
-                       |= CS8;
-
-               /* gb - 2000/12/03
-                * Contributed by Borislav Deianov
-                * Notify the tty driver that the termios have changed!!
-                */
-               port->tty->ldisc.set_termios(port->tty, NULL);
-
-               /* gb - 2000/11/05
-                * force low_latency on
-                *
-                * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
-                * force the data through if low_latency is set.  Otherwise the pushes are
-                * scheduled; this is bad as it opens up the possibility of dropping bytes
-                * on the floor.  We are trying to sustain high data transfer rates; and
-                * don't want to drop bytes on the floor.
-                * Moral: use low_latency - drop no bytes - life is good. :)
-                */
-               port->tty->low_latency = 1;
+               /* Force default termio settings */
+               empeg_set_termios (port, NULL) ;
 
                port->active = 1;
                bytes_in = 0;
@@ -578,65 +535,63 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign
 }
 
 
-/* This function is all nice and good, but we don't change anything based on it :) */
 static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
 {
-       unsigned int cflag = port->tty->termios->c_cflag;
 
        dbg(__FUNCTION__ " - port %d", port->number);
 
-       /* check that they really want us to change something */
-       if (old_termios) {
-               if ((cflag == old_termios->c_cflag) &&
-                   (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-                       dbg(__FUNCTION__ " - nothing to change...");
-                       return;
-               }
-       }
-
        if ((!port->tty) || (!port->tty->termios)) {
                dbg(__FUNCTION__" - no tty structures");
                return;
        }
 
-       /* get the byte size */
-       switch (cflag & CSIZE) {
-               case CS5:       dbg(__FUNCTION__ " - data bits = 5");   break;
-               case CS6:       dbg(__FUNCTION__ " - data bits = 6");   break;
-               case CS7:       dbg(__FUNCTION__ " - data bits = 7");   break;
-               default:
-               case CS8:       dbg(__FUNCTION__ " - data bits = 8");   break;
-       }
-
-       /* determine the parity */
-       if (cflag & PARENB)
-               if (cflag & PARODD)
-                       dbg(__FUNCTION__ " - parity = odd");
-               else
-                       dbg(__FUNCTION__ " - parity = even");
-       else
-               dbg(__FUNCTION__ " - parity = none");
-
-       /* figure out the stop bits requested */
-       if (cflag & CSTOPB)
-               dbg(__FUNCTION__ " - stop bits = 2");
-       else
-               dbg(__FUNCTION__ " - stop bits = 1");
-
-       /* figure out the flow control settings */
-       if (cflag & CRTSCTS)
-               dbg(__FUNCTION__ " - RTS/CTS is enabled");
-       else
-               dbg(__FUNCTION__ " - RTS/CTS is disabled");
-
-       /* determine software flow control */
-       if (I_IXOFF(port->tty))
-               dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
-       else
-               dbg(__FUNCTION__ " - XON/XOFF is disabled");
-
-       /* get the baud rate wanted */
-       dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+       /*
+         * The empeg-car player wants these particular tty settings.
+         * You could, for example, change the baud rate, however the
+         * player only supports 115200 (currently), so there is really
+         * no point in support for changes to the tty settings.
+         * (at least for now)
+         *
+         * The default requirements for this device are:
+         */
+       port->tty->termios->c_iflag
+               &= ~(IGNBRK     /* disable ignore break */
+               | BRKINT        /* disable break causes interrupt */
+               | PARMRK        /* disable mark parity errors */
+               | ISTRIP        /* disable clear high bit of input characters */
+               | INLCR         /* disable translate NL to CR */
+               | IGNCR         /* disable ignore CR */
+               | ICRNL         /* disable translate CR to NL */
+               | IXON);        /* disable enable XON/XOFF flow control */
+
+       port->tty->termios->c_oflag
+               &= ~OPOST;      /* disable postprocess output characters */
+
+       port->tty->termios->c_lflag
+               &= ~(ECHO       /* disable echo input characters */
+               | ECHONL        /* disable echo new line */
+               | ICANON        /* disable erase, kill, werase, and rprnt special characters */
+               | ISIG          /* disable interrupt, quit, and suspend special characters */
+               | IEXTEN);      /* disable non-POSIX special characters */
+
+       port->tty->termios->c_cflag
+               &= ~(CSIZE      /* no size */
+               | PARENB        /* disable parity bit */
+               | CBAUD);       /* clear current baud rate */
+
+       port->tty->termios->c_cflag
+               |= (CS8         /* character size 8 bits */
+               | B115200);     /* baud rate 115200 */
+
+       /*
+        * Force low_latency on; otherwise the pushes are scheduled;
+        * this is bad as it opens up the possibility of dropping bytes
+        * on the floor.  We don't want to drop bytes on the floor. :)
+        */
+       port->tty->low_latency = 1;
+
+       /* Notify the tty driver that the termios have changed. */
+       port->tty->ldisc.set_termios(port->tty, NULL);
 
        return;
 
index 76576dae0dbfb6542f9b79a1ca23a4532d46867c..5e264d766fca3f7d10bc988eea80600bc421703c 100644 (file)
@@ -2,7 +2,7 @@
  * URB OHCI HCD (Host Controller Driver) for USB.
  *
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * [ Initialisation is based on Linus'  ]
  * [ uhci code and gregs ohci fragments ]
@@ -12,7 +12,7 @@
  * 
  * History:
  * 
- * 2001/04/08 Identify version on module load gb
+ * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
  * 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
        pci_map_single (db)
  * 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
 
 
 #ifdef CONFIG_PMAC_PBOOK
-/* All this PMAC_PBOOK stuff should disappear when those
- * platforms fully support the 2.4 kernel PCI APIs.
- */
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#include <asm/feature.h>
+#include <asm/pci-bridge.h>
 #ifndef CONFIG_PM
 #define CONFIG_PM
 #endif
@@ -89,7 +86,7 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v5.2"
+#define DRIVER_VERSION "v5.3"
 #define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
 #define DRIVER_DESC "USB OHCI Host Controller Driver"
 
@@ -136,28 +133,39 @@ static void urb_free_priv (struct ohci *hc, urb_priv_t * urb_priv)
 {
        int             i;
        int             last = urb_priv->length - 1;
+       int             len;
+       int             dir;
        struct td       *td;
 
-       for (i = 0; i <= last; i++) {
-               td = urb_priv->td [i];
-               if (td) {
-                       int             len;
-                       int             dir;
-
-                       if ((td->hwINFO & cpu_to_le32 (TD_DP)) == TD_DP_SETUP) {
-                               len = 8;
-                               dir = PCI_DMA_TODEVICE;
-                       } else if (i == last) {
-                               len = td->urb->transfer_buffer_length,
-                               dir = usb_pipeout (td->urb->pipe)
+       if (last >= 0) {
+
+               /* ISOC, BULK, INTR data buffer starts at td 0 
+                * CTRL setup starts at td 0 */
+               td = urb_priv->td [0];
+
+               len = td->urb->transfer_buffer_length,
+               dir = usb_pipeout (td->urb->pipe)
                                        ? PCI_DMA_TODEVICE
                                        : PCI_DMA_FROMDEVICE;
-                       } else
-                               len = dir = 0;
-                       if (len && td->data_dma)
-                               pci_unmap_single (hc->ohci_dev,
-                                       td->data_dma, len, dir);
-                       td_free (hc, urb_priv->td [i]);
+
+               /* unmap CTRL URB setup */
+               if (usb_pipecontrol (td->urb->pipe)) {
+                       pci_unmap_single (hc->ohci_dev, 
+                                       td->data_dma, 8, PCI_DMA_TODEVICE);
+                       
+                       /* CTRL data buffer starts at td 1 if len > 0 */
+                       if (len && last > 0)
+                               td = urb_priv->td [1];          
+               } 
+
+               /* unmap data buffer */
+               if (len && td->data_dma)
+                       pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
+               
+               for (i = 0; i <= last; i++) {
+                       td = urb_priv->td [i];
+                       if (td)
+                               td_free (hc, td);
                }
        }
 
@@ -981,7 +989,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                }
                ed->ed_prev = ohci->ed_controltail;
                if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
-                       !ohci->ed_rm_list[1]) {
+                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
                        ohci->hc_control |= OHCI_CTRL_CLE;
                        writel (ohci->hc_control, &ohci->regs->control);
                }
@@ -997,7 +1005,7 @@ static int ep_link (ohci_t * ohci, ed_t * edi)
                }
                ed->ed_prev = ohci->ed_bulktail;
                if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
-                       !ohci->ed_rm_list[1]) {
+                       !ohci->ed_rm_list[1] && !ohci->sleeping) {
                        ohci->hc_control |= OHCI_CTRL_BLE;
                        writel (ohci->hc_control, &ohci->regs->control);
                }
@@ -1260,7 +1268,7 @@ static void ep_rm_ed (struct usb_device * usb_dev, ed_t * ed)
        ed->ed_rm_list = ohci->ed_rm_list[frame];
        ohci->ed_rm_list[frame] = ed;
 
-       if (!ohci->disabled) {
+       if (!ohci->disabled && !ohci->sleeping) {
                /* enable SOF interrupt */
                writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
                writel (OHCI_INTR_SF, &ohci->regs->intrenable);
@@ -1366,7 +1374,8 @@ static void td_submit_urb (urb_t * urb)
                                TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
                        td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
                        cnt++;
-                       writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+                       if (!ohci->sleeping)
+                               writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
                        break;
 
                case PIPE_INTERRUPT:
@@ -1391,7 +1400,8 @@ static void td_submit_urb (urb_t * urb)
                        info = usb_pipeout (urb->pipe)? 
                                TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
                        td_fill (ohci, info, data, 0, urb, cnt++);
-                       writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+                       if (!ohci->sleeping)
+                               writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
                        break;
 
                case PIPE_ISOCHRONOUS:
@@ -1611,7 +1621,7 @@ static void dl_del_list (ohci_t  * ohci, unsigned int frame)
                        writel (0, &ohci->regs->ed_controlcurrent);
                if (bulk)       /* reset bulk list */
                        writel (0, &ohci->regs->ed_bulkcurrent);
-               if (!ohci->ed_rm_list[!frame]) {
+               if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
                        if (ohci->ed_controltail)
                                ohci->hc_control |= OHCI_CTRL_CLE;
                        if (ohci->ed_bulktail)
@@ -2321,6 +2331,7 @@ static ohci_t * __devinit hc_alloc_ohci (struct pci_dev *dev, void * mem_base)
         memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 
        ohci->disabled = 1;
+       ohci->sleeping = 0;
        ohci->irq = -1;
        ohci->regs = mem_base;   
 
@@ -2480,6 +2491,7 @@ static void hc_restart (ohci_t *ohci)
                pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
 
        ohci->disabled = 1;
+       ohci->sleeping = 0;
        if (ohci->bus->root_hub)
                usb_disconnect (&ohci->bus->root_hub);
        
@@ -2588,7 +2600,9 @@ ohci_pci_remove (struct pci_dev *dev)
 static int
 ohci_pci_suspend (struct pci_dev *dev, u32 state)
 {
-       ohci_t          *ohci = (ohci_t *) dev->driver_data;
+       ohci_t                  *ohci = (ohci_t *) dev->driver_data;
+       unsigned long           flags;
+       u16 cmd;
 
        if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
                dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
@@ -2598,14 +2612,65 @@ ohci_pci_suspend (struct pci_dev *dev, u32 state)
 
        /* act as if usb suspend can always be used */
        info ("USB suspend: usb-%s", dev->slot_name);
+       ohci->sleeping = 1;
+
+       /* First stop processing */
+       spin_lock_irqsave (&usb_ed_lock, flags);
+       ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+       writel (ohci->hc_control, &ohci->regs->control);
+       writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+       (void) readl (&ohci->regs->intrstatus);
+       spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+       /* Wait a frame or two */
+       mdelay(1);
+       if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+               mdelay (1);
+               
 #ifdef CONFIG_PMAC_PBOOK
-       disable_irq (ohci->irq);
+       if (_machine == _MACH_Pmac)
+               disable_irq (ohci->irq);
        /* else, 2.4 assumes shared irqs -- don't disable */
 #endif
+       /* Enable remote wakeup */
+       writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
+
+       /* Suspend chip and let things settle down a bit */
        ohci->hc_control = OHCI_USB_SUSPEND;
        writel (ohci->hc_control, &ohci->regs->control);
-       wait_ms (10);
+       (void) readl (&ohci->regs->control);
+       mdelay (500); /* No schedule here ! */
+       switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+               case OHCI_USB_RESET:
+                       dbg("Bus in reset phase ???");
+                       break;
+               case OHCI_USB_RESUME:
+                       dbg("Bus in resume phase ???");
+                       break;
+               case OHCI_USB_OPER:
+                       dbg("Bus in operational phase ???");
+                       break;
+               case OHCI_USB_SUSPEND:
+                       dbg("Bus suspended");
+                       break;
+       }
+       /* In some rare situations, Apple's OHCI have happily trashed
+        * memory during sleep. We disable it's bus master bit during
+        * suspend
+        */
+       pci_read_config_word (dev, PCI_COMMAND, &cmd);
+       cmd &= ~PCI_COMMAND_MASTER;
+       pci_write_config_word (dev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+       {
+       struct device_node      *of_node;
 
+       /* Disable USB PAD & cell clock */
+       of_node = pci_device_to_OF_node (ohci->ohci_dev);
+       if (of_node && _machine == _MACH_Pmac)
+               feature_set_usb_power (of_node, 0);
+       }
+#endif
        return 0;
 }
 
@@ -2616,14 +2681,26 @@ ohci_pci_resume (struct pci_dev *dev)
 {
        ohci_t          *ohci = (ohci_t *) dev->driver_data;
        int             temp;
+       unsigned long   flags;
 
        /* guard against multiple resumes */
        atomic_inc (&ohci->resume_count);
        if (atomic_read (&ohci->resume_count) != 1) {
                err ("concurrent PCI resumes for usb-%s", dev->slot_name);
                atomic_dec (&ohci->resume_count);
-               return -EBUSY;
+               return 0;
+       }
+
+#ifdef CONFIG_PMAC_PBOOK
+       {
+       struct device_node *of_node;
+
+       /* Re-enable USB PAD & cell clock */
+       of_node = pci_device_to_OF_node (ohci->ohci_dev);
+       if (of_node && _machine == _MACH_Pmac)
+               feature_set_usb_power (of_node, 1);
        }
+#endif
 
        /* did we suspend, or were we powered off? */
        ohci->hc_control = readl (&ohci->regs->control);
@@ -2634,6 +2711,9 @@ ohci_pci_resume (struct pci_dev *dev)
        ohci_dump_status (ohci);
 #endif
 
+       /* Re-enable bus mastering */
+       pci_set_master(ohci->ohci_dev);
+       
        switch (temp) {
 
        case OHCI_USB_RESET:    // lost power
@@ -2648,8 +2728,10 @@ ohci_pci_resume (struct pci_dev *dev)
                                ? "host" : "remote");
                ohci->hc_control = OHCI_USB_RESUME;
                writel (ohci->hc_control, &ohci->regs->control);
-               wait_ms (20);
-
+               (void) readl (&ohci->regs->control);
+               mdelay (20); /* no schedule here ! */
+               /* Some controllers (lucent) need a longer delay here */
+               mdelay (15);
                temp = readl (&ohci->regs->control);
                temp = ohci->hc_control & OHCI_CTRL_HCFS;
                if (temp != OHCI_USB_RESUME) {
@@ -2658,18 +2740,38 @@ ohci_pci_resume (struct pci_dev *dev)
                        return -EIO;
                }
 
+               /* Some chips likes being resumed first */
+               writel (OHCI_USB_OPER, &ohci->regs->control);
+               (void) readl (&ohci->regs->control);
+               mdelay (3);
+
+               /* Then re-enable operations */
+               spin_lock_irqsave (&usb_ed_lock, flags);
                ohci->disabled = 0;
+               ohci->sleeping = 0;
                ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
-               if (!ohci->ed_rm_list[0] & !ohci->ed_rm_list[1]) {
+               if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
                        if (ohci->ed_controltail)
                                ohci->hc_control |= OHCI_CTRL_CLE;
                        if (ohci->ed_bulktail)
                                ohci->hc_control |= OHCI_CTRL_BLE;
                }
                writel (ohci->hc_control, &ohci->regs->control);
+               writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+               writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+               /* Check for a pending done list */
+               writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);       
+               (void) readl (&ohci->regs->intrdisable);
+               spin_unlock_irqrestore (&usb_ed_lock, flags);
 #ifdef CONFIG_PMAC_PBOOK
-               enable_irq (ohci->irq);
+               if (_machine == _MACH_Pmac)
+                       enable_irq (ohci->irq);
 #endif
+               if (ohci->hcca->done_head)
+                       dl_done_list (ohci, dl_reverse_done_list (ohci));
+               writel (OHCI_INTR_WDH, &ohci->regs->intrenable); 
+               writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+               writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
                break;
 
        default:
@@ -2724,71 +2826,24 @@ static struct pci_driver ohci_pci_driver = {
        probe:          ohci_pci_probe,
        remove:         ohci_pci_remove,
 
-#ifdef CONFIG_PMAC_PBOOK
-       /* pbook PCI thinks different ... for now :-) */
-#else
 #ifdef CONFIG_PM
        suspend:        ohci_pci_suspend,
        resume:         ohci_pci_resume,
 #endif /* PM */
-#endif /* PBOOK */
 };
 
  
-#ifdef CONFIG_PMAC_PBOOK
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
-{
-       struct list_head * ohci_l;
-       ohci_t * ohci;
-       
-       for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
-       ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
-               switch (when) {
-               case PBOOK_SLEEP_NOW:
-                       ohci_pci_suspend (ohci->ohci_dev, 3);
-                       break;
-               case PBOOK_WAKE:
-                       ohci_pci_resume (ohci->ohci_dev);
-                       break;
-               }
-       }
-       return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier ohci_sleep_notifier = {
-       ohci_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-
 /*-------------------------------------------------------------------------*/
 
 static int __init ohci_hcd_init (void) 
 {
-       int ret;
-
-       if ((ret = pci_module_init (&ohci_pci_driver)) < 0) {
-               return ret;
-       }
-
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_register_sleep_notifier (&ohci_sleep_notifier);
-#endif  
-       info(DRIVER_VERSION ":" DRIVER_DESC);
-       return ret;
+       return pci_module_init (&ohci_pci_driver);
 }
 
 /*-------------------------------------------------------------------------*/
 
 static void __exit ohci_hcd_cleanup (void) 
 {      
-#ifdef CONFIG_PMAC_PBOOK
-       pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
-#endif  
        pci_unregister_driver (&ohci_pci_driver);
 }
 
index 55be2faa0da3b7290fd4097940e0863ee3f69348..75288d333f7e99b524d71373630261159226f15b 100644 (file)
@@ -2,7 +2,7 @@
  * URB OHCI HCD (Host Controller Driver) for USB.
  * 
  * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
  * 
  * usb-ohci.h
  */
@@ -380,6 +380,7 @@ typedef struct ohci {
 
        int irq;
        int disabled;                   /* e.g. got a UE, we're hung */
+       int sleeping;
        atomic_t resume_count;          /* defending against multiple resumes */
        unsigned long flags;            /* for HC bugs */
 #define        OHCI_QUIRK_AMD756       0x01            /* erratum #4 */
index f69ffcf30a5d64ba0f1d3aa65c6b40301cbbddea..9cf72b80e94be42c0e88ec7bc41ebee0bde89d1e 100644 (file)
@@ -2220,7 +2220,6 @@ int usb_new_device(struct usb_device *dev)
                        dev->devnum, err);
                clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
                dev->devnum = -1;
-               usb_free_dev(dev);
                return 1;
        }
 
index 98d75b7a539840738c9d8553b465d900b6afb8ce..6d6a334b3717794fc42cf36dd6a4e880bdfc4a6b 100644 (file)
@@ -107,7 +107,7 @@ struct autofs_sb_info {
        unsigned long symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
 };
 
-extern inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
+static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
 {
        return (struct autofs_sb_info *)(sb->u.generic_sbp);
 }
index bff1cc366a0c017ffddccc58b65fcb6be3b39708..d8a4d0bdae1d1ad8bf9e2f0ff4a9f4cbdffb3dec 100644 (file)
@@ -100,62 +100,3 @@ void default_fat_ll_rw_block (
 {
        ll_rw_block(opr,nbreq,bh);
 }
-
-struct buffer_head *bigblock_fat_bread(struct super_block *sb, int block)
-{
-       unsigned int hardsect = get_hardsect_size(sb->s_dev);
-       int rblock, roffset;
-       struct buffer_head *real, *dummy;
-
-       if (hardsect <= sb->s_blocksize)
-               BUG();
-
-       dummy = NULL;
-       rblock = block / (hardsect / sb->s_blocksize);
-       roffset = (block % (hardsect / sb->s_blocksize)) * sb->s_blocksize;
-       real = bread(sb->s_dev, rblock, hardsect);
-       if (real != NULL) {
-               dummy = kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
-               if (dummy != NULL) {
-                       memset(dummy, 0, sizeof(*dummy));
-                       dummy->b_data = real->b_data + roffset;
-                       dummy->b_next = real;
-               } else
-                       brelse(real);
-       }
-
-       return dummy;
-}
-
-void bigblock_fat_brelse(struct super_block *sb, struct buffer_head *bh)
-{
-       brelse(bh->b_next);
-       kfree(bh);
-}
-
-void bigblock_fat_mark_buffer_dirty(struct super_block *sb, struct buffer_head *bh)
-{
-       mark_buffer_dirty(bh->b_next);
-}
-
-void bigblock_fat_set_uptodate(struct super_block *sb, struct buffer_head *bh,
-                              int val)
-{
-       mark_buffer_uptodate(bh->b_next, val);
-}
-
-int bigblock_fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
-{
-       return buffer_uptodate(bh->b_next);
-}
-
-void bigblock_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
-                              struct buffer_head *bh[32])
-{
-       struct buffer_head *tmp[32];
-       int i;
-
-       for (i = 0; i < nbreq; i++)
-               tmp[i] = bh[i]->b_next;
-       ll_rw_block(opr, nbreq, tmp);
-}
index 91462e135e5d77a1457149f06fda884c7394187f..37dd78c579431b85dbadefa9e9db4563720a2bc6 100644 (file)
 
 struct buffer_head *default_fat_bread(struct super_block *,int);
 struct buffer_head *default_fat_getblk(struct super_block *, int);
-struct buffer_head *bigblock_fat_bread(struct super_block *, int);
 void default_fat_brelse(struct super_block *, struct buffer_head *);
-void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
-void default_fat_mark_buffer_dirty (struct super_block *,
-       struct buffer_head *);
-void bigblock_fat_mark_buffer_dirty (struct super_block *,
-       struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *, struct buffer_head *);
 void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
-void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
 int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
-int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
 int default_fat_access(struct super_block *sb,int nr,int new_value);
-void default_fat_ll_rw_block (
-       struct super_block *sb,
-       int opr,
-       int nbreq,
-       struct buffer_head *bh[32]);
-void bigblock_fat_ll_rw_block (
-       struct super_block *sb,
-       int opr,
-       int nbreq,
-       struct buffer_head *bh[32]);
+void default_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
+                             struct buffer_head *bh[32]);
 int default_fat_bmap(struct inode *inode,int block);
-ssize_t default_fat_file_write(
-       struct file *filp,
-       const char *buf,
-       size_t count,
-       loff_t *ppos);
+ssize_t default_fat_file_write(struct file *filp, const char *buf,
+                              size_t count, loff_t *ppos);
 
 struct cvf_format default_cvf = {
-       0,      /* version - who cares? */      
-       "plain",
-       0,      /* flags - who cares? */
-       NULL,
-       NULL,
-       NULL,
-       default_fat_bread,
-       default_fat_getblk,
-       default_fat_brelse,
-       default_fat_mark_buffer_dirty,
-       default_fat_set_uptodate,
-       default_fat_is_uptodate,
-       default_fat_ll_rw_block,
-       default_fat_access,
-       NULL,
-       default_fat_bmap,
-       generic_file_read,
-       default_fat_file_write,
-       NULL,
-       NULL
-};
-
-struct cvf_format bigblock_cvf = {
-       0,      /* version - who cares? */      
-       "big_blocks",
-       0,      /* flags - who cares? */
-       NULL,
-       NULL,
-       NULL,
-       bigblock_fat_bread,
-       bigblock_fat_bread,
-       bigblock_fat_brelse,
-       bigblock_fat_mark_buffer_dirty,
-       bigblock_fat_set_uptodate,
-       bigblock_fat_is_uptodate,
-       bigblock_fat_ll_rw_block,
-       default_fat_access,
-       NULL,
-       default_fat_bmap,
-       NULL,
-       default_fat_file_write,
-       NULL,
-       NULL
+       cvf_version:            0,      /* version - who cares? */      
+       cvf_version_text:       "plain",
+       flags:                  0,      /* flags - who cares? */
+       cvf_bread:              default_fat_bread,
+       cvf_getblk:             default_fat_getblk,
+       cvf_brelse:             default_fat_brelse,
+       cvf_mark_buffer_dirty:  default_fat_mark_buffer_dirty,
+       cvf_set_uptodate:       default_fat_set_uptodate,
+       cvf_is_uptodate:        default_fat_is_uptodate,
+       cvf_ll_rw_block:        default_fat_ll_rw_block,
+       fat_access:             default_fat_access,
+       cvf_bmap:               default_fat_bmap,
+       cvf_file_read:          generic_file_read,
+       cvf_file_write:         default_fat_file_write,
 };
 
 struct cvf_format *cvf_formats[MAX_CVF_FORMATS];
index b08d30fdba354f319c3c3add6f545be750b383e2..53cc542ac067b1e24b13a997c21f5b5196507e28 100644 (file)
@@ -36,7 +36,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-extern struct cvf_format default_cvf, bigblock_cvf;
+extern struct cvf_format default_cvf;
 
 /* #define FAT_PARANOIA 1 */
 #define DEBUG_LEVEL 0
@@ -448,8 +448,6 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        hard_blksize = get_hardsect_size(sb->s_dev);
        if (!hard_blksize)
                hard_blksize = 512;
-       if (hard_blksize != 512)
-               printk("MSDOS: Hardware sector size is %d\n", hard_blksize);
 
        opts.isvfat = sbi->options.isvfat;
        if (!parse_options((char *) data, &fat, &debug, &opts,
@@ -464,8 +462,8 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        set_blocksize(sb->s_dev, hard_blksize);
        bh = bread(sb->s_dev, 0, sb->s_blocksize);
        if (bh == NULL) {
-               brelse (bh);
-               goto out_no_bread;
+               printk("FAT: unable to read boot sector\n");
+               goto out_fail;
        }
 
 /*
@@ -489,15 +487,23 @@ fat_read_super(struct super_block *sb, void *data, int silent,
                CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
        if (!logical_sector_size
            || (logical_sector_size & (logical_sector_size - 1))) {
-               printk("fatfs: bogus logical sector size %d\n",
+               printk("FAT: bogus logical sector size %d\n",
                       logical_sector_size);
                brelse(bh);
                goto out_invalid;
        }
 
        sbi->cluster_size = b->cluster_size;
-       if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size - 1))) {
-               printk("fatfs: bogus cluster size %d\n", sbi->cluster_size);
+       if (!sbi->cluster_size
+           || (sbi->cluster_size & (sbi->cluster_size - 1))) {
+               printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+               brelse(bh);
+               goto out_invalid;
+       }
+
+       if (logical_sector_size < hard_blksize) {
+               printk("FAT: logical sector size too small for device"
+                      " (logical sector size = %d)\n", logical_sector_size);
                brelse(bh);
                goto out_invalid;
        }
@@ -528,8 +534,8 @@ fat_read_super(struct super_block *sb, void *data, int silent,
                if (bh->b_blocknr != fsinfo_block) {
                        fsinfo_bh = bread(sb->s_dev, fsinfo_block, hard_blksize);
                        if (fsinfo_bh == NULL) {
-                               printk("FAT: bread failed, fsinfo block %d\n",
-                                      fsinfo_block);
+                               printk("FAT: bread failed, FSINFO block"
+                                      " (blocknr = %d)\n", fsinfo_block);
                                brelse(bh);
                                goto out_invalid;
                        }
@@ -585,20 +591,14 @@ fat_read_super(struct super_block *sb, void *data, int silent,
 
        sb->s_blocksize = logical_sector_size;
        sb->s_blocksize_bits = ffs(logical_sector_size) - 1;
-       if (sb->s_blocksize >= hard_blksize) {
-               set_blocksize(sb->s_dev, sb->s_blocksize);
-               sbi->cvf_format = &default_cvf;
-       } else {
-               set_blocksize(sb->s_dev, hard_blksize);
-               sbi->cvf_format = &bigblock_cvf;
-       }
-
-       if (!strcmp(cvf_format,"none"))
+       set_blocksize(sb->s_dev, sb->s_blocksize);
+       sbi->cvf_format = &default_cvf;
+       if (!strcmp(cvf_format, "none"))
                i = -1;
        else
                i = detect_cvf(sb,cvf_format);
        if (i >= 0)
-               error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+               error = cvf_formats[i]->mount_cvf(sb, cvf_options);
        if (error || debug) {
                /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
                printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
@@ -607,16 +607,14 @@ fat_read_super(struct super_block *sb, void *data, int silent,
                       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
                       MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
                printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
-                      "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
-                      b->media,sbi->cluster_size,
-                      sbi->fats,sbi->fat_start,
-                      sbi->fat_length,
-                      sbi->dir_start,sbi->dir_entries,
-                      sbi->data_start,
-                      CF_LE_W(*(unsigned short *) &b->sectors),
-                      (unsigned long)b->total_sect,logical_sector_size,
-                      sbi->root_cluster,sbi->free_clusters);
-               printk ("Transaction block size = %d\n", hard_blksize);
+                      "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
+                      b->media, sbi->cluster_size, sbi->fats,
+                      sbi->fat_start, sbi->fat_length, sbi->dir_start,
+                      sbi->dir_entries, sbi->data_start,
+                      CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
+                      CF_LE_L(b->total_sect), logical_sector_size,
+                      sbi->root_cluster, sbi->free_clusters);
+               printk ("hard sector size = %d\n", hard_blksize);
        }
        if (i < 0)
                if (sbi->clusters + 2 > fat_clusters)
@@ -653,7 +651,7 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        if (! sbi->nls_io)
                sbi->nls_io = load_nls_default();
 
-       root_inode=new_inode(sb);
+       root_inode = new_inode(sb);
        if (!root_inode)
                goto out_unload_nls;
        root_inode->i_ino = MSDOS_ROOT_INO;
@@ -662,29 +660,27 @@ fat_read_super(struct super_block *sb, void *data, int silent,
        sb->s_root = d_alloc_root(root_inode);
        if (!sb->s_root)
                goto out_no_root;
-       if(i>=0) {
+       if(i >= 0) {
                sbi->cvf_format = cvf_formats[i];
                ++cvf_format_use_count[i];
        }
        return sb;
 
 out_no_root:
-       printk("get root inode failed\n");
+       printk("FAT: get root inode failed\n");
        iput(root_inode);
        unload_nls(sbi->nls_io);
 out_unload_nls:
        unload_nls(sbi->nls_disk);
        goto out_fail;
 out_invalid:
-       if (!silent)
-               printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n",
+       if (!silent) {
+               printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
                        kdevname(sb->s_dev));
-       goto out_fail;
-out_no_bread:
-       printk("FAT bread failed\n");
+       }
 out_fail:
        if (opts.iocharset) {
-               printk("VFS: freeing iocharset=%s\n", opts.iocharset);
+               printk("FAT: freeing iocharset=%s\n", opts.iocharset);
                kfree(opts.iocharset);
        }
        if(sbi->private_data)
index 090f92f1d20b82dc97539f194be109fbe63a77c9..33d8dd01230074716404e710a0adfc32d780fbfe 100644 (file)
@@ -894,6 +894,11 @@ int ntfs_getdir_unsorted(ntfs_inode *ino, ntfs_u32 *p_high, ntfs_u32* p_low,
                return -EIO;
        }
        attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
+       if (!attr) {
+               ntfs_free(buf);
+               ntfs_debug(DEBUG_DIR3, "unsorted 9.5\n");
+               return -EIO;
+       }
        while (1) {
                if ((__s64)*p_high << vol->cluster_size_bits > attr->size) {
                        /* No more index records. */
index dbcf603e7315d7ef259b1fbdf536ea5fdf80eb3d..06ea87109e47353625588c192e281c03fa6e79d3 100644 (file)
@@ -95,6 +95,8 @@ static int ntfs_extend_mft(ntfs_volume *vol)
        ntfs_io io;
 
        mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+       if (!mdata)
+               return -EINVAL;
        /* First check whether there is uninitialized space. */
        if (mdata->allocated < mdata->size + vol->mft_record_size) {
                size = (__s64)ntfs_get_free_cluster_count(vol->bitmap) <<
@@ -127,6 +129,8 @@ static int ntfs_extend_mft(ntfs_volume *vol)
        /* Now extend the bitmap if necessary. */
        rcount = mdata->size >> vol->mft_record_size_bits;
        bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
+       if (!bmp)
+               return -EINVAL;
        if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */
                ntfs_u8 buf[1];
                /* Extend bitmap by one byte. */
@@ -1305,6 +1309,8 @@ static int ntfs_new_inode(ntfs_volume *vol, unsigned long *result)
        *result = 0;
        /* Determine the number of mft records in the mft. */
        data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+       if (!data)
+               return -EINVAL;
        length = data->size >> vol->mft_record_size_bits;
        /* Allocate sufficient space for the mft bitmap attribute value,
           inferring it from the number of mft records. */
index aaa182dbead1233f864639fae94146dee6c9b32f..8b60cba74a0cd7474a880e3d93fd155a6a5e2a9d 100644 (file)
@@ -25,6 +25,10 @@ if [ "$CONFIG_PARTITION_ADVANCED" = "y" ]; then
       bool '    Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
       bool '    Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
    fi
+   dep_bool '  Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
+   if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
+      bool '    Windows LDM extra logging' CONFIG_LDM_DEBUG
+   fi
    bool '  SGI partition support' CONFIG_SGI_PARTITION
    bool '  Ultrix partition table support' CONFIG_ULTRIX_PARTITION
    bool '  Sun partition tables support' CONFIG_SUN_PARTITION
index 1d2d79591aad86118282c5488b4b2ee276e50e84..2a7a0d642ec045217a2420cf3f131c3793f8d96b 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o
 obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
 obj-$(CONFIG_ATARI_PARTITION) += atari.o
 obj-$(CONFIG_MAC_PARTITION) += mac.o
+obj-$(CONFIG_LDM_PARTITION) += ldm.o
 obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
 obj-$(CONFIG_OSF_PARTITION) += osf.o
 obj-$(CONFIG_SGI_PARTITION) += sgi.o
index 58989b71b0ea6e4146b6623cba75d2738a79e837..40a05ce1ad107c07d56eba0aaae3eaae9b7e3b04 100644 (file)
@@ -25,6 +25,7 @@
 #include "acorn.h"
 #include "amiga.h"
 #include "atari.h"
+#include "ldm.h"
 #include "mac.h"
 #include "msdos.h"
 #include "osf.h"
@@ -42,6 +43,9 @@ static int (*check_part[])(struct gendisk *hd, kdev_t dev, unsigned long first_s
 #ifdef CONFIG_ACORN_PARTITION
        acorn_partition,
 #endif
+#ifdef CONFIG_LDM_PARTITION
+       ldm_partition,          /* this must come before msdos */
+#endif
 #ifdef CONFIG_MSDOS_PARTITION
        msdos_partition,
 #endif
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
new file mode 100644 (file)
index 0000000..81a0595
--- /dev/null
@@ -0,0 +1,980 @@
+/*
+ * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include "check.h"
+#include "ldm.h"
+#include "msdos.h"
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet. */
+/**
+ * ldm_debug - output an error message if debugging was enabled at compile time
+ * @f:         a printf format string containing the message
+ * @...:       the variables to substitute into @f
+ *
+ * ldm_debug() writes a DEBUG level message to the syslog but only if the
+ * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
+ */
+static void ldm_debug(const char *f, ...);
+#endif
+#ifdef CONFIG_LDM_DEBUG
+#define ldm_debug(f, a...)                                             \
+       {                                                               \
+               printk(LDM_DEBUG " DEBUG (%s, %d): %s: ",               \
+                               __FILE__, __LINE__, __FUNCTION__);      \
+               printk(f, ##a);                                         \
+       }
+#else  /* !CONFIG_LDM_DEBUG */
+#define ldm_debug(f, a...)     do {} while (0)
+#endif /* !CONFIG_LDM_DEBUG */
+
+/* Necessary forward declarations. */
+static int create_partition(struct gendisk *, int, int, int);
+static int parse_privhead(const u8 *, struct privhead *);
+static u64 get_vnum(const u8 *, int *);
+static int get_vstr(const u8 *, u8 *, const int);
+
+/**
+ * parse_vblk_part - parse a LDM database vblk partition record
+ * @buffer:    vblk partition record loaded from the LDM database
+ * @buf_size:  size of @buffer in bytes
+ * @vb:                in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
+ * record, supplied in @buffer and sets up the in memory vblk structure @vb
+ * with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vb is undefined.
+ */
+static int parse_vblk_part(const u8 *buffer, const int buf_size,
+               struct vblk *vb)
+{
+       int err, rel_objid, rel_name, rel_size, rel_parent;
+
+       if (0x34 >= buf_size)
+               return -1;
+       /* Calculate relative offsets. */
+       rel_objid  = 1 + buffer[0x18];
+       if (0x18 + rel_objid >= buf_size)
+               return -1;
+       rel_name   = 1 + buffer[0x18 + rel_objid] + rel_objid;
+       if (0x34 + rel_name >= buf_size)
+               return -1;
+       rel_size   = 1 + buffer[0x34 + rel_name] + rel_name;
+       if (0x34 + rel_size >= buf_size)
+               return -1;
+       rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
+       if (0x34 + rel_parent >= buf_size)
+               return -1;
+       /* Setup @vb. */
+       vb->vblk_type    = VBLK_PART;
+       vb->obj_id       = get_vnum(buffer + 0x18, &err);
+       if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
+               return -1;
+       vb->disk_id      = get_vnum(buffer + 0x34 + rel_parent, &err);
+       if (err || 0x24 + rel_name + 8 > buf_size)
+               return -1;
+       vb->start_sector = BE64(buffer + 0x24 + rel_name);
+       if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
+               return -1;
+       vb->num_sectors  = get_vnum(buffer + 0x34 + rel_name, &err);
+       if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
+               return -1;
+       err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
+       if (err == -1)
+               return err;
+       ldm_debug("Parsed Partition VBLK successfully.\n");
+       return 1;
+}
+
+/**
+ * parse_vblk - parse a LDM database vblk record
+ * @buffer:    vblk record loaded from the LDM database
+ * @buf_size:  size of @buffer in bytes
+ * @vb:                in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record supplied in @buffer and sets up
+ * the in memory vblk structure @vb with the obtained information.
+ *
+ * Return 1 on success, 0 if successful but record not in use, and -1 on error.
+ * If the return value is 0 or -1, @vb is undefined.
+ *
+ * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
+ * describing a partition. For all others, we just set @vb->vblk_type to 0 and
+ * return success. This of course means that if @vb->vblk_type is zero, all
+ * other fields in @vb are undefined.
+ */
+static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
+{
+       int err = 1;
+
+       if (buf_size < 0x14)
+               return -1;
+       if (MAGIC_VBLK != BE32(buffer)) {
+               printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
+               return -1;
+       }
+       if (BE16(buffer + 0x0E) == 0)   /* Record is not in use. */
+               return 0;
+       /* FIXME: What about extended VBLKs? */
+       switch (buffer[0x13]) {
+       case VBLK_PART:
+               err = parse_vblk_part(buffer, buf_size, vb);
+               break;
+       default:
+               vb->vblk_type = 0;
+       }
+       if (err != -1)
+               ldm_debug("Parsed VBLK successfully.\n");
+       return err;
+}
+
+/**
+ * create_data_partitions - create the data partition devices
+ * @hd:                        gendisk structure in which to create the data partitions
+ * @first_sector:      first sector within the disk device
+ * @first_part_minor:  first minor number of data partition devices
+ * @dev:               partition device holding the LDM database
+ * @vm:                        in memory vmdb structure of @dev
+ * @ph:                        in memory privhead structure of the disk device
+ * @dk:                        in memory ldmdisk structure of the disk device
+ *
+ * The database contains ALL the partitions for ALL the disks, so we need to
+ * filter out this specific disk. Using the disk's object id, we can find all
+ * the partitions in the database that belong to this disk.
+ *
+ * For each found partition, we create a corresponding partition device starting
+ * with minor number @first_part_minor.
+ *
+ * Return 1 on success and -1 on error.
+ */
+static int create_data_partitions(struct gendisk *hd,
+               const unsigned long first_sector, int first_part_minor,
+               const kdev_t dev, const struct vmdb *vm,
+               const struct privhead *ph, const struct ldmdisk *dk)
+{
+       struct buffer_head *bh;
+       struct vblk *vb;
+       int vblk;
+       int vsize;              /* VBLK size. */
+       int perbuf;             /* VBLKs per buffer. */
+       int buffer, lastbuf, lastofs, err;
+
+       vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
+       if (!vb)
+               goto no_mem;
+       vsize   = vm->vblk_size;
+       if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+               goto err_out;
+       perbuf  = LDM_BLOCKSIZE / vsize;
+       if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+               goto err_out;
+                                       /* 512 == VMDB size */
+       lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+       lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+       if (lastofs)
+               lastbuf++;
+       if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+                       ph->config_size * 512)
+               goto err_out;
+       printk(" <");
+       for (buffer = 0; buffer < lastbuf; buffer++) {
+               if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+                       goto read_err;
+               for (vblk = 0; vblk < perbuf; vblk++) {
+                       u8 *block;
+                       
+                       if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+                               break;
+                       block = bh->b_data + vsize * vblk;
+                       if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE)
+                               goto brelse_out;
+                       if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1)
+                               continue;
+                       if (vb->vblk_type != VBLK_PART)
+                               continue;
+                       if (dk->obj_id != vb->disk_id)
+                               continue;
+                       if (create_partition(hd, first_part_minor,
+                                       first_sector + vb->start_sector +
+                                       ph->logical_disk_start,
+                                       vb->num_sectors) == 1)
+                               first_part_minor++;
+               }
+               brelse(bh);
+       }
+       printk(" >\n");
+       err = 1;
+out:
+       kfree(vb);
+       return err;
+brelse_out:
+       brelse(bh);
+       goto err_out;
+no_mem:
+       printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+       goto err_out;
+read_err:
+       printk(LDM_CRIT "Disk read failed in create_partitions.\n");
+err_out:
+       err = -1;
+       goto out;
+}
+
+/**
+ * get_vnum - convert a variable-width, big endian number, to cpu u64 one
+ * @block:     pointer to the variable-width number to convert
+ * @err:       address of an integer into which to return the error code.
+ *
+ * This converts a variable-width, big endian number into a 64-bit, CPU format
+ * number and returns the result with err set to 0. If an error occurs return 0
+ * with err set to -1.
+ *
+ * The first byte of a variable-width number is the size of the number in bytes.
+ */
+static u64 get_vnum(const u8 *block, int *err)
+{
+       u64 tmp = 0ULL;
+       u8 length = *block++;
+
+       if (length && length <= 8) {
+               while (length--)
+                       tmp = (tmp << 8) | *block++;
+               *err = 0;
+       } else {
+               printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
+               *err = 1;
+       }
+       return tmp;
+}
+
+/**
+ * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
+ * @block:     string to convert
+ * @buffer:    output buffer
+ * @buflen:    size of output buffer
+ *
+ * This converts @block, a counted, non-null-terminated ASCII string, into a
+ * C-style, null-terminated, ASCII string and returns this in @buffer. The
+ * maximum number of characters converted is given by @buflen.
+ *
+ * The first bytes of a counted string stores the length of the string in bytes.
+ *
+ * Return the number of characters written to @buffer, not including the
+ * terminating null character, on success, and -1 on error, in which case
+ * @buffer is not defined.
+ */
+static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
+{
+       int length = block[0];
+
+       if (length < 1)
+               return -1;
+       if (length >= buflen) {
+               printk(LDM_ERR "String too long for buffer in get_vstr(): "
+                               "(%d/%d). Truncating.\n", length, buflen);
+               length = buflen - 1;
+       }
+       memcpy(buffer, block + 1, length);
+       buffer[length] = (u8)'\0';
+       return length;
+}
+
+/**
+ * get_disk_objid - obtain the object id for the device we are working on
+ * @dev:       partition device holding the LDM database
+ * @vm:                in memory vmdb structure of the LDM database
+ * @ph:                in memory privhead structure of the device we are working on
+ * @dk:                in memory ldmdisk structure to return information into
+ *
+ * This obtains the object id for the device we are working on as defined by
+ * the private header @ph. The obtained object id, together with the disk's
+ * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
+ *
+ * A Disk has two Ids. The main one is a GUID in string format. The second,
+ * used internally for cross-referencing, is a small, sequentially allocated,
+ * number. The PRIVHEAD, just after the partition table, tells us the disk's
+ * GUID. To find the disk's object id, we have to look through the database.
+ *
+ * Return 1 on success and -1 on error, in which case @dk is undefined.
+ */
+static int get_disk_objid(const kdev_t dev, const struct vmdb *vm,
+               const struct privhead *ph, struct ldmdisk *dk)
+{
+       struct buffer_head *bh;
+       u8 *disk_id;
+       int vblk;
+       int vsize;              /* VBLK size. */
+       int perbuf;             /* VBLKs per buffer. */
+       int buffer, lastbuf, lastofs, err;
+
+       disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
+       if (!disk_id)
+               goto no_mem;
+       vsize   = vm->vblk_size;
+       if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+               goto err_out;
+       perbuf  = LDM_BLOCKSIZE / vsize;
+       if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+               goto err_out;
+                                       /* 512 == VMDB size */
+       lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+       lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+       if (lastofs)
+               lastbuf++;
+       if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+                       ph->config_size * 512)
+               goto err_out;
+       for (buffer = 0; buffer < lastbuf; buffer++) {
+               if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+                       goto read_err;
+               for (vblk = 0; vblk < perbuf; vblk++) {
+                       int rel_objid, rel_name, delta;
+                       u8 *block;
+
+                       if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+                               break;
+                       block = bh->b_data + vblk * vsize;
+                       delta = vblk * vsize + 0x18;
+                       if (delta >= LDM_BLOCKSIZE)
+                               goto brelse_out;
+                       if (block[0x13] != VBLK_DISK)
+                               continue;
+                       /* Calculate relative offsets. */
+                       rel_objid = 1 + block[0x18];
+                       if (delta + rel_objid >= LDM_BLOCKSIZE)
+                               goto brelse_out;
+                       rel_name  = 1 + block[0x18 + rel_objid] + rel_objid;
+                       if (delta + rel_name >= LDM_BLOCKSIZE ||
+                           delta + rel_name + block[0x18 + rel_name] >=
+                                       LDM_BLOCKSIZE)
+                               goto brelse_out;
+                       err = get_vstr(block + 0x18 + rel_name, disk_id,
+                                       DISK_ID_SIZE);
+                       if (err == -1)
+                               goto brelse_out;
+                       if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
+                               dk->obj_id = get_vnum(block + 0x18, &err);
+                               brelse(bh);
+                               if (err)
+                                       goto out;
+                               strncpy(dk->disk_id, ph->disk_id,
+                                               sizeof(dk->disk_id));
+                               dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
+                               err = 1;
+                               goto out;
+                       }
+               }
+               brelse(bh);
+       }
+       err = -1;
+out:
+       kfree(disk_id);
+       return err;
+brelse_out:
+       brelse(bh);
+       goto err_out;
+no_mem:
+       printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+       goto err_out;
+read_err:
+       printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
+err_out:
+       err = -1;
+       goto out;
+}
+
+/**
+ * parse_vmdb - parse the LDM database vmdb structure
+ * @buffer:    LDM database vmdb structure loaded from the device
+ * @vm:                in memory vmdb structure to return parsed information in
+ *
+ * This parses the LDM database vmdb structure supplied in @buffer and sets up
+ * the in memory vmdb structure @vm with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ *
+ * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
+ * checked for validity, so make sure to check them when using them.
+ */
+static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
+{
+       if (MAGIC_VMDB != BE32(buffer)) {
+               printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
+               return -1;
+       }
+       vm->ver_major = BE16(buffer + 0x12);
+       vm->ver_minor = BE16(buffer + 0x14);
+       if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+               printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
+                               "Aborting.\n", 4, 10, vm->ver_major,
+                               vm->ver_minor);
+               return -1;
+       }
+       vm->vblk_size     = BE32(buffer + 0x08);
+       vm->vblk_offset   = BE32(buffer + 0x0C);
+       vm->last_vblk_seq = BE32(buffer + 0x04);
+
+       ldm_debug("Parsed VMDB successfully.\n");
+       return 1;
+}
+
+/**
+ * validate_vmdb - validate the vmdb
+ * @dev:       partition device holding the LDM database
+ * @vm:                in memory vmdb in which to return information
+ *
+ * Find the vmdb of the LDM database stored on @dev and return the parsed
+ * information into @vm.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ */
+static int validate_vmdb(const kdev_t dev, struct vmdb *vm)
+{
+       struct buffer_head *bh;
+       int ret;
+
+       if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
+               return -1;
+       }
+       ret = parse_vmdb(bh->b_data + 0x200, vm);
+       brelse(bh);
+       return ret;
+}
+
+/**
+ * compare_tocblocks - compare two tables of contents
+ * @toc1:      first toc
+ * @toc2:      second toc
+ *
+ * This compares the two tables of contents @toc1 and @toc2.
+ *
+ * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
+ */
+static int compare_tocblocks(const struct tocblock *toc1,
+               const struct tocblock *toc2)
+{
+       if ((toc1->bitmap1_start == toc2->bitmap1_start)        &&
+           (toc1->bitmap1_size  == toc2->bitmap1_size)         &&
+           (toc1->bitmap2_start == toc2->bitmap2_start)        &&
+           (toc1->bitmap2_size  == toc2->bitmap2_size)         &&
+           !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
+                       sizeof(toc1->bitmap1_name))             &&
+           !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
+                       sizeof(toc1->bitmap2_name)))
+               return 1;
+       return -1;
+}
+
+/**
+ * parse_tocblock - parse the LDM database table of contents structure
+ * @buffer:    LDM database toc structure loaded from the device
+ * @toc:       in memory toc structure to return parsed information in
+ *
+ * This parses the LDM database table of contents structure supplied in @buffer
+ * and sets up the in memory table of contents structure @toc with the obtained
+ * information.
+ *
+ * Return 1 on success and -1 on error, in which case @toc is undefined.
+ *
+ * FIXME: The *_start and *_size values returned in @toc are not been checked
+ * for validity but as we don't use the actual values for anything other than
+ * comparing between the toc and its backups, the values are not important.
+ */
+static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
+{
+       if (MAGIC_TOCBLOCK != BE64(buffer)) {
+               printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
+                               "corrupt.\n");
+               return -1;
+       }
+       strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
+       toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
+       toc->bitmap1_start = BE64(buffer + 0x2E);
+       toc->bitmap1_size  = BE64(buffer + 0x36);
+       /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
+       if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
+                       sizeof(toc->bitmap1_name)) != 0) {
+               printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
+                               "%s.\n", TOC_BITMAP1, toc->bitmap1_name);
+               return -1;
+       }
+       strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
+       toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
+       toc->bitmap2_start = BE64(buffer + 0x50);
+       toc->bitmap2_size  = BE64(buffer + 0x58);
+       /*toc->bitmap2_flags = BE64(buffer + 0x60);*/
+       if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
+                       sizeof(toc->bitmap2_name)) != 0) {
+               printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
+                               "%s.\n", TOC_BITMAP2, toc->bitmap2_name);
+               return -1;
+       }
+       ldm_debug("Parsed TOCBLOCK successfully.\n");
+       return 1;
+}
+
+/**
+ * validate_tocblocks - validate the table of contents and its backups
+ * @dev:       partition device holding the LDM database
+ * @toc1:      in memory table of contents in which to return information
+ *
+ * Find and compare the four tables of contents of the LDM database stored on
+ * @dev and return the parsed information into @toc1.
+ *
+ * Return 1 on success and -1 on error, in which case @toc1 is undefined.
+ */
+static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1)
+{
+       struct buffer_head *bh;
+       struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
+       int err;
+
+       toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
+       if (!toc2)
+               goto no_mem;
+       toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
+       if (!toc3)
+               goto no_mem;
+       toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
+       if (!toc4)
+               goto no_mem;
+       /* Read and parse first toc. */
+       if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
+               goto err_out;
+       }
+       err = parse_tocblock(bh->b_data + 0x0200, toc1);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       /* Read and parse second toc. */
+       if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
+               goto err_out;
+       }
+       err = parse_tocblock(bh->b_data, toc2);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       /* Read and parse third toc. */
+       if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
+               goto err_out;
+       }
+       err = parse_tocblock(bh->b_data + 0x0200, toc3);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       /* Read and parse fourth toc. */
+       if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
+               goto err_out;
+       }
+       err = parse_tocblock(bh->b_data, toc4);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       /* Compare all tocs. */
+       err = compare_tocblocks(toc1, toc2);
+       if (err != 1) {
+               printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
+               goto out;
+       }
+       err = compare_tocblocks(toc3, toc4);
+       if (err != 1) {
+               printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
+               goto out;
+       }
+       err = compare_tocblocks(toc1, toc3);
+       if (err != 1)
+               printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
+       else
+               ldm_debug("Validated TOCBLOCKs successfully.\n");
+out:
+       kfree(toc2);
+       kfree(toc3);
+       kfree(toc4);
+       return err;
+no_mem:
+       printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+       err = -1;
+       goto out;
+}
+
+/**
+ * compare_privheads - compare two privheads
+ * @ph1:       first privhead
+ * @ph2:       second privhead
+ *
+ * This compares the two privheads @ph1 and @ph2.
+ *
+ * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
+ */
+static int compare_privheads(const struct privhead *ph1,
+               const struct privhead *ph2)
+{
+       if ((ph1->ver_major == ph2->ver_major)                   &&
+           (ph1->ver_minor == ph2->ver_minor)                   &&
+           (ph1->logical_disk_start == ph2->logical_disk_start) &&
+           (ph1->logical_disk_size  == ph2->logical_disk_size)  &&
+           (ph1->config_start == ph2->config_start)             &&
+           (ph1->config_size  == ph2->config_size)              &&
+           !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
+               return 1;
+       return -1;
+}
+
+/**
+ * validate_privheads - compare the privhead backups to the first one
+ * @dev:       partition device holding the LDM database
+ * @ph1:       first privhead which we have already validated before
+ *
+ * We already have one privhead from the beginning of the disk.
+ * Now we compare the two other copies for safety.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int validate_privheads(const kdev_t dev, const struct privhead *ph1)
+{
+       struct buffer_head *bh;
+       struct privhead *ph2 = NULL, *ph3 = NULL;
+       int err;
+
+       ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
+       if (!ph2)
+               goto no_mem;
+       ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
+       if (!ph3)
+               goto no_mem;
+       if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
+               goto err_out;
+       }
+       err = parse_privhead(bh->b_data, ph2);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
+               goto err_out;
+       }
+       err = parse_privhead(bh->b_data + 0x0200, ph3);
+       brelse(bh);
+       if (err != 1)
+               goto out;
+       err = compare_privheads(ph1, ph2);
+       if (err != 1) {
+               printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
+               goto out;
+       }
+       err = compare_privheads(ph1, ph3);
+       if (err != 1)
+               printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
+       else
+               /* We _could_ have checked more. */
+               ldm_debug("Validated PRIVHEADs successfully.\n");
+out:
+       kfree(ph2);
+       kfree(ph3);
+       return err;
+no_mem:
+       printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+       err = -1;
+       goto out;
+}
+
+/**
+ * create_partition - validate input and create a kernel partition device
+ * @hd:                gendisk structure in which to create partition
+ * @minor:     minor number for device to create
+ * @start:     starting offset of the partition into the parent device
+ * @size:      size of the partition
+ *
+ * This validates the range, then puts an entry into the kernel's partition
+ * table.
+ *
+ * @start and @size are numbers of sectors.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int create_partition(struct gendisk *hd, const int minor,
+               const int start, const int size)
+{
+       int disk_minor;
+
+       if (!hd->part)
+               return -1;
+       /*
+        * Get the minor number of the parent device so we can check we don't
+        * go beyond the end of the device.
+        */
+       disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
+       if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+               printk(LDM_CRIT "LDM Partition exceeds physical disk. "
+                               "Aborting.\n");
+               return -1;
+       }
+       add_gd_partition(hd, minor, start, size);
+       ldm_debug("Created partition successfully.\n");
+       return 1;
+}
+
+/**
+ * parse_privhead - parse the LDM database PRIVHEAD structure
+ * @buffer:    LDM database privhead structure loaded from the device
+ * @ph:                in memory privhead structure to return parsed information in
+ *
+ * This parses the LDM database PRIVHEAD structure supplied in @buffer and
+ * sets up the in memory privhead structure @ph with the obtained information.
+ *
+ * Return 1 on succes and -1 on error, in which case @ph is undefined.
+ */
+static int parse_privhead(const u8 *buffer, struct privhead *ph)
+{
+       if (MAGIC_PRIVHEAD != BE64(buffer)) {
+               printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
+                               "is corrupt. Aborting.\n");
+               return -1;
+       }
+       ph->ver_major = BE16(buffer + 0x000C);
+       ph->ver_minor = BE16(buffer + 0x000E);
+       if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+               printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
+                               "Aborting.\n", 2, 11, ph->ver_major,
+                               ph->ver_minor);
+               return -1;
+       }
+       ph->config_start = BE64(buffer + 0x012B);
+       ph->config_size  = BE64(buffer + 0x0133);
+       if (ph->config_size != LDM_DB_SIZE) {   /* 1 MiB in sectors. */
+               printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
+                               "bytes. Aborting.\n", LDM_DB_SIZE,
+                               ph->config_size);
+               return -1;
+       }
+       ph->logical_disk_start = BE64(buffer + 0x011B);
+       ph->logical_disk_size  = BE64(buffer + 0x0123);
+       if (!ph->logical_disk_size ||
+           ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
+               return -1;
+
+       memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
+
+       ldm_debug("Parsed PRIVHEAD successfully.\n");
+       return 1;
+}
+
+/**
+ * create_db_partition - create a dedicated partition for our database
+ * @hd:                gendisk structure in which to create partition
+ * @dev:       device of which to create partition
+ * @ph:                @dev's LDM database private header
+ *
+ * Find the primary private header, locate the LDM database, then create a
+ * partition to wrap it.
+ *
+ * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
+ */
+static int create_db_partition(struct gendisk *hd, const kdev_t dev,
+               const unsigned long first_sector, const int first_part_minor,
+               struct privhead *ph)
+{
+       struct buffer_head *bh;
+       int err;
+
+       if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) {
+               printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
+               return -1;
+       }
+       if (BE64(bh->b_data) != MAGIC_PRIVHEAD) {
+               ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
+                               "or corrupt LDM database.\n");
+               return 0;
+       }
+       err = parse_privhead(bh->b_data, ph);
+       if (err == 1)
+               err = create_partition(hd, first_part_minor, first_sector +
+                               ph->config_start, ph->config_size);
+       brelse(bh);
+       return err;
+}
+
+/**
+ * validate_patition_table - check whether @dev is a dynamic disk
+ * @dev:       device to test
+ *
+ * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
+ * table with one or more entries of type 0x42 (the former Secure File System
+ * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
+ * If this succeeds we assume we have a dynamic disk, and not otherwise.
+ *
+ * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
+ */
+static int validate_partition_table(const kdev_t dev)
+{
+       struct buffer_head *bh;
+       struct partition *p;
+       int i, nr_sfs;
+
+       if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) {
+               if (warn_no_part)
+                       printk(LDM_ERR "Unable to read partition table.\n");
+               return -1;
+       }
+       if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+               ldm_debug("No MS-DOS partition found.\n");
+               goto no_msdos_partition;
+       }
+       nr_sfs = 0;
+       p = (struct partition*)(bh->b_data + 0x01BE);
+       for (i = 0; i < 4; i++) {
+               if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
+                       continue;
+               if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
+                       nr_sfs++;
+                       continue;
+               }
+               goto not_dynamic_disk;
+       }
+       if (!nr_sfs)
+               goto not_dynamic_disk;
+       ldm_debug("Parsed partition table successfully.\n");
+       brelse(bh);
+       return 1;
+not_dynamic_disk:
+       ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
+no_msdos_partition:
+       brelse(bh);
+       return 0;
+}
+
+/**
+ * ldm_partition - find out whether a device is a dynamic disk and handle it
+ * @hd:                        gendisk structure in which to return the handled disk
+ * @dev:               device we need to look at
+ * @first_sector:      first sector within the device
+ * @first_part_minor:  first minor number of partitions for the device
+ *
+ * Description:
+ *
+ * This determines whether the device @dev is a dynamic disk and if so creates
+ * the partitions necessary in the gendisk structure pointed to by @hd.
+ *
+ * We create a dummy device 1, which contains the LDM database, we skip
+ * devices 2-4 and then create each partition described by the LDM database
+ * in sequence as devices 5 and following. For example, if the device is hda,
+ * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
+ * actual data containing partitions.
+ *
+ * Return values:
+ *
+ *      1 if @dev is a dynamic disk and we handled it,
+ *      0 if @dev is not a dynamic disk,
+ *     -1 if an error occured.
+ */
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+               int first_part_minor)
+{
+       kdev_t devdb;
+       struct privhead *ph  = NULL;
+       struct tocblock *toc = NULL;
+       struct vmdb     *vm  = NULL;
+       struct ldmdisk  *dk  = NULL;
+       int err;
+
+       if (!hd)
+               return 0;
+       err = (int)get_ptable_blocksize(dev);
+       if (err != LDM_BLOCKSIZE) {     /* 1024 bytes */
+               ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n",
+                               LDM_BLOCKSIZE, get_ptable_blocksize(dev));
+               return 0;
+       }
+       err = get_hardsect_size(dev); 
+       if (err != 512) {
+               ldm_debug("Expected a sector size of %d bytes, got %d "
+                               "instead.\n", 512, get_hardsect_size(dev));
+               return 0;
+       }
+       /* Check the partition table. */
+       err = validate_partition_table(dev);
+       if (err != 1)
+               return err;
+       if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
+               goto no_mem;
+       /* Create the LDM database device. */
+       err = create_db_partition(hd, dev, first_sector, first_part_minor, ph);
+       if (err != 1)
+               goto out;
+       /* For convenience, work with the LDM database device from now on. */
+       devdb = MKDEV(MAJOR(dev), first_part_minor);
+       /* Check the backup privheads. */
+       err = validate_privheads(devdb, ph);
+       if (err != 1)
+               goto out;
+       /* Check the table of contents and its backups. */
+       if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
+               goto no_mem;
+       err = validate_tocblocks(devdb, toc);
+       if (err != 1)
+               goto out;
+       /* Check the vmdb. */
+       if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
+               goto no_mem;
+       err = validate_vmdb(devdb, vm);
+       if (err != 1)
+               goto out;
+       /* Find the object id for @dev in the LDM database. */
+       if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
+               goto no_mem;
+       err = get_disk_objid(devdb, vm, ph, dk);
+       if (err != 1)
+               goto out;
+       /* Finally, create the data partition devices. */
+       err = create_data_partitions(hd, first_sector, first_part_minor +
+                       LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk);
+       if (err == 1)
+               ldm_debug("Parsed LDM database successfully.\n");
+out:
+       kfree(ph);
+       kfree(toc);
+       kfree(vm);
+       kfree(dk);
+       return err;
+no_mem:
+       printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+       err = -1;
+       goto out;
+}
+
diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h
new file mode 100644 (file)
index 0000000..e6aa43b
--- /dev/null
@@ -0,0 +1,162 @@
+#ifndef _FS_PT_LDM_H_
+#define _FS_PT_LDM_H_
+/*
+ * $Id: ldm.h,v 1.13 2001/07/23 19:49:49 antona Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+
+/* Borrowed from kernel.h. */
+#define LDM_PREFIX     "LDM: "    /* Prefix our error messages with this. */
+#define LDM_CRIT       KERN_CRIT       LDM_PREFIX /* critical conditions */
+#define LDM_ERR                KERN_ERR        LDM_PREFIX /* error conditions */
+#define LDM_DEBUG      KERN_DEBUG      LDM_PREFIX /* debug-level messages */
+
+/* Magic numbers in CPU format. */
+#define MAGIC_VMDB     0x564D4442              /* VMDB */
+#define MAGIC_VBLK     0x56424C4B              /* VBLK */
+#define MAGIC_PRIVHEAD 0x5052495648454144      /* PRIVHEAD */
+#define MAGIC_TOCBLOCK 0x544F43424C4F434B      /* TOCBLOCK */
+
+/* The defined vblk types. */
+#define VBLK_COMP              0x32            /* Component */
+#define VBLK_PART              0x33            /* Partition */
+#define VBLK_DISK              0x34            /* Disk */
+#define VBLK_DGRP              0x45            /* Disk Group */
+#define VBLK_VOLU              0x51            /* Volume */
+
+/* Other constants. */
+#define LDM_BLOCKSIZE          1024            /* Size of block in bytes. */
+#define LDM_DB_SIZE            2048            /* Size in sectors (= 1MiB). */
+#define LDM_FIRST_PART_OFFSET  4               /* Add this to first_part_minor
+                                                  to get to the first data
+                                                  partition device minor. */
+
+#define OFF_PRIVHEAD1          3               /* Offset of the first privhead
+                                                  relative to the start of the
+                                                  device in units of
+                                                  LDM_BLOCKSIZE. */
+
+/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */
+#define OFF_PRIVHEAD2          928             /* Backup private headers. */
+#define OFF_PRIVHEAD3          1023
+
+#define OFF_TOCBLOCK1          0               /* Tables of contents. */
+#define OFF_TOCBLOCK2          1
+#define OFF_TOCBLOCK3          1022
+#define OFF_TOCBLOCK4          1023
+
+#define OFF_VMDB               8               /* List of partitions. */
+#define OFF_VBLK               9
+
+#define WIN2K_DYNAMIC_PARTITION                0x42    /* Formerly SFS (Landis). */
+#define WIN2K_EXTENDED_PARTITION       0x05    /* A standard extended
+                                                  partition. */
+
+#define TOC_BITMAP1            "config"        /* Names of the two defined */
+#define TOC_BITMAP2            "log"           /* bitmaps in the TOCBLOCK. */
+
+/* Borrowed from msdos.c */
+#define SYS_IND(p)             (get_unaligned(&p->sys_ind))
+#define NR_SECTS(p)            ({ __typeof__(p->nr_sects) __a =        \
+                                       get_unaligned(&p->nr_sects);    \
+                                       le32_to_cpu(__a);               \
+                               })
+#define START_SECT(p)          ({ __typeof__(p->start_sect) __a =      \
+                                       get_unaligned(&p->start_sect);  \
+                                       le32_to_cpu(__a);               \
+                               })
+
+/* Most numbers we deal with are big-endian and won't be aligned. */
+#define BE16(x)                        ((u16)be16_to_cpu(get_unaligned((u16*)(x))))
+#define BE32(x)                        ((u32)be32_to_cpu(get_unaligned((u32*)(x))))
+#define BE64(x)                        ((u64)be64_to_cpu(get_unaligned((u64*)(x))))
+
+/* Borrowed from msdos.c. */
+#define SYS_IND(p)             (get_unaligned(&(p)->sys_ind))
+#define NR_SECTS(p)            ({ __typeof__((p)->nr_sects) __a =      \
+                                       get_unaligned(&(p)->nr_sects);  \
+                                       le32_to_cpu(__a);               \
+                               })
+
+#define START_SECT(p)          ({ __typeof__((p)->start_sect) __a =    \
+                                       get_unaligned(&(p)->start_sect);\
+                                       le32_to_cpu(__a);               \
+                               })
+
+/* In memory LDM database structures. */
+
+#define DISK_ID_SIZE           64      /* Size in bytes. */
+
+struct ldmdisk {
+       u64     obj_id;
+       u8      disk_id[DISK_ID_SIZE];
+};
+
+struct privhead        {                       /* Offsets and sizes are in sectors. */
+       u16     ver_major;
+       u16     ver_minor;
+       u64     logical_disk_start;
+       u64     logical_disk_size;
+       u64     config_start;
+       u64     config_size;
+       u8      disk_id[DISK_ID_SIZE];
+};
+
+struct tocblock {                      /* We have exactly two bitmaps. */
+       u8      bitmap1_name[16];
+       u64     bitmap1_start;
+       u64     bitmap1_size;
+       /*u64   bitmap1_flags;*/
+       u8      bitmap2_name[16];
+       u64     bitmap2_start;
+       u64     bitmap2_size;
+       /*u64   bitmap2_flags;*/
+};
+
+struct vmdb {
+       u16     ver_major;
+       u16     ver_minor;
+       u32     vblk_size;
+       u32     vblk_offset;
+       u32     last_vblk_seq;
+};
+
+struct vblk {
+       u8      name[64];
+       u8      vblk_type;
+       u64     obj_id;
+       u64     disk_id;
+       u64     start_sector;
+       u64     num_sectors;
+};
+
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+               int first_part_minor);
+
+#endif /* _FS_PT_LDM_H_ */
+
index a1eb02f157a50c12ed1db4d2499b619fbb1b2e51..dc966d6aed2598eb49b76c33a9816b57b24f9807 100644 (file)
@@ -258,7 +258,7 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
        return buffer;
 }
 
-extern inline char *task_cap(struct task_struct *p, char *buffer)
+static inline char *task_cap(struct task_struct *p, char *buffer)
 {
     return buffer + sprintf(buffer, "CapInh:\t%016x\n"
                            "CapPrm:\t%016x\n"
index 7b4cd6c63ee15b00c1e70eb7a2cc31fd505ae79e..f2f51505d6dc47dc5e211dd31196c0ad2aac75f2 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: atomic.h,v 1.2 2000/07/13 16:51:57 bjornw Exp $ */
+/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
 
 #ifndef __ASM_CRIS_ATOMIC__
 #define __ASM_CRIS_ATOMIC__
@@ -139,4 +139,10 @@ static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
        return retval;
 }
 
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec()    barrier()
+#define smp_mb__after_atomic_dec()     barrier()
+#define smp_mb__before_atomic_inc()    barrier()
+#define smp_mb__after_atomic_inc()     barrier()
+
 #endif
index c0b0838b1ee6d26ffcde24f18c0c18688597eace..c54f65d4a4a7f83cc541eb1eabefec15037f2158 100644 (file)
@@ -15,7 +15,9 @@
  * tools/mkptable is used to generate the ptable. 
  */
 
-/* The partition table starts with code to "jump over" it: */
+/* The partition table starts with code to "jump over" it.  The ba
+   instruction and delay-slot is modified elsewhere (for example the
+   mkptable script); don't change this to fill the delay-slot.  */
 #define PARTITIONTABLE_CODE_START { \
  0x0f, 0x05, /* nop 0 */\
  0x25, 0xf0, /* di  2 */\
@@ -53,7 +55,7 @@ struct partitiontable_entry {
 #define PARTITIONTABLE_END_MARKER_SIZE 4
 
 /*#define PARTITION_TYPE_RESCUE 0x0000?*/  /* Not used, maybe it should? */
-#define PARTITION_TYPE_PARAM  0x0001 /* Hmm.. */
+#define PARTITION_TYPE_PARAM  0x0001
 #define PARTITION_TYPE_KERNEL 0x0002
 #define PARTITION_TYPE_JFFS   0x0003
 
index 6f93e59db07d4231e93deb7483e0995e47b8b256..4ed0f832b19db0100a38efea23e5f5775c93e6d7 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.3 2000/11/15 17:35:16 bjornw Exp $ */
+/* $Id: checksum.h,v 1.4 2001/06/28 03:58:36 hp Exp $ */
 /* TODO: csum_tcpudp_magic could be speeded up, and csum_fold as well */
 
 #ifndef _CRIS_CHECKSUM_H
@@ -69,17 +69,9 @@ csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len,
        return res;
 }      
 
-
-/* TODO we need to write this properly to handle userland VM exceptions!! */
-
-#define csum_partial_copy_from_user(a,b,c,d,errptr) csum_partial_copy_nocheck(a,b,c,d)
-
-#if 0
-unsigned int csum_partial_copy_from_user(const char *src, char *dst,
-                                       int len, unsigned int sum);
-#endif
-
-
+extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+                                               int len, unsigned int sum, 
+                                               int *errptr);
 
 /*
  *     This is a version of ip_compute_csum() optimized for IP headers,
index 325473e986a03a48f64732b8e367e846a44dc779..a9a848dd3b079d7fa93e8fad895654527bdef66f 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */
+/* $Id: delay.h,v 1.5 2001/06/28 04:59:25 hp Exp $ */
 
 #ifndef _CRIS_DELAY_H
 #define _CRIS_DELAY_H
 
 /*
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB
  *
  * Delay routines, using a pre-computed "loops_per_second" value.
  */
@@ -21,26 +21,18 @@ extern void __do_delay(void);       /* Special register call calling convention */
 extern __inline__ void __delay(int loops)
 {
        __asm__ __volatile__ (
-                             "move.d %0,r0\n\t"
-                             "1:\n\t"
-                             "cmpq 0,r0\n\t"
+                             "move.d %0,r9\n\t"
                              "beq 2f\n\t"
-                             "nop\n\t"
-                             "subq 1,r0\n\t"
-                             "ba 1b\n\t"
-                             "nop\n\t"
-                             "2:\n\t"
-                             : : "r" (loops) : "r0");
+                             "subq 1,r9\n\t"
+                             "1:\n\t"
+                             "bne 1b\n\t"
+                             "subq 1,r9\n"
+                             "2:"
+                             : : "g" (loops) : "r9");
 }
 
 
-/*
- * Use only for very small delays ( < 1 msec).  Should probably use a
- * lookup table, really, as the multiplications take much too long with
- * short delays.  This is a "reasonable" implementation, though (and the
- * first constant multiplications gets optimized away if the delay is
- * a constant)
- */
+/* Use only for very small delays ( < 1 msec).  */
 
 extern unsigned long loops_per_usec; /* arch/cris/mm/init.c */
 
index f5d717416caa12230c14ca705e7c7e1e92861c72..4a13a2445d5b2bba29d119ecffdc46a4be1ab1cd 100644 (file)
@@ -7,11 +7,11 @@
 
 /* entry.S is sensitive to the offsets of these fields */
 typedef struct {
-       unsigned int __softirq_active;
-       unsigned int __softirq_mask;
+       unsigned int __softirq_pending;
        unsigned int __local_irq_count;
        unsigned int __local_bh_count;
        unsigned int __syscall_count;
+       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
 } ____cacheline_aligned irq_cpustat_t;
 
 #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
index 4f05d74788d3436dc31e33ddbbb5ee07d2bd4e67..01c8b1dad1d94265eb37c87c412e1ed47b38cf26 100644 (file)
@@ -9,8 +9,16 @@
    use will be evident. */
 #ifdef CONFIG_SVINTO_SIM
   /* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
-\n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \
+#define SIMCOUT(s,len)                                                 \
+  asm ("moveq 4,r1     \n\t"                                           \
+       "moveq 2,r10    \n\t"                                           \
+       "move.d %0,r11  \n\t"                                           \
+       "move.d %1,r12  \n\t"                                           \
+       "push irp       \n\t"                                           \
+       "move 0f,irp    \n\t"                                           \
+       "jump -6809     \n"                                             \
+       "0:             \n\t"                                           \
+       "pop irp"                                                       \
        : : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory")
 #define TRACE_ON() __extension__ \
  ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
@@ -113,7 +121,10 @@ extern volatile unsigned long *port_csp4_addr;
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+         do{\
+                REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x)) 
 #endif
@@ -128,7 +139,10 @@ extern volatile unsigned long *port_csp4_addr;
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+        do{\
+                REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x))     
 #endif
@@ -155,7 +169,10 @@ extern volatile unsigned long *port_csp4_addr;
 #define LED_ACTIVE_SET_R(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x))
 #define LED_DISK_WRITE(x) \
-         REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x))
+        do{\
+                REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\
+                REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\
+        }while(0)
 #define LED_DISK_READ(x) \
          REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x))
 #define LED_BIT_SET(x)\
index 44fe42d0e09fa82ebcf2e317a3251082e72cc5f1..b7eb9c363795b8fc1e524e355793a6de73399825 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * Interrupt handling assembler and defines for Linux/CRIS
  *
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000, 2001 Axis Communications AB
  *
  * Authors:   Bjorn Wesen (bjornw@axis.com)
  *
- * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $
+ * $Id: irq.h,v 1.13 2001/07/06 18:52:08 hp Exp $
  */
 
 #ifndef _ASM_IRQ_H
@@ -29,7 +29,7 @@
 /* par1, scsi1 on 5 */
 #define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */
 
-#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 8 */
+#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */
 #define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */
 /* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */
 #define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0)
index 89c249f220fd32a8aaa61402c6ef3d6d054224c3..0291f21c27f2eb5d6cc4fb1bcf491b87657483a5 100644 (file)
@@ -100,7 +100,7 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 #define start_thread(regs, ip, usp) do { \
        set_fs(USER_DS);      \
        regs->irp = ip;       \
-       regs->dccr |= 1 << 8; \
+       regs->dccr |= 1 << U_DCCR_BITNR; \
        wrusp(usp);           \
 } while(0)
 
index 4607f276e47b4ec9608b18c8eb9389a8003a46bb..b7391cc079dcd530da2b2e49fcb5a6b424b586a9 100644 (file)
 #define PT_USP       23    /* special case - USP is not in the pt_regs */
 #define PT_MAX       23
 
+/* Condition code bit numbers.  The same numbers apply to CCR of course,
+   but we use DCCR everywhere else, so let's try and be consistent.  */
+#define C_DCCR_BITNR 0
+#define V_DCCR_BITNR 1
+#define Z_DCCR_BITNR 2
+#define N_DCCR_BITNR 3
+#define X_DCCR_BITNR 4
+#define I_DCCR_BITNR 5
+#define B_DCCR_BITNR 6
+#define M_DCCR_BITNR 7
+#define U_DCCR_BITNR 8
+#define P_DCCR_BITNR 9
+#define F_DCCR_BITNR 10
+
 /* Frame types */
 
 #define CRIS_FRAME_NORMAL   0 /* normal frame without SBFS stacking */
@@ -98,7 +112,7 @@ struct switch_stack {
 #define PTRACE_SETREGS            13
 
 /* bit 8 is user-mode flag */
-#define user_mode(regs) ((regs)->dccr & 0x100)
+#define user_mode(regs) (((regs)->dccr & 0x100) != 0)
 #define instruction_pointer(regs) ((regs)->irp)
 extern void show_regs(struct pt_regs *);
 #endif
index aab7ee7225768954a96773ee66caf98292c39028..89edfb11650f0afa8849e7aa65291288c599421d 100644 (file)
@@ -59,7 +59,7 @@
                                         /* level.  For writing rarp and */
                                         /* other similar things on the  */
                                         /* user level.                  */
-#define        SOCK_MAX        (SOCK_PACKET+1)
+#define        SOCK_MAX        (SOCK_PACKET+1)
 #endif
 
 #endif /* _ASM_SOCKET_H */
index a88b20576124e09706e29744c00ec722ff7fd212..5b831d3622df59c74419c1d586fd3b0ede5f5bcd 100644 (file)
@@ -4,9 +4,29 @@
 #include <asm/atomic.h>
 #include <asm/hardirq.h>
 
-#define local_bh_disable()      (local_bh_count(smp_processor_id())++)
-#define local_bh_enable()       (local_bh_count(smp_processor_id())--)
+#define local_bh_disable()                      \
+do {                                            \
+        local_bh_count(smp_processor_id())++;   \
+        barrier();                              \
+} while (0)
+
+#define __local_bh_enable()                     \
+do {                                            \
+        barrier();                              \
+        local_bh_count(smp_processor_id())--;   \
+} while (0)
+
+#define local_bh_enable()                               \
+do {                                                    \
+        if (!--local_bh_count(smp_processor_id())       \
+            && softirq_pending(smp_processor_id())) {   \
+                do_softirq();                           \
+                __sti();                                \
+        }                                               \
+} while (0)
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu))
+
 #endif /* __ASM_SOFTIRQ_H */
index abb627a4128056c57c3abf385effa04477d116c6..2d950382430f9a341034958fa0e17418d09923c7 100644 (file)
  * Basic functions accessing APICs.
  */
 
-extern __inline void apic_write(unsigned long reg, unsigned long v)
+static __inline void apic_write(unsigned long reg, unsigned long v)
 {
        *((volatile unsigned long *)(APIC_BASE+reg)) = v;
 }
 
-extern __inline void apic_write_atomic(unsigned long reg, unsigned long v)
+static __inline void apic_write_atomic(unsigned long reg, unsigned long v)
 {
        xchg((volatile unsigned long *)(APIC_BASE+reg), v);
 }
 
-extern __inline unsigned long apic_read(unsigned long reg)
+static __inline unsigned long apic_read(unsigned long reg)
 {
        return *((volatile unsigned long *)(APIC_BASE+reg));
 }
@@ -51,7 +51,7 @@ extern unsigned int apic_timer_irqs [NR_CPUS];
 # define apic_write_around(x,y) apic_write_atomic((x),(y))
 #endif
 
-extern inline void ack_APIC_irq(void)
+static inline void ack_APIC_irq(void)
 {
        /*
         * ack_APIC_irq() actually gets compiled as a single instruction:
index b5085f37645a257473a573a2de4439166c016791..0de58abeeb69ffa3291f94328cb7c36625669035 100644 (file)
@@ -34,14 +34,14 @@ asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, i
  *     If you use these functions directly please don't forget the 
  *     verify_area().
  */
-extern __inline__
+static __inline__
 unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
                                        int len, int sum)
 {
        return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
 }
 
-extern __inline__
+static __inline__
 unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
                                                int len, int sum, int *err_ptr)
 {
index 02c3b4ab3708fce01361f2b9a7ea5154488a8403..2e65b1f34eb6771407055c96816be8aed0f06beb 100644 (file)
 #define        CO_IRQ_8259     12
 
 #ifdef CONFIG_X86_VISWS_APIC
-extern __inline void co_cpu_write(unsigned long reg, unsigned long v)
+static __inline void co_cpu_write(unsigned long reg, unsigned long v)
 {
        *((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
 }
 
-extern __inline unsigned long co_cpu_read(unsigned long reg)
+static __inline unsigned long co_cpu_read(unsigned long reg)
 {
        return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
 }            
              
-extern __inline void co_apic_write(unsigned long reg, unsigned long v)
+static __inline void co_apic_write(unsigned long reg, unsigned long v)
 {
        *((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
 }            
              
-extern __inline unsigned long co_apic_read(unsigned long reg)
+static __inline unsigned long co_apic_read(unsigned long reg)
 {
        return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
 }
index bcfa2c65cc40ebfa171c8afcdb118e93fcfb5cd0..38642feaa4b2adeaf0f1b8f57a42208663602f8b 100644 (file)
@@ -69,7 +69,7 @@ extern void set_intr_gate(unsigned int irq, void * addr);
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
 
-extern inline void clear_LDT(void)
+static inline void clear_LDT(void)
 {
        int cpu = smp_processor_id();
        set_ldt_desc(cpu, &default_ldt[0], 5);
@@ -79,7 +79,7 @@ extern inline void clear_LDT(void)
 /*
  * load one particular LDT into the current CPU
  */
-extern inline void load_LDT (struct mm_struct *mm)
+static inline void load_LDT (struct mm_struct *mm)
 {
        int cpu = smp_processor_id();
        void *segments = mm->context.segments;
index 9a906bcff280ccfce72099b4eae91db060bf6cde..381e9e9f3b4f4ab242f9a0405d3a900e1da69cd0 100644 (file)
@@ -98,7 +98,7 @@ extern void __this_fixmap_does_not_exist(void);
  * directly without tranlation, we catch the bug with a NULL-deference
  * kernel oops. Illegal ranges of incoming indices are caught too.
  */
-extern inline unsigned long fix_to_virt(const unsigned int idx)
+static inline unsigned long fix_to_virt(const unsigned int idx)
 {
        /*
         * this branch gets completely eliminated after inlining,
index fd6a0e7b7e6381c31677e4e1de88bdfffa51446f..f3bc33ea141eff92443997500a707859cef9082d 100644 (file)
@@ -50,7 +50,7 @@
  * Talk about misusing macros..
  */
 #define __OUT1(s,x) \
-extern inline void out##s(unsigned x value, unsigned short port) {
+static inline void out##s(unsigned x value, unsigned short port) {
 
 #define __OUT2(s,s1,s2) \
 __asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
@@ -60,7 +60,7 @@ __OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "Nd" (port)); } \
 __OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
 
 #define __IN1(s) \
-extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
 
 #define __IN2(s,s1,s2) \
 __asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
@@ -70,12 +70,12 @@ __IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 __IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
 
 #define __INS(s) \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; ins" #s \
 : "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
 #define __OUTS(s) \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
 { __asm__ __volatile__ ("rep ; outs" #s \
 : "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
 
@@ -125,19 +125,19 @@ __OUTS(l)
  * Change virtual addresses to physical addresses and vv.
  * These are pretty trivial
  */
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
 {
        return __pa(address);
 }
 
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
 {
        return __va(address);
 }
 
 extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
 
-extern inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void * ioremap (unsigned long offset, unsigned long size)
 {
        return __ioremap(offset, size, 0);
 }
@@ -147,7 +147,7 @@ extern inline void * ioremap (unsigned long offset, unsigned long size)
  * it's useful if some control registers are in such an area and write combining
  * or read caching is not desirable:
  */
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
 {
         return __ioremap(offset, size, _PAGE_PCD);
 }
index 253472ee1e08a8cb0e2ed681d26a0edf0595a0c8..a29cc19395a4965f8c731063250313dac88ad21d 100644 (file)
 
 #ifdef CONFIG_X86_VISWS_APIC
 /* More special purpose macros... */
-extern __inline void li_pcia_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcia_write16(unsigned long reg, unsigned short v)
 {
        *((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v;
 }
 
-extern __inline unsigned short li_pcia_read16(unsigned long reg)
+static __inline unsigned short li_pcia_read16(unsigned long reg)
 {
         return *((volatile unsigned short *)(LI_PCIA_VADDR+reg));
 }
 
-extern __inline void li_pcib_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcib_write16(unsigned long reg, unsigned short v)
 {
        *((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v;
 }
 
-extern __inline unsigned short li_pcib_read16(unsigned long reg)
+static __inline unsigned short li_pcib_read16(unsigned long reg)
 {
        return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
 }
index 1cc171f9b600e758640d0af097c7c3a20419588c..ffcab0afb658459c733aab2c3ac1a40be9269203 100644 (file)
@@ -10,7 +10,7 @@
  *     to borrow for other processors if it was just assembler.
  */
 
-extern __inline__ void prim_spin_lock(struct spinlock *sp)
+static __inline__ void prim_spin_lock(struct spinlock *sp)
 {
        int processor=smp_processor_id();
        
@@ -56,7 +56,7 @@ extern __inline__ void prim_spin_lock(struct spinlock *sp)
  *     Release a spin lock
  */
  
-extern __inline__ int prim_spin_unlock(struct spinlock *sp)
+static __inline__ int prim_spin_unlock(struct spinlock *sp)
 {
        /* This is safe. The decrement is still guarded by the lock. A multilock would
           not be safe this way */
@@ -73,7 +73,7 @@ extern __inline__ int prim_spin_unlock(struct spinlock *sp)
  *     Non blocking lock grab
  */
  
-extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
+static __inline__ int prim_spin_lock_nb(struct spinlock *sp)
 {
        if(lock_set_bit(0,&sp->lock))
                return 0;               /* Locked already */
@@ -86,7 +86,7 @@ extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
  *     These wrap the locking primitives up for usage
  */
  
-extern __inline__ void spinlock(struct spinlock *sp)
+static __inline__ void spinlock(struct spinlock *sp)
 {
        if(sp->priority<current->lock_order)
                panic("lock order violation: %s (%d)\n", sp->name, current->lock_order);
@@ -100,7 +100,7 @@ extern __inline__ void spinlock(struct spinlock *sp)
        }
 }
 
-extern __inline__ void spinunlock(struct spinlock *sp)
+static __inline__ void spinunlock(struct spinlock *sp)
 {
        int pri;
        if(current->lock_order!=sp->priority)
@@ -116,7 +116,7 @@ extern __inline__ void spinunlock(struct spinlock *sp)
        }       
 }
 
-extern __inline__ void spintestlock(struct spinlock *sp)
+static __inline__ void spintestlock(struct spinlock *sp)
 {
        /*
         *      We do no sanity checks, it's legal to optimistically
@@ -125,7 +125,7 @@ extern __inline__ void spintestlock(struct spinlock *sp)
        prim_spin_lock_nb(sp);
 }
 
-extern __inline__ void spintestunlock(struct spinlock *sp)
+static __inline__ void spintestunlock(struct spinlock *sp)
 {
        /*
         *      A testlock doesn't update the lock chain so we
index 6114bcc08226d6055adfd65752a6752892ba09b0..de014031cda676cb8dd7996a06c1a4a959635049 100644 (file)
@@ -7,6 +7,7 @@
  */
 typedef struct { 
        void *segments;
+       unsigned long cpuvalid;
 } mm_context_t;
 
 #endif
index cdfb99b4d237a8a927dfa2c3fa2b2f22e109b8cb..43cabfcf2aab8a9ccac6337c88375005e5152404 100644 (file)
@@ -40,6 +40,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
                cpu_tlbstate[cpu].active_mm = next;
 #endif
                set_bit(cpu, &next->cpu_vm_mask);
+               set_bit(cpu, &next->context.cpuvalid);
                /* Re-load page tables */
                asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
        }
@@ -54,6 +55,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
                         */
                        local_flush_tlb();
                }
+               if (!test_and_set_bit(cpu, &next->context.cpuvalid))
+                       load_LDT(next);
        }
 #endif
 }
index 8bf9bd75c53aa92a106dfd744bed8a3592e810a7..40d17970405599c896fb2fb6fa950bb17cd24a71 100644 (file)
@@ -96,7 +96,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 } while (0)
 
 /* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static __inline__ int get_order(unsigned long size)
 {
        int order;
 
index 3c5f5c01fba62314684551e264b31df2517f4c8c..78c41d1397671677cac2cdd9549fdd540c67a057 100644 (file)
@@ -61,7 +61,7 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
  * Once the device is given the dma address, the device owns this memory
  * until either pci_unmap_single or pci_dma_sync_single is performed.
  */
-extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
                                        size_t size, int direction)
 {
        if (direction == PCI_DMA_NONE)
@@ -76,7 +76,7 @@ extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
  * After this call, reads by the cpu to the buffer are guarenteed to see
  * whatever the device wrote there.
  */
-extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
                                    size_t size, int direction)
 {
        if (direction == PCI_DMA_NONE)
@@ -99,7 +99,7 @@ extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
  * Device ownership issues as mentioned above for pci_map_single are
  * the same here.
  */
-extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                             int nents, int direction)
 {
        if (direction == PCI_DMA_NONE)
@@ -111,7 +111,7 @@ extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
  * Again, cpu read rules concerning calls here are the same as for
  * pci_unmap_single() above.
  */
-extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
                                int nents, int direction)
 {
        if (direction == PCI_DMA_NONE)
@@ -128,7 +128,7 @@ extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
  * next point you give the PCI dma address back to the card, the
  * device again owns the buffer.
  */
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
                                       dma_addr_t dma_handle,
                                       size_t size, int direction)
 {
@@ -143,7 +143,7 @@ extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
  * The same as pci_dma_sync_single but for a scatter-gather list,
  * same rules and usage.
  */
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
                                   struct scatterlist *sg,
                                   int nelems, int direction)
 {
@@ -157,7 +157,7 @@ extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
  * only drive the low 24-bits during PCI bus mastering, then
  * you would pass 0x00ffffff as the mask to this function.
  */
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
 {
         /*
          * we fall back to GFP_DMA when the mask isn't all 1s,
index 9700268437f78d893a3c97b368b2b23619e0ca29..232e18ab7ce027f8620c872051ffb596c959ae9e 100644 (file)
@@ -23,7 +23,7 @@
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
 {
        int i;
        pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
@@ -48,7 +48,7 @@ out_oom:
 
 #else
 
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
 {
        pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
 
@@ -61,7 +61,7 @@ extern __inline__ pgd_t *get_pgd_slow(void)
 
 #endif
 
-extern __inline__ pgd_t *get_pgd_fast(void)
+static __inline__ pgd_t *get_pgd_fast(void)
 {
        unsigned long *ret;
 
@@ -74,14 +74,14 @@ extern __inline__ pgd_t *get_pgd_fast(void)
        return (pgd_t *)ret;
 }
 
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+static __inline__ void free_pgd_fast(pgd_t *pgd)
 {
        *(unsigned long *)pgd = (unsigned long) pgd_quicklist;
        pgd_quicklist = (unsigned long *) pgd;
        pgtable_cache_size++;
 }
 
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static __inline__ void free_pgd_slow(pgd_t *pgd)
 {
 #if CONFIG_X86_PAE
        int i;
@@ -116,14 +116,14 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long addr
        return (pte_t *)ret;
 }
 
-extern __inline__ void pte_free_fast(pte_t *pte)
+static __inline__ void pte_free_fast(pte_t *pte)
 {
        *(unsigned long *)pte = (unsigned long) pte_quicklist;
        pte_quicklist = (unsigned long *) pte;
        pgtable_cache_size++;
 }
 
-extern __inline__ void pte_free_slow(pte_t *pte)
+static __inline__ void pte_free_slow(pte_t *pte)
 {
        free_page((unsigned long)pte);
 }
@@ -219,7 +219,7 @@ extern struct tlb_state cpu_tlbstate[NR_CPUS];
 
 #endif
 
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
                                      unsigned long start, unsigned long end)
 {
        /* i386 does not keep any page table caches in TLB */
index bb5c2077e71ad7b2624acd7562902a5470f42683..0c3f8ae5207877765c396b57b7b3b90d0673d362 100644 (file)
@@ -29,9 +29,9 @@
  * setup: the pgd is never bad, and a pmd always exists (as it's folded
  * into the pgd entry)
  */
-extern inline int pgd_none(pgd_t pgd)          { return 0; }
-extern inline int pgd_bad(pgd_t pgd)           { return 0; }
-extern inline int pgd_present(pgd_t pgd)       { return 1; }
+static inline int pgd_none(pgd_t pgd)          { return 0; }
+static inline int pgd_bad(pgd_t pgd)           { return 0; }
+static inline int pgd_present(pgd_t pgd)       { return 1; }
 #define pgd_clear(xp)                          do { } while (0)
 
 /*
@@ -50,7 +50,7 @@ extern inline int pgd_present(pgd_t pgd)      { return 1; }
 #define pgd_page(pgd) \
 ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
 
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
 {
        return (pmd_t *) dir;
 }
index 6253c0585e1f504f6cedb36a78820ce2dd52dd22..3fe1853898321e0a79d61fd35fea9ab99f4a4fb3 100644 (file)
@@ -33,9 +33,9 @@
 #define pgd_ERROR(e) \
        printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
 
-extern inline int pgd_none(pgd_t pgd)          { return 0; }
-extern inline int pgd_bad(pgd_t pgd)           { return 0; }
-extern inline int pgd_present(pgd_t pgd)       { return 1; }
+static inline int pgd_none(pgd_t pgd)          { return 0; }
+static inline int pgd_bad(pgd_t pgd)           { return 0; }
+static inline int pgd_present(pgd_t pgd)       { return 1; }
 
 /* Rules for using set_pte: the pte being assigned *must* be
  * either not present or in a state where the hardware will
@@ -60,7 +60,7 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
  * We do not let the generic code free and clear pgd entries due to
  * this erratum.
  */
-extern inline void pgd_clear (pgd_t * pgd) { }
+static inline void pgd_clear (pgd_t * pgd) { }
 
 #define pgd_page(pgd) \
 ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
index 99b6c97c0eb1dae61146873df2db6d392e483d0e..2373655be7384b348e4012055a59a3839b946f6a 100644 (file)
@@ -119,7 +119,7 @@ extern void dodgy_tsc(void);
 /*
  * Generic CPUID function
  */
-extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
 {
        __asm__("cpuid"
                : "=a" (*eax),
@@ -132,7 +132,7 @@ extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
 /*
  * CPUID functions returning a single datum
  */
-extern inline unsigned int cpuid_eax(unsigned int op)
+static inline unsigned int cpuid_eax(unsigned int op)
 {
        unsigned int eax;
 
@@ -142,7 +142,7 @@ extern inline unsigned int cpuid_eax(unsigned int op)
                : "bx", "cx", "dx");
        return eax;
 }
-extern inline unsigned int cpuid_ebx(unsigned int op)
+static inline unsigned int cpuid_ebx(unsigned int op)
 {
        unsigned int eax, ebx;
 
@@ -152,7 +152,7 @@ extern inline unsigned int cpuid_ebx(unsigned int op)
                : "cx", "dx" );
        return ebx;
 }
-extern inline unsigned int cpuid_ecx(unsigned int op)
+static inline unsigned int cpuid_ecx(unsigned int op)
 {
        unsigned int eax, ecx;
 
@@ -162,7 +162,7 @@ extern inline unsigned int cpuid_ecx(unsigned int op)
                : "bx", "dx" );
        return ecx;
 }
-extern inline unsigned int cpuid_edx(unsigned int op)
+static inline unsigned int cpuid_edx(unsigned int op)
 {
        unsigned int eax, edx;
 
@@ -439,7 +439,7 @@ extern void release_segments(struct mm_struct * mm);
 /*
  * Return saved PC of a blocked thread.
  */
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
 {
        return ((unsigned long *)t->esp)[3];
 }
@@ -472,7 +472,7 @@ struct microcode {
 #define MICROCODE_IOCFREE      _IO('6',0)
 
 /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-extern inline void rep_nop(void)
+static inline void rep_nop(void)
 {
        __asm__ __volatile__("rep;nop");
 }
index 8ec8a87a07e3e2ccc05473cdafac4a8493e5d76d..9abf5427a9dcab0e781b7682595052f794bed402 100644 (file)
@@ -216,7 +216,7 @@ typedef struct sigevent {
 #ifdef __KERNEL__
 #include <linux/string.h>
 
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
 {
        if (from->si_code < 0)
                memcpy(to, from, sizeof(siginfo_t));
index b2b8a76f0b333b24d28f8adfd4329307af02151c..8740d4ea24832a14f2e700700eaa36cf9468b062 100644 (file)
@@ -179,23 +179,23 @@ typedef struct sigaltstack {
 
 #define __HAVE_ARCH_SIG_BITOPS
 
-extern __inline__ void sigaddset(sigset_t *set, int _sig)
+static __inline__ void sigaddset(sigset_t *set, int _sig)
 {
        __asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ void sigdelset(sigset_t *set, int _sig)
+static __inline__ void sigdelset(sigset_t *set, int _sig)
 {
        __asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
 }
 
-extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+static __inline__ int __const_sigismember(sigset_t *set, int _sig)
 {
        unsigned long sig = _sig - 1;
        return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
 }
 
-extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+static __inline__ int __gen_sigismember(sigset_t *set, int _sig)
 {
        int ret;
        __asm__("btl %2,%1\n\tsbbl %0,%0"
@@ -210,7 +210,7 @@ extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
 
 #define sigmask(sig)   (1UL << ((sig) - 1))
 
-extern __inline__ int sigfindinword(unsigned long word)
+static __inline__ int sigfindinword(unsigned long word)
 {
        __asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc");
        return word;
index 77e8642ed1dec99ec40df33c4ae3c5c01e5e37a2..68e7aa9f8843b5f6d613fa599ba0b0d05000f2af 100644 (file)
@@ -46,11 +46,11 @@ extern void zap_low_mappings (void);
  * This simplifies scheduling and IPI sending and
  * compresses data structures.
  */
-extern inline int cpu_logical_map(int cpu)
+static inline int cpu_logical_map(int cpu)
 {
        return cpu;
 }
-extern inline int cpu_number_map(int cpu)
+static inline int cpu_number_map(int cpu)
 {
        return cpu;
 }
@@ -77,7 +77,7 @@ extern void smp_store_cpu_info(int id);               /* Store per CPU info (like the initial
 
 #define smp_processor_id() (current->processor)
 
-extern __inline int hard_smp_processor_id(void)
+static __inline int hard_smp_processor_id(void)
 {
        /* we don't want to mark this access volatile - bad code generation */
        return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
index f6f29383b1136f7116943c73d1f671914f06b295..864351c543a46549a602518b0b2909a0d127b426 100644 (file)
@@ -40,7 +40,7 @@ do { \
  * so we only need to worry about other
  * CPU's.
  */
-extern __inline__ void lock_kernel(void)
+static __inline__ void lock_kernel(void)
 {
 #if 1
        if (!++current->lock_depth)
@@ -56,7 +56,7 @@ extern __inline__ void lock_kernel(void)
 #endif
 }
 
-extern __inline__ void unlock_kernel(void)
+static __inline__ void unlock_kernel(void)
 {
        if (current->lock_depth < 0)
                BUG();
index a4f097312bf2a161b3a2a2ce335acef770856861..d4d7899dc1aa92536ba52c7fe55434f9a1fcd9d8 100644 (file)
@@ -300,7 +300,7 @@ static inline void * __constant_memcpy3d(void * to, const void * from, size_t le
        return _mmx_memcpy(to, from, len);
 }
 
-extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
+static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
 {
        if (len < 512)
                return __memcpy(to, from, len);
index 357362e8fc4022722ed9d1c4c0f7c694d604f295..6f2f63a8e3d336294ce74d99dbabb83d904a77b5 100644 (file)
@@ -141,7 +141,7 @@ struct __xchg_dummy { unsigned long a[100]; };
  * might have an implicit FPU-save as a cost, so it's not
  * clear which path to go.)
  */
-extern inline void __set_64bit (unsigned long long * ptr,
+static inline void __set_64bit (unsigned long long * ptr,
                unsigned int low, unsigned int high)
 {
        __asm__ __volatile__ (
@@ -157,7 +157,7 @@ extern inline void __set_64bit (unsigned long long * ptr,
                :       "ax","dx","memory");
 }
 
-extern void inline __set_64bit_constant (unsigned long long *ptr,
+static inline void __set_64bit_constant (unsigned long long *ptr,
                                                 unsigned long long value)
 {
        __set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
@@ -165,7 +165,7 @@ extern void inline __set_64bit_constant (unsigned long long *ptr,
 #define ll_low(x)      *(((unsigned int*)&(x))+0)
 #define ll_high(x)     *(((unsigned int*)&(x))+1)
 
-extern void inline __set_64bit_var (unsigned long long *ptr,
+static inline void __set_64bit_var (unsigned long long *ptr,
                         unsigned long long value)
 {
        __set_64bit(ptr,ll_low(value), ll_high(value));
index 74c43e03f00ec8dc30d25e6180aef13a87932ab1..db7eedb37bea4b52fa9bd2ccd4167d26bef23b8d 100644 (file)
@@ -58,7 +58,7 @@ extern int __verify_write(const void *, unsigned long);
 
 #endif
 
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
 {
        return access_ok(type,addr,size) ? 0 : -EFAULT;
 }
index d99d1aef9d71666d07cb09c129faa5ff116b5a2a..1d3c1957f58052a7dc5e8350dba6e3a7549e6199 100644 (file)
@@ -25,13 +25,13 @@ typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4)));
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
-#define __CS_LOOP(old, new, ptr, op_val, op_string)                    \
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)            \
         __asm__ __volatile__("   l     %0,0(%2)\n"                     \
                              "0: lr    %1,%0\n"                                \
                              op_string "  %1,%3\n"                     \
                              "   cs    %0,%1,0(%2)\n"                  \
                              "   jl    0b"                             \
-                             : "=&d" (old), "=&d" (new)                        \
+                             : "=&d" (old_val), "=&d" (new_val)                \
                             : "a" (ptr), "d" (op_val) : "cc" );
 
 static __inline__ int atomic_read(atomic_t *v)
@@ -52,80 +52,80 @@ static __inline__ void atomic_set(atomic_t *v, int i)
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "ar");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "ar");
-       return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "ar");
+       return new_val;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-       int old, new;
-        __CS_LOOP(old, new, v, i, "ar");
-        return new < 0;
+       int old_val, new_val;
+        __CS_LOOP(old_val, new_val, v, i, "ar");
+        return new_val < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "sr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
-        return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
+        return new_val;
 }
 
 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
-       return new != 0;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
+       return new_val != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
-        return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
-        return new == 0;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, ~mask, "nr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, mask, "or");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, mask, "or");
 }
 
 /*
index 370841fe9ebf2de5171aede5f11c717b9ce601f4..2cce4acd2b2580850937aef668bcef075b4ef99b 100644 (file)
@@ -831,7 +831,7 @@ ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset)
                         "   icm  %0,2,1(%1)\n"
                         "   icm  %0,4,2(%1)\n"
                         "   icm  %0,8,3(%1)"
-                        : "=&a" (word) : "a" (p) );
+                        : "=&a" (word) : "a" (p) : "cc" );
                word >>= bit;
                 res = bit;
                 /* Look for zero in first longword */
index b2fb3b9551fb8fc7010a8ca830c8265789aada00..591aec7c79327c54c6d7b8036475eb8c23e04a87 100644 (file)
@@ -23,7 +23,7 @@ static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
           "        icm   %0,4,2(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)"
-          : "+&d" (x) : "a" (&temp) : "memory" );
+          : "+&d" (x) : "a" (&temp) : "cc" );
   return x;
 }
 
@@ -36,7 +36,7 @@ static __inline__ __const__ __u32 ___arch__swab32p(__u32 *x)
           "        icm   %0,4,2(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)"
-          : "=&d" (result) : "a" (x) );
+          : "=&d" (result) : "a" (x) : "cc" );
   return result;
 }
 
@@ -48,7 +48,7 @@ static __inline__ void ___arch__swab32s(__u32 *x)
           "        icm   0,2,1(%0)\n"
           "        ic    0,0(%0)\n"
           "        st    0,0(%0)"
-          : : "a" (x) : "0", "memory");
+          : : "a" (x) : "0", "memory", "cc");
 }
 
 static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
@@ -59,7 +59,7 @@ static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
           "        sth   %0,0(%1)\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)\n"
-          : "+&d" (x) : "a" (&temp) : "memory");
+          : "+&d" (x) : "a" (&temp) : "memory", "cc" );
   return x;
 }
 
@@ -71,7 +71,7 @@ static __inline__ __const__ __u16 ___arch__swab16p(__u16 *x)
           "        sr    %0,%0\n"
           "        icm   %0,2,1(%1)\n"
           "        ic    %0,0(%1)\n"
-          : "=&d" (result) : "a" (x) );
+          : "=&d" (result) : "a" (x) : "cc" );
   return result;
 }
 
@@ -81,7 +81,7 @@ static __inline__ void ___arch__swab16s(__u16 *x)
           "        icm   0,2,1(%0)\n"
           "        ic    0,0(%0)\n"
           "        sth   0,0(%0)"
-          : : "a" (x) : "0", "memory");
+          : : "a" (x) : "0", "memory", "cc" );
 }
 
 #define __arch__swab32(x) ___arch__swab32(x)
index ad82cf8e074ee322fcb0f4b344e86316b587359f..93565f5e01914f3df2126ff3069685e62a758b1d 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __ARCH_S390_CACHE_H
 #define __ARCH_S390_CACHE_H
 
-#define L1_CACHE_BYTES     16
+#define L1_CACHE_BYTES     256
+#define L1_CACHE_SHIFT     16
 
 #endif
index 6c06c9b7c6255fcbe97e3db88fc7891dabe82a59..26dc6d6ebba9d3eea42a2847c06e40790f40bca2 100644 (file)
@@ -6,49 +6,86 @@
  * 
  *  Generic channel device initialisation support. 
  */
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
 #include <linux/version.h>
 #include <asm/types.h>
 #include <linux/netdevice.h>
 
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
 /* chandev_type is a bitmask for registering & describing device types. */
 typedef enum
 {
-       none=0x0,
-       ctc=0x1,
-       escon=0x2,
-       lcs=0x4,
-       osad=0x8,
-       qeth=0x10,
-       claw=0x20,
+       chandev_type_none=0x0,
+       chandev_type_ctc=0x1,
+       chandev_type_escon=0x2,
+       chandev_type_lcs=0x4,
+       chandev_type_osad=0x8,
+       chandev_type_qeth=0x10,
+       chandev_type_claw=0x20,
 } chandev_type;
 
 typedef enum
 {
-       no_category,
-       network_device,
-       serial_device,
+       chandev_category_none,
+       chandev_category_network_device,
+       chandev_category_serial_device,
 } chandev_category;
 
+
+
+typedef struct
+{
+       int     irq;
+       u16     devno;
+       u16     cu_type;      /* control unit type */
+       u8      cu_model;     /* control unit model */
+       u16     dev_type;     /* device type */
+       u8      dev_model;    /* device model */
+       u8      pim;          /* path installed mask */
+       u8      chpid[8];     /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+       
+       char     host_name[CLAW_NAMELEN];    /* local host name */
+       char     adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+       char     api_type[CLAW_NAMELEN];     /* API type either TCPIP or API */
+} chandev_claw_info;
+
 /*
  * The chandev_probeinfo structure is passed to the device driver with configuration
  * info for which irq's & ports to use when attempting to probe the device.
  */
 typedef struct
 {
-        int     read_irq;
-       int     write_irq;
-       u16     read_devno;
-       u16     write_devno;
-        s16     port_protocol_no; /* -1 don't care */
+       chandev_subchannel_info read;
+       chandev_subchannel_info write;
+       chandev_subchannel_info data;
+       /* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+       /* buffers -1 means use the driver default the driver should set this field to the */
+       /* amount of memory it actually uses when returning this probeinfo to the channel */
+       /* device layer with chandev_initdevice */
+       s32     memory_usage_in_k;
+       chandev_claw_info       claw;
+       u8      data_exists; /* whether this device has a data channel */
+       u8      cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+       u8      chpid_info_inconsistent;  /* either ctc or schib info bad */
+        s16     port_protocol_no; /* 0 by default, set specifically when forcing */
        u8      hint_port_no;   /* lcs specific */
-       u8      max_port_no;    /* lcs specific */
+       u8      max_port_no;    /* lcs/qeth specific */
        chandev_type chan_type;
        u8      checksum_received_ip_pkts;
        u8      use_hw_stats; /* where available e.g. lcs */
-       u16     cu_type;      /* control unit type */
-       u8      cu_model;     /* control unit model */
-       u16     dev_type;     /* device type */
-       u8      dev_model;    /* device model */
+       u8      device_forced; /* indicates the device hasn't been autodetected */
        char    *parmstr;       /* driver specific parameters added by add_parms keyword */
        /* newdevice used internally by chandev.c */
        struct  chandev_activelist *newdevice; 
@@ -75,19 +112,21 @@ void chandev_free_irq(unsigned int irq, void *dev_id);
 
 typedef enum
 {
-       good=0,
-       not_oper,
-       first_msck=not_oper,
-       no_path,
-       revalidate,
-       gone,
-       last_msck,
+       chandev_status_good,
+       chandev_status_not_oper,
+       chandev_status_first_msck=chandev_status_not_oper,
+       chandev_status_no_path,
+       chandev_status_revalidate,
+       chandev_status_gone,
+       chandev_status_last_msck,
+       chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
 } chandev_msck_status;
 
 typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
 typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
 
 
 
@@ -103,7 +142,7 @@ typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_m
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
                               chandev_shutdownfunc shutdownfunc,
-                              chandev_reoperfunc reoperfunc,
+                              chandev_msck_notification_func msck_notfunc,
                               chandev_type chan_type);
 
 /* The chandev_unregister function is typically called when a module is being removed 
@@ -117,6 +156,33 @@ void chandev_unregister(chandev_probefunc probefunc,int call_shutdown);
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
 chandev_category category,chandev_unregfunc unreg_dev);
 
+/* This function builds a device name & copies it into destnamebuff suitable for calling 
+   init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice 
+   setting the buildfullname flag to TRUE will cause it to always build a full unique name based 
+   on basename either honouring the chandev_use_devno_names flag if set or starting at index 
+   0 & checking the namespace of the channel device layer itself for a free index, this
+   may be useful when one doesn't have control of the name an upper layer may choose.
+   It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
 /* chandev_initnetdevice registers a network device with the channel layer. 
  * It returns the device structure if successful,if dev=NULL it kmallocs it, 
  * On device initialisation failure it will kfree it under ALL curcumstances
@@ -148,8 +214,18 @@ struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
                                     void (*unreg_netdevfunc)(struct device *dev));
 #endif
 
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+                      s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+                       u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
 
 
 
index 3ae00a0702493e88b2b76065d351132bbc339855..f2621064c8dc4d91bb290835e593ce749ed6c12c 100644 (file)
@@ -67,20 +67,27 @@ csum_partial_copy(const char *src, char *dst, int len,unsigned int sum)
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
  */
-
 extern inline unsigned int 
-csum_partial_copy_from_user(const char *src, char *dst,
-                            int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
 {
-       if (copy_from_user(dst, src, len)) {
-               *errp = -EFAULT;
-               memset(dst, 0, len);
-               return sum;
-        }
-        return csum_partial(dst, len, sum);
+       int missing;
+
+       missing = copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *err_ptr = -EFAULT;
+       }
+               
+       return csum_partial(dst, len, sum);
 }
 
+
 extern inline unsigned int
 csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
 {
index 88e8fc04e96402bac577a1e8772dc9758092bcfd..fbc9f101febf432613e2df7cd27f40cc24e8bb6b 100644 (file)
@@ -20,7 +20,7 @@ static inline struct task_struct * get_current(void)
         struct task_struct *current;
         __asm__("lhi   %0,-8192\n\t"
                 "nr    %0,15"
-                : "=&r" (current) );
+                : "=&r" (current) : : "cc" );
         return current;
  }
 
index d82fc455c30a41fb8e57cff334f6fb3c4683cf97..3bde842ce28838d54d25096dba0afcc106dafccd 100644 (file)
@@ -374,8 +374,6 @@ extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
 int dasd_oper_handler (int irq, devreg_t * devreg);
 void dasd_schedule_bh (dasd_device_t *);
 
-debug_info_t *dasd_debug_area;
-
 #endif /* __KERNEL__ */
 
 #endif                         /* DASD_H */
index 6de9551b96293db7c1daefb16338c1119df6d0f9..9be9863c8160b9e54667ede15568016b9657b164 100644 (file)
@@ -53,7 +53,7 @@ struct __debug_entry{
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)        asm volatile ("STCK %0":"=m" (x))
+#define STCK(x)        asm volatile ("STCK %0" : "=m" (x) : : "cc" )
 
 typedef struct __debug_entry debug_entry_t;
 
index 0dbb5075443bf57e3adfd2d222296ac48569f17c..33fc55da42ef3e94cb3fafd2a1fbf9f6c7440539 100644 (file)
@@ -36,7 +36,7 @@
             "1: st   1,4+%1\n"                                 \
              "   lr   %0,0"                                    \
             : "=d" (__r), "+m" (__n)                           \
-            : "d" (base) : "0", "1", "2" );                    \
+            : "d" (base) : "0", "1", "2", "cc" );              \
        (n) = (__n);                                            \
         __r;                                                    \
 })
index 05a95993cc4f1a5d5700752728d2a95b32706bbe..651e6691729ef230b5f946251a479fab95c03c78 100644 (file)
 #include <asm/lowcore.h>
 #include <linux/sched.h>
 
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+       unsigned int __softirq_pending;
+       unsigned int __local_irq_count;
+       unsigned int __local_bh_count;
+       unsigned int __syscall_count;
+       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
 
-/*
- * Simple wrappers reducing source bloat.  S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu)    (safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu)      (safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu)   (safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu)    (safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu)     (safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else  /* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu)    ((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu)      ((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu)   ((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu)    ((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu)     ((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif /* CONFIG_SMP */
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
  */
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-  
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+       (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
   
 #ifndef CONFIG_SMP
-  
+
 #define hardirq_trylock(cpu)   (local_irq_count(cpu) == 0)
 #define hardirq_endlock(cpu)   do { } while (0)
   
@@ -63,7 +47,7 @@
 
 #define synchronize_irq()      do { } while (0)
 
-#else
+#else  /* CONFIG_SMP */
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
@@ -77,7 +61,7 @@ static inline void release_irqlock(int cpu)
        /* if we didn't own the irq lock, just ignore.. */
        if (atomic_read(&global_irq_holder) ==  cpu) {
                atomic_set(&global_irq_holder,NO_PROC_ID);
-               clear_bit(0,&global_irq_lock);
+               atomic_set(&global_irq_lock,0);
        }
 }
 
@@ -95,13 +79,14 @@ static inline void hardirq_exit(int cpu)
 
 static inline int hardirq_trylock(int cpu)
 {
-       return !atomic_read(&global_irq_count) && !test_bit(0,&global_irq_lock);
+       return !atomic_read(&global_irq_count) &&
+              !atomic_read(&global_irq_lock);
 }
 
 #define hardirq_endlock(cpu)   do { } while (0)
 
 extern void synchronize_irq(void);
 
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_SMP */
 
 #endif /* __ASM_HARDIRQ_H */
index 7d5232b65c5e5241fd8a396b1510b89efbfe01e0..07efa62c3e86312cd944091df83ec0c0373a8405 100644 (file)
 #include <linux/config.h>
 #include <asm/irq.h>
 
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline idaw_t *
+static inline addr_t *
 idal_alloc ( int nridaws )
 {
        if ( nridaws > 33 )
                BUG();
-       return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+       return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
 }
 
 static inline void 
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
 {
        kfree (idal);
 }
 
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
 /*
  * Function: set_normalized_cda
  * sets the address of the data in CCW
  * if necessary it allocates an IDAL and sets sthe appropriate flags
  */
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
 set_normalized_cda(ccw1_t * ccw, unsigned long address)
 {
-       ccw->cda = address;
-}
+       int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+       if (((address + ccw->count) >> 31) != 0) {
+               if (ccw->flags & CCW_FLAG_IDA)
+                       BUG();
+               address = __create_idal(address, ccw->count);
+               if (address)
+                       ccw->flags |= CCW_FLAG_IDA;
+               else
+                       ret = -ENOMEM;
+       }
 #endif
+       ccw->cda = (__u32) address;
+       return ret;
+}
 
 /*
  * Function: clear_normalized_cda
@@ -48,10 +63,12 @@ set_normalized_cda(ccw1_t * ccw, unsigned long address)
 static inline void
 clear_normalized_cda ( ccw1_t * ccw ) 
 {
+#if defined(CONFIG_ARCH_S390X)
        if ( ccw -> flags & CCW_FLAG_IDA ) {
-               idal_free ( (idaw_t *) (ccw -> cda ));
+               idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
                ccw -> flags &= ~CCW_FLAG_IDA;
        }
+#endif
        ccw -> cda = 0;
 }
 
index 715485b7273aeb9eb9833e5e0966708b32d2ac91..88da030e0c04e108619054b7c8dddb3e6f4d1bc2 100644 (file)
@@ -23,7 +23,7 @@
 #define __INITDATA      .section        ".data.init",#alloc,#write
 */
 
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
 
 #endif
 
index 11bd4217ab0903ff426a4de8f918f4fee5e3d92b..a9c1a917a8fc58fff291f28bcf995f3e82978471 100644 (file)
@@ -31,7 +31,7 @@ extern inline unsigned long virt_to_phys(volatile void * address)
                  "   jz     0f\n"
                  "   sr     %0,%0\n"
                  "0:"
-                 : "=a" (real_address) : "a" (address) );
+                 : "=a" (real_address) : "a" (address) : "cc" );
         return real_address;
 }
 
index 48f630f87177c23b4cddb58fa8f6d8246bb0806f..626af86e574db291960f8a962e1def8b936e61cb 100644 (file)
@@ -572,6 +572,10 @@ int s390_request_irq_special( int                      irq,
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
 
 /*
  * Some S390 specific IO instructions as inline
index 59dfe5698f1578be61bce38290e90fb5a8b64255..4eec0a973b492c1d9fb629803337c54d5f5ea973 100644 (file)
 #define __LC_SAVE_AREA                  0xC00
 #define __LC_KERNEL_STACK               0xC40
 #define __LC_KERNEL_LEVEL               0xC44
-#define __LC_IRQ_STAT                   0xC48
 #define __LC_CPUID                      0xC60
 #define __LC_CPUADDR                    0xC68
 #define __LC_IPLDEV                     0xC7C
 #define __LC_PANIC_MAGIC                0xE00
 
+#define __LC_PFAULT_INTPARM             0x080
+
 /* interrupt handler start with all io, external and mcck interrupt disabled */
 
 #define _RESTART_PSW_MASK    0x00080000
@@ -148,13 +149,7 @@ struct _lowcore
        __u32        kernel_stack;             /* 0xc40 */
        __u32        kernel_level;             /* 0xc44 */
        /* entry.S sensitive area start */
-       /* Next 6 words are the s390 equivalent of irq_stat */
-       __u32        __softirq_active;         /* 0xc48 */
-       __u32        __softirq_mask;           /* 0xc4c */
-       __u32        __local_irq_count;        /* 0xc50 */
-       __u32        __local_bh_count;         /* 0xc54 */
-       __u32        __syscall_count;          /* 0xc58 */
-       __u8         pad10[0xc60-0xc5c];       /* 0xc5c */
+       __u8         pad10[0xc60-0xc48];       /* 0xc5c */
        struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
        __u32        ipl_device;               /* 0xc7c */
        /* entry.S sensitive area end */
index 6bc18fcffdf5387351223cc9b1cbe0491833e3de..13d411495e2f2e3b5789b3fd1c2794b6c87f79b2 100644 (file)
@@ -28,7 +28,7 @@ static inline void clear_page(void *page)
        rp.subreg.odd = (unsigned long) 4096;
         asm volatile ("   slr  1,1\n"
                      "   mvcl %0,0"
-                     : "+&a" (rp) : : "memory", "1" );
+                     : "+&a" (rp) : : "memory", "cc", "1" );
 }
 
 static inline void copy_page(void *to, void *from)
@@ -37,7 +37,7 @@ static inline void copy_page(void *to, void *from)
                asm volatile ("   sr   0,0\n"
                              "   mvpg %0,%1"
                              : : "a" ((void *)(to)), "a" ((void *)(from))
-                             : "memory", "0" );
+                             : "memory", "cc", "0" );
        else
                asm volatile ("   mvc  0(256,%0),0(%1)\n"
                              "   mvc  256(256,%0),256(%1)\n"
index 3c83ec404513edebedfedec0cf602db667bc1528..bf316297a0cad689da701d2bdd58c79f502e8c3e 100644 (file)
@@ -345,7 +345,7 @@ extern inline pte_t pte_mkdirty(pte_t pte)
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-       asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+       asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
        return pte;
 }
 
@@ -364,7 +364,8 @@ static inline int ptep_test_and_clear_young(pte_t *ptep)
 
        asm volatile ("rrbe 0,%1\n\t"
                      "ipm  %0\n\t"
-                     "srl  %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+                     "srl  %0,28\n\t" 
+                      : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
        return ccode & 2;
 }
 
index 63f7a2a72c7a42bfeb1e8a0c683233d7ec061d0c..c8ee18c9ec1bff90cfe15e7f23fae93795e19435 100644 (file)
@@ -87,8 +87,10 @@ struct thread_struct
         /* perform syscall argument validation (get/set_fs) */
         mm_segment_t fs;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
-       addr_t  ieee_instruction_pointer; 
        /* Used to give failing instruction back to user for ieee exceptions */
+       addr_t  ieee_instruction_pointer; 
+        /* pfault_wait is used to block the process on a pfault event */
+       addr_t  pfault_wait;
 };
 
 typedef struct thread_struct thread_struct;
@@ -105,7 +107,8 @@ VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL }
               (__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
                      0,0,0,                                       \
                      (mm_segment_t) { 0,1},                       \
-                     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}       \
+                     (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
+                     0, 0                                         \
 }
 
 /* need to define ... */
@@ -196,7 +199,7 @@ static inline void disabled_wait(unsigned long code)
                       "    stctl 0,15,0x1c0\n" /* store control registers */
                       "    oi    0(%1),0x10\n" /* fake protection bit */
                       "    lpsw 0(%0)"
-                      : : "a" (dw_psw), "a" (&ctl_buf));
+                      : : "a" (dw_psw), "a" (&ctl_buf) : "cc" );
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
index f7b0bc7534b5f305cac2a2a86fdb722b058e0094..1e78ea8bf58bae63800b8e7ca62d4474b0423a90 100644 (file)
@@ -7,7 +7,8 @@
  *
  *  A little set of queue utilies.
  */
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
 #include <linux/stddef.h>
 
 typedef struct queue
@@ -29,12 +30,11 @@ static __inline__ void init_queue(qheader *qhead)
 }
 
 static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
-       queue *tail=qhead->tail;
-       member->next=NULL;
-       
+{      
        if(member)
        {
+               queue *tail=qhead->tail;
+
                if(tail)
                        tail->next=member;
                else
@@ -166,5 +166,5 @@ static __inline__ int remove_from_queue(qheader *qhead,queue *member)
        return(0);
 }
 
-
+#endif /* __ASM_QUEUE_H */
 
index f0b38a95a13e0a4a9e8c1522bf7ca08196a2c9c1..4a2fe2ff051763ebb8c0e9a3acd29fb66c0a153c 100644 (file)
@@ -37,11 +37,14 @@ typedef struct _devreg {
        oper_handler_func_t  oper_func;
 } devreg_t;
 
-#define DEVREG_EXACT_MATCH      0x00000001
-#define DEVREG_MATCH_DEV_TYPE   0x00000002
-#define DEVREG_MATCH_CU_TYPE    0x00000004
-#define DEVREG_NO_CU_INFO       0x00000008
-#define DEVREG_NO_DEV_INFO      0x00000010
+#define DEVREG_MATCH_CU_TYPE    0x00000001
+#define DEVREG_MATCH_CU_MODEL   0x00000002
+#define DEVREG_MATCH_DEV_TYPE   0x00000004
+#define DEVREG_MATCH_DEV_MODEL  0x00000008
+
+#define DEVREG_EXACT_MATCH      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO       (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
 
 #define DEVREG_TYPE_DEVNO       0x80000000
 #define DEVREG_TYPE_DEVCHARS    0x40000000
index 3fd494c14895b4650aa273264f48be9388f6f949..5e8885fccf5440025856b700df6acbf283a88e3c 100644 (file)
@@ -31,6 +31,22 @@ extern unsigned long machine_flags;
 #define MACHINE_HAS_CSP  (machine_flags & 8)
 #define MACHINE_HAS_MVPG (machine_flags & 16)
 
+#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED   (console_mode == 0)
+#define CONSOLE_IS_HWC         (console_mode == 1)
+#define CONSOLE_IS_3215                (console_mode == 2)
+#define CONSOLE_IS_3270                (console_mode == 3)
+#define SET_CONSOLE_HWC                do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215       do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270       do { console_mode = 3; } while (0)
+
 #else 
 
 #define IPL_DEVICE        0x10404
index ce1254eba62d00a28a79949d1ce2173d4f9fa305..b5fb68fe173fe8a33fad92b2d2e1fd8cc44afe23 100644 (file)
 #include <asm/hardirq.h>
 #include <asm/lowcore.h>
 
-#define cpu_bh_disable(cpu)    do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count(cpu)--; } while (0)
-
-#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
+#define local_bh_disable()                     \
+do {                                           \
+       local_bh_count(smp_processor_id())++;   \
+       barrier();                              \
+} while (0)
+
+#define __local_bh_enable()                    \
+do {                                           \
+       barrier();                              \
+       local_bh_count(smp_processor_id())--;   \
+} while (0)
+
+#define local_bh_enable()                              \
+do {                                                   \
+       if (!--local_bh_count(smp_processor_id())       \
+           && softirq_pending(smp_processor_id())) {   \
+               do_softirq();                           \
+               __sti();                                \
+       }                                               \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
index 2153385dac6a343ef453c33dcbec7e45c868f396..d03ee49ab7012c7cf3f61eca658c23c64591f687 100644 (file)
@@ -61,7 +61,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+a&" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                        break;
                 case 2:
                         if(((__u32)ptr)&1)
@@ -84,7 +84,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+a&" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                         break;
                 case 4:
                         if(((__u32)ptr)&3)
@@ -95,7 +95,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "    jl  0b\n"
                                 "    lr  %0,0\n"
                                 : "+d&" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                default:
                         abort();
@@ -149,7 +149,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
         __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
 
 #define __load_psw(psw) \
-       __asm__ __volatile__("lpsw %0" : : "m" (psw));
+       __asm__ __volatile__("lpsw %0" : : "m" (psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
        __asm__ __volatile__ ( \
@@ -185,7 +185,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (1<<(bit)) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
@@ -204,7 +204,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                 "    st    0,0(1)\n" \
                 "1:  ex    %1,4(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 /* For spinlocks etc */
index 77676d42f771adc21bf7ddab261242269254dfaa..d8bf6be498f29f0571fb3ae317e9eb30ed7df9a9 100644 (file)
@@ -102,7 +102,7 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -130,7 +130,7 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -158,7 +158,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -223,7 +223,7 @@ extern int __put_user_bad(void);
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                      \
@@ -248,7 +248,7 @@ extern int __put_user_bad(void);
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                     \
@@ -274,7 +274,7 @@ extern int __put_user_bad(void);
                                 ".previous"                               \
                                 : "=d" (x) , "=&d" (err)                  \
                                 : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                  \
+                                : "cc", "4" );                            \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -340,7 +340,7 @@ __copy_to_user_asm(void* to, const void* from,  long n)
                                "   .long  0b,__copy_to_user_fixup\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
@@ -378,7 +378,7 @@ __copy_from_user_asm(void* to, const void* from,  long n)
                                "   .long  0b,__copy_from_user_fixup\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "2", "3", "4", "5" );
+                                : "cc", "2", "3", "4", "5" );
         return n;
 }
 
@@ -436,7 +436,7 @@ __strncpy_from_user(char *dst, const char *src, long count)
                                 : "=&a" (len)
                                 : "a" (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "2", "3", "4", "memory" );
+                                : "2", "3", "4", "memory", "cc" );
         return len;
 }
 
index e97e7bbe3c0b1a8218b8f1da55df59dfda1a2ec6..a96e1786c058f017583b383ce4f74c995588b1b6 100644 (file)
@@ -25,13 +25,13 @@ typedef struct { volatile int counter; } atomic_t __attribute__ ((aligned (4)));
 
 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
 
-#define __CS_LOOP(old, new, ptr, op_val, op_string)                    \
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)            \
         __asm__ __volatile__("   l     %0,0(%2)\n"                     \
                              "0: lr    %1,%0\n"                                \
                              op_string "  %1,%3\n"                     \
                              "   cs    %0,%1,0(%2)\n"                  \
                              "   jl    0b"                             \
-                             : "=&d" (old), "=&d" (new)                        \
+                             : "=&d" (old_val), "=&d" (new_val)                \
                             : "a" (ptr), "d" (op_val) : "cc" );
 
 static __inline__ int atomic_read(atomic_t *v)
@@ -52,80 +52,80 @@ static __inline__ void atomic_set(atomic_t *v, int i)
 
 static __inline__ void atomic_add(int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "ar");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "ar");
 }
 
 static __inline__ int atomic_add_return (int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "ar");
-       return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "ar");
+       return new_val;
 }
 
 static __inline__ int atomic_add_negative(int i, atomic_t *v)
 {
-       int old, new;
-        __CS_LOOP(old, new, v, i, "ar");
-        return new < 0;
+       int old_val, new_val;
+        __CS_LOOP(old_val, new_val, v, i, "ar");
+        return new_val < 0;
 }
 
 static __inline__ void atomic_sub(int i, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, i, "sr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, i, "sr");
 }
 
 static __inline__ void atomic_inc(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
 }
 
 static __inline__ int atomic_inc_return(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
-        return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
+        return new_val;
 }
 
 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "ar");
-       return new != 0;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "ar");
+       return new_val != 0;
 }
 
 static __inline__ void atomic_dec(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
 }
 
 static __inline__ int atomic_dec_return(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
-       return new;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
+       return new_val;
 }
 
 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, 1, "sr");
-        return new == 0;
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, 1, "sr");
+        return new_val == 0;
 }
 
 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, ~mask, "nr");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, ~mask, "nr");
 }
 
 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
 {
-       int old, new;
-       __CS_LOOP(old, new, v, mask, "or");
+       int old_val, new_val;
+       __CS_LOOP(old_val, new_val, v, mask, "or");
 }
 
 /*
index ad82cf8e074ee322fcb0f4b344e86316b587359f..93565f5e01914f3df2126ff3069685e62a758b1d 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __ARCH_S390_CACHE_H
 #define __ARCH_S390_CACHE_H
 
-#define L1_CACHE_BYTES     16
+#define L1_CACHE_BYTES     256
+#define L1_CACHE_SHIFT     16
 
 #endif
index 6c06c9b7c6255fcbe97e3db88fc7891dabe82a59..26dc6d6ebba9d3eea42a2847c06e40790f40bca2 100644 (file)
@@ -6,49 +6,86 @@
  * 
  *  Generic channel device initialisation support. 
  */
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
 #include <linux/version.h>
 #include <asm/types.h>
 #include <linux/netdevice.h>
 
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
 /* chandev_type is a bitmask for registering & describing device types. */
 typedef enum
 {
-       none=0x0,
-       ctc=0x1,
-       escon=0x2,
-       lcs=0x4,
-       osad=0x8,
-       qeth=0x10,
-       claw=0x20,
+       chandev_type_none=0x0,
+       chandev_type_ctc=0x1,
+       chandev_type_escon=0x2,
+       chandev_type_lcs=0x4,
+       chandev_type_osad=0x8,
+       chandev_type_qeth=0x10,
+       chandev_type_claw=0x20,
 } chandev_type;
 
 typedef enum
 {
-       no_category,
-       network_device,
-       serial_device,
+       chandev_category_none,
+       chandev_category_network_device,
+       chandev_category_serial_device,
 } chandev_category;
 
+
+
+typedef struct
+{
+       int     irq;
+       u16     devno;
+       u16     cu_type;      /* control unit type */
+       u8      cu_model;     /* control unit model */
+       u16     dev_type;     /* device type */
+       u8      dev_model;    /* device model */
+       u8      pim;          /* path installed mask */
+       u8      chpid[8];     /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+       
+       char     host_name[CLAW_NAMELEN];    /* local host name */
+       char     adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+       char     api_type[CLAW_NAMELEN];     /* API type either TCPIP or API */
+} chandev_claw_info;
+
 /*
  * The chandev_probeinfo structure is passed to the device driver with configuration
  * info for which irq's & ports to use when attempting to probe the device.
  */
 typedef struct
 {
-        int     read_irq;
-       int     write_irq;
-       u16     read_devno;
-       u16     write_devno;
-        s16     port_protocol_no; /* -1 don't care */
+       chandev_subchannel_info read;
+       chandev_subchannel_info write;
+       chandev_subchannel_info data;
+       /* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+       /* buffers -1 means use the driver default the driver should set this field to the */
+       /* amount of memory it actually uses when returning this probeinfo to the channel */
+       /* device layer with chandev_initdevice */
+       s32     memory_usage_in_k;
+       chandev_claw_info       claw;
+       u8      data_exists; /* whether this device has a data channel */
+       u8      cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+       u8      chpid_info_inconsistent;  /* either ctc or schib info bad */
+        s16     port_protocol_no; /* 0 by default, set specifically when forcing */
        u8      hint_port_no;   /* lcs specific */
-       u8      max_port_no;    /* lcs specific */
+       u8      max_port_no;    /* lcs/qeth specific */
        chandev_type chan_type;
        u8      checksum_received_ip_pkts;
        u8      use_hw_stats; /* where available e.g. lcs */
-       u16     cu_type;      /* control unit type */
-       u8      cu_model;     /* control unit model */
-       u16     dev_type;     /* device type */
-       u8      dev_model;    /* device model */
+       u8      device_forced; /* indicates the device hasn't been autodetected */
        char    *parmstr;       /* driver specific parameters added by add_parms keyword */
        /* newdevice used internally by chandev.c */
        struct  chandev_activelist *newdevice; 
@@ -75,19 +112,21 @@ void chandev_free_irq(unsigned int irq, void *dev_id);
 
 typedef enum
 {
-       good=0,
-       not_oper,
-       first_msck=not_oper,
-       no_path,
-       revalidate,
-       gone,
-       last_msck,
+       chandev_status_good,
+       chandev_status_not_oper,
+       chandev_status_first_msck=chandev_status_not_oper,
+       chandev_status_no_path,
+       chandev_status_revalidate,
+       chandev_status_gone,
+       chandev_status_last_msck,
+       chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
 } chandev_msck_status;
 
 typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
 typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
 
 
 
@@ -103,7 +142,7 @@ typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_m
  */
 int chandev_register_and_probe(chandev_probefunc probefunc,
                               chandev_shutdownfunc shutdownfunc,
-                              chandev_reoperfunc reoperfunc,
+                              chandev_msck_notification_func msck_notfunc,
                               chandev_type chan_type);
 
 /* The chandev_unregister function is typically called when a module is being removed 
@@ -117,6 +156,33 @@ void chandev_unregister(chandev_probefunc probefunc,int call_shutdown);
 int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
 chandev_category category,chandev_unregfunc unreg_dev);
 
+/* This function builds a device name & copies it into destnamebuff suitable for calling 
+   init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice 
+   setting the buildfullname flag to TRUE will cause it to always build a full unique name based 
+   on basename either honouring the chandev_use_devno_names flag if set or starting at index 
+   0 & checking the namespace of the channel device layer itself for a free index, this
+   may be useful when one doesn't have control of the name an upper layer may choose.
+   It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
 /* chandev_initnetdevice registers a network device with the channel layer. 
  * It returns the device structure if successful,if dev=NULL it kmallocs it, 
  * On device initialisation failure it will kfree it under ALL curcumstances
@@ -148,8 +214,18 @@ struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
                                     void (*unreg_netdevfunc)(struct device *dev));
 #endif
 
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+                      s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+                       u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
 
 
 
index bb825c546257c11e309c0a33d767268baad7f448..8c436737e6f02649d19c59ccafabc3d64b8dc6ac 100644 (file)
@@ -67,18 +67,24 @@ csum_partial_copy(const char *src, char *dst, int len,unsigned int sum)
  *
  * here even more important to align src and dst on a 32-bit (or even
  * better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum.  If we catch an exception
+ * then zero the rest of the buffer.
  */
-
 extern inline unsigned int 
-csum_partial_copy_from_user(const char *src, char *dst,
-                            int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+                                          int len, unsigned int sum,
+                                          int *err_ptr)
 {
-       if (copy_from_user(dst, src, len)) {
-               *errp = -EFAULT;
-               memset(dst, 0, len);
-               return sum;
-        }
-        return csum_partial_inline(dst, len, sum);
+       int missing;
+
+       missing = copy_from_user(dst, src, len);
+       if (missing) {
+               memset(dst + len - missing, 0, missing);
+               *err_ptr = -EFAULT;
+       }
+               
+       return csum_partial(dst, len, sum);
 }
 
 extern inline unsigned int
index 617c758bd8fa24ab0e549476dfa896d72a40007b..e7307c4f0f31db1318b9afb3f4b5252ea25468a8 100644 (file)
@@ -20,7 +20,7 @@ static inline struct task_struct * get_current(void)
         struct task_struct *current;
         __asm__("lghi  %0,-16384\n\t"
                 "ngr   %0,15"
-                : "=&r" (current) );
+                : "=&r" (current) : : "cc" );
         return current;
  }
 
index d82fc455c30a41fb8e57cff334f6fb3c4683cf97..3bde842ce28838d54d25096dba0afcc106dafccd 100644 (file)
@@ -374,8 +374,6 @@ extern int (*genhd_dasd_fillgeo) (int, struct hd_geometry *);
 int dasd_oper_handler (int irq, devreg_t * devreg);
 void dasd_schedule_bh (dasd_device_t *);
 
-debug_info_t *dasd_debug_area;
-
 #endif /* __KERNEL__ */
 
 #endif                         /* DASD_H */
index 6de9551b96293db7c1daefb16338c1119df6d0f9..9be9863c8160b9e54667ede15568016b9657b164 100644 (file)
@@ -53,7 +53,7 @@ struct __debug_entry{
 #define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
                                              /* the entry information */
 
-#define STCK(x)        asm volatile ("STCK %0":"=m" (x))
+#define STCK(x)        asm volatile ("STCK %0" : "=m" (x) : : "cc" )
 
 typedef struct __debug_entry debug_entry_t;
 
index d5ec49dde35ec0c0266f818484cee2737d5c705f..aa3414ff5e969dfa7edad90e4a8a2a4f654af0ca 100644 (file)
 #include <asm/lowcore.h>
 #include <linux/sched.h>
 
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+       unsigned int __softirq_pending;
+       unsigned int __local_irq_count;
+       unsigned int __local_bh_count;
+       unsigned int __syscall_count;
+       struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
 
-/*
- * Simple wrappers reducing source bloat.  S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu)    (safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu)      (safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu)   (safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu)    (safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu)     (safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else  /* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu)    ((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu)      ((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu)   ((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu)    ((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu)     ((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif /* CONFIG_SMP */
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
 
 /*
  * Are we in an interrupt context? Either doing bottom half
  * or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
  */
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-  
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
-  
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+       (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
 #ifndef CONFIG_SMP
   
 #define hardirq_trylock(cpu)   (local_irq_count(cpu) == 0)
index 27748969242b5f9b2ad997fd00e6e010b0b2f011..07efa62c3e86312cd944091df83ec0c0373a8405 100644 (file)
 #include <linux/config.h>
 #include <asm/irq.h>
 
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
 
-static inline idaw_t *
+static inline addr_t *
 idal_alloc ( int nridaws )
 {
        if ( nridaws > 33 )
                BUG();
-       return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+       return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
 }
 
 static inline void 
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
 {
        kfree (idal);
 }
 
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
 /*
  * Function: set_normalized_cda
  * sets the address of the data in CCW
  * if necessary it allocates an IDAL and sets sthe appropriate flags
  */
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
 set_normalized_cda(ccw1_t * ccw, unsigned long address)
 {
-       ccw->cda = address;
-}
+       int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+       if (((address + ccw->count) >> 31) != 0) {
+               if (ccw->flags & CCW_FLAG_IDA)
+                       BUG();
+               address = __create_idal(address, ccw->count);
+               if (address)
+                       ccw->flags |= CCW_FLAG_IDA;
+               else
+                       ret = -ENOMEM;
+       }
 #endif
+       ccw->cda = (__u32) address;
+       return ret;
+}
 
 /*
  * Function: clear_normalized_cda
@@ -48,10 +63,12 @@ set_normalized_cda(ccw1_t * ccw, unsigned long address)
 static inline void
 clear_normalized_cda ( ccw1_t * ccw ) 
 {
+#if defined(CONFIG_ARCH_S390X)
        if ( ccw -> flags & CCW_FLAG_IDA ) {
-               idal_free ( (idaw_t *)(unsigned long) (ccw -> cda ));
+               idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
                ccw -> flags &= ~CCW_FLAG_IDA;
        }
+#endif
        ccw -> cda = 0;
 }
 
index 715485b7273aeb9eb9833e5e0966708b32d2ac91..88da030e0c04e108619054b7c8dddb3e6f4d1bc2 100644 (file)
@@ -23,7 +23,7 @@
 #define __INITDATA      .section        ".data.init",#alloc,#write
 */
 
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
 
 #endif
 
index 9a4aabd6f6f0fa2bab605f5c178c41c44ff96546..2d0d2e79a274e758b32b7d681cb6e0ed4724b34c 100644 (file)
@@ -31,7 +31,7 @@ extern inline unsigned long virt_to_phys(volatile void * address)
                  "   jz     0f\n"
                  "   slgr   %0,%0\n"
                  "0:"
-                 : "=a" (real_address) : "a" (address) );
+                 : "=a" (real_address) : "a" (address) : "cc" );
         return real_address;
 }
 
index 48f630f87177c23b4cddb58fa8f6d8246bb0806f..626af86e574db291960f8a962e1def8b936e61cb 100644 (file)
@@ -572,6 +572,10 @@ int s390_request_irq_special( int                      irq,
 extern int set_cons_dev(int irq);
 extern int reset_cons_dev(int irq);
 extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
 
 /*
  * Some S390 specific IO instructions as inline
index fe03e63516f454f3da31dd4f4fe78e9557dd8435..1594560ae6abc9300a5621e7a6491c8916331eb8 100644 (file)
 #define __LC_MCCK_CODE                  0x0E8
 
 #define __LC_SAVE_AREA                  0xC00
-#define __LC_CREGS_SAVE_AREA            0xC80
-#define __LC_AREGS_SAVE_AREA            0xD00
 #define __LC_KERNEL_STACK               0xD40
 #define __LC_KERNEL_LEVEL               0xD48
-#define __LC_IRQ_STAT                   0xD50
 #define __LC_CPUID                      0xD90
 #define __LC_CPUADDR                    0xD98
 #define __LC_IPLDEV                     0xDB8
 
 #define __LC_PANIC_MAGIC                0xE00
 
+#define __LC_AREGS_SAVE_AREA            0x1340
+#define __LC_CREGS_SAVE_AREA            0x1380
+
+#define __LC_PFAULT_INTPARM             0x11B8
 
 /* interrupt handler start with all io, external and mcck interrupt disabled */
 
@@ -139,21 +140,14 @@ struct _lowcore
         __u8         pad8[0xc00-0x214];        /* 0x214 */
         /* System info area */
        __u64        save_area[16];            /* 0xc00 */
-       __u64        cregs_save_area[16];      /* 0xc80 */
-       __u32        access_regs_save_area[16];/* 0xd00 */
+        __u8         pad9[0xd40-0xc80];        /* 0xc80 */
        __u64        kernel_stack;             /* 0xd40 */
        __u64        kernel_level;             /* 0xd48 */
        /* entry.S sensitive area start */
-       /* Next 6 words are the s390 equivalent of irq_stat */
-       __u32        __softirq_active;         /* 0xd50 */
-       __u32        __softirq_mask;           /* 0xd54 */
-       __u32        __local_irq_count;        /* 0xd58 */
-       __u32        __local_bh_count;         /* 0xd5c */
-       __u32        __syscall_count;          /* 0xd60 */
-       __u8         pad10[0xd80-0xd64];       /* 0xd64 */
+       __u8         pad10[0xd80-0xd50];       /* 0xd64 */
        struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
        __u32        ipl_device;               /* 0xdb8 */
-       __u32        pad13;                    /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
+       __u32        pad11;                    /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
        /* entry.S sensitive area end */
 
         /* SMP info area: defined by DJB */
@@ -162,14 +156,33 @@ struct _lowcore
        __u64        ext_call_queue;           /* 0xdd0 */
         __u64        ext_call_count;           /* 0xdd8 */
 
-        __u8         pad11[0xe00-0xde0];       /* 0xde0 */
+        __u8         pad12[0xe00-0xde0];       /* 0xde0 */
 
         /* 0xe00 is used as indicator for dump tools */
         /* whether the kernel died with panic() or not */
         __u32        panic_magic;              /* 0xe00 */
 
-        /* Align to the top 1k of prefix area */
-       __u8         pad12[0x1000-0xe04];      /* 0xe04 */
+       __u8         pad13[0x1200-0xe04];      /* 0xe04 */
+
+        /* System info area */ 
+
+       __u64        floating_pt_save_area[16]; /* 0x1200 */
+       __u64        gpregs_save_area[16];      /* 0x1280 */
+       __u32        st_status_fixed_logout[4]; /* 0x1300 */
+       __u8         pad14[0x1318-0x1310];      /* 0x1310 */
+       __u32        prefixreg_save_area;       /* 0x1318 */
+       __u32        fpt_creg_save_area;        /* 0x131c */
+       __u8         pad15[0x1324-0x1320];      /* 0x1320 */
+       __u32        tod_progreg_save_area;     /* 0x1324 */
+       __u32        cpu_timer_save_area[2];    /* 0x1328 */
+       __u32        clock_comp_save_area[2];   /* 0x1330 */
+       __u8         pad16[0x1340-0x1338];      /* 0x1338 */ 
+       __u32        access_regs_save_area[16]; /* 0x1340 */ 
+       __u64        cregs_save_area[16];       /* 0x1380 */
+
+       /* align to the top of the prefix area */
+
+       __u8         pad17[0x2000-0x1400];      /* 0x1400 */
 } __attribute__((packed)); /* End structure*/
 
 extern __inline__ void set_prefix(__u32 address)
index dda09319f6607e20cd0a219c794d85d3a349ff5a..afad87da7b1fdec0da7349f0cd0dd2b1e17e9609 100644 (file)
@@ -26,7 +26,7 @@ static inline void clear_page(void *page)
                       "   slgr 1,1\n"
                       "   mvcl 2,0"
                       : : "a" ((void *) (page))
-                     : "memory", "1", "2", "3" );
+                     : "memory", "cc", "1", "2", "3" );
 }
 
 static inline void copy_page(void *to, void *from)
@@ -35,7 +35,7 @@ static inline void copy_page(void *to, void *from)
                asm volatile ("   sgr  0,0\n"
                              "   mvpg %0,%1"
                              : : "a" ((void *)(to)), "a" ((void *)(from))
-                             : "memory", "0" );
+                             : "memory", "cc", "0" );
        else
                asm volatile ("   mvc  0(256,%0),0(%1)\n"
                              "   mvc  256(256,%0),256(%1)\n"
diff --git a/include/asm-s390x/pci.h b/include/asm-s390x/pci.h
new file mode 100644 (file)
index 0000000..f2d43cb
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __ASM_S390_PCI_H
+#define __ASM_S390_PCI_H
+
+/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code
+ * includes it even if CONFIG_PCI is not set.
+ */
+
+#endif /* __ASM_S390_PCI_H */
+
index 96d527d64ca85014b1f72fef4aaaac9de67343ac..6a8e42e15973cd051618deaf6efecb0bbcbfb431 100644 (file)
@@ -253,7 +253,7 @@ static inline void global_flush_tlb(void)
                 "    slr  2,2\n"
                 "    slr  3,3\n"
                 "    csp  2,4"
-                : : "a" (&dummy) : "2", "3", "4" );
+                : : "a" (&dummy) : "cc", "2", "3", "4" );
 }
 
 /*
index 28309a0f43e36d3842344c3e833e9560559d3472..21937e571f5b6b89e8c81fa591699098e51836b7 100644 (file)
@@ -180,7 +180,7 @@ extern char empty_zero_page[PAGE_SIZE];
  */
 #define _REGION_THIRD       0x4
 #define _REGION_THIRD_LEN   0x3 
-#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN)
+#define _REGION_TABLE       (_REGION_THIRD|_REGION_THIRD_LEN|0x40)
 
 /* Bits in the storage key */
 #define _PAGE_CHANGED    0x02          /* HW changed bit                   */
@@ -363,7 +363,7 @@ extern inline pte_t pte_mkdirty(pte_t pte)
 
 extern inline pte_t pte_mkold(pte_t pte)
 {
-       asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+       asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
        return pte;
 }
 
@@ -382,7 +382,8 @@ static inline int ptep_test_and_clear_young(pte_t *ptep)
 
        asm volatile ("rrbe 0,%1\n\t"
                      "ipm  %0\n\t"
-                     "srl  %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+                     "srl  %0,28\n\t"
+                     : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
        return ccode & 2;
 }
 
index ea6561100a619f8475cb051cc5f52669710fa6e6..84bbf3db83131c46ed70ad527ea43ce83242f1e7 100644 (file)
@@ -90,9 +90,11 @@ struct thread_struct
         __u32   error_code;            /* error-code of last prog-excep.   */
         __u32   trap_no;
         per_struct per_info;/* Must be aligned on an 4 byte boundary*/
-       addr_t  ieee_instruction_pointer; 
        /* Used to give failing instruction back to user for ieee exceptions */
+       addr_t  ieee_instruction_pointer; 
        unsigned long flags;            /* various flags */
+        /* pfault_wait is used to block the process on a pfault event */
+       addr_t  pfault_wait;
 };
 
 typedef struct thread_struct thread_struct;
@@ -109,7 +111,7 @@ VM_READ | VM_WRITE | VM_EXEC, 1, NULL,NULL }
               (__pa((addr_t) &swapper_pg_dir[0]) + _REGION_TABLE),\
                      0,0,0,                                       \
                      (per_struct) {{{{0,}}},0,0,0,0,{{0,}}},      \
-                    0                                            \
+                    0, 0, 0                                      \
 } 
 
 /* need to define ... */
@@ -220,7 +222,7 @@ static inline void disabled_wait(addr_t code)
                       "    stctg 0,15,0x380(1)\n" /* store control registers */
                       "    oi    0x384(1),0x10\n" /* fake protection bit */
                       "    lpswe 0(%0)"
-                      : : "a" (dw_psw), "a" (&ctl_buf) : "0", "1");
+                      : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
 }
 
 #endif                                 /* __ASM_S390_PROCESSOR_H           */
index f7b0bc7534b5f305cac2a2a86fdb722b058e0094..1e78ea8bf58bae63800b8e7ca62d4474b0423a90 100644 (file)
@@ -7,7 +7,8 @@
  *
  *  A little set of queue utilies.
  */
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
 #include <linux/stddef.h>
 
 typedef struct queue
@@ -29,12 +30,11 @@ static __inline__ void init_queue(qheader *qhead)
 }
 
 static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
-       queue *tail=qhead->tail;
-       member->next=NULL;
-       
+{      
        if(member)
        {
+               queue *tail=qhead->tail;
+
                if(tail)
                        tail->next=member;
                else
@@ -166,5 +166,5 @@ static __inline__ int remove_from_queue(qheader *qhead,queue *member)
        return(0);
 }
 
-
+#endif /* __ASM_QUEUE_H */
 
index f0b38a95a13e0a4a9e8c1522bf7ca08196a2c9c1..4a2fe2ff051763ebb8c0e9a3acd29fb66c0a153c 100644 (file)
@@ -37,11 +37,14 @@ typedef struct _devreg {
        oper_handler_func_t  oper_func;
 } devreg_t;
 
-#define DEVREG_EXACT_MATCH      0x00000001
-#define DEVREG_MATCH_DEV_TYPE   0x00000002
-#define DEVREG_MATCH_CU_TYPE    0x00000004
-#define DEVREG_NO_CU_INFO       0x00000008
-#define DEVREG_NO_DEV_INFO      0x00000010
+#define DEVREG_MATCH_CU_TYPE    0x00000001
+#define DEVREG_MATCH_CU_MODEL   0x00000002
+#define DEVREG_MATCH_DEV_TYPE   0x00000004
+#define DEVREG_MATCH_DEV_MODEL  0x00000008
+
+#define DEVREG_EXACT_MATCH      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO       (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO      (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
 
 #define DEVREG_TYPE_DEVNO       0x80000000
 #define DEVREG_TYPE_DEVCHARS    0x40000000
index 7f1b076b18412640ec95c1c6ba7939ba17ace3b2..86e5a799e2e24b068310bc8cbac05026ffd0ecb7 100644 (file)
@@ -29,6 +29,22 @@ extern unsigned long machine_flags;
 #define MACHINE_IS_P390  (machine_flags & 4)
 #define MACHINE_HAS_MVPG (machine_flags & 16)
 
+#define MACHINE_HAS_HWC  (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED   (console_mode == 0)
+#define CONSOLE_IS_HWC         (console_mode == 1)
+#define CONSOLE_IS_3215                (console_mode == 2)
+#define CONSOLE_IS_3270                (console_mode == 3)
+#define SET_CONSOLE_HWC                do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215       do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270       do { console_mode = 3; } while (0)
+
 #else 
 
 #define IPL_DEVICE        0x10400
index d3841f92be356e7dfe32e134d80e82c91890e4b2..e1a18c8eb9ca5df2a5cb34f623b0d0e1700931d6 100644 (file)
@@ -166,9 +166,9 @@ struct sigaction {
           __sighandler_t _sa_handler;
           void (*_sa_sigaction)(int, struct siginfo *, void *);
         } _u;
-        sigset_t sa_mask;
         unsigned long sa_flags;
         void (*sa_restorer)(void);
+       sigset_t sa_mask;
 };
 
 #define sa_handler      _u._sa_handler
index ce1254eba62d00a28a79949d1ce2173d4f9fa305..b5fb68fe173fe8a33fad92b2d2e1fd8cc44afe23 100644 (file)
 #include <asm/hardirq.h>
 #include <asm/lowcore.h>
 
-#define cpu_bh_disable(cpu)    do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu)     do { barrier(); local_bh_count(cpu)--; } while (0)
-
-#define local_bh_disable()     cpu_bh_disable(smp_processor_id())
-#define local_bh_enable()      cpu_bh_enable(smp_processor_id())
+#define local_bh_disable()                     \
+do {                                           \
+       local_bh_count(smp_processor_id())++;   \
+       barrier();                              \
+} while (0)
+
+#define __local_bh_enable()                    \
+do {                                           \
+       barrier();                              \
+       local_bh_count(smp_processor_id())--;   \
+} while (0)
+
+#define local_bh_enable()                              \
+do {                                                   \
+       if (!--local_bh_count(smp_processor_id())       \
+           && softirq_pending(smp_processor_id())) {   \
+               do_softirq();                           \
+               __sti();                                \
+       }                                               \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
 
 #define in_softirq() (local_bh_count(smp_processor_id()) != 0)
 
index c6d049e42a03c4c396c8509095298feffc0b086f..6715f022d4613c2ae9c07703a3a07c754c2d2971 100644 (file)
@@ -63,7 +63,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+&a" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                        break;
                 case 2:
                         if(((addr_t)ptr)&1)
@@ -86,7 +86,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "   jl    1b\n"
                                 "   ex    0,4(2)"     /* store *ptr to x */
                                 : "+&a" (ptr) : "a" (&x)
-                                : "memory", "0", "1", "2");
+                                : "memory", "cc", "0", "1", "2");
                         break;
                 case 4:
                         if(((addr_t)ptr)&3)
@@ -97,7 +97,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "    jl   0b\n"
                                 "    lgfr %0,0\n"
                                 : "+d" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                 case 8:
                         if(((addr_t)ptr)&7)
@@ -108,7 +108,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                                 "    jl  0b\n"
                                 "    lgr %0,0\n"
                                 : "+d" (x) : "a" (ptr)
-                                : "memory", "0" );
+                                : "memory", "cc", "0" );
                         break;
                default:
                         abort();
@@ -161,7 +161,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
         __asm__ __volatile__("ssm   %0" : : "m" (x) : "memory")
 
 #define __load_psw(psw) \
-        __asm__ __volatile__("lpswe %0" : : "m" (psw));
+        __asm__ __volatile__("lpswe %0" : : "m" (psw) : "cc" );
 
 #define __ctl_load(array, low, high) ({ \
        __asm__ __volatile__ ( \
@@ -196,7 +196,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (1L<<(bit)) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 #define __ctl_clear_bit(cr, bit) ({ \
@@ -214,7 +214,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
                 "    stg   0,0(1)\n" \
                 "1:  ex    %1,6(2)"      /* execute lctl */ \
                 : "=m" (dummy) : "a" (cr*17), "a" (~(1L<<(bit))) \
-                : "0", "1", "2"); \
+                : "cc", "0", "1", "2"); \
         })
 
 /* For spinlocks etc */
index 24812b2c988fc737288f17bba2627cc18cbff647..a5da5be9e1a75a9f6fd5621731153b09d7c06868 100644 (file)
@@ -63,7 +63,7 @@ struct termio {
 #define N_IRDA         11      /* Linux IR - http://irda.sourceforge.net/ */
 #define N_SMSBLOCK     12      /* SMS block mode - for talking to GSM data cards about SMS messages */
 #define N_HDLC         13      /* synchronous HDLC */
-#define N_BT           15      /* bluetooth */
+#define N_HCI          15      /* Bluetooth HCI UART */
 
 #ifdef __KERNEL__
 
index 7e6cd7252d430dd7fffbad813e357998eab82916..9e51bb54f2a84081e19f7e54acfa3291870a192a 100644 (file)
@@ -97,7 +97,7 @@ extern inline int __put_user_asm_8(__u64 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u64*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 extern inline int __put_user_asm_4(__u32 x, void *ptr)
@@ -119,7 +119,7 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u32*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -142,7 +142,7 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u16*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "4" );
+                                : "cc", "4" );
         return err;
 }
 
@@ -165,7 +165,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr)
                                ".previous"
                                 : "=m" (*((__u8*) ptr)) , "=&d" (err)
                                 : "d" (x), "K" (-EFAULT)
-                                : "1", "4" );
+                                : "cc", "1", "4" );
         return err;
 }
 
@@ -228,7 +228,7 @@ extern int __put_user_bad(void);
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u64*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 #define __get_user_asm_4(x, ptr, err)                                      \
 ({                                                                         \
@@ -247,7 +247,7 @@ extern int __put_user_bad(void);
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_2(x, ptr, err)                                      \
@@ -267,7 +267,7 @@ extern int __put_user_bad(void);
                                 ".previous"                                \
                                 : "=d" (x) , "=&d" (err)                   \
                                 : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                   \
+                                : "cc", "4" );                             \
 })
 
 #define __get_user_asm_1(x, ptr, err)                                     \
@@ -288,7 +288,7 @@ extern int __put_user_bad(void);
                                 ".previous"                               \
                                 : "=d" (x) , "=&d" (err)                  \
                                 : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
-                                : "4" );                                  \
+                                : "cc", "4" );                            \
 })
 
 #define __get_user(x, ptr)                                      \
@@ -357,7 +357,7 @@ __copy_to_user_asm(void* to, const void* from,  long n)
                                "   .quad  0b,__copy_to_user_fixup\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "cc", "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -395,7 +395,7 @@ __copy_from_user_asm(void* to, const void* from,  long n)
                                "   .quad  0b,__copy_from_user_fixup\n"
                                ".previous"
                                 : "+&d" (n) : "d" (to), "d" (from)
-                                : "1", "2", "3", "4", "5" );
+                                : "cc", "1", "2", "3", "4", "5" );
         return n;
 }
 
@@ -450,7 +450,7 @@ __strncpy_from_user(char *dst, const char *src, long count)
                                 : "=&a" (len)
                                 : "a"  (dst), "d" (src), "d" (count),
                                   "K" (-EFAULT)
-                                : "2" ,"3", "4" );
+                                : "cc", "2" ,"3", "4" );
         return len;
 }
 
index 090fe68de56d0b2473779b7640a60b6845508fdc..34b72ab5b1a32b12751d38b88e4897b0b8046bef 100644 (file)
 #define __NR_mincore            218
 #define __NR_madvise            219
 #define __NR_getdents64         220
-#define __NR_fcntl64            221
 
 
 /* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
index f75dccef48bf8333943bafc5f0b6ce223b6875f8..814b4519ff2110132924d47b0d13b8660ec3cafb 100644 (file)
 #endif /* OPTIMIZE */
 
 
-extern __inline__ __const__ __u16 __fswab16(__u16 x)
+static __inline__ __const__ __u16 __fswab16(__u16 x)
 {
        return __arch__swab16(x);
 }
-extern __inline__ __u16 __swab16p(__u16 *x)
+static __inline__ __u16 __swab16p(__u16 *x)
 {
        return __arch__swab16p(x);
 }
-extern __inline__ void __swab16s(__u16 *addr)
+static __inline__ void __swab16s(__u16 *addr)
 {
        __arch__swab16s(addr);
 }
 
-extern __inline__ __const__ __u32 __fswab32(__u32 x)
+static __inline__ __const__ __u32 __fswab32(__u32 x)
 {
        return __arch__swab32(x);
 }
-extern __inline__ __u32 __swab32p(__u32 *x)
+static __inline__ __u32 __swab32p(__u32 *x)
 {
        return __arch__swab32p(x);
 }
-extern __inline__ void __swab32s(__u32 *addr)
+static __inline__ void __swab32s(__u32 *addr)
 {
        __arch__swab32s(addr);
 }
 
 #ifdef __BYTEORDER_HAS_U64__
-extern __inline__ __const__ __u64 __fswab64(__u64 x)
+static __inline__ __const__ __u64 __fswab64(__u64 x)
 {
 #  ifdef __SWAB_64_THRU_32__
        __u32 h = x >> 32;
@@ -165,11 +165,11 @@ extern __inline__ __const__ __u64 __fswab64(__u64 x)
        return __arch__swab64(x);
 #  endif
 }
-extern __inline__ __u64 __swab64p(__u64 *x)
+static __inline__ __u64 __swab64p(__u64 *x)
 {
        return __arch__swab64p(x);
 }
-extern __inline__ void __swab64s(__u64 *addr)
+static __inline__ void __swab64s(__u64 *addr)
 {
        __arch__swab64s(addr);
 }
index 3ce8382190f1031c10da3b23ddbf39a5843274a6..d28d9a804d3bc0c92e2dcde511e430b4c7a681ef 100644 (file)
 #endif /* OPTIMIZE */
 
 
-extern __inline__ __const__ __u32 __fswahw32(__u32 x)
+static __inline__ __const__ __u32 __fswahw32(__u32 x)
 {
        return __arch__swahw32(x);
 }
-extern __inline__ __u32 __swahw32p(__u32 *x)
+static __inline__ __u32 __swahw32p(__u32 *x)
 {
        return __arch__swahw32p(x);
 }
-extern __inline__ void __swahw32s(__u32 *addr)
+static __inline__ void __swahw32s(__u32 *addr)
 {
        __arch__swahw32s(addr);
 }
 
 
-extern __inline__ __const__ __u32 __fswahb32(__u32 x)
+static __inline__ __const__ __u32 __fswahb32(__u32 x)
 {
        return __arch__swahb32(x);
 }
-extern __inline__ __u32 __swahb32p(__u32 *x)
+static __inline__ __u32 __swahb32p(__u32 *x)
 {
        return __arch__swahb32p(x);
 }
-extern __inline__ void __swahb32s(__u32 *addr)
+static __inline__ void __swahb32s(__u32 *addr)
 {
        __arch__swahb32s(addr);
 }
index 4958aacbab2095ad569b8dfedab6b645c1cd55e9..a716192ba71630ab193e826e8091de78df487199 100644 (file)
@@ -997,7 +997,7 @@ static inline int locks_verify_truncate(struct inode *inode,
        return 0;
 }
 
-extern inline int get_lease(struct inode *inode, unsigned int mode)
+static inline int get_lease(struct inode *inode, unsigned int mode)
 {
        if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
                return __get_lease(inode, mode);
index b9cc125a436c94a6b2b8339422b91ab6ac066a78..3ac12961d8023c2e1434656f06f854319c9f39e7 100644 (file)
@@ -210,43 +210,43 @@ void unregister_hdlc_device(hdlc_device *hdlc);
 void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
 
 
-extern __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
+static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
 {
        return &hdlc->netdev;
 }
 
 
-extern __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
 {
        return (hdlc_device*)dev;
 }
 
 
-extern __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
+static __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
 {
        return &pvc->netdev;
 }
 
 
-extern __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
 {
        return (pvc_device*)dev;
 }
 
 
-extern __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
+static __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
 {
        return hdlc_to_dev(hdlc)->name;
 }
 
 
-extern __inline__ const char *pvc_to_name(pvc_device *pvc)
+static __inline__ const char *pvc_to_name(pvc_device *pvc)
 {
        return pvc_to_dev(pvc)->name;
 }
 
 
-extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
+static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
 {
        *state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
        if (status[2] & 0x08)
@@ -258,7 +258,7 @@ extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
 }
 
 
-extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
                                      u8 state)
 {
        status[0] = (dlci>>4) & 0x3F;
@@ -273,21 +273,21 @@ extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
 
 
 
-extern __inline__ u16 netdev_dlci(struct net_device *dev)
+static __inline__ u16 netdev_dlci(struct net_device *dev)
 {
        return ntohs(*(u16*)dev->dev_addr);
 }
 
 
 
-extern __inline__ u16 q922_to_dlci(u8 *hdr)
+static __inline__ u16 q922_to_dlci(u8 *hdr)
 {
        return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
 }
 
 
 
-extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
+static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
 {
        hdr[0] = (dlci>>2) & 0xFC;
        hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
@@ -295,14 +295,14 @@ extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
 
 
 
-extern __inline__ int mode_is(hdlc_device *hdlc, int mask)
+static __inline__ int mode_is(hdlc_device *hdlc, int mask)
 {
        return (hdlc->mode & mask) == mask;
 }
 
 
 
-extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 {
        pvc_device *pvc=hdlc->first_pvc;
        
@@ -317,7 +317,7 @@ extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
 
 
 
-extern __inline__ void debug_frame(const struct sk_buff *skb)
+static __inline__ void debug_frame(const struct sk_buff *skb)
 {
        int i;
 
index 4d9ef78e06e4289dfc2704f3507c0ddc6f1e5e1d..9c2d23ecb6024bf1cfcaa4927f4b40d9eb3a10b8 100644 (file)
@@ -49,7 +49,7 @@ struct i2c_rdwr_ioctl_data {
 
 #include <sys/ioctl.h>
 
-extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
+static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command, 
                                      int size, union i2c_smbus_data *data)
 {
        struct i2c_smbus_ioctl_data args;
@@ -62,12 +62,12 @@ extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
 }
 
 
-extern inline __s32 i2c_smbus_write_quick(int file, __u8 value)
+static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
 {
        return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
 }
        
-extern inline __s32 i2c_smbus_read_byte(int file)
+static inline __s32 i2c_smbus_read_byte(int file)
 {
        union i2c_smbus_data data;
        if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
@@ -76,13 +76,13 @@ extern inline __s32 i2c_smbus_read_byte(int file)
                return 0x0FF & data.byte;
 }
 
-extern inline __s32 i2c_smbus_write_byte(int file, __u8 value)
+static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
 {
        return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
                                I2C_SMBUS_BYTE,NULL);
 }
 
-extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
 {
        union i2c_smbus_data data;
        if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
@@ -92,7 +92,7 @@ extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
                return 0x0FF & data.byte;
 }
 
-extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command, 
                                               __u8 value)
 {
        union i2c_smbus_data data;
@@ -101,7 +101,7 @@ extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
                                I2C_SMBUS_BYTE_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
 {
        union i2c_smbus_data data;
        if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
@@ -111,7 +111,7 @@ extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
                return 0x0FFFF & data.word;
 }
 
-extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_word_data(int file, __u8 command, 
                                               __u16 value)
 {
        union i2c_smbus_data data;
@@ -120,7 +120,7 @@ extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
                                I2C_SMBUS_WORD_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
+static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
 {
        union i2c_smbus_data data;
        data.word = value;
@@ -133,7 +133,7 @@ extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
 
 
 /* Returns the number of read bytes */
-extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_read_block_data(int file, __u8 command, 
                                               __u8 *values)
 {
        union i2c_smbus_data data;
@@ -148,7 +148,7 @@ extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
        }
 }
 
-extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
+static inline __s32 i2c_smbus_write_block_data(int file, __u8 command, 
                                                __u8 length, __u8 *values)
 {
        union i2c_smbus_data data;
@@ -162,7 +162,7 @@ extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
                                I2C_SMBUS_BLOCK_DATA, &data);
 }
 
-extern inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
                                                __u8 length, __u8 *values)
 {
        union i2c_smbus_data data;
index 0496c344eacaead43b75eb2ad8b435d6d7606827..cebfa0df8717402a857e5f324e2e0e5a6bbf80fc 100644 (file)
@@ -240,47 +240,47 @@ struct i2o_sys_tbl
 /*
  *     Messenger inlines
  */
-extern inline u32 I2O_POST_READ32(struct i2o_controller *c)
+static inline u32 I2O_POST_READ32(struct i2o_controller *c)
 {
        return *c->post_port;
 }
 
-extern inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
 {
        *c->post_port = Val;
 }
 
 
-extern inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
+static inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
 {
        return *c->reply_port;
 }
 
-extern inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
 {
        *c->reply_port= Val;
 }
  
 
-extern inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
+static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
 {
        return *c->irq_mask;
 }
 
-extern inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
 {
        *c->irq_mask = Val;
 }
 
 
-extern inline void i2o_post_message(struct i2o_controller *c, u32 m)
+static inline void i2o_post_message(struct i2o_controller *c, u32 m)
 {
        /* The second line isnt spurious - thats forcing PCI posting */
        I2O_POST_WRITE32(c,m);
        (void) I2O_IRQ_READ32(c);
 }
 
-extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
 {
        I2O_REPLY_WRITE32(c,m);
 }
index ded38f67b36fbc16fb166969b582267d8a2e0dc9..47ee810f813c39ed72c2335cec9dfa9c07dc6c5c 100644 (file)
@@ -85,7 +85,7 @@ extern u32            inet_select_addr(const struct net_device *dev, u32 dst, int scope);
 extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
 extern void            inet_forward_change(void);
 
-extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
 {
        return !((addr^ifa->ifa_address)&ifa->ifa_mask);
 }
@@ -94,7 +94,7 @@ extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
  *     Check if a mask is acceptable.
  */
  
-extern __inline__ int bad_mask(u32 mask, u32 addr)
+static __inline__ int bad_mask(u32 mask, u32 addr)
 {
        if (addr & (mask = ~mask))
                return 1;
@@ -116,7 +116,7 @@ extern __inline__ int bad_mask(u32 mask, u32 addr)
 extern rwlock_t inetdev_lock;
 
 
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
 in_dev_get(const struct net_device *dev)
 {
        struct in_device *in_dev;
@@ -129,7 +129,7 @@ in_dev_get(const struct net_device *dev)
        return in_dev;
 }
 
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
 __in_dev_get(const struct net_device *dev)
 {
        return (struct in_device*)dev->ip_ptr;
@@ -137,7 +137,7 @@ __in_dev_get(const struct net_device *dev)
 
 extern void in_dev_finish_destroy(struct in_device *idev);
 
-extern __inline__ void
+static __inline__ void
 in_dev_put(struct in_device *idev)
 {
        if (atomic_dec_and_test(&idev->refcnt))
@@ -149,14 +149,14 @@ in_dev_put(struct in_device *idev)
 
 #endif /* __KERNEL__ */
 
-extern __inline__ __u32 inet_make_mask(int logmask)
+static __inline__ __u32 inet_make_mask(int logmask)
 {
        if (logmask)
                return htonl(~((1<<(32-logmask))-1));
        return 0;
 }
 
-extern __inline__ int inet_mask_len(__u32 mask)
+static __inline__ int inet_mask_len(__u32 mask)
 {
        if (!(mask = ntohl(mask)))
                return 0;
index dbc375bd515060c9f6d3ae6cb7849825d2f35e14..f0644ca302e8863bdcbfb628134c0687f89729bf 100644 (file)
@@ -132,11 +132,11 @@ typedef int (*__init_module_func_t)(void);
 typedef void (*__cleanup_module_func_t)(void);
 #define module_init(x) \
        int init_module(void) __attribute__((alias(#x))); \
-       extern inline __init_module_func_t __init_module_inline(void) \
+       static inline __init_module_func_t __init_module_inline(void) \
        { return x; }
 #define module_exit(x) \
        void cleanup_module(void) __attribute__((alias(#x))); \
-       extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+       static inline __cleanup_module_func_t __cleanup_module_inline(void) \
        { return x; }
 
 #define __setup(str,func) /* nothing */
index b9d7bcc63820965ac6dffeef66a98d4b39ccbae8..2ccf61d088dddf789bbbe237c937b52e1a1bf919 100644 (file)
@@ -49,7 +49,7 @@
  */
  
 #ifdef CONFIG_NET_SECURITY
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
 {
        return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
                (skb->security & RCV_AUTH)) &&
@@ -59,7 +59,7 @@ extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
 
 #else
 
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
 {
        return 1;
 }
index f44001df9c58de8dc640b9faa828c4727818fdef..f42165a80799f793384ee2192312ae0b90d4d3d6 100644 (file)
@@ -217,37 +217,37 @@ extern struct list_head isapnp_devices;
 #else /* !CONFIG_ISAPNP */
 
 /* lowlevel configuration */
-extern inline int isapnp_present(void) { return 0; }
-extern inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
-extern inline int isapnp_cfg_end(void) { return -ENODEV; }
-extern inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
-extern inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
-extern inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
-extern inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
-extern inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
-extern inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
-extern inline void isapnp_wake(unsigned char csn) { ; }
-extern inline void isapnp_device(unsigned char device) { ; }
-extern inline void isapnp_activate(unsigned char device) { ; }
-extern inline void isapnp_deactivate(unsigned char device) { ; }
+static inline int isapnp_present(void) { return 0; }
+static inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
+static inline int isapnp_cfg_end(void) { return -ENODEV; }
+static inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
+static inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
+static inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
+static inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
+static inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
+static inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
+static inline void isapnp_wake(unsigned char csn) { ; }
+static inline void isapnp_device(unsigned char device) { ; }
+static inline void isapnp_activate(unsigned char device) { ; }
+static inline void isapnp_deactivate(unsigned char device) { ; }
 /* manager */
-extern inline struct pci_bus *isapnp_find_card(unsigned short vendor,
+static inline struct pci_bus *isapnp_find_card(unsigned short vendor,
                                               unsigned short device,
                                               struct pci_bus *from) { return NULL; }
-extern inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+static inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
                                              unsigned short vendor,
                                              unsigned short function,
                                              struct pci_dev *from) { return NULL; }
-extern inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
+static inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
                                     int (*probe)(struct pci_bus *card,
                                                  const struct isapnp_card_id *id)) { return -ENODEV; }
-extern inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
+static inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
                                    int (*probe)(struct pci_dev *dev,
                                                 const struct isapnp_device_id *id)) { return -ENODEV; }
-extern inline void isapnp_resource_change(struct resource *resource,
+static inline void isapnp_resource_change(struct resource *resource,
                                          unsigned long start,
                                          unsigned long size) { ; }
-extern inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
+static inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
 
 #endif /* CONFIG_ISAPNP */
 
index 670d72f4eb6611e117ef96224efdee5a04f6471c..6b0fc14f83e56349fd4c1a78cf00af262420b20e 100644 (file)
@@ -169,7 +169,7 @@ struct      isi_port {
  *  ISI Card specific ops ...
  */
  
-extern inline void raise_dtr(struct isi_port * port)
+static inline void raise_dtr(struct isi_port * port)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -189,7 +189,7 @@ extern inline void raise_dtr(struct isi_port * port)
        port->status |= ISI_DTR;
 }
 
-extern inline void drop_dtr(struct isi_port * port)
+static inline void drop_dtr(struct isi_port * port)
 {      
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -208,7 +208,7 @@ extern inline void drop_dtr(struct isi_port * port)
        InterruptTheCard(base); 
        port->status &= ~ISI_DTR;
 }
-extern inline void raise_rts(struct isi_port * port)
+static inline void raise_rts(struct isi_port * port)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -227,7 +227,7 @@ extern inline void raise_rts(struct isi_port * port)
        InterruptTheCard(base); 
        port->status |= ISI_RTS;
 }
-extern inline void drop_rts(struct isi_port * port)
+static inline void drop_rts(struct isi_port * port)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -246,7 +246,7 @@ extern inline void drop_rts(struct isi_port * port)
        InterruptTheCard(base); 
        port->status &= ~ISI_RTS;
 }
-extern inline void raise_dtr_rts(struct isi_port * port)
+static inline void raise_dtr_rts(struct isi_port * port)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -265,7 +265,7 @@ extern inline void raise_dtr_rts(struct isi_port * port)
        InterruptTheCard(base);
        port->status |= (ISI_DTR | ISI_RTS);
 }
-extern inline void drop_dtr_rts(struct isi_port * port)
+static inline void drop_dtr_rts(struct isi_port * port)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
@@ -285,7 +285,7 @@ extern inline void drop_dtr_rts(struct isi_port * port)
        port->status &= ~(ISI_RTS | ISI_DTR);
 }
 
-extern inline void kill_queue(struct isi_port * port, short queue)
+static inline void kill_queue(struct isi_port * port, short queue)
 {
        struct isi_board * card = port->card;
        unsigned short base = card->base;
index ef922b03977af3a83eb7935c7e538679942ba7d3..cc442a6b865b63f6a378b81a0c7928aff5c98acb 100644 (file)
@@ -75,69 +75,69 @@ extern int do_poke_blanked_console;
 
 extern void (*kbd_ledfunc)(unsigned int led);
 
-extern inline void show_console(void)
+static inline void show_console(void)
 {
        do_poke_blanked_console = 1;
        tasklet_schedule(&console_tasklet);
 }
 
-extern inline void set_console(int nr)
+static inline void set_console(int nr)
 {
        want_console = nr;
        tasklet_schedule(&console_tasklet);
 }
 
-extern inline void set_leds(void)
+static inline void set_leds(void)
 {
        tasklet_schedule(&keyboard_tasklet);
 }
 
-extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
        return ((kbd->modeflags >> flag) & 1);
 }
 
-extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
        return ((kbd->ledflagstate >> flag) & 1);
 }
 
-extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
        kbd->modeflags |= 1 << flag;
 }
 
-extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
        kbd->ledflagstate |= 1 << flag;
 }
 
-extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
        kbd->modeflags &= ~(1 << flag);
 }
 
-extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
        kbd->ledflagstate &= ~(1 << flag);
 }
 
-extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
 {
        kbd->lockstate ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
 {
        kbd->slockstate ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
 {
        kbd->modeflags ^= 1 << flag;
 }
 
-extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
 {
        kbd->ledflagstate ^= 1 << flag;
 }
@@ -161,7 +161,7 @@ extern unsigned int keymap_count;
 
 extern task_queue con_task_queue;
 
-extern inline void con_schedule_flip(struct tty_struct *t)
+static inline void con_schedule_flip(struct tty_struct *t)
 {
        queue_task(&t->flip.tqueue, &con_task_queue);
        tasklet_schedule(&console_tasklet);
index 179963c779d2ef4a0738e335e2ffe00534c76a00..d685da827ef2cec4f5ffe74017db43513e53a78e 100644 (file)
@@ -41,7 +41,7 @@ extern struct kernel_stat kstat;
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
-extern inline int kstat_irqs (int irq)
+static inline int kstat_irqs (int irq)
 {
        int i, sum=0;
 
index 694046eaa21513cd32318d2c9ad6f7882ea30a2e..5df76c9c4321fe6af88a7134b3dc2330feaa6a78 100644 (file)
@@ -173,7 +173,7 @@ void                  nlm_release_file(struct nlm_file *);
 void             nlmsvc_mark_resources(void);
 void             nlmsvc_free_host_resources(struct nlm_host *);
 
-extern __inline__ struct inode *
+static __inline__ struct inode *
 nlmsvc_file_inode(struct nlm_file *file)
 {
        return file->f_file.f_dentry->d_inode;
@@ -182,7 +182,7 @@ nlmsvc_file_inode(struct nlm_file *file)
 /*
  * Compare two host addresses (needs modifying for ipv6)
  */
-extern __inline__ int
+static __inline__ int
 nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
 {
        return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
@@ -192,7 +192,7 @@ nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
  * Compare two NLM locks.
  * When the second lock is of type F_UNLCK, this acts like a wildcard.
  */
-extern __inline__ int
+static __inline__ int
 nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2)
 {
        return  fl1->fl_pid   == fl2->fl_pid
index 1c3fa10b92709f08d37f5c45d599cec5ae31c35f..ef48a874ab1493617178e01e16105649b1b662a3 100644 (file)
  */
 extern void __wait_on_buffer(struct buffer_head *);
 
-extern inline void wait_on_buffer(struct buffer_head * bh)
+static inline void wait_on_buffer(struct buffer_head * bh)
 {
        if (test_bit(BH_Lock, &bh->b_state))
                __wait_on_buffer(bh);
 }
 
-extern inline void lock_buffer(struct buffer_head * bh)
+static inline void lock_buffer(struct buffer_head * bh)
 {
        while (test_and_set_bit(BH_Lock, &bh->b_state))
                __wait_on_buffer(bh);
@@ -34,12 +34,12 @@ extern void unlock_buffer(struct buffer_head *bh);
  * nfs may need it).
  */
 
-extern inline void lock_super(struct super_block * sb)
+static inline void lock_super(struct super_block * sb)
 {
        down(&sb->s_lock);
 }
 
-extern inline void unlock_super(struct super_block * sb)
+static inline void unlock_super(struct super_block * sb)
 {
        up(&sb->s_lock);
 }
index 983cb6a3d805955f834f43970662034630107918..37eefbb13f9b916c43b8fa5358aa04772483d1a5 100644 (file)
@@ -62,7 +62,7 @@ typedef       int (* transfer_proc_t)(struct loop_device *, int cmd,
                                char *raw_buf, char *loop_buf, int size,
                                int real_block);
 
-extern inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
+static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
                                 char *lbuf, int size, int rblock)
 {
        if (!lo->transfer)
index 938b43d77fa36a5b697db6a0add5bbe480425a0f..8b6dc4a8bf57b8e387691e976f337c0c6dabd8e4 100644 (file)
@@ -82,14 +82,14 @@ enum ip_conntrack_dir
        IP_CT_DIR_MAX
 };
 
-extern inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
                                        const struct ip_conntrack_tuple *t2)
 {
        return t1->src.ip == t2->src.ip
                && t1->src.u.all == t2->src.u.all;
 }
 
-extern inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
                                        const struct ip_conntrack_tuple *t2)
 {
        return t1->dst.ip == t2->dst.ip
@@ -97,13 +97,13 @@ extern inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
                && t1->dst.protonum == t2->dst.protonum;
 }
 
-extern inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
                                    const struct ip_conntrack_tuple *t2)
 {
        return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
 }
 
-extern inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
+static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
                                       const struct ip_conntrack_tuple *tuple,
                                       const struct ip_conntrack_tuple *mask)
 {
index 66e1702ce955f8cdde5ffde9aa9ad48f049c5536..88ecbad9dd6b99b7780ef6b758c724e2efa771af 100644 (file)
@@ -289,7 +289,7 @@ struct ipt_get_entries
 #define IPT_ERROR_TARGET "ERROR"
 
 /* Helper functions */
-extern __inline__ struct ipt_entry_target *
+static __inline__ struct ipt_entry_target *
 ipt_get_target(struct ipt_entry *e)
 {
        return (void *)e + e->target_offset;
index e64a0eeb86427763cfec163bd78b44d0f27b5cc5..3f82ad2bdeb2137ad62cdf48113d4c9290e7673c 100644 (file)
        (type)__i;                              \
 })
 
-extern inline int
+static inline int
 __list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
 
 /* Is this entry in the list? */
-extern inline int
+static inline int
 list_inlist(struct list_head *head, const void *entry)
 {
        return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
@@ -64,7 +64,7 @@ do {                                                                  \
 #endif
 
 /* Append. */
-extern inline void
+static inline void
 list_append(struct list_head *head, void *new)
 {
        ASSERT_WRITE_LOCK(head);
@@ -72,7 +72,7 @@ list_append(struct list_head *head, void *new)
 }
 
 /* Prepend. */
-extern inline void
+static inline void
 list_prepend(struct list_head *head, void *new)
 {
        ASSERT_WRITE_LOCK(head);
@@ -92,13 +92,13 @@ do {                                                                \
 
 /* If the field after the list_head is a nul-terminated string, you
    can use these functions. */
-extern inline int __list_cmp_name(const void *i, const char *name)
+static inline int __list_cmp_name(const void *i, const char *name)
 {
        return strcmp(name, i+sizeof(struct list_head)) == 0;
 }
 
 /* Returns false if same name already in list, otherwise does insert. */
-extern inline int
+static inline int
 list_named_insert(struct list_head *head, void *new)
 {
        if (LIST_FIND(head, __list_cmp_name, void *,
index 0716ae947661e6c9862a453646c387eb4dc5e5ff..76fba12faa87d5cfdc5ed4a0e63e2824b497882f 100644 (file)
@@ -295,7 +295,7 @@ struct ip6t_get_entries
 #define IP6T_ERROR_TARGET "ERROR"
 
 /* Helper functions */
-extern __inline__ struct ip6t_entry_target *
+static __inline__ struct ip6t_entry_target *
 ip6t_get_target(struct ip6t_entry *e)
 {
        return (void *)e + e->target_offset;
index ce7f93b9e9d043888765af15f6254c9f5d80b029..3bc55e03d1e309dd24209e74fd95b26af3d901e1 100644 (file)
@@ -127,7 +127,7 @@ struct netlink_callback
        long            args[4];
 };
 
-extern __inline__ struct nlmsghdr *
+static __inline__ struct nlmsghdr *
 __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
 {
        struct nlmsghdr *nlh;
index 2149cff1db25a3891ca458b929dcdc6c477c304a..11ffdacdadf8af29d29c35a8c6a77f31b0de5060 100644 (file)
@@ -120,22 +120,22 @@ struct knfsd_fh {
 /*
  * Conversion macros for the filehandle fields.
  */
-extern inline __u32 kdev_t_to_u32(kdev_t dev)
+static inline __u32 kdev_t_to_u32(kdev_t dev)
 {
        return (__u32) dev;
 }
 
-extern inline kdev_t u32_to_kdev_t(__u32 udev)
+static inline kdev_t u32_to_kdev_t(__u32 udev)
 {
        return (kdev_t) udev;
 }
 
-extern inline __u32 ino_t_to_u32(ino_t ino)
+static inline __u32 ino_t_to_u32(ino_t ino)
 {
        return (__u32) ino;
 }
 
-extern inline ino_t u32_to_ino_t(__u32 uino)
+static inline ino_t u32_to_ino_t(__u32 uino)
 {
        return (ino_t) uino;
 }
index adf59d870aa7519c9d324f3aa7ad9c28f3f1ceb0..0e0ef4f73d6d361a5c6f2df54357d76a71423b59 100644 (file)
@@ -314,7 +314,7 @@ void nubus_get_rsrc_str(void* dest,
                        int maxlen);
 
 /* We'd like to get rid of this eventually.  Only daynaport.c uses it now. */
-extern inline void *nubus_slot_addr(int slot)
+static inline void *nubus_slot_addr(int slot)
 {
        return (void *)(0xF0000000|(slot<<24));
 }
index 0febcc2a1899a1c9ec87acf670c099349d60ab73..47845c644dba8849e78d89fda6d02bd61540a9d9 100644 (file)
@@ -60,7 +60,7 @@ extern void page_cache_init(unsigned long);
  * For the time being it will work for struct address_space too (most of
  * them sitting inside the inodes). We might want to change it later.
  */
-extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
+static inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
 {
 #define i (((unsigned long) mapping)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
 #define s(x) ((x)+((x)>>PAGE_HASH_BITS))
@@ -91,7 +91,7 @@ extern void add_to_page_cache_locked(struct page * page, struct address_space *m
 
 extern void ___wait_on_page(struct page *);
 
-extern inline void wait_on_page(struct page * page)
+static inline void wait_on_page(struct page * page)
 {
        if (PageLocked(page))
                ___wait_on_page(page);
index 8d148b6db6e9e6866d56d1ae7f47788ad900c189..f0659c771ff37f89370c9c0030c7e28daabc4c96 100644 (file)
@@ -415,7 +415,7 @@ extern void parport_release(struct pardevice *dev);
  * timeslice is half a second, but it can be adjusted via the /proc
  * interface.
  **/
-extern __inline__ int parport_yield(struct pardevice *dev)
+static __inline__ int parport_yield(struct pardevice *dev)
 {
        unsigned long int timeslip = (jiffies - dev->time);
        if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
@@ -433,7 +433,7 @@ extern __inline__ int parport_yield(struct pardevice *dev)
  * parport_claim_or_block(), and the return value is the same as for
  * parport_claim_or_block().
  **/
-extern __inline__ int parport_yield_blocking(struct pardevice *dev)
+static __inline__ int parport_yield_blocking(struct pardevice *dev)
 {
        unsigned long int timeslip = (jiffies - dev->time);
        if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
@@ -518,7 +518,7 @@ extern int parport_find_device (const char *mfg, const char *mdl, int from);
 extern int parport_find_class (parport_device_class cls, int from);
 
 /* Lowlevel drivers _can_ call this support function to handle irqs.  */
-extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+static __inline__ void parport_generic_irq(int irq, struct parport *port,
                                           struct pt_regs *regs)
 {
        parport_ieee1284_interrupt (irq, port, regs);
index 9e2f6468c63c6587f8a4a00f437ca9c118e60cbf..fb48227816b9025a0cc48a6b3ff0cc948a911c76 100644 (file)
@@ -41,7 +41,7 @@ struct parport_pc_private {
        struct pci_dev *dev;
 };
 
-extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
+static __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
 {
 #ifdef DEBUG_PARPORT
        printk (KERN_DEBUG "parport_pc_write_data(%p,0x%02x)\n", p, d);
@@ -49,7 +49,7 @@ extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
        outb(d, DATA(p));
 }
 
-extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
+static __inline__ unsigned char parport_pc_read_data(struct parport *p)
 {
        unsigned char val = inb (DATA (p));
 #ifdef DEBUG_PARPORT
@@ -60,7 +60,7 @@ extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
 }
 
 #ifdef DEBUG_PARPORT
-extern __inline__ void dump_parport_state (char *str, struct parport *p)
+static __inline__ void dump_parport_state (char *str, struct parport *p)
 {
        /* here's hoping that reading these ports won't side-effect anything underneath */
        unsigned char ecr = inb (ECONTROL (p));
@@ -124,17 +124,17 @@ static __inline__ unsigned char __parport_pc_frob_control (struct parport *p,
        return ctr;
 }
 
-extern __inline__ void parport_pc_data_reverse (struct parport *p)
+static __inline__ void parport_pc_data_reverse (struct parport *p)
 {
        __parport_pc_frob_control (p, 0x20, 0x20);
 }
 
-extern __inline__ void parport_pc_data_forward (struct parport *p)
+static __inline__ void parport_pc_data_forward (struct parport *p)
 {
        __parport_pc_frob_control (p, 0x20, 0x00);
 }
 
-extern __inline__ void parport_pc_write_control (struct parport *p,
+static __inline__ void parport_pc_write_control (struct parport *p,
                                                 unsigned char d)
 {
        const unsigned char wm = (PARPORT_CONTROL_STROBE |
@@ -152,7 +152,7 @@ extern __inline__ void parport_pc_write_control (struct parport *p,
        __parport_pc_frob_control (p, wm, d & wm);
 }
 
-extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
+static __inline__ unsigned char parport_pc_read_control(struct parport *p)
 {
        const unsigned char rm = (PARPORT_CONTROL_STROBE |
                                  PARPORT_CONTROL_AUTOFD |
@@ -162,7 +162,7 @@ extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
        return priv->ctr & rm; /* Use soft copy */
 }
 
-extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
+static __inline__ unsigned char parport_pc_frob_control (struct parport *p,
                                                         unsigned char mask,
                                                         unsigned char val)
 {
@@ -189,18 +189,18 @@ extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
        return __parport_pc_frob_control (p, mask, val);
 }
 
-extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
+static __inline__ unsigned char parport_pc_read_status(struct parport *p)
 {
        return inb(STATUS(p));
 }
 
 
-extern __inline__ void parport_pc_disable_irq(struct parport *p)
+static __inline__ void parport_pc_disable_irq(struct parport *p)
 {
        __parport_pc_frob_control (p, 0x10, 0x00);
 }
 
-extern __inline__ void parport_pc_enable_irq(struct parport *p)
+static __inline__ void parport_pc_enable_irq(struct parport *p)
 {
        __parport_pc_frob_control (p, 0x10, 0x10);
 }
index 42d28f3cb7930cece4d005626924b8b183f7e012..8cefa88e6183bdcf9ef30e345d1d05f0c038e96e 100644 (file)
@@ -147,41 +147,41 @@ int pm_send_all(pm_request_t rqst, void *data);
  */
 struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from);
 
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
 
 #else /* CONFIG_PM */
 
 #define PM_IS_ACTIVE() 0
 
-extern inline struct pm_dev *pm_register(pm_dev_t type,
+static inline struct pm_dev *pm_register(pm_dev_t type,
                                         unsigned long id,
                                         pm_callback callback)
 {
        return 0;
 }
 
-extern inline void pm_unregister(struct pm_dev *dev) {}
+static inline void pm_unregister(struct pm_dev *dev) {}
 
-extern inline void pm_unregister_all(pm_callback callback) {}
+static inline void pm_unregister_all(pm_callback callback) {}
 
-extern inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+static inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
 {
        return 0;
 }
 
-extern inline int pm_send_all(pm_request_t rqst, void *data)
+static inline int pm_send_all(pm_request_t rqst, void *data)
 {
        return 0;
 }
 
-extern inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
+static inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
 {
        return 0;
 }
 
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
 
 #endif /* CONFIG_PM */
 
index 24138dbd2514ab299ac0ca941b739f776fd420da..796aac51388a499a917e855a2cc16d179f0495ee 100644 (file)
@@ -19,7 +19,7 @@ typedef struct poll_table_struct {
 
 extern void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);
 
-extern inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
+static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
 {
        if (p && wait_address)
                __pollwait(filp, wait_address, p);
index dff8588a2bfef4e7ac9c6014c735ff233a6e7608..308a21c004b6ceae754df799b2fdda8f9002d81d 100644 (file)
@@ -35,13 +35,13 @@ extern int  dquot_transfer(struct dentry *dentry, struct iattr *iattr);
 /*
  * Operations supported for diskquotas.
  */
-extern __inline__ void DQUOT_INIT(struct inode *inode)
+static __inline__ void DQUOT_INIT(struct inode *inode)
 {
        if (inode->i_sb && inode->i_sb->dq_op)
                inode->i_sb->dq_op->initialize(inode, -1);
 }
 
-extern __inline__ void DQUOT_DROP(struct inode *inode)
+static __inline__ void DQUOT_DROP(struct inode *inode)
 {
        if (IS_QUOTAINIT(inode)) {
                if (inode->i_sb && inode->i_sb->dq_op)
@@ -49,7 +49,7 @@ extern __inline__ void DQUOT_DROP(struct inode *inode)
        }
 }
 
-extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
        if (sb->dq_op) {
                if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 1) == NO_QUOTA)
@@ -58,7 +58,7 @@ extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct
        return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
        if (sb->dq_op) {
                if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 0) == NO_QUOTA)
@@ -67,7 +67,7 @@ extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct ino
        return 0;
 }
 
-extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
 {
        if (sb->dq_op) {
                sb->dq_op->initialize (inode, -1);
@@ -78,19 +78,19 @@ extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *in
        return 0;
 }
 
-extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
 {
        if (sb->dq_op)
                sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize));
 }
 
-extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
 {
        if (sb->dq_op)
                sb->dq_op->free_inode(inode, 1);
 }
 
-extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
+static __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
 {
        int error = -EDQUOT;
 
index 35e60bd1ab4681e4121998b1ea0fe3f343245410..f693fcf58e021d15419aa3c43ffd57ae7279b073 100644 (file)
@@ -29,7 +29,7 @@
 
 #ifdef __i386__
 /* 001 */
-extern __inline__ int md_cpu_has_mmx(void)
+static __inline__ int md_cpu_has_mmx(void)
 {
        return test_bit(X86_FEATURE_MMX,  &boot_cpu_data.x86_capability);
 }
@@ -51,7 +51,7 @@ extern __inline__ int md_cpu_has_mmx(void)
 #define md_put_user put_user
 
 /* 007 */
-extern inline int md_capable_admin(void)
+static inline int md_capable_admin(void)
 {
        return capable(CAP_SYS_ADMIN);
 }
@@ -60,7 +60,7 @@ extern inline int md_capable_admin(void)
 #define MD_FILE_TO_INODE(file) ((file)->f_dentry->d_inode)
 
 /* 009 */
-extern inline void md_flush_signals (void)
+static inline void md_flush_signals (void)
 {
        spin_lock(&current->sigmask_lock);
        flush_signals(current);
@@ -68,7 +68,7 @@ extern inline void md_flush_signals (void)
 }
  
 /* 010 */
-extern inline void md_init_signals (void)
+static inline void md_init_signals (void)
 {
         current->exit_signal = SIGCHLD;
         siginitsetinv(&current->blocked, sigmask(SIGKILL));
index f04b145825c4d22b2eb561920fef2b2d10f6a317..8b6c3d7c006067bc409530264f86845e7018f50d 100644 (file)
@@ -39,7 +39,7 @@ static inline int pers_to_level (int pers)
        return MD_RESERVED;
 }
 
-extern inline int level_to_pers (int level)
+static inline int level_to_pers (int level)
 {
        switch (level) {
                case -3: return HSM;
index 2bd224e60dd6fc2c8c19273cae3561f99ec7aa6f..bcb9a1752d0cc8592d1689a709e6ca3a44f21ae4 100644 (file)
 #define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
 #define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
 
-extern inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
+static inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
 {
     return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, 
                      strlen ( REISERFS_SUPER_MAGIC_STRING)) ||
@@ -434,7 +434,7 @@ struct item_head
 //
 // here are conversion routines
 //
-extern inline int uniqueness2type (__u32 uniqueness)
+static inline int uniqueness2type (__u32 uniqueness)
 {
     switch (uniqueness) {
     case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
@@ -451,7 +451,7 @@ extern inline int uniqueness2type (__u32 uniqueness)
     return TYPE_ANY;
 }
 
-extern inline __u32 type2uniqueness (int type)
+static inline __u32 type2uniqueness (int type)
 {
     switch (type) {
     case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
@@ -472,46 +472,46 @@ extern inline __u32 type2uniqueness (int type)
 // there is no way to get version of object from key, so, provide
 // version to these defines
 //
-extern inline loff_t le_key_k_offset (int version, struct key * key)
+static inline loff_t le_key_k_offset (int version, struct key * key)
 {
     return (version == ITEM_VERSION_1) ? key->u.k_offset_v1.k_offset :
        le64_to_cpu (key->u.k_offset_v2.k_offset);
 }
-extern inline loff_t le_ih_k_offset (struct item_head * ih)
+static inline loff_t le_ih_k_offset (struct item_head * ih)
 {
     return le_key_k_offset (ih_version (ih), &(ih->ih_key));
 }
 
 
-extern inline loff_t le_key_k_type (int version, struct key * key)
+static inline loff_t le_key_k_type (int version, struct key * key)
 {
     return (version == ITEM_VERSION_1) ? uniqueness2type (key->u.k_offset_v1.k_uniqueness) :
        le16_to_cpu (key->u.k_offset_v2.k_type);
 }
-extern inline loff_t le_ih_k_type (struct item_head * ih)
+static inline loff_t le_ih_k_type (struct item_head * ih)
 {
     return le_key_k_type (ih_version (ih), &(ih->ih_key));
 }
 
 
-extern inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
+static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
 {
     (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_offset = offset) :
        (key->u.k_offset_v2.k_offset = cpu_to_le64 (offset));
 }
-extern inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
+static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
 {
     set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
 }
 
 
 
-extern inline void set_le_key_k_type (int version, struct key * key, int type)
+static inline void set_le_key_k_type (int version, struct key * key, int type)
 {
     (version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
        (key->u.k_offset_v2.k_type = cpu_to_le16 (type));
 }
-extern inline void set_le_ih_k_type (struct item_head * ih, int type)
+static inline void set_le_ih_k_type (struct item_head * ih, int type)
 {
     set_le_key_k_type (ih_version (ih), &(ih->ih_key), type);
 }
@@ -535,32 +535,32 @@ extern inline void set_le_ih_k_type (struct item_head * ih, int type)
 //
 // key is pointer to cpu key, result is cpu
 //
-extern inline loff_t cpu_key_k_offset (struct cpu_key * key)
+static inline loff_t cpu_key_k_offset (struct cpu_key * key)
 {
     return (key->version == ITEM_VERSION_1) ? key->on_disk_key.u.k_offset_v1.k_offset :
        key->on_disk_key.u.k_offset_v2.k_offset;
 }
 
-extern inline loff_t cpu_key_k_type (struct cpu_key * key)
+static inline loff_t cpu_key_k_type (struct cpu_key * key)
 {
     return (key->version == ITEM_VERSION_1) ? uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
        key->on_disk_key.u.k_offset_v2.k_type;
 }
 
-extern inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
+static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
 {
     (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
        (key->on_disk_key.u.k_offset_v2.k_offset = offset);
 }
 
 
-extern inline void set_cpu_key_k_type (struct cpu_key * key, int type)
+static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
 {
     (key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
        (key->on_disk_key.u.k_offset_v2.k_type = type);
 }
 
-extern inline void cpu_key_k_offset_dec (struct cpu_key * key)
+static inline void cpu_key_k_offset_dec (struct cpu_key * key)
 {
     if (key->version == ITEM_VERSION_1)
        key->on_disk_key.u.k_offset_v1.k_offset --;
@@ -828,7 +828,7 @@ struct reiserfs_de_head
 
 /* compose directory item containing "." and ".." entries (entries are
    not aligned to 4 byte boundary) */
-extern inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
                                           __u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -859,7 +859,7 @@ extern inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid
 }
 
 /* compose directory item containing "." and ".." entries */
-extern inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
                                        __u32 par_dirid, __u32 par_objid)
 {
     struct reiserfs_de_head * deh;
@@ -905,7 +905,7 @@ extern inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
 #define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
 ((i) ? (((deh)-1)->deh_location - (deh)->deh_location) : ((ih)->ih_item_len) - (deh)->deh_location)
 */
-extern inline int entry_length (struct buffer_head * bh, struct item_head * ih,
+static inline int entry_length (struct buffer_head * bh, struct item_head * ih,
                                int pos_in_item)
 {
     struct reiserfs_de_head * deh;
@@ -1137,7 +1137,7 @@ struct path var = {ILLEGAL_PATH_ELEMENT_OFFSET, }
 
 // reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
 #define U32_MAX (~(__u32)0)
-extern inline loff_t max_reiserfs_offset (struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
 {
     if (inode_items_version (inode) == ITEM_VERSION_1)
        return (loff_t)U32_MAX;
@@ -1673,7 +1673,7 @@ extern inline int comp_short_le_keys (struct key *, struct key *);
 //
 // get key version from on disk key - kludge
 //
-extern inline int le_key_version (struct key * key)
+static inline int le_key_version (struct key * key)
 {
     int type;
     
@@ -1686,7 +1686,7 @@ extern inline int le_key_version (struct key * key)
 }
 
 
-extern inline void copy_key (void * to, void * from)
+static inline void copy_key (void * to, void * from)
 {
   memcpy (to, from, KEY_SIZE);
 }
@@ -1963,7 +1963,7 @@ char *reiserfs_get_version_string(void) ;
 
 #ifdef __i386__
 
-extern __inline__ int 
+static __inline__ int 
 find_first_nonzero_bit(void * addr, unsigned size) {
   int res;
   int __d0;
@@ -1992,7 +1992,7 @@ find_first_nonzero_bit(void * addr, unsigned size) {
 
 #else /* __i386__ */
 
-extern __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
+static __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
 {
        unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
        unsigned int result = offset & ~31UL;
@@ -2040,10 +2040,10 @@ found_middle:
    absolutely safe */
 #define SPARE_SPACE 500
 
-extern inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
     return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_journal_block) ;
 }
-extern inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
     return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size) ;
 }
 
index 0c7cab0de05cde4111ffad31b1ae0a7f01594a16..dd55198d9397184604274e74602ba10065e6d846 100644 (file)
@@ -538,7 +538,7 @@ enum
 
 #include <linux/config.h>
 
-extern __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
+static __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
 {
        int len = strlen(str) + 1;
        return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
index 3f8d354bd0f820f4c87e02b799bc66657e17d39d..37feb6f6ef53374517bd48b9f0b3fdb03919627e 100644 (file)
@@ -130,7 +130,7 @@ int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
 }
                
 
-extern __inline__ void
+static __inline__ void
 rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
 {
        xprt_set_timeout(&clnt->cl_timeout, retr, incr);
index e106bf92ce96a05e561d182dd1b502e3803ce072..eee6756b842a8fe8cc22bd31c4b5869dd6a32a44 100644 (file)
@@ -180,13 +180,13 @@ void              rpciod_wake_up(void);
 void           rpc_show_tasks(void);
 #endif
 
-extern __inline__ void *
+static __inline__ void *
 rpc_malloc(struct rpc_task *task, unsigned int size)
 {
        return rpc_allocate(task->tk_flags, size);
 }
 
-extern __inline__ void
+static __inline__ void
 rpc_exit(struct rpc_task *task, int status)
 {
        task->tk_status = status;
@@ -194,7 +194,7 @@ rpc_exit(struct rpc_task *task, int status)
 }
 
 #ifdef RPC_DEBUG
-extern __inline__ char *
+static __inline__ char *
 rpc_qname(struct rpc_wait_queue *q)
 {
        return q->name? q->name : "unknown";
index 24da571cb52d9e43235213ffeaee145ba59ee49e..13c7989d67d78135f0a861b08d10c8e3c35427ba 100644 (file)
@@ -59,13 +59,13 @@ void                        svc_proc_zero(struct svc_program *);
 
 #else
 
-extern inline void svc_proc_unregister(const char *p) {}
-extern inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
+static inline void svc_proc_unregister(const char *p) {}
+static inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
 {
        return NULL;
 }
 
-extern inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
+static inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
 {
        return 0;
 }
index 467445e06db93398d0e6545eed673172f072f3b3..232ac45c725e27a3c470c45de604a0ba2a04f34a 100644 (file)
@@ -21,7 +21,7 @@ struct rpc_listitem   {
        struct rpc_listitem *   next;
 };
 
-extern __inline__ void
+static __inline__ void
 __rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
        struct rpc_listitem     *next, *prev;
@@ -37,14 +37,14 @@ __rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
        }
 }
 
-extern __inline__ void
+static __inline__ void
 __rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
        __rpc_append_list(q, item);
        *q = item;
 }
 
-extern __inline__ void
+static __inline__ void
 __rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
 {
        struct rpc_listitem     *prev = item->prev,
index 3f4a3c3c33564054ddd088c955b0b983ab3c7451..26aa7d757d52a18b74b640247df071b35b5bc2c4 100644 (file)
@@ -121,10 +121,16 @@ extern wait_queue_head_t kswapd_wait;
 extern wait_queue_head_t kreclaimd_wait;
 extern int page_launder(int, int);
 extern int free_shortage(void);
+extern int total_free_shortage(void);
 extern int inactive_shortage(void);
+extern int total_inactive_shortage(void);
 extern void wakeup_kswapd(void);
 extern int try_to_free_pages(unsigned int gfp_mask);
 
+extern unsigned int zone_free_shortage(zone_t *zone);
+extern unsigned int zone_inactive_shortage(zone_t *zone);
+extern unsigned int zone_inactive_plenty(zone_t *zone);
+
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, struct page *);
 extern void rw_swap_page_nolock(int, swp_entry_t, char *);
index 00d314fb918e8db64d5dca98e1c5724b206ec38e..b88f13aff2a6ad67db922c5db66cdb870fff04e5 100644 (file)
@@ -271,14 +271,14 @@ struct sysv_inode {
  */
 #define COH_KLUDGE_SYMLINK_MODE        (S_IFREG | S_ISVTX)
 #define COH_KLUDGE_NOT_SYMLINK (S_IFREG | S_ISVTX | S_IRUSR) /* force read access */
-extern inline mode_t from_coh_imode(unsigned short mode)
+static inline mode_t from_coh_imode(unsigned short mode)
 {
        if (mode == COH_KLUDGE_SYMLINK_MODE)
                return (S_IFLNK | 0777);
        else
                return mode;
 }
-extern inline unsigned short to_coh_imode(mode_t mode)
+static inline unsigned short to_coh_imode(mode_t mode)
 {
        if (S_ISLNK(mode))
                return COH_KLUDGE_SYMLINK_MODE;
index 948e54550d95b54bfa0bfa7145a158585b959a25..51a74dff1541409e6f365dd16f08b5ef632f8396 100644 (file)
@@ -4,7 +4,7 @@
 #ifdef INCLUDE_INLINE_FUNCS
 #define _INLINE_ extern
 #else
-#define _INLINE_ extern __inline__
+#define _INLINE_ static __inline__
 #endif
 
 _INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
index 6dbe38adfa929df90b8347f27c474c0267a9bcd8..007639810d75b1a0233c35641169f67812c3fcf2 100644 (file)
@@ -376,6 +376,7 @@ struct video_code
 #define VID_HARDWARE_SE401     30      /* SE401 USB webcams */
 #define VID_HARDWARE_PWC       31      /* Philips webcams */
 #define VID_HARDWARE_MEYE      32      /* Sony Vaio MotionEye cameras */
+#define VID_HARDWARE_CPIA2     33
 
 /*
  *     Initialiser list
index fd53797957eeb8cf1faf0fd75680f7c4cddd0ea0..fa94305456b5b99979a978ccac183e281be419d7 100644 (file)
    - Bottom halves: globally serialized, grr...
  */
 
-/* No separate irq_stat for s390, it is part of PSA */
-#if !defined(CONFIG_ARCH_S390)
 irq_cpustat_t irq_stat[NR_CPUS];
-#endif /* CONFIG_ARCH_S390 */
 
 static struct softirq_action softirq_vec[32] __cacheline_aligned;
 
index 3bbfb2b68896d24abeabdab2a629ca59867723bf..4b5c05ffc07a55869961fe8d0ed139472fd46d1a 100644 (file)
@@ -472,7 +472,7 @@ asmlinkage long sys_setgid(gid_t gid)
  * files..
  * Thanks to Olaf Kirch and Peter Benie for spotting this.
  */
-extern inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
+static inline void cap_emulate_setxuid(int old_ruid, int old_euid, 
                                       int old_suid)
 {
        if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
index ce3390a88e4b71cceb351172708fa1e000db0651..9cc086c726c861af98e733dac3cee323971db4bf 100644 (file)
@@ -293,34 +293,6 @@ void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
        spin_unlock(&pagecache_lock);
 }
 
-/*
- * This function is pretty much like __find_page_nolock(), but it only
- * requires 2 arguments and doesn't mark the page as touched, making it
- * ideal for ->writepage() clustering and other places where you don't
- * want to mark the page referenced.
- *
- * The caller needs to hold the pagecache_lock.
- */
-static struct page * FASTCALL(__find_page_simple(struct address_space *, unsigned long));
-static struct page * __find_page_simple(struct address_space *mapping, unsigned long index)
-{
-       struct page **next = page_hash(mapping, index);;
-
-       for (;;) {
-               struct page *page = *next;
-               if (!page)
-                       break;
-               next = &page->next_hash;
-               if (page->mapping != mapping)
-                       continue;
-               if (page->index != index)
-                       continue;
-               return page;
-       }
-
-       return NULL;
-}
-
 static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
 {
        goto inside;
@@ -777,51 +749,6 @@ repeat:
 #define DEBUG_READAHEAD
 #endif
 
-/*
- * We combine this with read-ahead to deactivate pages when we
- * think there's sequential IO going on. Note that this is
- * harmless since we don't actually evict the pages from memory
- * but just move them to the inactive list.
- *
- * TODO:
- * - make the readahead code smarter
- * - move readahead to the VMA level so we can do the same
- *   trick with mmap()
- *
- * Rik van Riel, 2000
- */
-static void drop_behind(struct file * file, unsigned long index)
-{
-       struct inode *inode = file->f_dentry->d_inode;
-       struct address_space *mapping = inode->i_mapping;
-       struct page *page;
-       unsigned long start;
-
-       /* Nothing to drop-behind if we're on the first page. */
-       if (!index)
-               return;
-
-       if (index > file->f_rawin)
-               start = index - file->f_rawin;
-       else
-               start = 0;
-
-       /*
-        * Go backwards from index-1 and drop all pages in the
-        * readahead window. Since the readahead window may have
-        * been increased since the last time we were called, we
-        * stop when the page isn't there.
-        */
-       spin_lock(&pagecache_lock);
-       while (--index >= start) {
-               page = __find_page_simple(mapping, index);
-               if (!page)
-                       break;
-               deactivate_page(page);
-       }
-       spin_unlock(&pagecache_lock);
-}
-
 /*
  * Read-ahead profiling information
  * --------------------------------
@@ -1041,12 +968,6 @@ static void generic_file_readahead(int reada_ok,
                if (filp->f_ramax > max_readahead)
                        filp->f_ramax = max_readahead;
 
-               /*
-                * Move the pages that have already been passed
-                * to the inactive list.
-                */
-               drop_behind(filp, index);
-
 #ifdef PROFILE_READAHEAD
                profile_readahead((reada_ok == 2), filp);
 #endif
@@ -1056,6 +977,14 @@ static void generic_file_readahead(int reada_ok,
 }
 
 
+static inline void check_used_once (struct page *page)
+{
+       if (!page->age) {
+               page->age = PAGE_AGE_START;
+               ClearPageReferenced(page);
+       }
+}
+
 /*
  * This is a generic file read routine, and uses the
  * inode->i_op->readpage() function for the actual low-level
@@ -1171,7 +1100,8 @@ page_ok:
                offset += ret;
                index += offset >> PAGE_CACHE_SHIFT;
                offset &= ~PAGE_CACHE_MASK;
-       
+
+               check_used_once (page);
                page_cache_release(page);
                if (ret == nr && desc->count)
                        continue;
@@ -2608,7 +2538,6 @@ generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
        while (count) {
                unsigned long index, offset;
                char *kaddr;
-               int deactivate = 1;
 
                /*
                 * Try to find the page in the cache. If it isn't there,
@@ -2617,10 +2546,8 @@ generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
                offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
                index = pos >> PAGE_CACHE_SHIFT;
                bytes = PAGE_CACHE_SIZE - offset;
-               if (bytes > count) {
+               if (bytes > count)
                        bytes = count;
-                       deactivate = 0;
-               }
 
                /*
                 * Bring in the user page that we will copy from _first_.
@@ -2664,8 +2591,7 @@ generic_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 unlock:
                /* Mark it unlocked again and drop the page.. */
                UnlockPage(page);
-               if (deactivate)
-                       deactivate_page(page);
+               check_used_once(page);
                page_cache_release(page);
 
                if (status < 0)
index 4d9dc3d6fe3bf1bf38f69dc1ae038a0ded030d34..feb3835405428be728fc79b593986377477f1a2c 100644 (file)
@@ -865,7 +865,6 @@ static inline void establish_pte(struct vm_area_struct * vma, unsigned long addr
 static inline void break_cow(struct vm_area_struct * vma, struct page *        old_page, struct page * new_page, unsigned long address, 
                pte_t *page_table)
 {
-       copy_cow_page(old_page,new_page,address);
        flush_page_to_ram(new_page);
        flush_cache_page(vma, address);
        establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
@@ -937,14 +936,16 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
         * Ok, we need to copy. Oh, well..
         */
        spin_unlock(&mm->page_table_lock);
+
        new_page = alloc_page(GFP_HIGHUSER);
-       spin_lock(&mm->page_table_lock);
        if (!new_page)
-               return -1;
+               goto no_mem;
+       copy_cow_page(old_page,new_page,address);
 
        /*
         * Re-check the pte - we dropped the lock
         */
+       spin_lock(&mm->page_table_lock);
        if (pte_same(*page_table, pte)) {
                if (PageReserved(old_page))
                        ++mm->rss;
@@ -959,6 +960,9 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
 bad_wp_page:
        printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
        return -1;
+no_mem:
+       spin_lock(&mm->page_table_lock);
+       return -1;
 }
 
 static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
@@ -1163,16 +1167,18 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
 
                /* Allocate our own private page. */
                spin_unlock(&mm->page_table_lock);
+
                page = alloc_page(GFP_HIGHUSER);
-               spin_lock(&mm->page_table_lock);
                if (!page)
-                       return -1;
+                       goto no_mem;
+               clear_user_highpage(page, addr);
+
+               spin_lock(&mm->page_table_lock);
                if (!pte_none(*page_table)) {
                        page_cache_release(page);
                        return 1;
                }
                mm->rss++;
-               clear_user_highpage(page, addr);
                flush_page_to_ram(page);
                entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
        }
@@ -1182,6 +1188,10 @@ static int do_anonymous_page(struct mm_struct * mm, struct vm_area_struct * vma,
        /* No need to invalidate - it was non-present before */
        update_mmu_cache(vma, addr, entry);
        return 1;       /* Minor fault */
+
+no_mem:
+       spin_lock(&mm->page_table_lock);
+       return -1;
 }
 
 /*
index 1e30dbf28cdb2425de8ce43c73bf00aec846c9c8..a8df2173cfed51fcdd85a328ab627a5fd14f1e57 100644 (file)
@@ -448,7 +448,7 @@ try_again:
                 * to give up than to deadlock the kernel looping here.
                 */
                if (gfp_mask & __GFP_WAIT) {
-                       if (!order || free_shortage()) {
+                       if (!order || total_free_shortage()) {
                                int progress = try_to_free_pages(gfp_mask);
                                if (progress || (gfp_mask & __GFP_FS))
                                        goto try_again;
@@ -622,6 +622,53 @@ unsigned int nr_free_highpages (void)
 }
 #endif
 
+unsigned int zone_free_shortage(zone_t *zone)
+{
+       int sum = 0;
+
+       if (!zone->size)
+               goto ret;
+
+       if (zone->inactive_clean_pages + zone->free_pages
+                       < zone->pages_min) {
+               sum += zone->pages_min;
+               sum -= zone->free_pages;
+               sum -= zone->inactive_clean_pages;
+       }
+ret:
+       return sum;
+}
+
+unsigned int zone_inactive_plenty(zone_t *zone)
+{
+       int inactive;
+
+       if (!zone->size)
+               return 0;
+               
+       inactive = zone->inactive_dirty_pages;
+       inactive += zone->inactive_clean_pages;
+       inactive += zone->free_pages;
+
+       return (inactive > (zone->size / 3));
+
+}
+unsigned int zone_inactive_shortage(zone_t *zone) 
+{
+       int sum = 0;
+
+       if (!zone->size)
+               goto ret;
+
+       sum = zone->pages_high;
+       sum -= zone->inactive_dirty_pages;
+       sum -= zone->inactive_clean_pages;
+       sum -= zone->free_pages;
+
+ret:
+     return (sum > 0 ? sum : 0);
+}
+
 /*
  * Show free area list (used inside shift_scroll-lock stuff)
  * We also calculate the percentage fragmentation. We do this by counting the
index b1a6640bc5e56f7d90429dbffb60e40047807433..590f59f75c161f647742018280b4d4e5ab1ed4f6 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -231,11 +231,8 @@ void lru_cache_add(struct page * page)
        spin_lock(&pagemap_lru_lock);
        if (!PageLocked(page))
                BUG();
-       DEBUG_ADD_PAGE
-       add_page_to_active_list(page);
-       /* This should be relatively rare */
-       if (!page->age)
-               deactivate_page_nolock(page);
+       add_page_to_inactive_dirty_list(page);
+       page->age = 0;
        spin_unlock(&pagemap_lru_lock);
 }
 
index 5647e933608ede68e7d97a5fa031dc4768a65ce4..840bc68b43effe89cf93ffc0751336b1bb604bf8 100644 (file)
@@ -41,6 +41,14 @@ static void try_to_swap_out(struct mm_struct * mm, struct vm_area_struct* vma, u
        pte_t pte;
        swp_entry_t entry;
 
+       /* 
+        * If we are doing a zone-specific scan, do not
+        * touch pages from zones which don't have a 
+        * shortage.
+        */
+       if (zone_inactive_plenty(page->zone))
+               return;
+
        /* Don't look at this pte if it's been accessed recently. */
        if (ptep_test_and_clear_young(page_table)) {
                page->age += PAGE_AGE_ADV;
@@ -355,10 +363,10 @@ struct page * reclaim_page(zone_t * zone)
                }
 
                /* Page is or was in use?  Move it to the active list. */
-               if (PageReferenced(page) || page->age > 0 ||
-                               (!page->buffers && page_count(page) > 1)) {
+               if (PageReferenced(page) || (!page->buffers && page_count(page) > 1)) {
                        del_page_from_inactive_clean_list(page);
                        add_page_to_active_list(page);
+                       page->age = PAGE_AGE_START;
                        continue;
                }
 
@@ -426,7 +434,7 @@ out:
 #define MAX_LAUNDER            (4 * (1 << page_cluster))
 #define CAN_DO_FS              (gfp_mask & __GFP_FS)
 #define CAN_DO_IO              (gfp_mask & __GFP_IO)
-int page_launder(int gfp_mask, int sync)
+int do_page_launder(zone_t *zone, int gfp_mask, int sync)
 {
        int launder_loop, maxscan, cleaned_pages, maxlaunder;
        struct list_head * page_lru;
@@ -453,11 +461,22 @@ dirty_page_rescan:
                }
 
                /* Page is or was in use?  Move it to the active list. */
-               if (PageReferenced(page) || page->age > 0 ||
-                               (!page->buffers && page_count(page) > 1) ||
+               if (PageReferenced(page) || (!page->buffers && page_count(page) > 1) ||
                                page_ramdisk(page)) {
                        del_page_from_inactive_dirty_list(page);
                        add_page_to_active_list(page);
+                       page->age = PAGE_AGE_START;
+                       continue;
+               }
+
+               /* 
+                * If we are doing zone-specific laundering, 
+                * avoid touching pages from zones which do 
+                * not have a free shortage.
+                */
+               if (zone && !zone_free_shortage(page->zone)) {
+                       list_del(page_lru);
+                       list_add(page_lru, &inactive_dirty_list);
                        continue;
                }
 
@@ -574,8 +593,13 @@ dirty_page_rescan:
                         * If we're freeing buffer cache pages, stop when
                         * we've got enough free memory.
                         */
-                       if (freed_page && !free_shortage())
-                               break;
+                       if (freed_page) {
+                               if (zone) {
+                                       if (!zone_free_shortage(zone))
+                                               break;
+                               } else if (!free_shortage()) 
+                                       break;
+                       }
                        continue;
                } else if (page->mapping && !PageDirty(page)) {
                        /*
@@ -613,7 +637,7 @@ page_active:
         * loads, flush out the dirty pages before we have to wait on
         * IO.
         */
-       if (CAN_DO_IO && !launder_loop && free_shortage()) {
+       if (CAN_DO_IO && !launder_loop && total_free_shortage()) {
                launder_loop = 1;
                /* If we cleaned pages, never do synchronous IO. */
                if (cleaned_pages)
@@ -629,6 +653,33 @@ page_active:
        return cleaned_pages;
 }
 
+int page_launder(int gfp_mask, int sync)
+{
+       int type = 0, ret = 0;
+       pg_data_t *pgdat = pgdat_list;
+       /*
+        * First do a global scan if there is a 
+        * global shortage.
+        */
+       if (free_shortage())
+               ret += do_page_launder(NULL, gfp_mask, sync);
+
+       /*
+        * Then check if there is any specific zone 
+        * needs laundering.
+        */
+       for (type = 0; type < MAX_NR_ZONES; type++) {
+               zone_t *zone = pgdat->node_zones + type;
+               
+               if (zone_free_shortage(zone)) 
+                       ret += do_page_launder(zone, gfp_mask, sync);
+       } 
+
+       return ret;
+}
+
+
+
 /**
  * refill_inactive_scan - scan the active list and find pages to deactivate
  * @priority: the priority at which to scan
@@ -637,7 +688,7 @@ page_active:
  * This function will scan a portion of the active list to find
  * unused pages, those pages will then be moved to the inactive list.
  */
-int refill_inactive_scan(unsigned int priority, int target)
+int refill_inactive_scan(zone_t *zone, unsigned int priority, int target)
 {
        struct list_head * page_lru;
        struct page * page;
@@ -665,6 +716,16 @@ int refill_inactive_scan(unsigned int priority, int target)
                        continue;
                }
 
+               /*
+                * Do not deactivate pages from zones which 
+                * have plenty inactive pages.
+                */
+
+               if (zone_inactive_plenty(page->zone)) {
+                       page_active = 1;
+                       goto skip_page;
+               }
+
                /* Do aging on the pages. */
                if (PageTestandClearReferenced(page)) {
                        age_page_up_nolock(page);
@@ -695,10 +756,12 @@ int refill_inactive_scan(unsigned int priority, int target)
                 * we have done enough work.
                 */
                if (page_active || PageActive(page)) {
+skip_page:
                        list_del(page_lru);
                        list_add(page_lru, &active_list);
                } else {
-                       nr_deactivated++;
+                       if (!zone || (zone && (zone == page->zone)))
+                               nr_deactivated++;
                        if (target && nr_deactivated >= target)
                                break;
                }
@@ -709,19 +772,32 @@ int refill_inactive_scan(unsigned int priority, int target)
 }
 
 /*
- * Check if there are zones with a severe shortage of free pages,
- * or if all zones have a minor shortage.
+ * Check if we have are low on free pages globally.
  */
 int free_shortage(void)
 {
-       pg_data_t *pgdat = pgdat_list;
-       int sum = 0;
        int freeable = nr_free_pages() + nr_inactive_clean_pages();
        int freetarget = freepages.high;
 
        /* Are we low on free pages globally? */
        if (freeable < freetarget)
                return freetarget - freeable;
+       return 0;
+}
+
+/*
+ *
+ * Check if there are zones with a severe shortage of free pages,
+ * or if all zones have a minor shortage.
+ */
+int total_free_shortage(void)
+{
+       int sum = 0;
+       pg_data_t *pgdat = pgdat_list;
+
+       /* Do we have a global free shortage? */
+       if((sum = free_shortage()))
+               return sum;
 
        /* If not, are we very low on any particular zone? */
        do {
@@ -739,15 +815,15 @@ int free_shortage(void)
        } while (pgdat);
 
        return sum;
+
 }
 
 /*
- * How many inactive pages are we short?
+ * How many inactive pages are we short globally?
  */
 int inactive_shortage(void)
 {
        int shortage = 0;
-       pg_data_t *pgdat = pgdat_list;
 
        /* Is the inactive dirty list too small? */
 
@@ -759,10 +835,20 @@ int inactive_shortage(void)
 
        if (shortage > 0)
                return shortage;
+       return 0;
+}
+/*
+ * Are we low on inactive pages globally or in any zone?
+ */
+int total_inactive_shortage(void)
+{
+       int shortage = 0;
+       pg_data_t *pgdat = pgdat_list;
 
-       /* If not, do we have enough per-zone pages on the inactive list? */
+       if((shortage = inactive_shortage()))
+               return shortage;
 
-       shortage = 0;
+       shortage = 0;   
 
        do {
                int i;
@@ -802,7 +888,7 @@ int inactive_shortage(void)
  * when called from a user process.
  */
 #define DEF_PRIORITY (6)
-static int refill_inactive(unsigned int gfp_mask, int user)
+static int refill_inactive_global(unsigned int gfp_mask, int user)
 {
        int count, start_count, maxtry;
 
@@ -826,7 +912,7 @@ static int refill_inactive(unsigned int gfp_mask, int user)
                /* Walk the VM space for a bit.. */
                swap_out(DEF_PRIORITY, gfp_mask);
 
-               count -= refill_inactive_scan(DEF_PRIORITY, count);
+               count -= refill_inactive_scan(NULL, DEF_PRIORITY, count);
                if (count <= 0)
                        goto done;
 
@@ -839,6 +925,59 @@ done:
        return (count < start_count);
 }
 
+static int refill_inactive_zone(zone_t *zone, unsigned int gfp_mask, int user) 
+{
+       int count, start_count, maxtry; 
+       
+       count = start_count = zone_inactive_shortage(zone);
+
+       maxtry = (1 << DEF_PRIORITY);
+
+       do {
+               swap_out(DEF_PRIORITY, gfp_mask);
+
+               count -= refill_inactive_scan(zone, DEF_PRIORITY, count);
+
+               if (count <= 0)
+                       goto done;
+
+               if (--maxtry <= 0)
+                       return 0;
+
+       } while(zone_inactive_shortage(zone));
+done:
+       return (count < start_count);
+}
+
+
+static int refill_inactive(unsigned int gfp_mask, int user) 
+{
+       int type = 0, ret = 0;
+       pg_data_t *pgdat = pgdat_list;
+       /*
+        * First do a global scan if there is a 
+        * global shortage.
+        */
+       if (inactive_shortage())
+               ret += refill_inactive_global(gfp_mask, user);
+
+       /*
+        * Then check if there is any specific zone 
+        * with a shortage and try to refill it if
+        * so.
+        */
+       for (type = 0; type < MAX_NR_ZONES; type++) {
+               zone_t *zone = pgdat->node_zones + type;
+               
+               if (zone_inactive_shortage(zone)) 
+                       ret += refill_inactive_zone(zone, gfp_mask, user);
+       } 
+
+       return ret;
+}
+
+#define DEF_PRIORITY (6)
+
 static int do_try_to_free_pages(unsigned int gfp_mask, int user)
 {
        int ret = 0;
@@ -851,8 +990,10 @@ static int do_try_to_free_pages(unsigned int gfp_mask, int user)
         * before we get around to moving them to the other
         * list, so this is a relatively cheap operation.
         */
-       if (free_shortage()) {
-               ret += page_launder(gfp_mask, user);
+
+       ret += page_launder(gfp_mask, user);
+
+       if (total_free_shortage()) {
                shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
                shrink_icache_memory(DEF_PRIORITY, gfp_mask);
        }
@@ -861,8 +1002,7 @@ static int do_try_to_free_pages(unsigned int gfp_mask, int user)
         * If needed, we move pages from the active list
         * to the inactive list.
         */
-       if (inactive_shortage())
-               ret += refill_inactive(gfp_mask, user);
+       ret += refill_inactive(gfp_mask, user);
 
        /*      
         * Reclaim unused slab cache if memory is low.
@@ -917,7 +1057,7 @@ int kswapd(void *unused)
                static long recalc = 0;
 
                /* If needed, try to free some memory. */
-               if (inactive_shortage() || free_shortage()) 
+               if (total_inactive_shortage() || total_free_shortage()) 
                        do_try_to_free_pages(GFP_KSWAPD, 0);
 
                /* Once a second ... */
@@ -928,7 +1068,7 @@ int kswapd(void *unused)
                        recalculate_vm_stats();
 
                        /* Do background page aging. */
-                       refill_inactive_scan(DEF_PRIORITY, 0);
+                       refill_inactive_scan(NULL, DEF_PRIORITY, 0);
                }
 
                run_task_queue(&tq_disk);
@@ -944,7 +1084,7 @@ int kswapd(void *unused)
                 * We go to sleep for one second, but if it's needed
                 * we'll be woken up earlier...
                 */
-               if (!free_shortage() || !inactive_shortage()) {
+               if (!total_free_shortage() || !total_inactive_shortage()) {
                        interruptible_sleep_on_timeout(&kswapd_wait, HZ);
                /*
                 * If we couldn't free enough memory, we see if it was
index c7d931b98429dd304f7b5585d6558b5115db90cb..eb711c50e36c8789c8750dc2dc85ef3319bf64a6 100644 (file)
@@ -468,7 +468,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
        /* Check if this is a "normal" ircomm device, or an irlpt device */
        if (line < 0x10) {
                self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
-               self->settings.service_type = IRCOMM_9_WIRE; /* Default */
+               self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
+               self->settings.dce = IRCOMM_CTS | IRCOMM_CD; /* Default line settings */
                IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
        } else {
                IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
index ad5ee4b0f28b0d694adeaef217531cccc0bd1f03..68bba8b54fc11a7b153bab59a6e1d6d2d4bfa753 100644 (file)
@@ -505,7 +505,7 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
         * will have to wait for the peer device (DCE) to raise the CTS
         * line.  
         */
-       if (self->flags & ASYNC_CTS_FLOW) {
+       if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
                IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
                return;
        } else {