patch-2.2.8 linux/drivers/scsi/ibmmca.c

Next file: linux/drivers/scsi/ibmmca.h
Previous file: linux/drivers/scsi/README.ibmmca
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.7/linux/drivers/scsi/ibmmca.c linux/drivers/scsi/ibmmca.c
@@ -3,291 +3,30 @@
  *
  * Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU 
  * General Public License. Written by Martin Kolinek, December 1995.
+ * Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang
+ * See the file README.ibmmca for a detailed description of this driver,
+ * the commandline arguments and the history of its development.
+ * See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
+ * updates and info.
  */
 
-/* Update history:
-   Jan 15 1996:  First public release.
-   - Martin Kolinek
-
-   Jan 23 1996:  Scrapped code which reassigned scsi devices to logical
-   device numbers. Instead, the existing assignment (created
-   when the machine is powered-up or rebooted) is used. 
-   A side effect is that the upper layer of Linux SCSI 
-   device driver gets bogus scsi ids (this is benign), 
-   and also the hard disks are ordered under Linux the 
-   same way as they are under dos (i.e., C: disk is sda, 
-   D: disk is sdb, etc.).
-   - Martin Kolinek
-
-   I think that the CD-ROM is now detected only if a CD is 
-   inside CD_ROM while Linux boots. This can be fixed later,
-   once the driver works on all types of PS/2's.
-   - Martin Kolinek
-
-   Feb 7 1996:   Modified biosparam function. Fixed the CD-ROM detection. 
-   For now, devices other than harddisk and CD_ROM are 
-   ignored. Temporarily modified abort() function 
-   to behave like reset().
-   - Martin Kolinek
-
-   Mar 31 1996:  The integrated scsi subsystem is correctly found
-   in PS/2 models 56,57, but not in model 76. Therefore
-   the ibmmca_scsi_setup() function has been added today.
-   This function allows the user to force detection of
-   scsi subsystem. The kernel option has format
-   ibmmcascsi=n
-   where n is the scsi_id (pun) of the subsystem. Most likely, n is 7.
-   - Martin Kolinek
-
-   Aug 21 1996:  Modified the code which maps ldns to (pun,0).  It was
-   insufficient for those of us with CD-ROM changers.
-   - Chris Beauregard
- 
-   Dec 14 1996: More improvements to the ldn mapping.  See check_devices
-   for details.  Did more fiddling with the integrated SCSI detection,
-   but I think it's ultimately hopeless without actually testing the
-   model of the machine.  The 56, 57, 76 and 95 (ultimedia) all have
-   different integrated SCSI register configurations.  However, the 56
-   and 57 are the only ones that have problems with forced detection.
-   - Chris Beauregard
- 
-   Mar 8-16 1997: Modified driver to run as a module and to support 
-   multiple adapters. A structure, called ibmmca_hostdata, is now
-   present, containing all the variables, that were once only
-   available for one single adapter. The find_subsystem-routine has vanished.
-   The hardware recognition is now done in ibmmca_detect directly.
-   This routine checks for presence of MCA-bus, checks the interrupt
-   level and continues with checking the installed hardware.
-   Certain PS/2-models do not recognize a SCSI-subsystem automatically.
-   Hence, the setup defined by command-line-parameters is checked first.
-   Thereafter, the routine probes for an integrated SCSI-subsystem.
-   Finally, adapters are checked. This method has the advantage to cover all
-   possible combinations of multiple SCSI-subsystems on one MCA-board. Up to
-   eight SCSI-subsystems can be recognized and announced to the upper-level
-   drivers with this improvement. A set of defines made changes to other
-   routines as small as possible.
-   - Klaus Kudielka
-   
-   May 30 1997: (v1.5b)
-   1) SCSI-command capability enlarged by the recognition of MODE_SELECT.
-      This needs the RD-Bit to be disabled on IM_OTHER_SCSI_CMD_CMD which 
-      allows data to be written from the system to the device. It is a
-      necessary step to be allowed to set blocksize of SCSI-tape-drives and 
-      the tape-speed, whithout confusing the SCSI-Subsystem.
-   2) The recognition of a tape is included in the check_devices routine.
-      This is done by checking for TYPE_TAPE, that is already defined in
-      the kernel-scsi-environment. The markup of a tape is done in the 
-      global ldn_is_tape[] array. If the entry on index ldn 
-      is 1, there is a tapedrive connected.
-   3) The ldn_is_tape[] array is necessary to distinguish between tape- and 
-      other devices. Fixed blocklength devices should not cause a problem
-      with the SCB-command for read and write in the ibmmca_queuecommand
-      subroutine. Therefore, I only derivate the READ_XX, WRITE_XX for
-      the tape-devices, as recommended by IBM in this Technical Reference,
-      mentioned below. (IBM recommends to avoid using the read/write of the
-      subsystem, but the fact was, that read/write causes a command error from
-      the subsystem and this causes kernel-panic.)
-   4) In addition, I propose to use the ldn instead of a fix char for the
-      display of PS2_DISK_LED_ON(). On 95, one can distinguish between the
-      devices that are accessed. It shows activity and easyfies debugging.   
-   The tape-support has been tested with a SONY SDT-5200 and a HP DDS-2
-   (I do not know yet the type). Optimization and CD-ROM audio-support, 
-   I am working on ...
-   - Michael Lang
-   
-   June 19 1997: (v1.6b)
-   1) Submitting the extra-array ldn_is_tape[] -> to the local ld[]
-      device-array. 
-   2) CD-ROM Audio-Play seems to work now.
-   3) When using DDS-2 (120M) DAT-Tapes, mtst shows still density-code
-      0x13 for ordinary DDS (61000 BPM) instead 0x24 for DDS-2. This appears 
-      also on Adaptec 2940 adaptor in a PCI-System. Therefore, I assume that 
-      the problem is independent of the low-level-driver/bus-architecture.
-   4) Hexadecimal ldn on PS/2-95 LED-display.
-   5) Fixing of the PS/2-LED on/off that it works right with tapedrives and
-      does not confuse the disk_rw_in_progress counter.
-   - Michael Lang
-  
-   June 21 1997: (v1.7b)
-   1) Adding of a proc_info routine to inform in /proc/scsi/ibmmca/<host> the
-      outer-world about operational load statistics on the different ldns,
-      seen by the driver. Everybody that has more than one IBM-SCSI should
-      test this, because I only have one and cannot see what happens with more
-      than one IBM-SCSI hosts.
-   2) Definition of a driver version-number to have a better recognition of 
-      the source when there are existing too much releases that may confuse
-      the user, when reading about release-specific problems. Up to know,
-      I calculated the version-number to be 1.7. Because we are in BETA-test
-      yet, it is today 1.7b.
-   3) Sorry for the heavy bug I programmed on June 19 1997! After that, the
-      CD-ROM did not work any more! The C7-command was a fake impression
-      I got while programming. Now, the READ and WRITE commands for CD-ROM are
-      no longer running over the subsystem, but just over 
-      IM_OTHER_SCSI_CMD_CMD. On my observations (PS/2-95), now CD-ROM mounts
-      much faster(!) and hopefully all fancy multimedia-functions, like direct
-      digital recording from audio-CDs also work. (I tried it with cdda2wav
-      from the cdwtools-package and it filled up the harddisk immediately :-).)
-      To easify boolean logics, a further local device-type in ld[], called
-      is_cdrom has been included.
-   4) If one uses a SCSI-device of unsupported type/commands, one
-      immediately runs into a kernel-panic caused by Command Error. To better
-      understand which SCSI-command caused the problem, I extended this
-      specific panic-message slightly.
-   - Michael Lang
- 
-   June 25 1997: (v1.8b)
-   1) Some cosmetical changes for the handling of SCSI-device-types.
-      Now, also CD-Burners / WORMs and SCSI-scanners should work. For
-      MO-drives I have no experience, therefore not yet supported.
-      In logical_devices I changed from different type-variables to one
-      called 'device_type' where the values, corresponding to scsi.h,
-      of a SCSI-device are stored.
-   2) There existed a small bug, that maps a device, coming after a SCSI-tape
-      wrong. Therefore, e.g. a CD-ROM changer would have been mapped wrong
-      -> problem removed.
-   3) Extension of the logical_device structure. Now it contains also device,
-      vendor and revision-level of a SCSI-device for internal usage.
-   - Michael Lang
-
-   June 26-29 1997: (v2.0b)
-   1) The release number 2.0b is necessary because of the completely new done
-      recognition and handling of SCSI-devices with the adapter. As I got
-      from Chris the hint, that the subsystem can reassign ldns dynamically,
-      I remembered this immediate_assign-command, I found once in the handbook.
-      Now, the driver first kills all ldn assignments that are set by default
-      on the SCSI-subsystem. After that, it probes on all puns and luns for
-      devices by going through all combinations with immediate_assign and
-      probing for devices, using device_inquiry. The found physical(!) pun,lun
-      structure is stored in get_scsi[][] as device types. This is followed
-      by the assignment of all ldns to existing SCSI-devices. If more ldns
-      than devices are available, they are assigned to non existing pun,lun
-      combinations to satisfy the adapter. With this, the dynamical mapping
-      was possible to implement. (For further info see the text in the 
-      source-code and in the description below. Read the description
-      below BEFORE installing this driver on your system!)
-   2) Changed the name IBMMCA_DRIVER_VERSION to IBMMCA_SCSI_DRIVER_VERSION.
-   3) The LED-display shows on PS/2-95 no longer the ldn, but the SCSI-ID
-      (pun) of the accessed SCSI-device. This is now senseful, because the 
-      pun known within the driver is exactly the pun of the physical device
-      and no longer a fake one.
-   4) The /proc/scsi/ibmmca/<host_no> consists now of the first part, where
-      hit-statistics of ldns is shown and a second part, where the maps of 
-      physical and logical SCSI-devices are displayed. This could be very 
-      interesting, when one is using more than 15 SCSI-devices in order to 
-      follow the dynamical remapping of ldns.
-   - Michael Lang
- 
-   June 26-29 1997: (v2.0b-1)
-   1) I forgot to switch the local_checking_phase_flag to 1 and back to 0
-      in the dynamical remapping part in ibmmca_queuecommand for the 
-      device_exist routine. Sorry.
-   - Michael Lang
- 
-   July 1-13 1997: (v3.0b,c)
-   1) Merging of the driver-developments of Klaus Kudielka and Michael Lang 
-      in order to get a optimum and unified driver-release for the 
-      IBM-SCSI-Subsystem-Adapter(s).
-         For people, using the Kernel-release >=2.1.0, module-support should 
-      be no problem. For users, running under <2.1.0, module-support may not 
-      work, because the methods have changed between 2.0.x and 2.1.x.
-   2) Added some more effective statistics for /proc-output.
-   3) Change typecasting at necessary points from (unsigned long) to
-      virt_to_bus().
-   4) Included #if... at special points to have specific adaption of the
-      driver to kernel 2.0.x and 2.1.x. It should therefore also run with 
-      later releases.
-   5) Magneto-Optical drives and medium-changers are also recognized, now.
-      Therefore, we have a completely gapfree recognition of all SCSI-
-      device-types, that are known by Linux up to kernel 2.1.31.
-   6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
-      the configuration, each connected SCSI-device will get a reset command
-      during boottime. This can be necessary for some special SCSI-devices.
-      This flag should be included in Config.in.
-      (See also the new Config.in file.)
-   Probable next improvement: bad disk handler.
-   - Michael Lang
- 
-   Sept 14 1997: (v3.0c)
-   1) Some debugging and speed optimization applied.
-   - Michael Lang
-
-   Dec 15, 1997
-    - chrisb@truespectra.com
-    - made the front panel display thingy optional, specified from the
-    command-line via ibmmcascsi=display.  Along the lines of the /LED
-    option for the OS/2 driver.
-    - fixed small bug in the LED display that would hang some machines.
-    - reversed ordering of the drives (using the
-    IBMMCA_SCSI_ORDER_STANDARD define).  This is necessary for two main
-    reasons:
-	- users who've already installed Linux won't be screwed.  Keep
-	in mind that not everyone is a kernel hacker.
-	- be consistent with the BIOS ordering of the drives.  In the
-	BIOS, id 6 is C:, id 0 might be D:.  With this scheme, they'd be
-	backwards.  This confuses the crap out of those heathens who've
-	got a impure Linux installation (which, <wince>, I'm one of).
-    This whole problem arises because IBM is actually non-standard with
-    the id to BIOS mappings.  You'll find, in fdomain.c, a similar
-    comment about a few FD BIOS revisions.  The Linux (and apparently
-    industry) standard is that C: maps to scsi id (0,0).  Let's stick
-    with that standard.
-    - Since this is technically a branch of my own, I changed the
-    version number to 3.0e-cpb.
-
-   Jan 17, 1998: (v3.0f)
-   1) Addition of some statistical info for /proc in proc_info.
-   2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
-      1997. In fact, IBM is right, concerning the assignment of SCSI-devices 
-      to driveletters. It is conform to the ANSI-definition of the SCSI-
-      standard to assign drive C: to SCSI-id 6, because it is the highest
-      hardware priority after the hostadapter (that has still today by
-      default everywhere id 7). Also realtime-operating systems that I use, 
-      like LynxOS and OS9, which are quite industrial systems use top-down
-      numbering of the harddisks, that is also starting at id 6. Now, one
-      sits a bit between two chairs. On one hand side, using the define
-      IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
-      the IBM- and ANSI-SCSI-standard and keeps this driver downward
-      compatible to older releases, on the other hand side, people is quite
-      habituated in believing that C: is assigned to (0,0) and much other
-      SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD 
-      define out of the driver and put it into Config.in as subitem of 
-      'IBM SCSI support'. A help, added to Documentation/Configure.help 
-      explains the differences between saying 'y' or 'n' to the user, when 
-      IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to 
-      choose the way of assignment, depending on his own situation and gusto.
-   3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
-      now called IBMMCA_SCSI_DEV_RESET.
-   4) Optimization of proc_info and its subroutines.
-   5) Added more in-source-comments and extended the driver description by
-      some explanation about the SCSI-device-assignment problem.
-   - Michael Lang
-   
-   Jan 18, 1998: (v3.0g)
-   1) Correcting names to be absolutely conform to the later 2.1.x releases.
-      This is necessary for 
-            IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
-            IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   - Michael Lang
-
-	TODO:
- 
-	- It seems that the handling of bad disks is really bad -
-	  non-existent, in fact.
-        - More testing of the full driver-controlled dynamical ldn 
-          (re)mapping for up to 56 SCSI-devices.
-        - Support more SCSI-device-types, if Linux defines more.
-        - Support more of the SCSI-command set.
-	- Support some of the caching abilities, particularly Read Prefetch.
-	  This fetches data into the cache, which later gets hit by the
-	  regular Read Data.
-        - Abort and Reset functions still slightly buggy. Especially when
-          floppydisk(!) operations report errors.
+/******************* HEADER FILE INCLUDES ************************************/
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
 
-******************************************************************************/
+/* choose adaption for Kernellevel */
+#define local_LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#if LINUX_VERSION_CODE < local_LinuxVersionCode(2,1,0)
+#define OLDKERN
+#else
+#undef OLDKERN
+#endif
 
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
+#include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
@@ -297,7 +36,9 @@
 #include <linux/stat.h>
 #include <linux/mca.h>
 #include <asm/system.h>
+#ifndef OLDKERN
 #include <asm/spinlock.h>
+#endif
 #include <asm/io.h>
 #include "sd.h"
 #include "scsi.h"
@@ -306,199 +47,29 @@
 
 #include <linux/config.h>		/* for CONFIG_SCSI_IBMMCA etc. */
 
-/*--------------------------------------------------------------------*/
-
-/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "3.0f"
-
-/* use standard Linux ordering, where C: maps to (0,0), unlike the IBM
-standard which seems to like C: => (6,0) */
-/* #define IBMMCA_SCSI_ORDER_STANDARD is defined/undefined in Config.in
- * now, while configuring the kernel. */
+/******************* LOCAL DEFINES *******************************************/
 
-/*
-   Driver Description
-
-   (A) Subsystem Detection
-   This is done in the ibmmca_detect() function and is easy, since
-   the information about MCA integrated subsystems and plug-in 
-   adapters is readily available in structure *mca_info.
-
-   (B) Physical Units, Logical Units, and Logical Devices
-   There can be up to 56 devices on SCSI bus (besides the adapter):
-   there are up to 7 "physical units" (each identified by physical unit 
-   number or pun, also called the scsi id, this is the number you select
-   with hardware jumpers), and each physical unit can have up to 8 
-   "logical units" (each identified by logical unit number, or lun, 
-   between 0 and 7). 
-
-   Typically the adapter has pun=7, so puns of other physical units
-   are between 0 and 6. Almost all physical units have only one   
-   logical unit, with lun=0. A CD-ROM jukebox would be an example of 
-   a physical unit with more than one logical unit.
-
-   The embedded microprocessor of IBM SCSI subsystem hides the complex
-   two-dimensional (pun,lun) organization from the operating system.
-   When the machine is powered-up (or rebooted, I am not sure), the 
-   embedded microprocessor checks, on it own, all 56 possible (pun,lun) 
-   combinations, and first 15 devices found are assigned into a 
-   one-dimensional array of so-called "logical devices", identified by 
-   "logical device numbers" or ldn. The last ldn=15 is reserved for 
-   the subsystem itself. 
-
-   One consequence of information hiding is that the real (pun,lun)    
-   numbers are also hidden. Therefore this driver takes the following
-   approach: It checks the ldn's (0 to 6) to find out which ldn's
-   have devices assigned. This is done by function check_devices() and
-   device_exists(). The interrupt handler has a special paragraph of code
-   (see local_checking_phase_flag) to assist in the checking. Assume, for
-   example, that three logical devices were found assigned at ldn 0, 1, 2.
-   These are presented to the upper layer of Linux SCSI driver
-   as devices with bogus (pun, lun) equal to (0,0), (1,0), (2,0). 
-   On the other hand, if the upper layer issues a command to device
-   say (4,0), this driver returns DID_NO_CONNECT error.
-
-   That last paragraph is no longer correct, but is left for
-   historical purposes.  It limited the number of devices to 7, far
-   fewer than the 15 that it could use.  Now it just maps
-   ldn -> (ldn/8,ldn%8).  We end up with a real mishmash of puns
-   and luns, but it all seems to work. - Chris Beaurgard
-
-   And that last paragraph is also no longer correct.  It uses a
-   slightly more complex mapping that will always map hard disks to
-   (x,0), for some x, and consecutive none disk devices will usually
-   share puns.
- 
-   Again, the last paragraphs are no longer correct. Now, the physical
-   SCSI-devices on the SCSI-bus are probed via immediate_assign- and
-   device_inquiry-commands. This delivers a exact map of the physical
-   SCSI-world that is now stored in the get_scsi[][]-array. This means,
-   that the once hidden pun,lun assignment is now known to this driver.
-   It no longer believes in default-settings of the subsystem and maps all
-   ldns to existing pun,lun by foot. This assures full control of the ldn
-   mapping and allows dynamical remapping of ldns to different pun,lun, if
-   there are more SCSI-devices installed than ldns available (n>15). The
-   ldns from 0 to 6 get 'hardwired' by this driver to puns 0 to 7 at lun=0,
-   excluding the pun of the subsystem. This assures, that at least simple 
-   SCSI-installations have optimum access-speed and are not touched by
-   dynamical remapping. The ldns 7 to 14 are put to existing devices with 
-   lun>0 or to non-existing devices, in order to satisfy the subsystem, if 
-   there are less than 15 SCSI-devices connected. In the case of more than 15 
-   devices, the dynamical mapping goes active. If the get_scsi[][] reports a 
-   device to be existant, but it has no ldn assigned, it gets a ldn out of 7 
-   to 14. The numbers are assigned in cyclic order. Therefore it takes 8 
-   dynamical assignments on SCSI-devices, until a certain device 
-   looses its ldn again. This assures, that dynamical remapping is avoided 
-   during intense I/O between up to eight SCSI-devices (means pun,lun 
-   combinations). A further advantage of this method is, that people who
-   build their kernel without probing on all luns will get what they expect.
- 
-   IMPORTANT: Because of the now correct recognition of physical pun,lun, and 
-   their report to mid-level- and higher-level-drivers, the new reported puns
-   can be different from the old, faked puns. Therefore, Linux will eventually
-   change /dev/sdXXX assignments and prompt you for corrupted superblock
-   repair on boottime. In this case DO NOT PANIC, YOUR DISKS ARE STILL OK!!!
-   You have to reboot (CTRL-D) with a old kernel and set the /etc/fstab-file
-   entries right. After that, the system should come up as errorfree as before.
-   If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
-   in a Linux session booted on old kernel and run lilo before reboot. Check
-   lilo.conf anyway to get boot on other partitions with foreign OSes right
-   again. 
- 
-   The problem is, that Linux does not assign the SCSI-devices in the
-   way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to 
-   the device with at minimum id 0. But the first drive should be at id 6,
-   because for historical reasons, drive at id 6 has, by hardware, the highest
-   priority and a drive at id 0 the lowest. IBM was one of the rare producers,
-   where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most 
-   other producers' BIOS does not (I think even Adaptec-BIOS). The 
-   IBMMCA_SCSI_ORDER_STANDARD flag helps to be able to choose the preferred 
-   way of SCSI-device-assignment. Defining this flag would result in Linux 
-   determining the devices in the same order as DOS and OS/2 does on your 
-   MCA-machine. This is also standard on most industrial computers. Leaving 
-   this flag undefined will get your devices ordered in the default way of 
-   Linux. See also the remarks of Chris Beauregard from Dec 15, 1997 and
-   the followups.
-   
-   (C) Regular Processing 
-   Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
-   and interrupt_handler().
-
-   The upper layer issues a scsi command by calling function 
-   ibmmca_queuecommand(). This function fills a "subsystem control block"
-   (scb) and calls a local function issue_cmd(), which writes a scb 
-   command into subsystem I/O ports. Once the scb command is carried out, 
-   interrupt_handler() is invoked. If a device is determined to be existant
-   and it has not assigned any ldn, it gets one dynamically.
-
-   (D) Abort, Reset.
-   These are implemented with busy waiting for interrupt to arrive.
-   The abort does not worked well for me, so I instead call the 
-   ibmmca_reset() from the ibmmca_abort() function.
-
-   (E) Disk Geometry
-   The ibmmca_biosparams() function should return same disk geometry 
-   as bios. This is needed for fdisk, etc. The returned geometry is 
-   certainly correct for disk smaller than 1 gigabyte, but I am not 
-   100% sure that it is correct for larger disks.
-
-   (F) Kernel Boot Option 
-   The function ibmmca_scsi_setup() is called if option ibmmcascsi=n 
-   is passed to the kernel. See file linux/init/main.c for details.
-   
-   (G) Driver Module Support
-   Is implemented and tested by K. Kudielka. This could probably not work
-   on kernels <2.1.0.
-  
-   (H) Multiple Hostadapter Support
-   This driver supports up to eight interfaces of type IBM-SCSI-Subsystem. 
-   Integrated-, and MCA-adapters are automatically recognized. Unrecognizable
-   IBM-SCSI-Subsystem interfaces can be specified as kernel-parameters.
- 
-   (I) /proc-Filesystem Information
-   Information about the driver condition is given in 
-   /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info provides this information.
- */
+#ifndef mdelay
+#define mdelay(a)    udelay((a) * 1000)
+#endif
 
 /*--------------------------------------------------------------------*/
-/* Here are the values and structures specific for the subsystem. 
- * The source of information is "Update for the PS/2 Hardware 
- * Interface Technical Reference, Common Interfaces", September 1991, 
- * part number 04G3281, available in the U.S. for $21.75 at 
- * 1-800-IBM-PCTB, elsewhere call your local friendly IBM 
- * representative.
- * In addition to SCSI subsystem, this update contains fairly detailed 
- * (at hardware register level) sections on diskette  controller,
- * keyboard controller, serial port controller, VGA, and XGA.
- *
- * Additional information from "Personal System/2 Micro Channel SCSI
- * Adapter with Cache Technical Reference", March 1990, PN 68X2365,
- * probably available from the same source (or possibly found buried
- * in officemates desk).
- *
- * Further literature/program-sources referred for this driver:
- * 
- * Friedhelm Schmidt, "SCSI-Bus und IDE-Schnittstelle - Moderne Peripherie-
- * Schnittstellen: Hardware, Protokollbeschreibung und Anwendung", 2. Aufl.
- * Addison Wesley, 1996.
- * 
- * Michael K. Johnson, "The Linux Kernel Hackers' Guide", Version 0.6, Chapel
- * Hill - North Carolina, 1995
- * 
- * Andreas Kaiser, "SCSI TAPE BACKUP for OS/2 2.0", Version 2.12, Stuttgart
- * 1993
- */
+
+/* current version of this driver-source: */
+#define IBMMCA_SCSI_DRIVER_VERSION "3.1e"
 
 /*--------------------------------------------------------------------*/
 
 /* driver configuration */
 #define IM_MAX_HOSTS      8             /* maximum number of host adapters */
-#define IM_RESET_DELAY    10            /* seconds allowed for a reset */
+#define IM_RESET_DELAY    60            /* seconds allowed for a reset */
 
 /* driver debugging - #undef all for normal operation */
 
 /* if defined: count interrupts and ignore this special one: */
 #undef  IM_DEBUG_TIMEOUT  50            
+#define TIMEOUT_PUN   0
+#define TIMEOUT_LUN   0
 /* verbose interrupt: */
 #undef  IM_DEBUG_INT                   
 /* verbose queuecommand: */
@@ -512,11 +83,11 @@
 #define IM_DEBUG_CMD_DEVICE   TYPE_TAPE
 
 /* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG   (shpnt->io_port)   /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG  (shpnt->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG   (shpnt->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG  (shpnt->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG  (shpnt->io_port+7) /*Basic Status (1 byte, read only) */
+#define IM_CMD_REG(hi)   (hosts[(hi)]->io_port)   /*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(hi)  (hosts[(hi)]->io_port+4) /*Attention (1 byte) */
+#define IM_CTR_REG(hi)   (hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */
+#define IM_INTR_REG(hi)  (hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(hi)  (hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */
 
 /* basic I/O-port of first adapter */
 #define IM_IO_PORT   0x3540
@@ -668,9 +239,15 @@
 
 /* use_display is set by the ibmmcascsi=display command line arg */
 static int use_display = 0;
+/* use_adisplay is set by ibmmcascsi=adisplay, which offers a higher
+ * level of displayed luxus on PS/2 95 (really fancy! :-))) */
+static int use_adisplay = 0;
+
 #define PS2_DISK_LED_ON(ad,id) {\
 	if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \
         outb((char)(ad+48), MOD95_LED_PORT+1); } \
+        else if( use_adisplay ) { if (id<7) outb((char)(id+48), \
+	MOD95_LED_PORT+1+id); outb((char)(ad+48), MOD95_LED_PORT); } \
 	else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
 }
 
@@ -678,6 +255,11 @@
 #define PS2_DISK_LED_OFF() {\
 	if( use_display ) { outb( ' ', MOD95_LED_PORT ); \
         outb(' ', MOD95_LED_PORT+1); } \
+        if ( use_adisplay ) { outb(' ',MOD95_LED_PORT ); \
+	outb(' ',MOD95_LED_PORT+1); outb(' ',MOD95_LED_PORT+2); \
+        outb(' ',MOD95_LED_PORT+3); outb(' ',MOD95_LED_PORT+4); \
+        outb(' ',MOD95_LED_PORT+5); outb(' ',MOD95_LED_PORT+6); \
+	outb(' ',MOD95_LED_PORT+7); } \
 	else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
 }
 
@@ -693,18 +275,20 @@
 /* List of possible IBM-SCSI-adapters */
 struct subsys_list_struct subsys_list[] =
 {
-  {0x8efc, "IBM Fast SCSI-2 Adapter"},
-  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"},
-  {0x8ef8, "IBM Expansion Unit SCSI Controller"},
-  {0x8eff, "IBM SCSI Adapter w/Cache"},
-  {0x8efe, "IBM SCSI Adapter"},
-};
+  {0x8efc, "IBM Fast SCSI-2 Adapter"}, /* special = 0 */
+  {0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/cache"}, /* special = 1 */
+  {0x8ef8, "IBM Expansion Unit SCSI Controller"},/* special = 2 */
+  {0x8eff, "IBM SCSI Adapter w/Cache"}, /* special = 3 */
+  {0x8efe, "IBM SCSI Adapter"}, /* special = 4 */
+};                   
 
 /*for /proc filesystem */
 struct proc_dir_entry proc_scsi_ibmmca =
 {
   PROC_SCSI_IBMMCA, 6, "ibmmca",
-  S_IFDIR | S_IRUGO | S_IXUGO, 2
+  S_IFDIR | S_IRUGO | S_IXUGO, 2,
+  0, 0, 0, NULL, NULL, NULL, NULL,
+  NULL, NULL, NULL 
 };
 
 /* Max number of logical devices (can be up from 0 to 14).  15 is the address
@@ -715,8 +299,9 @@
 struct logical_device
   {
     struct im_scb scb; /* SCSI-subsystem-control-block structure */
-    struct im_tsb tsb;
-    struct im_sge sge[16];
+    struct im_tsb tsb; /* SCSI command complete status block structure */
+    struct im_sge sge[16]; /* scatter gather list structure */
+    unsigned char buf[256]; /* SCSI command return data buffer */
     Scsi_Cmnd *cmd;  /* SCSI-command that is currently in progress */
      
     int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
@@ -736,6 +321,7 @@
       int total_accesses;                    /* total accesses on all ldns */
       int total_interrupts;                  /* total interrupts (should be
 						same as total_accesses) */
+      int total_errors;                      /* command completed with error */
       /* dynamical assignment statistics */
       int total_scsi_devices;                /* number of physical pun,lun */
       int dyn_flag;                          /* flag showing dynamical mode */
@@ -747,44 +333,54 @@
 /* data structure for each host adapter */
 struct ibmmca_hostdata
 {
-  /* array of logical devices: */
-    struct logical_device _ld[MAX_LOG_DEV];   
-  /* array to convert (pun, lun) into logical device number: */
-    unsigned char _get_ldn[8][8];
-  /*array that contains the information about the physical SCSI-devices
-   attached to this host adapter: */
-    unsigned char _get_scsi[8][8];
-  /* used only when checking logical devices: */
-    int _local_checking_phase_flag;
-  /* report received interrupt: */
-    int _got_interrupt;
-  /* report termination-status of SCSI-command: */
-    int _stat_result;
-  /* reset status (used only when doing reset): */
-    int _reset_status;
-  /* code of the last SCSI command (needed for panic info): */
-    int _last_scsi_command;
-  /* Counter that points on the next reassignable ldn for dynamical 
-   remapping. The default value is 7, that is the first reassignable 
-   number in the list at boottime: */
-    int _next_ldn;
-  /* Statistics-structure for this IBM-SCSI-host: */
-    struct Driver_Statistics _IBM_DS;
+   /* array of logical devices: */
+   struct logical_device _ld[MAX_LOG_DEV+1];   
+   /* array to convert (pun, lun) into logical device number: */
+   unsigned char _get_ldn[8][8];
+   /*array that contains the information about the physical SCSI-devices
+    attached to this host adapter: */
+   unsigned char _get_scsi[8][8];
+   /* used only when checking logical devices: */
+   int _local_checking_phase_flag;
+   /* report received interrupt: */
+   int _got_interrupt;
+   /* report termination-status of SCSI-command: */
+   int _stat_result;
+   /* reset status (used only when doing reset): */
+   int _reset_status;
+   /* code of the last SCSI command (needed for panic info): */
+   int _last_scsi_command[MAX_LOG_DEV+1];
+   /* identifier of the last SCSI-command type */
+   int _last_scsi_type[MAX_LOG_DEV+1];
+   /* Counter that points on the next reassignable ldn for dynamical 
+    remapping. The default value is 7, that is the first reassignable 
+    number in the list at boottime: */
+   int _next_ldn;
+   /* Statistics-structure for this IBM-SCSI-host: */
+   struct Driver_Statistics _IBM_DS;
+   /* This hostadapters pos-registers pos2 and pos3 */
+   unsigned _pos2, _pos3;
+   /* assign a special variable, that contains dedicated info about the
+    adaptertype */
+   int _special;
 };
 
 /* macros to access host data structure */
-#define HOSTDATA(shpnt) ((struct ibmmca_hostdata *) shpnt->hostdata)
-#define subsystem_pun (shpnt->this_id)
-#define ld (HOSTDATA(shpnt)->_ld)
-#define get_ldn (HOSTDATA(shpnt)->_get_ldn)
-#define get_scsi (HOSTDATA(shpnt)->_get_scsi)
-#define local_checking_phase_flag (HOSTDATA(shpnt)->_local_checking_phase_flag)
-#define got_interrupt (HOSTDATA(shpnt)->_got_interrupt)
-#define stat_result (HOSTDATA(shpnt)->_stat_result)
-#define reset_status (HOSTDATA(shpnt)->_reset_status)
-#define last_scsi_command (HOSTDATA(shpnt)->_last_scsi_command)
-#define next_ldn (HOSTDATA(shpnt)->_next_ldn)
-#define IBM_DS (HOSTDATA(shpnt)->_IBM_DS)
+#define subsystem_pun(hi) (hosts[(hi)]->this_id)
+#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
+#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
+#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
+#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)
+#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)
+#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)
+#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
+#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
+#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
+#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
+#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos2)
+#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos3)
 
 /* Define a arbitrary number as subsystem-marker-type. This number is, as 
    described in the ANSI-SCSI-standard, not occupied by other device-types. */
@@ -805,11 +401,23 @@
 #define SET_LDN        0
 #define REMOVE_LDN     1
 
+/* ldn which is used to probe the SCSI devices */
+#define PROBE_LDN      0
+
 /* reset status flag contents */
-#define IM_RESET_NOT_IN_PROGRESS   0
-#define IM_RESET_IN_PROGRESS       1
-#define IM_RESET_FINISHED_OK       2
-#define IM_RESET_FINISHED_FAIL     3
+#define IM_RESET_NOT_IN_PROGRESS         0
+#define IM_RESET_IN_PROGRESS             1
+#define IM_RESET_FINISHED_OK             2
+#define IM_RESET_FINISHED_FAIL           3
+#define IM_RESET_NOT_IN_PROGRESS_NO_INT  4
+#define IM_RESET_FINISHED_OK_NO_INT      5
+
+/* special flags for hostdata structure */
+#define FORCED_DETECTION         100
+#define INTEGRATED_SCSI          101
+
+/* define undefined SCSI-command */
+#define NO_SCSI                  0xffff
 
 /*-----------------------------------------------------------------------*/
 
@@ -823,277 +431,517 @@
 MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
 MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i"); 
 MODULE_PARM(display, "1i");
+MODULE_PARM(adisplay, "1i");
+MODULE_PARM(bypass, "1i");
+MODULE_PARM(normal, "1i");
+MODULE_PARM(ansi, "1i");
 #endif
 
 /*counter of concurrent disk read/writes, to turn on/off disk led */
 static int disk_rw_in_progress = 0;
 
+/* spinlock handling to avoid command clash while in operation */
+#ifndef OLDKERN
+spinlock_t info_lock  = SPIN_LOCK_UNLOCKED;
+spinlock_t proc_lock  = SPIN_LOCK_UNLOCKED;
+spinlock_t abort_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t reset_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t issue_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t intr_lock  = SPIN_LOCK_UNLOCKED;
+#endif
+
 /* host information */
 static int found = 0;
 static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = { NULL };
+static unsigned int pos[8]; /* whole pos register-line */
+/* Taking into account the additions, made by ZP Gu.
+ * This selects now the preset value from the configfile and
+ * offers the 'normal' commandline option to be accepted */
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+static char ibm_ansi_order = 1;
+#else
+static char ibm_ansi_order = 0;
+#endif
+
 /*-----------------------------------------------------------------------*/
 
-/*local functions in forward declaration */
-static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs);
-static void issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
-                       unsigned char attn_reg);
+/******************* FUNCTIONS IN FORWARD DECLARATION ************************/
+
+static void interrupt_handler (int, void *, struct pt_regs *);
+#ifndef OLDKERN
+static void do_interrupt_handler (int, void *, struct pt_regs *);
+#endif
+static void issue_cmd (int, unsigned long, unsigned char);
 static void internal_done (Scsi_Cmnd * cmd);
-static void check_devices (struct Scsi_Host *shpnt);
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, 
-                            unsigned int lun, unsigned int ldn, 
-                            unsigned int operation);
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn, 
-                          unsigned char *buf);
-static char *ti_p(int value);
-static char *ti_l(int value);
-static int device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length,
-                          int *device_type);
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * template, 
-					 int port, int id);
+static void check_devices (int);
+static int immediate_assign(int, unsigned int, unsigned int, unsigned int, 
+                            unsigned int);
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int, unsigned int);
+#endif
+static int device_inquiry(int, int);
+static int read_capacity(int, int);
+static char *ti_p(int);
+static char *ti_l(int);
+static int device_exists (int, int, int *, int *);
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, 
+					 int, int, char *);
 
 /* local functions needed for proc_info */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn);
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt);
+static int ldn_access_load(int, int);
+static int ldn_access_total_read_write(int);
 
+static int bypass_controller = 0;   /* bypass integrated SCSI-cmd set flag */
 /*--------------------------------------------------------------------*/
 
-static void 
-do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+/******************* LOCAL FUNCTIONS IMPLEMENTATION *************************/
+
+#ifndef OLDKERN
+/* newer Kernels need the spinlock interrupt handler */
+static void do_interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
   unsigned long flags;
 
   spin_lock_irqsave(&io_request_lock, flags);
   interrupt_handler(irq, dev_id, regs);
   spin_unlock_irqrestore(&io_request_lock, flags);
+  return; 
 }
+#endif
 
-static void 
-interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
-  int i = 0;
-  struct Scsi_Host *shpnt;
-  unsigned int intr_reg;
-  unsigned int cmd_result;
-  unsigned int ldn;
-  unsigned long flags;
+   int host_index;
+   unsigned int intr_reg;
+   unsigned int cmd_result;
+   unsigned int ldn;
+   static unsigned long flags;
+   Scsi_Cmnd *cmd;
+   int errorflag;
+   int interror;
 
-  /* search for one adapter-response on shared interrupt */
-  do
-    shpnt = hosts[i++];
-  while (shpnt && !(inb(IM_STAT_REG) & IM_INTR_REQUEST));
-
-  /* return if some other device on this IRQ caused the interrupt */
-  if (!shpnt) return;
-
-  /*get command result and logical device */
-  intr_reg = inb (IM_INTR_REG);
-  cmd_result = intr_reg & 0xf0;
-  ldn = intr_reg & 0x0f;
-
-  /*must wait for attention reg not busy, then send EOI to subsystem */
-  save_flags(flags);
-  while (1) {
-      cli ();
-      if (!(inb (IM_STAT_REG) & IM_BUSY)) 
-        break;
-      restore_flags(flags);
-    }
-  outb (IM_EOI | ldn, IM_ATTN_REG);
-  restore_flags (flags);
-
-  /*these should never happen (hw fails, or a local programming bug) */
-  if (cmd_result == IM_ADAPTER_HW_FAILURE)
-    panic ("IBM MCA SCSI: subsystem hardware failure. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-  if (cmd_result == IM_CMD_ERROR)
-    panic ("IBM MCA SCSI: command error. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-  if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
-    panic ("IBM MCA SCSI: software sequencing error. Last SCSI_CMD=0x%X. \n",
-	   last_scsi_command);
-
-  /* if no panic appeared, increase the interrupt-counter */
-  IBM_DS.total_interrupts++;
-   
-  /*only for local checking phase */
-  if (local_checking_phase_flag)
-    {
-      stat_result = cmd_result;
-      got_interrupt = 1;
-      reset_status = IM_RESET_FINISHED_OK;
-      return;
-    }
-
-  /*handling of commands coming from upper level of scsi driver */
-  else
-    {
-      Scsi_Cmnd *cmd;
-
-      /*verify ldn, and may handle rare reset immediate command */
-      if (ldn >= MAX_LOG_DEV)
-	{
-	  if (ldn == 0xf && reset_status == IM_RESET_IN_PROGRESS)
-	    {
-	      if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-		{
-		  reset_status = IM_RESET_FINISHED_FAIL;
-		}
-	      else
-		{
-		  /*reset disk led counter, turn off disk led */
-		  disk_rw_in_progress = 0;
-		  PS2_DISK_LED_OFF ();
-		  reset_status = IM_RESET_FINISHED_OK;
-		}
-	      return;
-	    }
-	  else
-	    panic ("IBM MCA SCSI: invalid logical device number.\n");
-	}
+   host_index=0; /* make sure, host_index is 0, else this won't work and
+		    never dare to ask, what happens, if an interrupt-handler
+		    does not work :-((( .... */
+   
+   /* search for one adapter-response on shared interrupt */
+   while (hosts[host_index]
+	  && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST))
+     host_index++;
+   
+   /* return if some other device on this IRQ caused the interrupt */
+   if (!hosts[host_index]) return;
 
-#ifdef IM_DEBUG_TIMEOUT
-      {
-        static int count = 0;
+   /* the reset-function already did all the job, even ints got
+      renabled on the subsystem, so just return */
+   if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)||
+       (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT))
+     {
+	reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
+	return;
+     }
+   
+   /*get command result and logical device */
+   intr_reg = inb (IM_INTR_REG(host_index));
+   cmd_result = intr_reg & 0xf0;
+   ldn = intr_reg & 0x0f;
 
-        if (++count == IM_DEBUG_TIMEOUT) {
-          printk("IBM MCA SCSI: Ignoring interrupt.\n");
-          return;
-        }
-      }
+   /*must wait for attention reg not busy, then send EOI to subsystem */
+   while (1) 
+     {
+#ifdef OLDKERN
+	save_flags(flags);
+	cli();
+#else
+	spin_lock_irqsave(&intr_lock, flags);
+#endif	
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) 
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&intr_lock, flags);
 #endif
+     }
+   outb (IM_EOI | ldn, IM_ATTN_REG(host_index));
+   /* get the last_scsi_command here */
+   interror = last_scsi_command(host_index)[ldn];   
+#ifdef OLDKERN
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&intr_lock, flags);
+#endif      
+   errorflag = 0; /* no errors by default */   
+   /*these should never happen (hw fails, or a local programming bug) */
+   if (cmd_result == IM_ADAPTER_HW_FAILURE)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - subsystem hardware failure!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;
+     }
+   if (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - software sequencing error!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;	
+     }
+   if (cmd_result == IM_CMD_ERROR)
+     {
+	printk("\n");
+	printk("IBM MCA SCSI: ERROR - command error!\n");
+	printk("              Last SCSI-command=0x%X, ldn=%d, host=%d.\n",
+	       last_scsi_command(host_index)[ldn],ldn,host_index);
+	errorflag = 1;	
+     }
+   if (errorflag)
+     { /* if errors appear, enter this section to give detailed info */
+	printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
+	printk("              Command Type................: %x\n",
+	       last_scsi_type(host_index)[ldn]);
+	printk("              Attention Register..........: %x\n",
+	       inb (IM_ATTN_REG(host_index)));
+        printk("              Basic Control Register......: %x\n",
+	       inb (IM_CTR_REG(host_index)));
+	printk("              Interrupt Status Register...: %x\n",
+	       intr_reg);
+	printk("              Basic Status Register.......: %x\n",
+	       inb (IM_STAT_REG(host_index)));
+	if ((last_scsi_type(host_index)[ldn]==IM_SCB)||
+	    (last_scsi_type(host_index)[ldn]==IM_LONG_SCB))
+	  {
+	     printk("              SCB End Status Word.........: %x\n",
+		    ld(host_index)[ldn].tsb.end_status);
+	     printk("              Command Status..............: %x\n",
+		    ld(host_index)[ldn].tsb.cmd_status);
+	     printk("              Device Status...............: %x\n",
+		    ld(host_index)[ldn].tsb.dev_status);
+	     printk("              Command Error...............: %x\n",
+		    ld(host_index)[ldn].tsb.cmd_error);
+	     printk("              Device Error................: %x\n",
+		    ld(host_index)[ldn].tsb.dev_error);
+	     printk("              Last SCB Address (LSW)......: %x\n",
+		    ld(host_index)[ldn].tsb.low_of_last_scb_adr);
+	     printk("              Last SCB Address (MSW)......: %x\n",
+		    ld(host_index)[ldn].tsb.high_of_last_scb_adr);
+	  }
+	printk("              Send report to the maintainer.\n");
+	panic("IBM MCA SCSI: Fatal errormessage from the subsystem!\n");
+     }
+   
+   /* if no panic appeared, increase the interrupt-counter */
+   IBM_DS(host_index).total_interrupts++;
 
-      /*if no command structure, just return, else clear cmd */
-      cmd = ld[ldn].cmd;
-      if (!cmd)
+   /*only for local checking phase */
+   if (local_checking_phase_flag(host_index))
+     {
+	stat_result(host_index) = cmd_result;
+	got_interrupt(host_index) = 1;
+	reset_status(host_index) = IM_RESET_FINISHED_OK;
+	last_scsi_command(host_index)[ldn] = NO_SCSI;
 	return;
-      ld[ldn].cmd = 0;
-
+     }   
+   /*handling of commands coming from upper level of scsi driver */
+   else
+     {
+	if (last_scsi_type(host_index)[ldn] == IM_IMM_CMD)
+	  {
+	     /*verify ldn, and may handle rare reset immediate command */
+	     if ((reset_status(host_index) == IM_RESET_IN_PROGRESS)&&
+		 (last_scsi_command(host_index)[ldn] == IM_RESET_IMM_CMD))
+	       {
+		  if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+		    {
+		       disk_rw_in_progress = 0;
+		       PS2_DISK_LED_OFF ();
+		       reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		    }
+		  else
+		    {
+		       /*reset disk led counter, turn off disk led */
+		       disk_rw_in_progress = 0;
+		       PS2_DISK_LED_OFF ();
+		       reset_status(host_index) = IM_RESET_FINISHED_OK;
+		    }
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  return;
+	       }
+	     else if (last_scsi_command(host_index)[ldn] == IM_ABORT_IMM_CMD)
+	       { /* react on SCSI abort command */
+#ifdef IM_DEBUG_PROBE
+		  printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
+#endif	
+		  disk_rw_in_progress = 0;
+		  PS2_DISK_LED_OFF();
+		  cmd = ld(host_index)[ldn].cmd;
+		  if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+		    cmd->result = DID_NO_CONNECT << 16;
+		  else
+		    cmd->result = DID_ABORT << 16;
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  if (cmd->scsi_done)
+		    (cmd->scsi_done) (cmd); /* should be the internal_done */
+		  return;
+	       }
+	     else
+	       {
+		  disk_rw_in_progress = 0;
+		  PS2_DISK_LED_OFF ();
+		  reset_status(host_index) = IM_RESET_FINISHED_OK;
+		  stat_result(host_index) = cmd_result;
+		  last_scsi_command(host_index)[ldn] = NO_SCSI;
+		  return;
+	       }	     
+	  }
+	last_scsi_command(host_index)[ldn] = NO_SCSI;	     
+	cmd = ld(host_index)[ldn].cmd;
+#ifdef IM_DEBUG_TIMEOUT
+	if (cmd)
+	  {
+	     if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN))
+	       {
+		  printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n",
+			 cmd->target, cmd->lun);
+		  return;
+	       }
+	  }
+#endif
+	/*if no command structure, just return, else clear cmd */
+	if (!cmd)
+	  return;
+	ld(host_index)[ldn].cmd = NULL;
+	
 #ifdef IM_DEBUG_INT
-      printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", 
-         cmd->cmnd[0], intr_reg, 
-         ld[ldn].tsb.dev_status, ld[ldn].tsb.cmd_status, 
-         ld[ldn].tsb.dev_error, ld[ldn].tsb.cmd_error); 
-#endif
-
-      /*if this is end of media read/write, may turn off PS/2 disk led */
-      if ((ld[ldn].device_type!=TYPE_NO_LUN)&&
-	  (ld[ldn].device_type!=TYPE_NO_DEVICE))
-	{ /* only access this, if there was a valid device addressed */
-	  switch (cmd->cmnd[0])
-	    {
-	    case READ_6:
-	    case WRITE_6:
-	    case READ_10:
-	    case WRITE_10:
-	    case READ_12:
-	    case WRITE_12:
-	      if (--disk_rw_in_progress == 0)
-		PS2_DISK_LED_OFF ();
-	    }
-	}
-       
-      /*write device status into cmd->result, and call done function */
-      if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-	cmd->result = ld[ldn].tsb.dev_status & 0x1e;
-      else
-	cmd->result = 0;
-      (cmd->scsi_done) (cmd);
-    }
-}
-
-/*--------------------------------------------------------------------*/
-
-static void 
-issue_cmd (struct Scsi_Host *shpnt, unsigned long cmd_reg, 
-           unsigned char attn_reg)
-{
-  unsigned long flags;
-  /*must wait for attention reg not busy */
-  save_flags(flags);
-  while (1)
-    {
-      cli ();
-      if (!(inb (IM_STAT_REG) & IM_BUSY))
-	break;
-      restore_flags (flags);
-    }
+	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", 
+	       cmd->cmnd[0], intr_reg, 
+	       ld(host_index)[ldn].tsb.dev_status, 
+	       ld(host_index)[ldn].tsb.cmd_status,
+	       ld(host_index)[ldn].tsb.dev_error, 
+	       ld(host_index)[ldn].tsb.cmd_error);
+#endif
+	
+	/*if this is end of media read/write, may turn off PS/2 disk led */
+	if ((ld(host_index)[ldn].device_type!=TYPE_NO_LUN)&&
+	    (ld(host_index)[ldn].device_type!=TYPE_NO_DEVICE))
+	  { /* only access this, if there was a valid device addressed */
+	     switch (cmd->cmnd[0])
+	       {
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+		case READ_12:
+		case WRITE_12:
+		  if (--disk_rw_in_progress == 0)
+		    PS2_DISK_LED_OFF ();
+	       }
+	  }
 
-  /*write registers and enable system interrupts */
-  outl (cmd_reg, IM_CMD_REG);
-  outb (attn_reg, IM_ATTN_REG);
-  restore_flags (flags);
+	/* IBM describes the status-mask to be 0x1e, but this is not conform
+	 * with SCSI-defintion, I suppose, it is a printing error in the
+	 * technical reference and assume as mask 0x3e. (ML) */
+	cmd->result = (ld(host_index)[ldn].tsb.dev_status & 0x3e);
+	/* write device status into cmd->result, and call done function */
+	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+	  IBM_DS(host_index).total_errors++;
+	if (interror == NO_SCSI) /* unexpected interrupt :-( */
+	  cmd->result |= DID_BAD_INTR << 16;
+	else
+	  cmd->result |= DID_OK << 16;
+	(cmd->scsi_done) (cmd);
+     }
+   if (interror == NO_SCSI)
+     printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
+   return;
 }
 
 /*--------------------------------------------------------------------*/
 
-static void 
-internal_done (Scsi_Cmnd * cmd)
+static void issue_cmd (int host_index, unsigned long cmd_reg, 
+		       unsigned char attn_reg)
 {
-  cmd->SCp.Status++;
+   static unsigned long flags;
+   /* must wait for attention reg not busy */   
+   while (1)
+     {
+#ifdef OLDKERN	
+	save_flags(flags);
+	cli();
+#else
+	spin_lock_irqsave(&issue_lock, flags);
+#endif	
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&issue_lock, flags);
+#endif	
+     }
+   /*write registers and enable system interrupts */
+   outl (cmd_reg, IM_CMD_REG(host_index));
+   outb (attn_reg, IM_ATTN_REG(host_index));
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&issue_lock, flags);
+#endif
 }
 
 /*--------------------------------------------------------------------*/
 
-static int ibmmca_getinfo (char *buf, int slot, void *dev)
+static void internal_done (Scsi_Cmnd * cmd)
 {
-  struct Scsi_Host *shpnt = dev;
-  int len = 0;
-
-  len += sprintf (buf + len, "Subsystem PUN: %d\n", subsystem_pun);
-  len += sprintf (buf + len, "I/O base address: 0x%lx\n", IM_CMD_REG);
-  return len;
+   cmd->SCp.Status++;
 }
 
 /*--------------------------------------------------------------------*/
 
 /* SCSI-SCB-command for device_inquiry */
-static int device_inquiry(struct Scsi_Host *shpnt, int ldn, unsigned char *buf)
+static int device_inquiry(int host_index, int ldn)
 {   
-  struct im_scb scb;
-  struct im_tsb tsb;
-  int retries;
-
-  for (retries = 0; retries < 3; retries++)
-    {
-      /*fill scb with inquiry command */
-      scb.command = IM_DEVICE_INQUIRY_CMD;
-      scb.enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      scb.sys_buf_adr = virt_to_bus(buf);
-      scb.sys_buf_length = 255;
-      scb.tsb_adr = virt_to_bus(&tsb);
-
-      /*issue scb to passed ldn, and busy wait for interrupt */
-      got_interrupt = 0;
-      issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-      while (!got_interrupt)
-	barrier ();
-
-      /*if command succesful, break */
-      if (stat_result == IM_SCB_CMD_COMPLETED)
-	break;
-    }
+   int retries;
+   Scsi_Cmnd cmd;
+   struct im_scb *scb;
+   struct im_tsb *tsb;
+   unsigned char *buf;
+   
+   scb = &(ld(host_index)[ldn].scb);
+   tsb = &(ld(host_index)[ldn].tsb);
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
+   ld(host_index)[ldn].tsb.dev_status = 0; /* prepare stusblock */
+
+   if (bypass_controller)
+     { /* fill the commonly known field for device-inquiry SCSI cmnd */
+	cmd.cmd_len = 6;
+        memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
+	cmd.cmnd[0] = INQUIRY; /* device inquiry */
+	cmd.cmnd[4] = 0xff; /* return buffer size = 255 */
+     }   
+   for (retries = 0; retries < 3; retries++)
+     {
+	if (bypass_controller)
+	  { /* bypass the hardware integrated command set */
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT; 
+	     scb->u1.scsi_cmd_length = cmd.cmd_len;
+	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
+	     last_scsi_command(host_index)[ldn] = INQUIRY;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;
+	  }
+	else
+	  {
+	     /*fill scb with inquiry command */
+	     scb->command = IM_DEVICE_INQUIRY_CMD;
+	     scb->enable = IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
+	  }
+	scb->sys_buf_adr = virt_to_bus(buf);
+	scb->sys_buf_length = 0xff; /* maximum bufferlength gives max info */
+	scb->tsb_adr = virt_to_bus(tsb);
+	
+	/*issue scb to passed ldn, and busy wait for interrupt */
+	got_interrupt(host_index) = 0;
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	while (!got_interrupt(host_index))
+	  barrier ();
+	
+	/*if command succesful, break */
+	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+	  {
+	     return 1;
+	  }
+     }
+   
+   /*if all three retries failed, return "no device at this ldn" */
+   if (retries >= 3)
+     return 0;
+   else
+     return 1;
+}
 
-  /*if all three retries failed, return "no device at this ldn" */
-  if (retries >= 3)
-    return 0;
-  else
-    return 1;
+static int read_capacity(int host_index, int ldn)
+{
+   int retries;
+   Scsi_Cmnd cmd;
+   struct im_scb *scb;
+   struct im_tsb *tsb;
+   unsigned char *buf;
+   
+   scb = &(ld(host_index)[ldn].scb);
+   tsb = &(ld(host_index)[ldn].tsb);
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
+   ld(host_index)[ldn].tsb.dev_status = 0;
+   
+   if (bypass_controller)
+     { /* read capacity in commonly known default SCSI-format */
+	cmd.cmd_len = 10;
+        memset (&(cmd.cmnd), 0x0, sizeof(char) * cmd.cmd_len);
+	cmd.cmnd[0] = READ_CAPACITY; /* read capacity */
+     }	
+   for (retries = 0; retries < 3; retries++)
+     {
+	/*fill scb with read capacity command */
+	if (bypass_controller)
+	  { /* bypass the SCSI-command */
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd.cmd_len;
+	     memcpy (scb->u2.scsi_command, &(cmd.cmnd), cmd.cmd_len);
+	     last_scsi_command(host_index)[ldn] = READ_CAPACITY;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;
+	  }
+	else
+	  {
+	     scb->command = IM_READ_CAPACITY_CMD;
+	     scb->enable = IM_READ_CONTROL;
+	     last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
+	     last_scsi_type(host_index)[ldn] = IM_SCB;	     
+	  }
+	scb->sys_buf_adr = virt_to_bus(buf);
+	scb->sys_buf_length = 8;
+	scb->tsb_adr = virt_to_bus(tsb);
+	
+	/*issue scb to passed ldn, and busy wait for interrupt */
+	got_interrupt(host_index) = 0;
+	issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+	while (!got_interrupt(host_index))
+	  barrier ();
+	     
+	     /*if got capacity, get block length and return one device found */
+	if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
+	    (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+	  {
+	     return 1;
+	  }
+     }
+   /*if all three retries failed, return "no device at this ldn" */
+   if (retries >= 3)
+     return 0;
+   else
+     return 1;
 }
 
 /* SCSI-immediate-command for assign. This functions maps/unmaps specific
-   ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
-   subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, 
+ ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
+ subsystem and for dynamical remapping od ldns. */
+static int immediate_assign(int host_index, unsigned int pun, 
                             unsigned int lun, unsigned int ldn, 
                             unsigned int operation)
 {
    int retries;
    unsigned long imm_command;
-
+   
    for (retries=0; retries<3; retries ++)
-     {	
-        imm_command = inl(IM_CMD_REG);
+     {
+        imm_command = inl(IM_CMD_REG(host_index));
         imm_command &= (unsigned long)(0xF8000000); /* keep reserved bits */
         imm_command |= (unsigned long)(IM_ASSIGN_IMM_CMD);
         imm_command |= (unsigned long)((lun & 7) << 24);
@@ -1101,14 +949,64 @@
         imm_command |= (unsigned long)((pun & 7) << 20);
         imm_command |= (unsigned long)((ldn & 15) << 16);
 	
-        got_interrupt = 0;
-        issue_cmd (shpnt, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
-        while (!got_interrupt)
-           barrier ();
-	       
+	last_scsi_command(host_index)[0xf] = IM_ASSIGN_IMM_CMD;
+	last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+        got_interrupt(host_index) = 0;
+        issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | 0xf);
+        while (!got_interrupt(host_index))
+	  barrier ();
+	
+        /*if command succesful, break */
+	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  {
+	     return 1;
+	  }
+     }
+   
+   if (retries >= 3) 
+     return 0;
+   else
+     return 1;
+}
+
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int host_index, unsigned int ldn)
+{
+   int retries;
+   int ticks;
+   unsigned long imm_command;
+   
+   for (retries=0; retries<3; retries ++)
+     {
+        imm_command = inl(IM_CMD_REG(host_index));
+        imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */
+        imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
+	last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
+	last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+
+	got_interrupt(host_index) = 0;
+	reset_status(host_index) = IM_RESET_IN_PROGRESS;        
+	issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn);
+	ticks = IM_RESET_DELAY*HZ;	
+	while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) 
+	  {
+	     mdelay(1+999/HZ);
+	     barrier();
+	  }
+	/* if reset did not complete, just claim */
+	if (!ticks) 
+	  {
+	     printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
+		    IM_RESET_DELAY);
+	     reset_status(host_index) = IM_RESET_FINISHED_OK; 
+	     /* did not work, finish */
+	     return 1;
+	  }
         /*if command succesful, break */
-        if (stat_result == IM_IMMEDIATE_CMD_COMPLETED)
-           break;
+	if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+	  {
+	     return 1;
+	  }
      }
    
    if (retries >= 3) 
@@ -1116,24 +1014,25 @@
    else
      return 1;
 }
+#endif
 
 /* type-interpreter for physical device numbers */
 static char *ti_p(int value)
 {
    switch (value)
      {
-	case TYPE_IBM_SCSI_ADAPTER: return("A"); break;
-	case TYPE_DISK:             return("D"); break;
-	case TYPE_TAPE:             return("T"); break;
-	case TYPE_PROCESSOR:        return("P"); break;
-	case TYPE_WORM:             return("W"); break;
-	case TYPE_ROM:              return("R"); break;
-	case TYPE_SCANNER:          return("S"); break;
-	case TYPE_MOD:              return("M"); break;
-        case TYPE_MEDIUM_CHANGER:   return("C"); break;
-	case TYPE_NO_LUN:           return("+"); break; /* show NO_LUN */
-        case TYPE_NO_DEVICE:
-	default:                    return("-"); break;
+      case TYPE_IBM_SCSI_ADAPTER: return("A"); break;
+      case TYPE_DISK:             return("D"); break;
+      case TYPE_TAPE:             return("T"); break;
+      case TYPE_PROCESSOR:        return("P"); break;
+      case TYPE_WORM:             return("W"); break;
+      case TYPE_ROM:              return("R"); break;
+      case TYPE_SCANNER:          return("S"); break;
+      case TYPE_MOD:              return("M"); break;
+      case TYPE_MEDIUM_CHANGER:   return("C"); break;
+      case TYPE_NO_LUN:           return("+"); break; /* show NO_LUN */
+      case TYPE_NO_DEVICE:
+      default:                    return("-"); break;
      }
    return("-");
 }
@@ -1141,9 +1040,9 @@
 /* interpreter for logical device numbers (ldn) */
 static char *ti_l(int value)
 {
-   const char hex[16] = ("0123456789abcdef");
+   const char hex[16] = "0123456789abcdef";
    static char answer[2];
-
+   
    answer[1] = (char)(0x0);
    if (value<=MAX_LOG_DEV)
      answer[0] = hex[value];
@@ -1154,182 +1053,181 @@
 }
 
 /* 
-   The following routine probes the SCSI-devices in four steps:
-   1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
-   2. ldn 0 is used to go through all possible combinations of pun,lun and
-      a device_inquiry is done to fiddle out whether there is a device
-      responding or not. This physical map is stored in get_scsi[][].
-   3. The 15 available ldns (0-14) are mapped to existing pun,lun.
-      If there are more devices than ldns, it stops at 14 for the boot
-      time. Dynamical remapping will be done in ibmmca_queuecommand.
-   4. If there are less than 15 valid pun,lun, the remaining ldns are
-      mapped to NON-existing pun,lun to satisfy the adapter. Information
-      about pun,lun -> ldn is stored as before in get_ldn[][].
-   This method leads to the result, that the SCSI-pun,lun shown to Linux
-   mid-level- and higher-level-drivers is exactly corresponding to the
-   physical reality on the SCSI-bus. Therefore, it is possible that users
-   of older releases of this driver have to rewrite their fstab-file, because
-   the /dev/sdXXX could have changed due to the right pun,lun report, now.
-   The assignment of ALL ldns avoids dynamical remapping by the adapter
-   itself.
+ The following routine probes the SCSI-devices in four steps:
+ 1. The current ldn -> pun,lun mapping is removed on the SCSI-adapter.
+ 2. ldn 0 is used to go through all possible combinations of pun,lun and
+ a device_inquiry is done to fiddle out whether there is a device
+ responding or not. This physical map is stored in get_scsi[][].
+ 3. The 15 available ldns (0-14) are mapped to existing pun,lun.
+ If there are more devices than ldns, it stops at 14 for the boot
+ time. Dynamical remapping will be done in ibmmca_queuecommand.
+ 4. If there are less than 15 valid pun,lun, the remaining ldns are
+ mapped to NON-existing pun,lun to satisfy the adapter. Information
+ about pun,lun -> ldn is stored as before in get_ldn[][].
+ This method leads to the result, that the SCSI-pun,lun shown to Linux
+ mid-level- and higher-level-drivers is exactly corresponding to the
+ physical reality on the SCSI-bus. Therefore, it is possible that users
+ of older releases of this driver have to rewrite their fstab-file, because
+ the /dev/sdXXX could have changed due to the right pun,lun report, now.
+ The assignment of ALL ldns avoids dynamical remapping by the adapter
+ itself.
  */
-static void check_devices (struct Scsi_Host *shpnt)
+static void check_devices (int host_index)
 {
-  int id, lun, ldn;
-  unsigned char buf[256];
-  int count_devices = 0; /* local counter for connected device */
-   
-  /* assign default values to certain variables */
-  
-  IBM_DS.dyn_flag = 0; /* normally no need for dynamical ldn management */
-  next_ldn = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
-  last_scsi_command = 0; /* emptify last SCSI-command storage */
-  
-  /* initialize the very important driver-informational arrays/structs */
-  memset (ld, 0, sizeof ld);
-  memset (get_ldn, TYPE_NO_DEVICE, sizeof get_ldn); /* this is essential ! */
-  memset (get_scsi, TYPE_NO_DEVICE, sizeof get_scsi); /* this is essential ! */
-
-  for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
-    {
-      get_scsi[subsystem_pun][lun] = TYPE_IBM_SCSI_ADAPTER; 
-      get_ldn[subsystem_pun][lun] = MAX_LOG_DEV; /* make sure, the subsystem
-						    ldn is active for all
-						    luns. */
-    }
-
-  /* STEP 1: */
-  printk("IBM MCA SCSI: Removing current logical SCSI-device mapping.");
-  for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
-    {
+   int id, lun, ldn, ticks;
+   int count_devices; /* local counter for connected device */
+   
+   /* assign default values to certain variables */
+
+   ticks = 0;
+   count_devices = 0;
+   IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
+   IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
+   next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
+   for (ldn=0; ldn<=MAX_LOG_DEV; ldn++)
+     {
+	last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
+	last_scsi_type(host_index)[ldn] = 0;
+     }
+
+   /* initialize the very important driver-informational arrays/structs */
+   memset (ld(host_index), 0, 
+	   sizeof(ld(host_index)));
+   memset (get_ldn(host_index), TYPE_NO_DEVICE, 
+	   sizeof(get_ldn(host_index))); /* this is essential ! */
+   memset (get_scsi(host_index), TYPE_NO_DEVICE,
+	   sizeof(get_scsi(host_index))); /* this is essential ! */
+   
+   for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
+     {
+	get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
+	get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
+								ldn is active for all
+								luns. */
+     }
+   
+   /* STEP 1: */
 #ifdef IM_DEBUG_PROBE
-      printk(".");
+   printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index);
 #endif
-      immediate_assign(shpnt,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
-    }
-
-  lun = 0; /* default lun is 0 */
+   printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
+   for (ldn=0; ldn<MAX_LOG_DEV; ldn++)
+     {
+#ifdef IM_DEBUG_PROBE
+	printk(".");
+#endif
+	immediate_assign(host_index,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
+     }
 
-  /* STEP 2: */
-  printk("\nIBM MCA SCSI: Probing SCSI-devices.");
-  for (id=0; id<8; id++)
+   lun = 0; /* default lun is 0 */
+   
+   /* STEP 2: */
+   printk("\nIBM MCA SCSI: Probing SCSI-devices.");
+   for (id=0; id<8; id++)
 #ifdef CONFIG_SCSI_MULTI_LUN
-    for (lun=0; lun<8; lun++)
+     for (lun=0; lun<8; lun++)
 #endif
-      {
+     {
 #ifdef IM_DEBUG_PROBE
 	printk(".");
 #endif
-	if (id != subsystem_pun) 
+	if (id != subsystem_pun(host_index))
 	  {            /* if pun is not the adapter: */
-	    immediate_assign(shpnt,id,lun,0,SET_LDN); /*set ldn=0 to pun,lun*/
-	    if (device_inquiry(shpnt, 0, buf)) /* probe device */
-	      {
-		get_scsi[id][lun]=(unsigned char)buf[0];  /* entry, even 
-							     for NO_LUN */
-		if (buf[0] != TYPE_NO_LUN)
-		  count_devices++; /* a existing device is found */
-	      }
-	    immediate_assign(shpnt,id,lun,0,REMOVE_LDN); /* remove ldn */
+	     /*set ldn=0 to pun,lun*/
+	     immediate_assign(host_index,id,lun,PROBE_LDN,SET_LDN); 
+	     if (device_inquiry(host_index, PROBE_LDN)) /* probe device */
+	       {
+		  get_scsi(host_index)[id][lun]=
+		    (unsigned char)(ld(host_index)[PROBE_LDN].buf[0]);
+		  /* entry, even for NO_LUN */
+		  if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+		    count_devices++; /* a existing device is found */
+	       }
+	     /* remove ldn */
+	     immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN); 
 	  }
-      }
-  
-  /* STEP 3: */   
-  printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+     }
+   
+   /* STEP 3: */   
+   printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+   
+   ldn = 0;
+   lun = 0;
    
-  ldn = 0;
-  lun = 0;
-
 #ifdef CONFIG_SCSI_MULTI_LUN   
-  for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
+   for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
 #endif
-    for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
-      {
+     for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
+     {
 #ifdef IM_DEBUG_PROBE
 	printk(".");
 #endif
-	if (id != subsystem_pun)
+	if (id != subsystem_pun(host_index))
 	  {
-	    if (get_scsi[id][lun] != TYPE_NO_LUN && 
-		get_scsi[id][lun] != TYPE_NO_DEVICE)
-	      {
-		/* Only map if accepted type. Always enter for 
+	     if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && 
+		 get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE)
+	       {
+		  /* Only map if accepted type. Always enter for 
 		   lun == 0 to get no gaps into ldn-mapping for ldn<7. */
-		immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-		get_ldn[id][lun]=ldn; /* map ldn */
-		if (device_exists (shpnt, ldn, &ld[ldn].block_length,
-				   &ld[ldn].device_type))
-		  {
+		  immediate_assign(host_index,id,lun,ldn,SET_LDN);
+		  get_ldn(host_index)[id][lun]=ldn; /* map ldn */
+		  if (device_exists (host_index, ldn, 
+				     &ld(host_index)[ldn].block_length,
+				     &ld(host_index)[ldn].device_type))
+		    {
 #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-		    int ticks;
-		    printk("(resetting)");
-		    ticks = IM_RESET_DELAY*HZ;
-		    reset_status = IM_RESET_IN_PROGRESS;
-		    issue_cmd (shpnt, IM_RESET_IMM_CMD, IM_IMM_CMD | ldn);
-		    while (reset_status == IM_RESET_IN_PROGRESS && --ticks) 
-		      {
-			mdelay(1+999/HZ);
-			barrier();
-		      }
-		    /* if reset did not complete, just claim */
-		    if (!ticks) 
-		       {
-		          printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-			         IM_RESET_DELAY);
-		          reset_status = IM_RESET_FINISHED_OK; 
-			                       /* did not work, finish */
-		       }
-#endif
-		    ldn++;
-		  }
-		else
-		  {
-		    /* device vanished, probably because we don't know how to
-		     * handle it or because it has problems */
-		     if (lun > 0)
-		       {
-			  /* remove mapping */
-			  get_ldn[id][lun]=TYPE_NO_DEVICE;
-			  immediate_assign(shpnt,0,0,ldn,REMOVE_LDN);
-		       }
-		     else ldn++;
-		  }
-	      }
-	   else if (lun == 0)
-	      {
-		 /* map lun == 0, even if no device exists */
-		 immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-		 get_ldn[id][lun]=ldn; /* map ldn */
-		 ldn++;
-	      }
+		       printk("resetting device at ldn=%x ... ",ldn);
+		       immediate_reset(host_index,ldn);
+#endif
+		       ldn++;
+		    }
+		  else
+		    {
+		       /* device vanished, probably because we don't know how to
+			* handle it or because it has problems */
+		       if (lun > 0)
+			 {
+			    /* remove mapping */
+			    get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE;
+			    immediate_assign(host_index,0,0,ldn,REMOVE_LDN);
+			 }
+		       else ldn++;
+		    }
+	       }
+	     else if (lun == 0)
+	       {
+		  /* map lun == 0, even if no device exists */
+		  immediate_assign(host_index,id,lun,ldn,SET_LDN);
+		  get_ldn(host_index)[id][lun]=ldn; /* map ldn */
+		  ldn++;
+	       }
 	  }	 
-      }
-
+     }
+   
    /* STEP 4: */
    
    /* map remaining ldns to non-existing devices */
    for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
      for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
      {
-	if (get_scsi[id][lun] == TYPE_NO_LUN ||
-	    get_scsi[id][lun] == TYPE_NO_DEVICE)
+	if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN ||
+	    get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE)
 	  {
 	     /* Map remaining ldns only to NON-existing pun,lun
-	        combinations to make sure an inquiry will fail. 
-	        For MULTI_LUN, it is needed to avoid adapter autonome
-	        SCSI-remapping. */
-	     immediate_assign(shpnt,id,lun,ldn,SET_LDN);
-	     get_ldn[id][lun]=ldn;
+	      combinations to make sure an inquiry will fail. 
+	      For MULTI_LUN, it is needed to avoid adapter autonome
+	      SCSI-remapping. */
+	     immediate_assign(host_index,id,lun,ldn,SET_LDN);
+	     get_ldn(host_index)[id][lun]=ldn;
 	     ldn++;
 	  }
      }	
-	
+   
    printk("\n");
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   printk("IBM MCA SCSI: SCSI-access-order: IBM/ANSI.\n");
-#else
-   printk("IBM MCA SCSI: SCSI-access-order: Linux.\n");
-#endif
+   if (ibm_ansi_order)
+     printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
+   else
+     printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
    
 #ifdef IM_DEBUG_PROBE
    /* Show the physical and logical mapping during boot. */
@@ -1338,336 +1236,525 @@
    printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
    for (id=0; id<8; id++)
      {
-        printk("%2d     %2s %2s %2s %2s %2s %2s %2s %2s",
-	       id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]), 
-	       ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]), 
-	       ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]), 
-	       ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
-
-	printk("       %2d     ",id);
+        printk("%2d     ",id);
+	for (lun=0; lun<8; lun++)
+	  printk("%2s ",ti_p(get_scsi(host_index)[id][lun]));
+	printk("      %2d     ",id);
 	for (lun=0; lun<8; lun++)
-	  printk("%2s ",ti_l(get_ldn[id][lun]));
+	  printk("%2s ",ti_l(get_ldn(host_index)[id][lun]));
 	printk("\n");
      }
 #endif
-
+   
    /* assign total number of found SCSI-devices to the statistics struct */
-   IBM_DS.total_scsi_devices = count_devices;
-    
+   IBM_DS(host_index).total_scsi_devices = count_devices;
+   
    /* decide for output in /proc-filesystem, if the configuration of
-      SCSI-devices makes dynamical reassignment of devices necessary */
+    SCSI-devices makes dynamical reassignment of devices necessary */
    if (count_devices>=MAX_LOG_DEV) 
-     IBM_DS.dyn_flag = 1; /* dynamical assignment is necessary */
+     IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
    else 
-     IBM_DS.dyn_flag = 0; /* dynamical assignment is not necessary */
-
+     IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
+   
    /* If no SCSI-devices are assigned, return 1 in order to cause message. */
    if (ldn == 0)
-     printk("IBM MCA SCSI: Warning: No SCSI-devices found/assignable!\n");
-
-  /* reset the counters for statistics on the current adapter */
-  IBM_DS.total_accesses = 0;
-  IBM_DS.total_interrupts = 0;
-  IBM_DS.dynamical_assignments = 0;
-  memset (IBM_DS.ldn_access, 0x0, sizeof (IBM_DS.ldn_access));
-  memset (IBM_DS.ldn_read_access, 0x0, sizeof (IBM_DS.ldn_read_access));
-  memset (IBM_DS.ldn_write_access, 0x0, sizeof (IBM_DS.ldn_write_access));
-  memset (IBM_DS.ldn_inquiry_access, 0x0, sizeof (IBM_DS.ldn_inquiry_access));
-  memset (IBM_DS.ldn_modeselect_access, 0x0, sizeof (IBM_DS.ldn_modeselect_access));
-  memset (IBM_DS.ldn_assignments, 0x0, sizeof (IBM_DS.ldn_assignments));
+     printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
    
-  return;
-}
-
-/*--------------------------------------------------------------------*/
-
-static int 
-device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length, 
-	       int *device_type)
-{
-  struct im_scb scb;
-  struct im_tsb tsb;
-  unsigned char buf[256];
-  int retries;
-
-  /* if no valid device found, return immediately with 0 */
-  if (!(device_inquiry(shpnt, ldn, buf))) return 0;
-   
-  /*if device is CD_ROM, assume block size 2048 and return */
-  if (buf[0] == TYPE_ROM)
-    {
-      *device_type = TYPE_ROM;
-      *block_length = 2048; /* (standard blocksize for yellow-/red-book) */
-      return 1;
-    }
-  
-  if (buf[0] == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM 
-			      therefore, the block_length is also 2048. */
-    {
-      *device_type = TYPE_WORM;
-      *block_length = 2048;
-      return 1;
-    }
-   
-  /* if device is disk, use "read capacity" to find its block size */
-  if (buf[0] == TYPE_DISK)
-    {
-      *device_type = TYPE_DISK;
-
-      for (retries = 0; retries < 3; retries++)
-	{
-	  /*fill scb with read capacity command */
-	  scb.command = IM_READ_CAPACITY_CMD;
-	  scb.enable = IM_READ_CONTROL;
-	  scb.sys_buf_adr = virt_to_bus(buf);
-	  scb.sys_buf_length = 8;
-	  scb.tsb_adr = virt_to_bus(&tsb);
-
-	  /*issue scb to passed ldn, and busy wait for interrupt */
-	  got_interrupt = 0;
-	  issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-	  while (!got_interrupt)
-	    barrier ();
-
-	  /*if got capacity, get block length and return one device found */
-	  if (stat_result == IM_SCB_CMD_COMPLETED)
-	    {
-	      *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
-	      return 1;
-	    }
-	}
-
-      /*if all three retries failed, return "no device at this ldn" */
-      if (retries >= 3)
-	return 0;
-    }
-
-  /* if this is a magneto-optical drive, treat it like a harddisk */
-  if (buf[0] == TYPE_MOD)
-    {
-      *device_type = TYPE_MOD;
-
-      for (retries = 0; retries < 3; retries++)
-	{
-	  /*fill scb with read capacity command */
-	  scb.command = IM_READ_CAPACITY_CMD;
-	  scb.enable = IM_READ_CONTROL;
-	  scb.sys_buf_adr = virt_to_bus(buf);
-	  scb.sys_buf_length = 8;
-	  scb.tsb_adr = virt_to_bus(&tsb);
-
-	  /*issue scb to passed ldn, and busy wait for interrupt */
-	  got_interrupt = 0;
-	  issue_cmd (shpnt, virt_to_bus(&scb), IM_SCB | ldn);
-	  while (!got_interrupt)
-	    barrier ();
-
-	  /*if got capacity, get block length and return one device found */
-	  if (stat_result == IM_SCB_CMD_COMPLETED)
-	    {
-	      *block_length = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24);
-	      return 1;
-	    }
-	}
-
-      /*if all three retries failed, return "no device at this ldn" */
-      if (retries >= 3)
-	return 0;
-    }   
+   /* reset the counters for statistics on the current adapter */
+   IBM_DS(host_index).total_accesses = 0;
+   IBM_DS(host_index).total_interrupts = 0;
+   IBM_DS(host_index).dynamical_assignments = 0;
+   memset (IBM_DS(host_index).ldn_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_access));
+   memset (IBM_DS(host_index).ldn_read_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_read_access));
+   memset (IBM_DS(host_index).ldn_write_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_write_access));
+   memset (IBM_DS(host_index).ldn_inquiry_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_inquiry_access));
+   memset (IBM_DS(host_index).ldn_modeselect_access, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_modeselect_access));
+   memset (IBM_DS(host_index).ldn_assignments, 0x0, 
+	   sizeof (IBM_DS(host_index).ldn_assignments));
    
-  if (buf[0] == TYPE_TAPE) /* TAPE-device found */
-    {
-      *device_type = TYPE_TAPE;
-      *block_length = 0; /* not in use (setting by mt and mtst in op.) */
-      return 1;   
-    }
-
-  if (buf[0] == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/
-    {
-      *device_type = TYPE_PROCESSOR;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-    }
-  
-  if (buf[0] == TYPE_SCANNER) /* other SCSI-scanners */
-    {
-      *device_type = TYPE_SCANNER;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-    }
-
-  if (buf[0] == TYPE_MEDIUM_CHANGER) /* Medium-Changer */
-    {
-      *device_type = TYPE_MEDIUM_CHANGER;
-      *block_length = 0; /* One never knows, what to expect on a medium
-			    changer device. */
-      return 1;
-    }
-
-  /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are
-     ignored! MO-drives are now supported and treated as harddisk. */   
-  return 0;
+   return;
 }
 
 /*--------------------------------------------------------------------*/
 
-#ifdef CONFIG_SCSI_IBMMCA
-
-void 
-ibmmca_scsi_setup (char *str, int *ints)
+static int device_exists (int host_index, int ldn, int *block_length, 
+			  int *device_type)
 {
-   if( str && !strcmp( str, "display" ) ) {
-   	use_display = 1;
-   } else if( ints ) {
-	   int i;
-	   for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) {
-	      io_port[i] = ints[2*i+2];
-	      scsi_id[i] = ints[2*i+2];
-	   }
-   }
-}
+   unsigned char *buf;
+   
+   /* if no valid device found, return immediately with 0 */
+   if (!(device_inquiry(host_index, ldn)))
+     return 0;
+   
+   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
 
-#endif
+   /*if device is CD_ROM, assume block size 2048 and return */
+   if (*buf == TYPE_ROM)
+     {
+	*device_type = TYPE_ROM;
+	*block_length = 2048; /* (standard blocksize for yellow-/red-book) */
+	return 1;
+     }
+   
+   if (*buf == TYPE_WORM) /* CD-burner, WORM, Linux handles this as CD-ROM 
+			     therefore, the block_length is also 2048. */
+     {
+	*device_type = TYPE_WORM;
+	*block_length = 2048;
+	return 1;
+     }
+   
+   /* if device is disk, use "read capacity" to find its block size */
+   if (*buf == TYPE_DISK)
+     {
+	*device_type = TYPE_DISK;
+        if (read_capacity( host_index, ldn))
+	  {
+	     *block_length = *(buf+7) + (*(buf+6) << 8) + 
+	                    (*(buf+5) << 16) + (*(buf+4) << 24);
+	     return 1;
+	  }
+	else
+	  return 0;
+     }
+   
+   /* if this is a magneto-optical drive, treat it like a harddisk */
+   if (*buf == TYPE_MOD)
+     {
+	*device_type = TYPE_MOD;
+        if (read_capacity( host_index, ldn))
+	  {
+	     *block_length = *(buf+7) + (*(buf+6) << 8) + 
+	                    (*(buf+5) << 16) + (*(buf+4) << 24);
+	     return 1;
+	  }
+	else
+	  return 0;
+     }   
+   
+   if (*buf == TYPE_TAPE) /* TAPE-device found */
+     {
+	*device_type = TYPE_TAPE;
+	*block_length = 0; /* not in use (setting by mt and mtst in op.) */
+	return 1;   
+     }
+   
+   if (*buf == TYPE_PROCESSOR) /* HP-Scanners, diverse SCSI-processing units*/
+     {
+	*device_type = TYPE_PROCESSOR;
+	*block_length = 0; /* they set their stuff on drivers */
+	return 1;
+     }
+   
+   if (*buf == TYPE_SCANNER) /* other SCSI-scanners */
+     {
+	*device_type = TYPE_SCANNER;
+	*block_length = 0; /* they set their stuff on drivers */
+	return 1;
+     }
+   
+   if (*buf == TYPE_MEDIUM_CHANGER) /* Medium-Changer */
+     {
+	*device_type = TYPE_MEDIUM_CHANGER;
+	*block_length = 0; /* One never knows, what to expect on a medium
+			    changer device. */
+	return 1;
+     }
+   
+   /* Up to now, no SCSI-devices that are known up to kernel 2.1.31 are
+      ignored! MO-drives are now supported and treated as harddisk. */   
+   return 0;
+}
 
 /*--------------------------------------------------------------------*/
+   
+#ifdef CONFIG_SCSI_IBMMCA
 
-int
-ibmmca_detect (Scsi_Host_Template * template)
+void ibmmca_scsi_setup (char *str, int *ints)
 {
-  struct Scsi_Host *shpnt;
-  int port, id, i, list_size, slot;
-  unsigned pos2, pos3;
-
-  /* if this is not MCA machine, return "nothing found" */
-  if (!MCA_bus)
-    return 0;
-
-  /* get interrupt request level */
-  if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmca", hosts))
-    {
-      printk("IBM MCA SCSI: Unable to get IRQ %d.\n", IM_IRQ);
-      return 0;
-    }
-
-  /* if ibmmcascsi setup option was passed to kernel, return "found" */
-  for (i = 0; i < IM_MAX_HOSTS; i++)
-    if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
-      {
-      printk("IBM MCA SCSI: forced detection, io=0x%x, scsi id=%d.\n",
-              io_port[i], scsi_id[i]);
-      ibmmca_register(template, io_port[i], scsi_id[i]);
-      }
-  if (found) return found;
+   int i, j, io_base, id_base;
+   char *token;
+   
+   io_base = 0;
+   id_base = 0;
+   
+   if (str)
+     {
+	token = strtok(str,",");
+	j = 0;
+	while (token)
+	  {
+	     if (!strcmp(token,"display"))
+	       {
+		  use_display = 1;
+	       }
+	     if (!strcmp(token,"adisplay"))
+	       {
+		  use_adisplay = 1;
+	       }
+	     if (!strcmp(token,"bypass"))
+	       {
+		  bypass_controller = 1;
+	       }
+	     if (!strcmp(token,"normal"))
+	       {
+		  ibm_ansi_order = 0;
+	       }
+	     if (!strcmp(token,"ansi"))
+	       {
+		  ibm_ansi_order = 1;
+	       }
+	     if ( (*token == '-') || (isdigit(*token)) )
+	       {
+		  if (!(j%2) && (io_base < IM_MAX_HOSTS))
+		    {
+		       io_port[io_base++] = simple_strtoul(token,NULL,0);
+		    }
+		  if ((j%2) && (id_base < IM_MAX_HOSTS))
+		    {
+		       scsi_id[id_base++] = simple_strtoul(token,NULL,0);
+		    }
+		  j++;
+	       }
+	     token = strtok(NULL,",");
+	  }
+     }
+   else if (ints)
+     {
+	for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) 
+	  {
+	     io_port[i] = ints[2*i+2];
+	     scsi_id[i] = ints[2*i+2];
+	  }
+     }
+   return;
+}
 
-    /*
-     * Patched by ZP Gu to work with the 9556 as well; the 9556 has
-     * pos2 = 05, but it should be 00, as it should be interfaced
-     * via port = 0x3540.
-     */
-
-  /* first look for the SCSI integrated on the motherboard */
-  pos2 = mca_read_stored_pos(MCA_INTEGSCSI, 2);
-//  if (pos2 != 0xff) {
-    if ((pos2 & 1) == 0) {
-      port = IM_IO_PORT + ((pos2 & 0x0e) << 2);
-    } else {
-      port = IM_IO_PORT;
-    }
-      pos3 = mca_read_stored_pos(MCA_INTEGSCSI, 3);
-      id = (pos3 & 0xe0) >> 5;
-
-      printk("IBM MCA SCSI: integrated SCSI found, io=0x%x, scsi id=%d.\n",
-              port, id);
-      if ((shpnt = ibmmca_register(template, port, id)))
-        {
-          mca_set_adapter_name(MCA_INTEGSCSI, "PS/2 Integrated SCSI");
-          mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
-                                 shpnt);
-        }
-//    }
-
-  /* now look for other adapters */
-  list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
-  for (i = 0; i < list_size; i++)
-    {
-      slot = 0;
-      while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
-             != MCA_NOTFOUND)
-        {
-          pos2 = mca_read_stored_pos(slot, 2);
-          pos3 = mca_read_stored_pos(slot, 3);
-          port = IM_IO_PORT + ((pos2 & 0x0e) << 2);
-          id = (pos3 & 0xe0) >> 5;
-          printk ("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d.\n",
-                  subsys_list[i].description, slot + 1, port, id);
-          if ((shpnt = ibmmca_register(template, port, id)))
-            {
-              mca_set_adapter_name (slot, subsys_list[i].description);
-              mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
-                                      shpnt);
-            }
-          slot++;
-        }
-    }
-
-  if (!found) {
-    free_irq (IM_IRQ, hosts);
-    printk("IBM MCA SCSI: No adapter attached.\n");
-  }
+#endif
+
+/*--------------------------------------------------------------------*/
+
+static int ibmmca_getinfo (char *buf, int slot, void *dev)
+{
+   struct Scsi_Host *shpnt;
+   int len, special;
+   unsigned int pos2, pos3;
+   static unsigned long flags;
+     
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
+#else
+   spin_lock_irqsave(&info_lock, flags);
+#endif   
+   
+   shpnt = dev; /* assign host-structure to local pointer */
+   len = 0; /* set filled text-buffer index to 0 */
+   /* get the _special contents of the hostdata structure */
+   special = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
+   pos2 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2;
+   pos3 = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3;
+   
+   if (special == FORCED_DETECTION) /* forced detection */
+     {
+	len += sprintf (buf + len, "Adapter cathegory: forced detected\n");
+	len += sprintf(buf + len, "***************************************\n");
+	len += sprintf(buf + len, "***  Forced detected SCSI Adapter   ***\n");
+	len += sprintf(buf + len, "***  No chip-information available  ***\n");
+	len += sprintf(buf + len, "***************************************\n");
+     }
+   else if (special == INTEGRATED_SCSI)
+     { /* if the integrated subsystem has been found automatically: */
+	len += sprintf (buf + len, "Adapter cathegory: integrated\n");
+	len += sprintf (buf + len, "Chip revision level: %d\n",
+			((pos2 & 0xf0) >> 4));
+	len += sprintf (buf + len, "Chip status: %s\n",
+			(pos2 & 1) ? "enabled" : "disabled");
+	len += sprintf (buf + len, "8 kByte NVRAM status: %s\n",
+			(pos2 & 2) ? "locked" : "accessible");
+     }
+   else if ((special>=0)&&
+	   (special<(sizeof(subsys_list)/sizeof(struct subsys_list_struct))))
+     { /* if the subsystem is a slot adapter */
+	len += sprintf (buf + len, "Adapter cathegory: slot-card\n");
+	len += sprintf (buf + len, "Chip revision level: %d\n",
+			((pos2 & 0xf0) >> 4));
+	len += sprintf (buf + len, "Chip status: %s\n",
+			(pos2 & 1) ? "enabled" : "disabled");
+	len += sprintf (buf + len, "Port offset: 0x%x\n",
+			((pos2 & 0x0e) << 2));
+     }
+   else
+     {
+	len += sprintf (buf + len, "Adapter cathegory: unknown\n");
+     }
+   /* common subsystem information to write to the slotn file */
+   len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
+   len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x",
+		   (unsigned int)(shpnt->io_port), 
+		   (unsigned int)(shpnt->io_port+7));
+   /* Now make sure, the bufferlength is devideable by 4 to avoid
+    * paging problems of the buffer. */
+   while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
+     {
+	len += sprintf (buf + len, " ");
+     }
+   len += sprintf (buf + len, "\n");
 
-  return found;
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&info_lock, flags);
+#endif   
+   return len;
+}
+   
+int ibmmca_detect (Scsi_Host_Template * scsi_template)
+{
+   struct Scsi_Host *shpnt;
+   int port, id, i, j, list_size, slot;
+   
+   found = 0; /* make absolutely sure, that found is set to 0 */
+   
+   /* if this is not MCA machine, return "nothing found" */
+   if (!MCA_bus)
+     {
+	printk("IBM MCA SCSI: No Microchannel-bus support present -> Aborting.\n");
+	return 0;
+     }
+   else
+     printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
+   
+   /* get interrupt request level */
+#ifdef OLDKERN
+   if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi",
+		    hosts))
+#else
+   if (request_irq (IM_IRQ, do_interrupt_handler, SA_SHIRQ, "ibmmcascsi",
+		    hosts))
+#endif
+     {
+	printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
+	return 0;
+     }
+   
+   /* if ibmmcascsi setup option was passed to kernel, return "found" */
+   for (i = 0; i < IM_MAX_HOSTS; i++)
+     if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8)
+     {
+	printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n",
+	       io_port[i], scsi_id[i]);
+	if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i],
+		     "forced detected SCSI Adapter")))
+	  {
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = 0;
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
+	       FORCED_DETECTION;
+	     mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
+	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
+				    shpnt);
+	     mca_mark_as_used(MCA_INTEGSCSI);
+	  }	
+     }
+   if (found) return found;
+   
+   /* The POS2-register of all PS/2 model SCSI-subsystems has the following
+    * interpretation of bits:
+    *                             Bit 7 - 4 : Chip Revision ID (Release)
+    *                             Bit 3 - 2 : Reserved
+    *                             Bit 1     : 8k NVRAM Disabled
+    *                             Bit 0     : Chip Enable (EN-Signal)
+    * The POS3-register is interpreted as follows:
+    *                             Bit 7 - 5 : SCSI ID
+    *                             Bit 4     : Reserved = 0
+    *                             Bit 3 - 0 : Reserved = 0
+    * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
+    * Interfaces (1991)"). 
+    * In short words, this means, that IBM PS/2 machines only support 
+    * 1 single subsystem by default. The slot-adapters must have another 
+    * configuration on pos2. Here, one has to assume the following
+    * things for POS2-register:
+    *                             Bit 7 - 4 : Chip Revision ID (Release)
+    *                             Bit 3 - 1 : port offset factor
+    *                             Bit 0     : Chip Enable (EN-Signal)
+    * As I found a patch here, setting the IO-registers to 0x3540 forced,
+    * as there was a 0x05 in POS2 on a model 56, I assume, that the 
+    * port 0x3540 must be fix for integrated SCSI-controllers.
+    * Ok, this discovery leads to the following implementation: (M.Lang) */
+
+   /* first look for the IBM SCSI integrated subsystem on the motherboard */
+   for (j=0;j<8;j++) /* read the pos-information */
+     pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j);
+   /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present  */
+   if (( pos[2] != 0xff) || (pos[3] != 0xff ))
+     {
+	if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+	  {
+	     port = IM_IO_PORT;
+	  } 
+	else 
+	  { /* if disabled, no IRQs will be generated, as the chip won't
+	     * listen to the incomming commands and will do really nothing,
+	     * except for listening to the pos-register settings. If this
+	     * happens, I need to hugely think about it, as one has to
+	     * write something to the MCA-Bus pos register in order to
+	     * enable the chip. Normally, IBM-SCSI won't pass the POST,
+	     * when the chip is disabled (see IBM tech. ref.). */
+	     port = IM_IO_PORT; /* anyway, set the portnumber and warn */
+	     printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+	     printk("              SCSI-operations may not work.\n");
+	  }      
+	id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
+	
+	/* give detailed information on the subsystem. This helps me 
+	 * additionally during debugging and analyzing bug-reports. */
+	printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n",
+	       port, id);
+	printk("              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n",
+	       ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible",
+	       (pos[2] & 1) ? "enabled." : "disabled.");
+
+	/* register the found integrated SCSI-subsystem */
+	if ((shpnt = ibmmca_register(scsi_template, port, id,
+		     "IBM Integrated SCSI Controller")))
+	  {
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = 
+	       INTEGRATED_SCSI;
+	     mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
+	     mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
+				    shpnt);
+	     mca_mark_as_used(MCA_INTEGSCSI);
+	  }
+     }
+   
+   /* now look for other adapters in MCA slots, */   
+   /* determine the number of known IBM-SCSI-subsystem types */
+   /* see the pos[2] dependence to get the adapter port-offset. */
+   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+   for (i = 0; i < list_size; i++)
+     { /* scan each slot for a fitting adapter id */
+	slot = 0; /* start at slot 0 */
+	while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
+	       != MCA_NOTFOUND)
+	  { /* scan through all slots */
+	     for (j=0;j<8;j++) /* read the pos-information */
+	       pos[j] = mca_read_stored_pos(slot, j);
+	     if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
+	       { /* (explanations see above) */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+	       } 
+	     else 
+	       { /* anyway, set the portnumber and warn */
+		  port = IM_IO_PORT + ((pos[2] & 0x0e) << 2); 
+		  printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+		  printk("              SCSI-operations may not work.\n");
+	       }      	     
+	     id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
+	     printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
+		     subsys_list[i].description, slot + 1, port, id);
+	     printk("              chip rev.=%d, port-offset=0x%x, subsystem=%s\n",
+		    ((pos[2] & 0xf0) >> 4), 
+		    ((pos[2] & 0x0e) << 2),
+		    (pos[2] & 1) ? "enabled." : "disabled.");
+	     
+	     /* register the hostadapter */
+	     if ((shpnt = ibmmca_register(scsi_template, port, id,
+		          subsys_list[i].description)))
+	       {
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos2 = pos[2];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos3 = pos[3];
+		  ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
+
+		  mca_set_adapter_name (slot, subsys_list[i].description);
+		  mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
+					  shpnt);
+		  mca_mark_as_used(slot);
+	       }
+	     slot++; /* advance to next slot */
+	  } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
+     }
+   
+   if (!found) 
+     { /* maybe ESDI, or other producers' SCSI-hosts */
+	free_irq (IM_IRQ, hosts);
+	printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
+     }  
+   return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
 }
 
 static struct Scsi_Host *
-ibmmca_register(Scsi_Host_Template * template, int port, int id)
+ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
+		char *hostname)
 {
-  struct Scsi_Host *shpnt;
-  int i, j;
+   struct Scsi_Host *shpnt;
+   int i, j;
+   unsigned int ctrl;
+   
+   /* check I/O region */
+   if (check_region(port, IM_N_IO_PORT))
+     {
+	printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n",
+	       port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
+	return NULL;
+     }
+   
+   /* register host */
+   shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+   if (!shpnt)
+     {
+	printk("IBM MCA SCSI: Unable to register host.\n");
+	return NULL;
+     }
+   
+   /* request I/O region */
+   request_region(port, IM_N_IO_PORT, hostname);
 
-  /* check I/O region */
-  if (check_region(port, IM_N_IO_PORT))
-    {
-      printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x.\n",
-        port, port + IM_N_IO_PORT);
-      return NULL;
-    }
-
-  /* register host */
-  shpnt = scsi_register(template, sizeof(struct ibmmca_hostdata));
-  if (!shpnt)
-    {
-      printk("IBM MCA SCSI: Unable to register host.\n");
-      return NULL;
-    }
-
-  /* request I/O region */
-  request_region(port, IM_N_IO_PORT, "ibmmca");
-
-  hosts[found++] = shpnt;
-  shpnt->irq = IM_IRQ;
-  shpnt->io_port = port;
-  shpnt->n_io_port = IM_N_IO_PORT;
-  shpnt->this_id = id;
-
-  reset_status = IM_RESET_NOT_IN_PROGRESS;
-
-  for (i = 0; i < 8; i++)
-    for (j = 0; j < 8; j++)
-      get_ldn[i][j] = MAX_LOG_DEV;
-
-  /* check which logical devices exist */
-  local_checking_phase_flag = 1;
-  check_devices(shpnt);
-  local_checking_phase_flag = 0;
+   hosts[found] = shpnt; /* add new found hostadapter to the list */
+   shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
+   shpnt->io_port = port;
+   shpnt->n_io_port = IM_N_IO_PORT;
+   shpnt->this_id = id;
+   /* now, the SCSI-subsystem is connected to Linux */
 
-  /* an ibm mca subsystem has been detected */
-  return shpnt;
+   ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
+#ifdef IM_DEBUG_PROBE
+   printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n",
+	  ctrl,inb(IM_STAT_REG(found)));
+   printk("IBM MCA SCSI: This adapters' POS-registers: ");
+   for (i=0;i<8;i++)
+     printk("%x ",pos[i]);
+   printk("\n");
+   if (bypass_controller)
+     printk("IBM MCA SCSI: Subsystem SCSI-commands get bypassed.\n");
+#endif
+   
+   reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+
+   for (i = 0; i < 8; i++) /* reset the tables */
+     for (j = 0; j < 8; j++)
+     get_ldn(found)[i][j] = MAX_LOG_DEV;
+
+   /* check which logical devices exist */
+   local_checking_phase_flag(found) = 1;
+   check_devices(found); /* call by value, using the global variable hosts*/
+   local_checking_phase_flag(found) = 0;
+   
+   found++; /* now increase index to be prepared for next found subsystem */
+   /* an ibm mca subsystem has been detected */
+   return shpnt;
 }
 
 /*--------------------------------------------------------------------*/
 
-int 
-ibmmca_command (Scsi_Cmnd * cmd)
+int ibmmca_command (Scsi_Cmnd * cmd)
 {
   ibmmca_queuecommand (cmd, internal_done);
   cmd->SCp.Status = 0;
@@ -1678,8 +1765,7 @@
 
 /*--------------------------------------------------------------------*/
 
-int
-ibmmca_release(struct Scsi_Host *shpnt)
+int ibmmca_release(struct Scsi_Host *shpnt)
 {
   release_region(shpnt->io_port, shpnt->n_io_port);
   if (!(--found))
@@ -1708,231 +1794,267 @@
    are sufficient. (The adapter uses always ldn=15, at whatever pun it is.) */
 int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
-  unsigned int ldn;
-  unsigned int scsi_cmd;
-  struct im_scb *scb;
-  struct Scsi_Host *shpnt = cmd->host;
-  
-  int current_ldn;
-  int id,lun;
-
-  /* use industry standard ordering of the IDs */
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-  int target = 6 - cmd->target;
-#else
-  int target = cmd->target;
-#endif
-
-  /*if (target,lun) is NO LUN or not existing at all, return error */
-  if ((get_scsi[target][cmd->lun] == TYPE_NO_LUN)||
-      (get_scsi[target][cmd->lun] == TYPE_NO_DEVICE))
+   unsigned int ldn;
+   unsigned int scsi_cmd;
+   struct im_scb *scb;
+   struct Scsi_Host *shpnt;
+   int current_ldn;
+   int id,lun;
+   int target;
+   int host_index;
+   
+   if (ibm_ansi_order)
+     target = 6 - cmd->target;
+   else
+     target = cmd->target;
+   
+   shpnt = cmd->host;
+   
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+   
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	cmd->result = DID_NO_CONNECT << 16;
+	done (cmd);
+	return 0;
+     }
+   
+   /*if (target,lun) is NO LUN or not existing at all, return error */
+   if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)||
+       (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE))
      {
 	cmd->result = DID_NO_CONNECT << 16;
 	done (cmd);
 	return 0;
      }
    
-  /*if (target,lun) unassigned, do further checks... */
-  ldn = get_ldn[target][cmd->lun];
-  if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
-    {
-      if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */
-	 {
-	    current_ldn = next_ldn; /* stop-value for one circle */
-	    while (ld[next_ldn].cmd) /* search for a occupied, but not in */
-	      {                      /* command-processing ldn. */
-		 next_ldn ++;
-		 if (next_ldn>=MAX_LOG_DEV) 
-		   next_ldn = 7;
-		 if (current_ldn == next_ldn) /* One circle done ? */
-		   {         /* no non-processing ldn found */
-		      printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n");
-		      printk("              On ldn 7-14 SCSI-commands everywhere in progress.\n");
-		      printk("              Reporting DID_NO_CONNECT for device (%d,%d).\n",
-			     target, cmd->lun);
-		      cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
-		      done (cmd);
-		      return 0;
-		   }
-	      }
-
-	    /* unmap non-processing ldn */
-	    for (id=0; id<8; id ++)
-	      for (lun=0; lun<8; lun++)
-	      {
-		 if (get_ldn[id][lun] == next_ldn)
-		   {
-		      get_ldn[id][lun] = TYPE_NO_DEVICE; /* unmap entry */
-		      goto DYN_ASSIGN;  /* jump out as fast as possible */
-		   }
-	      }
-
-DYN_ASSIGN:	    
-	    /* unassign found ldn (pun,lun does not matter for remove) */
-	    immediate_assign(shpnt,0,0,next_ldn,REMOVE_LDN);
-	    /* assign found ldn to aimed pun,lun */
-	    immediate_assign(shpnt,target,cmd->lun,next_ldn,SET_LDN);
-	    /* map found ldn to pun,lun */
-	    get_ldn[target][cmd->lun] = next_ldn;
-            /* change ldn to the right value, that is now next_ldn */
-	    ldn = next_ldn;
-	    /* set reduced interrupt_handler-mode for checking */
-	    local_checking_phase_flag = 1;
-	    /* get device information for ld[ldn] */
-	    if (device_exists (shpnt, ldn, &ld[ldn].block_length,
-			       &ld[ldn].device_type))
+   /*if (target,lun) unassigned, do further checks... */
+   ldn = get_ldn(host_index)[target][cmd->lun];
+   if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
+     {
+	if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */
+	  {
+	     current_ldn = next_ldn(host_index); /* stop-value for one circle */
+	     while (ld(host_index)[next_ldn(host_index)].cmd) /* search for a occupied, but not in */
+	       {                      /* command-processing ldn. */
+		  next_ldn(host_index)++;
+		  if (next_ldn(host_index)>=MAX_LOG_DEV) 
+		    next_ldn(host_index) = 7;
+		  if (current_ldn == next_ldn(host_index)) /* One circle done ? */
+		    {         /* no non-processing ldn found */
+		       printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n");
+		       printk("              On ldn 7-14 SCSI-commands everywhere in progress.\n");
+		       printk("              Reporting DID_NO_CONNECT for device (%d,%d).\n",
+			      target, cmd->lun);
+		       cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
+		       done (cmd);
+		       return 0;
+		    }
+	       }
+	     
+	     /* unmap non-processing ldn */
+	     for (id=0; id<8; id ++)
+	       for (lun=0; lun<8; lun++)
 	       {
-		 ld[ldn].cmd = 0; /* To prevent panic set 0, because
-				     devices that were not assigned,
-				     should have nothing in progress. */
+		  if (get_ldn(host_index)[id][lun] == next_ldn(host_index))
+		    {
+		       get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE; 
+		       /* unmap entry */
+		    }
+	       }
+	     /* set reduced interrupt_handler-mode for checking */
+	     local_checking_phase_flag(host_index) = 1;
+	     /* unassign found ldn (pun,lun does not matter for remove) */
+	     immediate_assign(host_index,0,0,next_ldn(host_index),REMOVE_LDN);
+	     /* assign found ldn to aimed pun,lun */
+	     immediate_assign(host_index,target,cmd->lun,next_ldn(host_index),SET_LDN);
+	     /* map found ldn to pun,lun */
+	     get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index);
+	     /* change ldn to the right value, that is now next_ldn */
+	     ldn = next_ldn(host_index);
+	     /* get device information for ld[ldn] */
+	     if (device_exists (host_index, ldn, 
+				&ld(host_index)[ldn].block_length,
+				&ld(host_index)[ldn].device_type))
+	       {
+		  ld(host_index)[ldn].cmd = 0; /* To prevent panic set 0, because
+						devices that were not assigned,
+						should have nothing in progress. */
 		  
-		 /* increase assignment counters for statistics in /proc */
-		 IBM_DS.dynamical_assignments++;
-		 IBM_DS.ldn_assignments[ldn]++;
+		  /* increase assignment counters for statistics in /proc */
+		  IBM_DS(host_index).dynamical_assignments++;
+		  IBM_DS(host_index).ldn_assignments[ldn]++;
 	       }
-	    else
-	         /* panic here, because a device, found at boottime has 
-		    vanished */
-	         panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
-		       ldn, target, cmd->lun);
-	    
-	    /* set back to normal interrupt_handling */
-	    local_checking_phase_flag = 0;
-	    
-	    /* Information on syslog terminal */
-	    printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
-		   ldn, target, cmd->lun);
-	    
-	    /* increase next_ldn for next dynamical assignment */ 
-	    next_ldn ++;
-	    if (next_ldn>=MAX_LOG_DEV) next_ldn = 7;
-	 }       
-      else
-	 {  /* wall against Linux accesses to the subsystem adapter */	 
-            cmd->result = DID_NO_CONNECT << 16;
-            done (cmd);
-            return 0;
-	 }
-    }
-
-  /*verify there is no command already in progress for this log dev */
-  if (ld[ldn].cmd)
-    panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
-  /*save done in cmd, and save cmd for the interrupt handler */
-  cmd->scsi_done = done;
-  ld[ldn].cmd = cmd;
-
-  /*fill scb information independent of the scsi command */
-  scb = &(ld[ldn].scb);
-  scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
-  scb->tsb_adr = virt_to_bus(&(ld[ldn].tsb));
-  if (cmd->use_sg)
-    {
-      int i = cmd->use_sg;
-      struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
-      if (i > 16)
-	panic ("IBM MCA SCSI: scatter-gather list too long.\n");
-      while (--i >= 0)
-	{
-	  ld[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
-	  ld[ldn].sge[i].byte_length = sl[i].length;
-	}
-      scb->enable |= IM_POINTER_TO_LIST;
-      scb->sys_buf_adr = virt_to_bus(&(ld[ldn].sge[0]));
-      scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
-    }
-  else
-    {
-      scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
-      scb->sys_buf_length = cmd->request_bufflen;
-    }
-
-  /*fill scb information dependent on scsi command */
-  scsi_cmd = cmd->cmnd[0];
+	     else
+	       /* panic here, because a device, found at boottime has 
+		vanished */
+	       panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
+		     ldn, target, cmd->lun);
+	     
+	     /* set back to normal interrupt_handling */
+	     local_checking_phase_flag(host_index) = 0;
+	     
+	     /* Information on syslog terminal */
+	     printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
+		    ldn, target, cmd->lun);
+	     
+	     /* increase next_ldn for next dynamical assignment */ 
+	     next_ldn(host_index)++;
+	     if (next_ldn(host_index)>=MAX_LOG_DEV) 
+	       next_ldn(host_index) = 7;
+	  }       
+	else
+	  {  /* wall against Linux accesses to the subsystem adapter */	 
+	     cmd->result = DID_BAD_TARGET << 16;
+	     done (cmd);
+	     return 0;
+	  }
+     }
+   
+   /*verify there is no command already in progress for this log dev */
+   if (ld(host_index)[ldn].cmd)
+     panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
+   
+   /*save done in cmd, and save cmd for the interrupt handler */
+   cmd->scsi_done = done;
+   ld(host_index)[ldn].cmd = cmd;
+   
+   /*fill scb information independent of the scsi command */
+   scb = &(ld(host_index)[ldn].scb);
+   ld(host_index)[ldn].tsb.dev_status = 0;
+   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR;
+   scb->tsb_adr = virt_to_bus(&(ld(host_index)[ldn].tsb));
+   if (cmd->use_sg)
+     {
+	int i = cmd->use_sg;
+	struct scatterlist *sl = (struct scatterlist *) cmd->request_buffer;
+	if (i > 16)
+	  panic ("IBM MCA SCSI: scatter-gather list too long.\n");
+	while (--i >= 0)
+	  {
+	     ld(host_index)[ldn].sge[i].address = (void *) virt_to_bus(sl[i].address);
+	     ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+	  }
+	scb->enable |= IM_POINTER_TO_LIST;
+	scb->sys_buf_adr = virt_to_bus(&(ld(host_index)[ldn].sge[0]));
+	scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
+     }
+   else
+     {
+	scb->sys_buf_adr = virt_to_bus(cmd->request_buffer);
+	scb->sys_buf_length = cmd->request_bufflen;
+     }
+   
+   /*fill scb information dependent on scsi command */
+   scsi_cmd = cmd->cmnd[0];
    
 #ifdef IM_DEBUG_CMD
-  printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
+   printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
 #endif
-
-  /* for specific device-type debugging: */
+   
+   /* for specific device-type debugging: */
 #ifdef IM_DEBUG_CMD_SPEC_DEV
-  if (ld[ldn].device_type==IM_DEBUG_CMD_DEVICE)
+   if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE)
      printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", 
-	    ld[ldn].device_type, scsi_cmd, ldn);
+	    ld(host_index)[ldn].device_type, scsi_cmd, ldn);
 #endif
-
-  /* for possible panics store current command */
-  last_scsi_command = scsi_cmd; 
    
-  /* update statistical info */
-  IBM_DS.total_accesses++;
-  IBM_DS.ldn_access[ldn]++;
-   
-  switch (scsi_cmd)
-    {
-    case READ_6:
-    case WRITE_6:
-    case READ_10:
-    case WRITE_10:
-    case READ_12:
-    case WRITE_12:       
-      /* statistics for proc_info */
-      if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
-	 IBM_DS.ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
-      else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
-	       (scsi_cmd == WRITE_12))
-	 IBM_DS.ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
-
-      /* Distinguish between disk and other devices. Only disks (that are the
-	 most frequently accessed devices) should be supported by the 
+   /* for possible panics store current command */
+   last_scsi_command(host_index)[ldn] = scsi_cmd; 
+   last_scsi_type(host_index)[ldn] = IM_SCB;
+   
+   /* update statistical info */
+   IBM_DS(host_index).total_accesses++;
+   IBM_DS(host_index).ldn_access[ldn]++;
+   
+   switch (scsi_cmd)
+     {
+      case READ_6:
+      case WRITE_6:
+      case READ_10:
+      case WRITE_10:
+      case READ_12:
+      case WRITE_12:       
+	/* statistics for proc_info */
+	if ((scsi_cmd == READ_6)||(scsi_cmd == READ_10)||(scsi_cmd == READ_12))
+	  IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
+	else if ((scsi_cmd == WRITE_6)||(scsi_cmd == WRITE_10)||
+		 (scsi_cmd == WRITE_12))
+	  IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
+	
+	/* Distinguish between disk and other devices. Only disks (that are the
+	   most frequently accessed devices) should be supported by the 
          IBM-SCSI-Subsystem commands. */
-      switch (ld[ldn].device_type)
-	 {
-	  case TYPE_DISK: /* for harddisks enter here ... */
-	  case TYPE_MOD:  /* ... try it also for MO-drives (send flames as */
-			  /* you like, if this won't work.) */
-           if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
-	       scsi_cmd == READ_12)
-	     {
-	       scb->command = IM_READ_DATA_CMD;
-	       scb->enable |= IM_READ_CONTROL;
-	     }
-           else
-	     {
-	       scb->command = IM_WRITE_DATA_CMD;
-	     }
-           if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6)
-	     {
-	       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
-	         (((unsigned) cmd->cmnd[2]) << 8) |
-	         ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
-	       scb->u2.blk.count = (unsigned) cmd->cmnd[4];
-	     }
-           else
-	     {
-	       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) |
-	         (((unsigned) cmd->cmnd[4]) << 8) |
-	         (((unsigned) cmd->cmnd[3]) << 16) |
-	         (((unsigned) cmd->cmnd[2]) << 24);
-	       scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
-	         (((unsigned) cmd->cmnd[7]) << 8);
-	     }
-           scb->u2.blk.length = ld[ldn].block_length;
-	   if (++disk_rw_in_progress == 1)
-	      PS2_DISK_LED_ON (shpnt->host_no, target);
-	  break;
-	    
-	  /* for other devices, enter here. Other types are not known by
-	     Linux! TYPE_NO_LUN is forbidden as valid device. */
-          case TYPE_ROM:
-	  case TYPE_TAPE:
-	  case TYPE_PROCESSOR:
-	  case TYPE_WORM:
-	  case TYPE_SCANNER:
-	  case TYPE_MEDIUM_CHANGER:
-	  
-	   /* If there is a sequential-device, IBM recommends to use
+	switch (ld(host_index)[ldn].device_type)
+	  {
+	   case TYPE_DISK: /* for harddisks enter here ... */
+	   case TYPE_MOD:  /* ... try it also for MO-drives (send flames as */
+	                   /*     you like, if this won't work.) */
+	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
+		 scsi_cmd == READ_12)
+	       { /* read command preparations */
+		  if (bypass_controller)
+		    {
+		       scb->command = IM_OTHER_SCSI_CMD_CMD;
+		       scb->enable |= IM_READ_CONTROL;
+		       scb->u1.scsi_cmd_length = cmd->cmd_len;
+		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		    }
+		  else
+		    {
+		       scb->command = IM_READ_DATA_CMD;
+		       scb->enable |= IM_READ_CONTROL;
+		    }
+	       }
+	     else
+	       { /* write command preparations */
+		  if (bypass_controller)
+		    {
+		       scb->command = IM_OTHER_SCSI_CMD_CMD;
+		       scb->u1.scsi_cmd_length = cmd->cmd_len;
+		       memcpy(scb->u2.scsi_command,cmd->cmnd,cmd->cmd_len);
+		    }
+		  else
+		    { 
+		       scb->command = IM_WRITE_DATA_CMD;
+		    }
+	       }
+	     
+	     if (!bypass_controller)
+	       {		 
+		  if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6)
+		    {
+		       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
+			 (((unsigned) cmd->cmnd[2]) << 8) |
+			 ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
+		       scb->u2.blk.count = (unsigned) cmd->cmnd[4];
+		    }
+		  else
+		    {
+		       scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) |
+			 (((unsigned) cmd->cmnd[4]) << 8) |
+			 (((unsigned) cmd->cmnd[3]) << 16) |
+			 (((unsigned) cmd->cmnd[2]) << 24);
+		       scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
+			 (((unsigned) cmd->cmnd[7]) << 8);
+		    }
+		  scb->u2.blk.length = ld(host_index)[ldn].block_length;
+	       }	    
+	     if (++disk_rw_in_progress == 1)
+	       PS2_DISK_LED_ON (shpnt->host_no, target);
+	     break;
+	     
+	     /* for other devices, enter here. Other types are not known by
+	      Linux! TYPE_NO_LUN is forbidden as valid device. */
+	   case TYPE_ROM:
+	   case TYPE_TAPE:
+	   case TYPE_PROCESSOR:
+	   case TYPE_WORM:
+	   case TYPE_SCANNER:
+	   case TYPE_MEDIUM_CHANGER:
+	     
+	     /* If there is a sequential-device, IBM recommends to use
 	      IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. 
 	      Good/modern CD-ROM-drives are capable of
 	      reading sequential AND random-access. This leads to the problem,
@@ -1943,241 +2065,422 @@
 	      to have a stable state. In addition, data-access on CD-ROMs
 	      works faster like that. Strange, but obvious. */
 	    
-           scb->command = IM_OTHER_SCSI_CMD_CMD;
-	   if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
-	       scsi_cmd == READ_12) /* enable READ */
-              scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-	   else
-	      scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /* assume WRITE */
-	    
-           scb->u1.scsi_cmd_length = cmd->cmd_len;
-           memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-	    
-	   /* Read/write on this non-disk devices is also displayworthy, 
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || 
+		 scsi_cmd == READ_12) /* enable READ */
+	       {
+		  scb->enable |= IM_READ_CONTROL;
+	       }
+	     
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	     
+	     /* Read/write on this non-disk devices is also displayworthy, 
 	      so flash-up the LED/display. */
-	   if (++disk_rw_in_progress == 1)
-	      PS2_DISK_LED_ON (shpnt->host_no, target);
-	 break;
-	 }
-      break;
-    case INQUIRY:
-      IBM_DS.ldn_inquiry_access[ldn]++;
-      scb->command = IM_DEVICE_INQUIRY_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      break;
-
-    case READ_CAPACITY:
-      scb->command = IM_READ_CAPACITY_CMD;
-      scb->enable |= IM_READ_CONTROL;
-      /* the length of system memory buffer must be exactly 8 bytes */
-      if (scb->sys_buf_length >= 8)
-	scb->sys_buf_length = 8;
-      break;
-
-    /* Commands that need read-only-mode (system <- device): */
-    case REQUEST_SENSE:
-      scb->command = IM_REQUEST_SENSE_CMD;
-      scb->enable |= IM_READ_CONTROL;
-      break;
-       
-    /* Commands that need write-only-mode (system -> device): */
-    case MODE_SELECT:
-    case MODE_SELECT_10:
-      IBM_DS.ldn_modeselect_access[ldn]++;
-      scb->command = IM_OTHER_SCSI_CMD_CMD;      
-      scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      break;
-            
-    /* For other commands, read-only is useful. Most other commands are 
-       running without an input-data-block. */
-    default:
-      scb->command = IM_OTHER_SCSI_CMD_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      break;
-    }
+	     if (++disk_rw_in_progress == 1)
+	       PS2_DISK_LED_ON (shpnt->host_no, target);
+	     break;
+	  }
+	break;
+      case INQUIRY:
+	IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	  }
+	else
+	  {
+	     scb->command = IM_DEVICE_INQUIRY_CMD;
+	     scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	  }
+	break;	
 
-  /*issue scb command, and return */
-  issue_cmd (shpnt, virt_to_bus(scb), IM_SCB | ldn);
-  return 0;
+      case READ_CAPACITY:
+	/* the length of system memory buffer must be exactly 8 bytes */
+	if (scb->sys_buf_length > 8)
+	  scb->sys_buf_length = 8;
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);	     
+	  }
+	else
+	  {
+	     scb->command = IM_READ_CAPACITY_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	  }
+	break;
+	
+	/* Commands that need read-only-mode (system <- device): */
+      case REQUEST_SENSE:
+	if (bypass_controller)
+	  {
+	     scb->command = IM_OTHER_SCSI_CMD_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	     scb->u1.scsi_cmd_length = cmd->cmd_len;
+	     memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	  }
+	else
+	  {
+	     scb->command = IM_REQUEST_SENSE_CMD;
+	     scb->enable |= IM_READ_CONTROL;
+	  }
+	break;
+	
+	/* Commands that need write-only-mode (system -> device): */
+      case MODE_SELECT:
+      case MODE_SELECT_10:
+	IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+	scb->command = IM_OTHER_SCSI_CMD_CMD;      
+	scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
+	scb->u1.scsi_cmd_length = cmd->cmd_len;
+	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	break;
+	
+	/* For other commands, read-only is useful. Most other commands are 
+	 running without an input-data-block. */
+      default:
+	scb->command = IM_OTHER_SCSI_CMD_CMD;
+	scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
+	scb->u1.scsi_cmd_length = cmd->cmd_len;
+	memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+	break;
+     }
+   
+   /*issue scb command, and return */
+   issue_cmd (host_index, virt_to_bus(scb), IM_SCB | ldn);
+   return 0;
 }
 
 /*--------------------------------------------------------------------*/
 
-int 
-ibmmca_abort (Scsi_Cmnd * cmd)
+int ibmmca_abort (Scsi_Cmnd * cmd)
 {
-  /* The code below doesn't work right now, so we tell the upper layer
-     that we can't abort. This eventually causes a reset.
-     */
-  return SCSI_ABORT_SNOOZE ;
-
-#if 0
-  struct Scsi_host *shpnt = cmd->host;
-  unsigned int ldn;
-  void (*saved_done) (Scsi_Cmnd *);
+   /* Abort does not work, as the adapter never generates an interrupt on
+    * whatever situation is simulated, even when really pending commands
+    * are running on the adapters' hardware ! */
+   
+   struct Scsi_Host *shpnt;
+   unsigned int ldn;
+   void (*saved_done) (Scsi_Cmnd *);
+   int target;
+   int host_index;
+   static unsigned long flags;
+   unsigned long imm_command;
 
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-  int target = 6 - cmd->target;
+   /* return SCSI_ABORT_SNOOZE ; */
+
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
 #else
-  int target = cmd->target;
-#endif
+   spin_lock_irqsave(&abort_lock, flags);
+#endif         
+   if (ibm_ansi_order)
+     target = 6 - cmd->target;
+   else
+     target = cmd->target;
+   
+   shpnt = cmd->host;
 
-  /*get logical device number, and disable system interrupts */
-  printk ("IBM MCA SCSI: sending abort to device id=%d lun=%d.\n",
-	  target, cmd->lun);
-  ldn = get_ldn[target][cmd->lun];
-  cli ();
-
-  /*if cmd for this ldn has already finished, no need to abort */
-  if (!ld[ldn].cmd)
-    {
-      /* sti (); */
-      return SCSI_ABORT_NOT_RUNNING;
-    }
-
-  /* Clear ld.cmd, save done function, install internal done, 
-   * send abort immediate command (this enables sys. interrupts), 
-   * and wait until the interrupt arrives. 
-   */
-  ld[ldn].cmd = 0;
-  saved_done = cmd->scsi_done;
-  cmd->scsi_done = internal_done;
-  cmd->SCp.Status = 0;
-  issue_cmd (shpnt, T_IMM_CMD, IM_IMM_CMD | ldn);
-  while (!cmd->SCp.Status)
-    barrier ();
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);   
+   
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	cmd->result = DID_NO_CONNECT << 16;
+	if (cmd->scsi_done)
+	  (cmd->done) (cmd);
+	return SCSI_ABORT_SNOOZE;
+     }
+ 
+   /*get logical device number, and disable system interrupts */
+   printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n",
+	   target, cmd->lun);
+   ldn = get_ldn(host_index)[target][cmd->lun];
+
+   /*if cmd for this ldn has already finished, no need to abort */
+   if (!ld(host_index)[ldn].cmd)
+     {
+#ifdef OLDKERN   
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&abort_lock, flags);
+#endif   	
+	return SCSI_ABORT_NOT_RUNNING;
+     }
 
-  /*if abort went well, call saved done, then return success or error */
-  if (cmd->result == 0)
-    {
-      cmd->result |= DID_ABORT << 16;
-      saved_done (cmd);
-      return SCSI_ABORT_SUCCESS;
-    }
-  else
-    return SCSI_ABORT_ERROR;
+   /* Clear ld.cmd, save done function, install internal done, 
+    * send abort immediate command (this enables sys. interrupts), 
+    * and wait until the interrupt arrives. 
+    */
+   saved_done = cmd->scsi_done;
+   cmd->scsi_done = internal_done;
+   cmd->SCp.Status = 0;
+   last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
+   last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+   imm_command = inl(IM_CMD_REG(host_index));
+   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
+   imm_command |= (unsigned long)(IM_ABORT_IMM_CMD);
+   /* must wait for attention reg not busy */
+   while (1)
+     {
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags (flags);
+#else
+	spin_unlock_irqrestore(&abort_lock, flags);
+#endif	
+#ifdef OLDKERN   
+	save_flags(flags);
+	cli();   
+#else
+	spin_lock_irqsave(&abort_lock, flags);
+#endif   
+     }
+   /*write registers and enable system interrupts */
+   outl (imm_command, IM_CMD_REG(host_index));
+   outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+#ifdef OLDKERN   
+   restore_flags (flags);
+#else
+   spin_unlock_irqrestore(&abort_lock, flags);
 #endif
+   
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort submitted, waiting for adapter response...\n");
+#endif	
+   while (!cmd->SCp.Status)
+     barrier ();   
+   cmd->scsi_done = saved_done;   
+   /*if abort went well, call saved done, then return success or error */   
+   if (cmd->result == (DID_ABORT << 16))
+     {
+	cmd->result |= DID_ABORT << 16;
+	if (cmd->scsi_done)
+	  (cmd->scsi_done) (cmd);
+	ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort finished with success.\n");
+#endif	
+	return SCSI_ABORT_SUCCESS;
+     }
+   else
+     {
+	cmd->result |= DID_NO_CONNECT << 16;
+	if (cmd->scsi_done)
+	  (cmd->scsi_done) (cmd);
+	ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort failed.\n");
+#endif		
+	return SCSI_ABORT_ERROR;
+     }
 }
 
 /*--------------------------------------------------------------------*/
 
-int
-ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
+int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
 {
-  struct Scsi_Host *shpnt = cmd->host;
-  int ticks = IM_RESET_DELAY*HZ;
+   struct Scsi_Host *shpnt;
+   Scsi_Cmnd *cmd_aid;
+   int ticks,i;
+   int host_index;
+   static unsigned long flags;
+   unsigned long imm_command;
+   
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();   
+#else
+   spin_lock_irqsave(&reset_lock, flags);
+#endif   
+   ticks = IM_RESET_DELAY*HZ;
+   shpnt = cmd->host;
+   /* search for the right hostadapter */
+   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+   if (!hosts[host_index])
+     { /* invalid hostadapter descriptor address */
+	if (!local_checking_phase_flag(host_index))
+	  {
+	     cmd->result = DID_NO_CONNECT << 16;
+	     if (cmd->scsi_done)
+	       (cmd->done) (cmd);
+	  }
+	return SCSI_ABORT_SNOOZE;
+     }
 
-  if (local_checking_phase_flag) {
-    printk("IBM MCA SCSI: unable to reset while checking devices.\n");
-    return SCSI_RESET_SNOOZE;
-  }
-
-  /* issue reset immediate command to subsystem, and wait for interrupt */
-  printk("IBM MCA SCSI: resetting all devices.\n");
-  cli ();
-  reset_status = IM_RESET_IN_PROGRESS;
-  issue_cmd (shpnt, IM_RESET_IMM_CMD, IM_IMM_CMD | 0xf);
-  while (reset_status == IM_RESET_IN_PROGRESS && --ticks) {
-    mdelay(1+999/HZ);
-    barrier();
-  }
-  /* if reset did not complete, just return an error*/
-  if (!ticks) {
-    printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-           IM_RESET_DELAY);
-    reset_status = IM_RESET_FINISHED_FAIL;
-    return SCSI_RESET_ERROR;
-  }
-
-  /* if reset failed, just return an error */
-  if (reset_status == IM_RESET_FINISHED_FAIL) {
-    printk("IBM MCA SCSI: reset failed.\n");
-    return SCSI_RESET_ERROR;
-  }
+   if (local_checking_phase_flag(host_index))
+     {
+	printk("IBM MCA SCSI: unable to reset while checking devices.\n");
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&reset_lock, flags);
+#endif		
+	return SCSI_RESET_SNOOZE;
+     }
 
-  /* so reset finished ok - call outstanding done's, and return success */
-  printk ("IBM MCA SCSI: reset completed without error.\n");
-  {
-    int i;
-    for (i = 0; i < MAX_LOG_DEV; i++)
-      {
-        Scsi_Cmnd *cmd = ld[i].cmd;
-        if (cmd && cmd->scsi_done)
-          {
-            ld[i].cmd = 0;
-            cmd->result = DID_RESET;
-            (cmd->scsi_done) (cmd);
-          }
-      }
-  }
-  return SCSI_RESET_SUCCESS;
+   /* issue reset immediate command to subsystem, and wait for interrupt */
+   printk("IBM MCA SCSI: resetting all devices.\n");
+   reset_status(host_index) = IM_RESET_IN_PROGRESS;
+   last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
+   last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+   imm_command = inl(IM_CMD_REG(host_index));
+   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
+   imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
+   /* must wait for attention reg not busy */
+   while (1)
+     {
+	if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
+	  break;
+#ifdef OLDKERN	
+	restore_flags(flags);
+#else
+	spin_unlock_irqrestore(&reset_lock, flags);
+#endif	
+#ifdef OLDKERN   
+	save_flags(flags);
+	cli();   
+#else
+	spin_lock_irqsave(&reset_lock, flags);
+#endif   
+     }
+   /*write registers and enable system interrupts */
+   outl (imm_command, IM_CMD_REG(host_index));
+   outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+   /* wait for interrupt finished or intr_stat register to be set, as the
+    * interrupt will not be executed, while we are in here! */
+   while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks
+	  && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) {
+      mdelay(1+999/HZ);
+      barrier();
+   }
+   /* if reset did not complete, just return an error*/
+   if (!ticks) {
+      printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
+	     IM_RESET_DELAY);
+      reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+#ifdef OLDKERN   
+      restore_flags(flags);
+#else
+      spin_unlock_irqrestore(&reset_lock, flags);
+#endif   
+      return SCSI_RESET_ERROR;
+   }
+   
+   if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f)
+     { /* analysis done by this routine and not by the intr-routine */
+	if (inb(IM_INTR_REG(host_index))==0xaf)
+	  reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
+	else if (inb(IM_INTR_REG(host_index))==0xcf)
+	  reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+	else /* failed, 4get it */
+	  reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+	outb (IM_EOI | 0xf, IM_ATTN_REG(host_index));
+     }	
+   
+   /* if reset failed, just return an error */
+   if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+      printk("IBM MCA SCSI: reset failed.\n");
+#ifdef OLDKERN   
+      restore_flags(flags);
+#else
+      spin_unlock_irqrestore(&reset_lock, flags);
+#endif         
+      return SCSI_RESET_ERROR;
+   }
+   
+   /* so reset finished ok - call outstanding done's, and return success */
+   printk ("IBM MCA SCSI: Reset completed without known error.\n");
+#ifdef OLDKERN   
+   restore_flags(flags);
+#else
+   spin_unlock_irqrestore(&reset_lock, flags);
+#endif      
+   for (i = 0; i < MAX_LOG_DEV; i++)
+     {
+	cmd_aid = ld(host_index)[i].cmd;
+	if (cmd_aid && cmd_aid->scsi_done)
+	  {
+	     ld(host_index)[i].cmd = NULL;
+	     cmd_aid->result = DID_RESET << 16;
+	     (cmd_aid->scsi_done) (cmd_aid);
+	  }
+     }
+   return SCSI_RESET_SUCCESS;
 }
 
 /*--------------------------------------------------------------------*/
 
-int 
-ibmmca_biosparam (Disk * disk, kdev_t dev, int *info)
+int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info)
 {
-  info[0] = 64;
-  info[1] = 32;
-  info[2] = disk->capacity / (info[0] * info[1]);
-  if (info[2] >= 1024)
-    {
-      info[0] = 128;
-      info[1] = 63;
-      info[2] = disk->capacity / (info[0] * info[1]);
-      if (info[2] >= 1024)
-	{
-	  info[0] = 255;
-	  info[1] = 63;
-	  info[2] = disk->capacity / (info[0] * info[1]);
-	  if (info[2] >= 1024)
-	    info[2] = 1023;
-	}
-    }
-  return 0;
+   info[0] = 64;
+   info[1] = 32;
+   info[2] = disk->capacity / (info[0] * info[1]);
+   if (info[2] >= 1024)
+     {
+	info[0] = 128;
+	info[1] = 63;
+	info[2] = disk->capacity / (info[0] * info[1]);
+	if (info[2] >= 1024)
+	  {
+	     info[0] = 255;
+	     info[1] = 63;
+	     info[2] = disk->capacity / (info[0] * info[1]);
+	     if (info[2] >= 1024)
+	       info[2] = 1023;
+	  }
+     }
+   return 0;
 }
 
 /* calculate percentage of total accesses on a ldn */
-static int ldn_access_load(struct Scsi_Host *shpnt, int ldn)
+static int ldn_access_load(int host_index, int ldn)
 {
-   if (IBM_DS.total_accesses == 0) return (0);
-   if (IBM_DS.ldn_access[ldn] == 0) return (0);
-   return (IBM_DS.ldn_access[ldn] * 100) / IBM_DS.total_accesses;
+   if (IBM_DS(host_index).total_accesses == 0) return (0);
+   if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0);
+   return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
 }
 
 /* calculate total amount of r/w-accesses */
-static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
+static int ldn_access_total_read_write(int host_index)
 {
-   int a = 0;
+   int a;
    int i;
    
+   a = 0;
    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_read_access[i]+IBM_DS.ldn_write_access[i];
+     a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i];
    return(a);
 }
 
-static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
+static int ldn_access_total_inquiry(int host_index)
 {
-   int a = 0;
+   int a;
    int i;
    
+   a = 0;
    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_inquiry_access[i];
+     a+=IBM_DS(host_index).ldn_inquiry_access[i];
    return(a);
 }
 
-static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
+static int ldn_access_total_modeselect(int host_index)
 {
-   int a = 0;
+   int a;
    int i;
    
+   a = 0;
    for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS.ldn_modeselect_access[i];
+     a+=IBM_DS(host_index).ldn_modeselect_access[i];
    return(a);
 }
 
@@ -2186,28 +2489,30 @@
 		      int hostno, int inout)
 {
    int len=0;
-   int i,id,lun;
+   int i,id,lun,host_index;
    struct Scsi_Host *shpnt;
    unsigned long flags;
 
+#ifdef OLDKERN   
+   save_flags(flags);
+   cli();
+#else
+   spin_lock_irqsave(&proc_lock, flags);
+#endif   
+
    for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
    shpnt = hosts[i];
+   host_index = i;
    if (!shpnt) {
        len += sprintf(buffer+len, "\nCan't find adapter for host number %d\n", hostno);
        return len;
    }
 
-   save_flags(flags);
-   cli();
-
    len += sprintf(buffer+len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
 		  IBMMCA_SCSI_DRIVER_VERSION);
    len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
-   len += sprintf(buffer+len, "               ANSI-SCSI-standard order.: Yes\n");
-#else
-   len += sprintf(buffer+len, "               ANSI-SCSI-standard order.: No\n");
-#endif
+   len += sprintf(buffer+len, "               Device Scanning Order....: %s\n",
+		  (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
 #ifdef CONFIG_SCSI_MULTI_LUN
    len += sprintf(buffer+len, "               Multiple LUN probing.....: Yes\n");
 #else
@@ -2215,72 +2520,74 @@
 #endif
    len += sprintf(buffer+len, "               This Hostnumber..........: %d\n",
 		  hostno);
-   len += sprintf(buffer+len, "               Base I/O-Port............: 0x%lx\n",
-		  IM_CMD_REG);
+   len += sprintf(buffer+len, "               Base I/O-Port............: 0x%x\n",
+		  (unsigned int)(IM_CMD_REG(host_index)));
    len += sprintf(buffer+len, "               (Shared) IRQ.............: %d\n",
 		  IM_IRQ);
+   len += sprintf(buffer+len, "               SCSI-command set used....: %s\n",
+		  (bypass_controller) ? "software" : "hardware integrated");
    len += sprintf(buffer+len, "               Total Interrupts.........: %d\n",
-		  IBM_DS.total_interrupts);
+		  IBM_DS(host_index).total_interrupts);
    len += sprintf(buffer+len, "               Total SCSI Accesses......: %d\n",
-		  IBM_DS.total_accesses);
+		  IBM_DS(host_index).total_accesses);
    len += sprintf(buffer+len, "                 Total SCSI READ/WRITE..: %d\n",
-		  ldn_access_total_read_write(shpnt));
+		  ldn_access_total_read_write(host_index));
    len += sprintf(buffer+len, "                 Total SCSI Inquiries...: %d\n",
-		  ldn_access_total_inquiry(shpnt));
+		  ldn_access_total_inquiry(host_index));
    len += sprintf(buffer+len, "                 Total SCSI Modeselects.: %d\n",
-		  ldn_access_total_modeselect(shpnt));
-   len += sprintf(buffer+len, "                 Total SCSI other cmds..: %d\n\n",
-		  IBM_DS.total_accesses - ldn_access_total_read_write(shpnt)
-		  - ldn_access_total_modeselect(shpnt)
-		  - ldn_access_total_inquiry(shpnt));
-   
+		  ldn_access_total_modeselect(host_index));
+   len += sprintf(buffer+len, "                 Total SCSI other cmds..: %d\n",
+		  IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
+		  - ldn_access_total_modeselect(host_index)
+		  - ldn_access_total_inquiry(host_index));
+   len += sprintf(buffer+len, "               Total SCSI command fails.: %d\n\n",
+		  IBM_DS(host_index).total_errors);
    len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n");
    len += sprintf(buffer+len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
    len += sprintf(buffer+len, "        -----|--------------|-----------|-----------|--------------\n");
    for (i=0; i<=MAX_LOG_DEV; i++)
       len += sprintf(buffer+len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n",
-		     i, ldn_access_load(shpnt, i), IBM_DS.ldn_read_access[i],
-		     IBM_DS.ldn_write_access[i], IBM_DS.ldn_assignments[i]);
+		     i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i],
+		     IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
    len += sprintf(buffer+len, "        -----------------------------------------------------------\n\n");
    
    len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n");
    len += sprintf(buffer+len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n",
-		  IBM_DS.total_scsi_devices);
+		  IBM_DS(host_index).total_scsi_devices);
    len += sprintf(buffer+len, "               Dynamical Assignment necessaray..: %s\n", 
-		  IBM_DS.dyn_flag ? "Yes" : "No ");
+		  IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
    len += sprintf(buffer+len, "               Next LDN to be assigned..........: 0x%x\n",
-		  next_ldn);
+		  next_ldn(host_index));
    len += sprintf(buffer+len, "               Dynamical assignments done yet...: %d\n",
-		  IBM_DS.dynamical_assignments);
+		  IBM_DS(host_index).dynamical_assignments);
 
    len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n");
    len += sprintf(buffer+len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
    len += sprintf(buffer+len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
    for (id=0; id<=7; id++)
      {
-	len += sprintf(buffer+len, "    %2d     %2s %2s %2s %2s %2s %2s %2s %2s",
-	       id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]), 
-	       ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]), 
-	       ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]), 
-	       ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
-	
-	len += sprintf(buffer+len, "       %2d     ",id);
+	len += sprintf(buffer+len, "    %2d     ",id);
 	for (lun=0; lun<8; lun++)
-	  len += sprintf(buffer+len,"%2s ",ti_l(get_ldn[id][lun]));
+	  len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun]));	
+	len += sprintf(buffer+len, "      %2d     ",id);
+	for (lun=0; lun<8; lun++)
+	  len += sprintf(buffer+len,"%2s ",ti_l(get_ldn(host_index)[id][lun]));
 	len += sprintf(buffer+len,"\n");
      }
    
    len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
    len += sprintf(buffer+len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
-   len += sprintf(buffer+len, " - = nothing found)\n\n");
+   len += sprintf(buffer+len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
    
    *start = buffer + offset;
    len -= offset;
    if (len > length) 
      len = length;
-   
+#ifdef OLDKERN   
    restore_flags(flags);
-   
+#else
+   spin_unlock_irqrestore(&proc_lock, flags);
+#endif   
    return len;
 }
 
@@ -2292,6 +2599,4 @@
 #endif
 
 /*--------------------------------------------------------------------*/
-
-
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)