--- /dev/null
+
+
+ -=< The IBM Microchannel SCSI-Subsystem >=-
+
+ for the IBM PS/2 series
+
+ Low Level Software-Driver for Linux
+
+ Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU
+ General Public License. Originally written by Martin Kolinek, December 1995.
+ Officially maintained by Michael Lang since January 1999.
+
+ Version 3.1e
+
+
+ Last update: 20 February 1999
+
+
+ Authors of this Driver
+ ----------------------
+ - Chris Beauregard (improvement of the SCSI-device mapping by the driver)
+ - Martin Kolinek (origin, first release of this driver)
+ - Klaus Kudielka (multiple SCSI-host management/detection, adaption to
+ Linux Kernel 2.1.x, module support)
+ - Michael Lang (assigning original pun,lun mapping, dynamical ldn
+ assignment, this file, patch, official driver maintenance)
+
+ Table of Contents
+ -----------------
+ 1 Abstract
+ 2 Driver Description
+ 2.1 IBM SCSI-Subsystem Detection
+ 2.2 Physical Units, Logical Units, and Logical Devices
+ 2.3 SCSI-Device Recognition and dynamical ldn Assignment
+ 2.4 SCSI-Device Order
+ 2.5 Regular SCSI-Command-Processing
+ 2.6 Abort & Reset Commands
+ 2.7 Disk Geometry
+ 2.8 Kernel Boot Option
+ 2.9 Driver Module Support
+ 2.10 Multiple Hostadapter Support
+ 2.11 /proc/scsi-Filesystem Information
+ 2.12 /proc/mca-Filesystem Information
+ 2.13 Supported IBM SCSI-Subsystems
+ 2.14 Linux Kernel Versions
+ 3 Code History
+ 4 To do
+ 5 Users' Manual
+ 5.1 Commandline Parameters
+ 5.2 Troubleshooting
+ 5.3 Bugreports
+ 5.4 Support WWW-page
+ 6 References
+ 7 Trademarks
+
+ * * *
+
+ 1 Abstract
+ ----------
+ This README-file describes the IBM SCSI-subsystem low level driver for
+ Linux. The descriptions which were formerly kept in the source-code have
+ been taken out to this file to easify the codes' readability. The driver
+ description has been updated, as most of the former description was already
+ quite outdated. The history of the driver development is also kept inside
+ here. Multiple historical developments have been summarized to shorten the
+ textsize a bit. At the end of this file you can find a small manual for
+ this driver and hints to get it running even on your machine (hopefully).
+
+ 2 Driver Description
+ --------------------
+ 2.1 IBM SCSI-Subsystem Detection
+ --------------------------------
+ This is done in the ibmmca_detect() function. It first checks, if the
+ Microchannel-bus support is enabled, as the IBM SCSI-subsystem needs the
+ Microchannel. In a next step, a free interrupt is chosen and the main
+ interrupt handler is connected to it to handle answers of the SCSI-
+ subsystem(s). In a further step, it is checked, wether there was a forced
+ detection of the adapter via the kernel commandline, where the I/O port
+ and the SCSI-subsystem id can be specified. The next step checks if there
+ is an integrated SCSI-subsystem installed. This register area is fixed
+ through all IBM PS/2 MCA-machines and appears as something like a virtual
+ slot 10 of the MCA-bus. If POS-register 2 is not 0xff, there must be a SCSI-
+ subsystem present and it will be registered as IBM Integrated SCSI-
+ Subsystem. The next step checks, if there is a slot-adapter installed on
+ the MCA-bus. To get this, the first two POS-registers, that represent the
+ adapter ID are checked. If they fit to one of the ids, stored in the
+ adapter list, a SCSI-subsystem is assumed to be found and will be
+ registered. This check is done through all possible MCA-bus slots to allow
+ more than one SCSI-adapter to be present in the PS/2-system and this is
+ already the first point of problems. Looking into the technical reference
+ manual for the IBM PS/2 common interfaces, the POS2 register must have
+ different interpretation of its single bits. While one can assume, that the
+ integrated subsystem has a fix I/O-address at 0x3540 - 0x3547, further
+ installed IBM SCSI-adapters must use a different I/O-address. This is
+ expressed by bit 1 to 3 of POS2 (multiplied by 8 + 0x3540). Bits 2 and 3
+ are reserved for the integrated subsystem, but not for the adapters! The
+ following list shows, how the bits of POS2 and POS3 should be interpreted.
+
+ The POS2-register of all PS/2 models' integrated 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 (for ALL IBM SCSI-subsys.):
+ Bit 7 - 5 : SCSI ID
+ Bit 4 - 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. But (additional) slot-adapters must have another
+ configuration on pos2 in order to be enabled to use more than one IBM SCSI-
+ subsystem, e.g. for a network server. From tests with the IBM SCSI Adapter
+ w/cache, the POS2-register for slot adapters should be interpreted in the
+ following way:
+ Bit 7 - 4 : Chip Revision ID (Release)
+ Bit 3 - 1 : port offset factor ( * 8 + 0x3540 )
+ Bit 0 : Chip Enable (EN-Signal)
+
+ One day I found a patch in ibmmca_detect(), forcing the I/O-address to be
+ 0x3540 for integrated SCSI-subsystems, there was a remark placed, that on
+ integrated IBM SCSI-subsystems of model 56, the POS2 register was showing 5.
+ This means, that really for these models, POS2 has to be interpreted
+ sticking to the technical reference guide. In this case, the bit 2 (4) is
+ a reserved bit and may not be interpreted. These differences between the
+ adapters and the integrated controllers are taken into account by the
+ detection routine of the driver on from version >3.0g.
+
+ Every time, a SCSI-subsystem is discovered, the ibmmca_register() function
+ is called. This function checks first, if the requested area for the I/O-
+ address of this SCSI-subsystem is still available and assigns this I/O-
+ area to the SCSI-subsystem. There are always 8 sequential I/O-addresses
+ taken for each individual SCSI-subsystem found, which are:
+
+ Offset Type Permissions
+ 0 Command Interface Register 1 Read/Write
+ 1 Command Interface Register 2 Read/Write
+ 2 Command Interface Register 3 Read/Write
+ 3 Command Interface Register 4 Read/Write
+ 4 Attention Register Read/Write
+ 5 Basic Control Register Read/Write
+ 6 Interrupt Status Register Read
+ 7 Basic Status Register Read
+
+ After the I/O-address range is assigned, the host-adapter is assigned
+ to a local structure which keeps all adapter information needed for the
+ driver itself and the mid- and higher-level SCSI-drivers. The SCSI pun/lun
+ and the adapters' ldn tables are initialized and get probed afterwards by
+ the check_devices() function. If no further adapters are found,
+ ibmmca_detect() quits.
+
+ 2.2 Physical Units, Logical Units, and Logical Devices
+ ------------------------------------------------------
+ There can be up to 56 devices on the 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 the IBM SCSI-subsystem hides the complex
+ two-dimensional (pun,lun) organization from the operating system.
+ When the machine is powered-up (or rebooted), the embedded microprocessor
+ checks, on its own, all 56 possible (pun,lun) combinations, and the 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.
+
+ 2.3 SCSI-Device Recognition and dynamical ldn Assignment
+ --------------------------------------------------------
+ One consequence of information hiding is that the real (pun,lun)
+ numbers are also hidden. The two possibilities to get around this problem
+ is to offer fake pun/lun combinations to the operating system or to
+ delete the whole mapping of the adapter and to reassign the ldns, using
+ the immediate assign command of the SCSI-subsystem. At the beginning of the
+ development of this driver, the following approach was used:
+ First, the driver checked the ldn's (0 to 6) to find out which ldn's
+ have devices assigned. This was done by the functions 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.
+
+ In a second step of the driver development, the following improvement has
+ been applied: The first approach limited the number of devices to 7, far
+ fewer than the 15 that it could usem then it just maped ldn ->
+ (ldn/8,ldn%8) for pun,lun. We ended up with a real mishmash of puns
+ and luns, but it all seemed to work.
+
+ The latest development, which is implemented from the driver version 3.0
+ and later, realizes the device recognition in the following way:
+ The physical SCSI-devices on the SCSI-bus are probed via immediate_assign-
+ and device_inquiry-commands, that is all implemented in a completely new
+ made check_devices() subroutine. 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 reassignments on the SCSI-devices, until a certain device
+ looses its ldn again. This assures, that dynamical remapping is avoided
+ during intense I/O between up to 15 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,
+ because the driver just won't assign everything with lun>0 when
+ multpile lun probing is inactive.
+
+ 2.4 SCSI-Device Order
+ ---------------------
+ 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. But there exists a feature of this driver that allows you to change
+ the assignment order of the SCSI-devices by flipping the PUN-assignment.
+ See the next paragraph for a description.
+
+ The problem for this 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, which you set while configuring the
+ kernel enables 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 and OSes, like e.g. OS-9. 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
+ in section 3.
+
+ 2.5 Regular SCSI-Command-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,
+ the interrupt_handler() is invoked. If a device is determined to be
+ existant and it has not assigned any ldn, it gets one dynamically.
+ For this, the whole stuff is done in ibmmca_queuecommand().
+
+ 2.6 Abort & Reset Commands
+ --------------------------
+ These are implemented with busy waiting for interrupt to arrive.
+ ibmmca_reset() and ibmmca_abort() do not work sufficently well
+ up to now and need still a lot of development work. But, this seems
+ to be even a problem with other SCSI-low level drivers, too. However,
+ this should be no excuse.
+
+ 2.7 Disk Geometry
+ -----------------
+ The ibmmca_biosparams() function should return the same disk geometry
+ as the bios. This is needed for fdisk, etc. The returned geometry is
+ certainly correct for disks smaller than 1 gigabyte. In the meantime,
+ it has been proved, that this works fine even with disks larger than
+ 1 gigabyte.
+
+ 2.8 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.
+
+ 2.9 Driver Module Support
+ -------------------------
+ Is implemented and tested by K. Kudielka. This could probably not work
+ on kernels <2.1.0.
+
+ 2.10 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.
+
+ 2.11 /proc/scsi-Filesystem Information
+ --------------------------------------
+ Information about the driver condition is given in
+ /proc/scsi/ibmmca/<host_no>. ibmmca_proc_info() provides this information.
+
+ This table is quite informative for interested users. It shows the load
+ of commands on the subsystem and wether you are running the bypassed
+ (software) or integrated (hardware) SCSI-command set (see below). The
+ amount of accesses is shown. Read, write, modeselect is shown seperately
+ in order to help debugging problems with CD-ROMs or tapedrives.
+
+ The following table shows the list of 15 logical device numbers, that are
+ used by the SCSI-subsystem. The load on each ldn is shown in the table,
+ again, read and write commands are split. The last column shows the amount
+ of reassignments, that have been applied to the ldns, if you have more than
+ 15 pun/lun combinations available on the SCSI-bus.
+
+ The last two tables show the pun/lun map and the positions of the ldns
+ on this pun/lun map. This may change during operation, when a ldn is
+ reassigned to another pun/lun combination. If the necessity for dynamical
+ assignments is set to 'no', the ldn structure keeps static.
+
+ 2.12 /proc/mca-Filesystem Information
+ -------------------------------------
+ The slot-file contains all default entries and in addition chip and I/O-
+ address information of the SCSI-subsystem. This information is provided
+ by ibmmca_getinfo().
+
+ 2.13 Supported IBM SCSI-Subsystems
+ ----------------------------------
+ The following IBM SCSI-subsystems are supported by this driver:
+
+ - IBM Fast SCSI-2 Adapter
+ - IBM 7568 Industrial Computer SCSI Adapter w/cache
+ - IBM Expansion Unit SCSI Controller
+ - IBM SCSI Adapter w/Cache
+ - IBM SCSI Adapter
+ - IBM Integrated SCSI Controller
+
+ 2.14 Linux Kernel Versions
+ --------------------------
+ The IBM SCSI-subsystem low level driver is prepared to be used with
+ all versions of Linux between 2.0.x and 2.2.x. The compatibility checks
+ are fully implemented up from version 3.1e of the driver. This means, that
+ you just need the latest ibmmca.h and ibmmca.c file and copy it in the
+ linux/drivers/scsi directory. The code is automatically adapted during
+ kernel compilation.
+
+ 3 Code 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
+
+ Jan 18, 1999: (v3.1 MCA-team internal)
+ 1) The multiple hosts structure is accessed from every subroutine, so there
+ is no longer the address of the device structure passed from function
+ to function, but only the hostindex. A call by value, nothing more. This
+ should really be understood by the compiler and the subsystem should get
+ the right values and addresses.
+ 2) The SCSI-subsystem detection was not complete and quite hugely buggy up
+ to now, compared to the technical manual. The interpretation of the pos2
+ register is not as assumed by people before, therefore, I dropped a note
+ in the ibmmca_detect function to show the registers' interpretation.
+ The pos-registers of integrated SCSI-subsystems do not contain any
+ information concerning the IO-port offset, really. Instead, they contain
+ some info about the adapter, the chip, the NVRAM .... The I/O-port is
+ fixed to 0x3540 - 0x3547. There can be more than one adapters in the
+ slots and they get an offset for the I/O area in order to get their own
+ I/O-address area. See chapter 2 for detailed description. At least, the
+ detection should now work right, even on models other than 95. The 95ers
+ came happily around the bug, as their pos2 register contains always 0
+ in the critical area. Reserved bits are not allowed to be interpreted,
+ therefore, IBM is allowed to set those bits as they like and they may
+ really vary between different PS/2 models. So, now, no interpretation
+ of reserved bits - hopefully no trouble here anymore.
+ 3) The command error, which you may get on models 55, 56, 57, 70, 77 and
+ P70 may have been caused by the fact, that adapters of older design do
+ not like sending commands to non-existing SCSI-devices and will react
+ with a command error as a sign of protest. While this error is not
+ present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
+ Adapters. Therefore, I implemented a workarround to forgive those
+ adapters their protests, but it is marked up in the statisctis, so
+ after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
+ how often the command errors have been forgiven to the SCSI-subsystem.
+ If the number is bigger than 0, you have a SCSI subsystem of older
+ design, what should no longer matter.
+ 4) ibmmca_getinfo() has been adapted very carefully, so it shows in the
+ slotn file really, what is senseful to be presented.
+ 5) ibmmca_register() has been extended in its parameter list in order to
+ pass the right name of the SCSI-adapter to Linux.
+ - Michael Lang
+
+ Feb 6, 1999: (v3.1)
+ 1) Finally, after some 3.1Beta-releases, the 3.1 release. Sorry, for
+ the delayed release, but it was not finished with the release of
+ Kernel 2.2.0.
+ - Michael Lang
+
+ Feb 10, 1999 (v3.1)
+ 1) Added a new commandline parameter called 'bypass' in order to bypass
+ every integrated subsystem SCSI-command consequently in case of
+ troubles.
+ 2) Concatenated read_capacity requests to the harddisks. It gave a lot
+ of troubles with some controllers and after I wanted to apply some
+ extensions, it jumped out in the same situation, on my w/cache, as like
+ on D. Weinehalls' Model 56, having integrated SCSI. This gave me the
+ descissive hint to move the code-part out and declare it global. Now,
+ it seems to work by far much better an more stable. Let us see, what
+ the world thinks of it...
+ 3) By the way, only Sony DAT-drives seem to show density code 0x13. A
+ test with a HP drive gave right results, so the problem is vendor-
+ specific and not a problem of the OS or the driver.
+ - Michael Lang
+
+ Feb 18, 1999 (v3.1d)
+ 1) The abort command and the reset function have been checked for
+ inconsistencies. From the logical point of thinking, they work
+ at their optimum, now, but as the subsystem does not answer with an
+ interrupt, abort never finishes, sigh...
+ 2) Everything, that is accessed by a busmaster request from the adapter
+ is now declared as global variable, even the return-buffer in the
+ local checking phase. This assures, that no accesses to undefined memory
+ areas are performed.
+ 3) In ibmmca.h, the line unchecked_isa_dma is added with 1 in order to
+ avoid memory-pointers for the areas higher than 16MByte in order to
+ be sure, it also works on 16-Bit Microchannel bus systems.
+ 4) A lot of small things have been found, but nothing that endangered the
+ driver operations. Just it should be more stable, now.
+ - Michael Lang
+
+ Feb 20, 1999 (v3.1e)
+ 1) I took the warning from the Linux Kernel Hackers Guide serious and
+ checked the cmd->result return value to the done-function very carefuly.
+ It is obvious, that the IBM SCSI only delivers the tsb.dev_status, if
+ some error appeared, else it is undefined. Now, this is fixed. Before
+ any SCB command gets queued, the tsb.dev_status is set to 0, so the
+ cmd->result won't screw up Linux higher level drivers.
+ 2) The reset-function has slightly improved. This is still planed for
+ abort. During the abort and the reset function, no interrupts are
+ allowed. This is however quite hard to cope with, so the INT-status
+ register is read. When the interrupt gets queued, one can find its
+ status immediately on that register and is enabled to continue in the
+ reset function. I had no chance to test this really, only in a bogus
+ situation, I got this function running, but the situation was too much
+ worse for Linux :-(, so tests will continue.
+ 3) Buffers got now consistent. No open address mapping, as before and
+ therefore no further troubles with the unassigned memory segmentation
+ faults that scrambled probes on 95XX series and even on 85XX series,
+ when the kernel is done in a not so perfectly fitting way.
+ 4) Spontaneous interrupts from the subsystem, appearing without any
+ command previously queued are answered with a DID_BAD_INTR result.
+ 5) Taken into account ZP Gus' proposals to reverse the SCSI-device
+ scan order. As it does not work on Kernel 2.1.x or 2.2.x, as proposed
+ by him, I implemented it in a slightly derived way, which offers in
+ addition more flexibility.
+ - Michael Lang
+
+ 4 To do
+ -------
+ - 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 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. (<--- This is coming soon!!!!)
+ - Abort and Reset functions still slightly buggy or better say,
+ it is the new episode, called SCREAM III.
+
+ 5 Users' Manual
+ ---------------
+ 5.1 Commandline Parameters
+ --------------------------
+ There exist several features for the IBM SCSI-subsystem driver.
+ The commandline parameter format is:
+
+ ibmmcascsi=<command1>,<command2>,<command3>,...
+
+ where commandN can be one of the following:
+
+ display Owners of a model 95 or other PS/2 systems with an
+ alphanumeric LED display may set this to have their
+ display showing the following output of the 8 digits:
+
+ ------DA
+
+ where '-' stays dark, 'D' shows the SCSI-device id
+ and 'A' shows the SCSI hostindex, beeing currently
+ accessed.
+ adisplay This works like display, but gives more optical overview
+ of the activities on the SCSI-bus. The display will have
+ the following output:
+
+ 6543210A
+
+ where the numbers 0 to 6 light up at the shown position,
+ when the SCSI-device is accessed. A shows again the SCSI
+ hostindex. If display nor adisplay is set, the internal
+ PS/2 harddisk LED is used for media-activities. So, if
+ you really do not have a system with a LED-display, you
+ should not set display or adisplay.
+ bypass This commandline parameter forces the driver never to use
+ SCSI-subsystems' integrated SCSI-command set. Except of
+ the immediate assign, which is of vital importance for
+ every IBM SCSI-subsystem to set its ldns right. Instead,
+ the ordinary ANSI-SCSI-commands are used and passed by the
+ controller to the SCSI-devices, therefore 'bypass'. The
+ effort, done by the subsystem is quite bogus and at a
+ minimum and therefore it should work everywhere. This
+ could maybe solve troubles with old or integrated SCSI-
+ controllers and nasty harddisks. Keep in mind, that using
+ this flag will slow-down SCSI-accesses slightly, as the
+ software generated commands are always slower than the
+ hardware. Non-harddisk devices always get read/write-
+ commands in bypass mode.
+ normal This is the parameter, introduced on the 2.0.x development
+ rail by ZP Gu. This parameter defines the SCSI-device
+ scan order in the new industry standard. This means, that
+ the first SCSI-device is the one with the lowest pun.
+ E.g. harddisk at pun=0 is scanned before harddisk at
+ pun=6, which means, that harddisk at pun=0 gets sda
+ and the one at pun=6 gets sdb.
+ ansi The ANSI-standard for the right scan order, as done by
+ IBM, Microware and Microsoft, scans SCSI-devices starting
+ at the highest pun, which means, that e.g. harddisk at
+ pun=6 gets sda and a harddisk at pun=0 gets sdb. If you
+ like to have the same SCSI-device order, as in DOS, OS-9
+ or OS/2, just use this parameter.
+
+ A further option is that you can force the SCSI-driver to accept a SCSI-
+ subsystem at a certain I/O-address with a predefined adapter PUN. This
+ is done by entering
+
+ commandN = I/O-base
+ commandN+1 = adapter PUN
+
+ e.g. ibmmcascsi=0x3540,7 will force the driver to detect a SCSI-subsystem
+ at I/O-address 0x3540 with adapter PUN 7.
+
+ Examples:
+
+ ibmmcascsi=adisplay,bypass
+
+ This will use the advanced display mode for the model 95 LED display and
+ every SCSI-command passed to a attached device will get bypassed in order
+ not to use any of the subsystem built-in commands.
+
+ ibmmcascsi=display,0x3558,7
+
+ This will activate the default display mode for the model 95 LED display
+ and will force the driver to accept a SCSI-subsystem at I/O-base 0x3558
+ with adapter PUN 7.
+
+ 5.2 Troubleshooting
+ -------------------
+ The following FAQs should help you to solve some major problems with this
+ driver.
+
+ Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
+ A: This is only tested with the IBM SCSI Adapter w/cache. It is not
+ yet prooved to run on other adapters, however you may be lucky.
+ In version 3.1d this has been hugely improved and should work better,
+ now. Normally you really won't need to activate this flag in the
+ kernel configuration, as all post 1989 SCSI-devices should accept
+ the reset-signal, when the computer is switched on. The SCSI-
+ subsystem generates this reset while beeing initialized. This flag
+ is really reserved for users with very old, very strange or self-made
+ SCSI-devices.
+ Q: Why is the SCSI-order of my drives mirrored to the device-order
+ seen from OS/2 or DOS ?
+ A: It depends on the operating system, if it looks at the devices in
+ ANSI-SCSI-standard (starting from pun 6 and going down to pun 0) or
+ if it just starts at pun 0 and counts up. If you want to be conform
+ with OS/2 and DOS, you have to activate this flag in the kernel
+ configuration or you should set 'ansi' as parameter for the kernel.
+ The parameter 'normal' sets the new industry standard, starting
+ from pun 0, scaning up to pun 6. This allows you to change your
+ opinion still after having already compiled the kernel.
+ Q: Why can I not find the IBM MCA SCSI support in the config menue?
+ A: You have to activate MCA bus support, first.
+ Q: Where can I find the latest info about this driver?
+ A: See the file MAINTAINERS for the current WWW-address, which offers
+ updates, info and Q/A lists. At this files' origin, the webaddress
+ was: http://www.uni-mainz.de/~langm000/linux.html
+ Q: My SCSI-adapter is not recognized by the driver, what can I do?
+ A: Just force it to be recognized by kernel parameters. See section 5.1.
+ Q: The driver screws up, if it starts to probe SCSI-devices, is there
+ some way out of it?
+ A: This is based on some problems with the driver. In such cases, send
+ e-mail to the maintainer. If you are owner of a model with the serial
+ number 95XX, just send as subject NOTIFY 95XX PROBLEM and the
+ maintainer immediately knows about your problem. But please:
+ Check your hardware and only if it works fine with other operating
+ systems, send E-Mail to me to notify the troubles. See the homepage
+ for how to send bug-reports or please read the next Q/A, here:
+ Q: I get a message: panic IBM MCA SCSI: command error .... , what can
+ I do against this?
+ A: Previously, I followed the way by ignoring command errors by using
+ ibmmcascsi=forgiveall, but this command no longer exists and is
+ obsolete. If such a problem appears, it is caused by some segmentation
+ fault of the driver, which maps to some unallowed area. The latest
+ version of the driver should be ok, as most bugs have been solved.
+ Q: There are still kernel panics, even after having set
+ ibmmcascsi=forgiveall. Are there other possibilities to prevent
+ such panics?
+ A: No, get just the latest release of the driver and it should work
+ better and better with increasing version number. Forget this
+ ibmmcascsi=forgiveall, as also ignorecmd are obsolete.
+ Q: Linux panics or stops without any comment, but it is probable, that my
+ harddisk(s) have bad blocks.
+ A: Sorry, the bad-block handling is still a feeble point of this driver,
+ but is on the schedule for development in the near future.
+ Q: Linux panics while dynamically assigning SCSI-ids or ldns.
+ A: If you disconnect a SCSI-device from the machine, while Linux is up
+ and the driver uses dynamical reassignment of logical device numbers
+ (ldn), it really gets "angry" if it won't find devices, that were still
+ present at boottime and stops Linux.
+ Q: The system does not recover after an abort-command has been generated.
+ A: This is regrettably true, as it is not yet understood, why the
+ SCSI-adapter does really NOT generate any interrupt at the end of
+ the abort-command. As no interrupt is generated, the abort command
+ cannot get finished and the system hangs, sorry, but checks are
+ running to hunt down this problem. If there is a real pending command,
+ the interrupt MUST get generated after abort. In this case, it
+ should finish well.
+ Q: The system gets in bad shape after a SCSI-reset, is this known?
+ A: Yes, as there are a lot of prescriptions (see the Linux Hackers'
+ Guide) what has to be done for reset, we still share the bad shape of
+ the reset functions with all other low level SCSI-drivers.
+ Astonishingly, reset works in most cases quite ok, but the harddisks
+ won't run in synchonous mode anymore after a reset, until you reboot.
+ Q: Why does my XXX w/Cache adapter not use read-prefetch?
+ A: w/Cache technical manuals are incoming here, so if I understood the
+ command of read-prefetch, it should be an easy thing to get harddisks
+ read in read-prefetch with w/Cache controllers. Some weeks or months,
+ still ahead and a lot of work still to do, sigh ...
+
+ 5.3 Bugreports
+ --------------
+ If you really find bugs in the sourcecode or the driver will successfully
+ refuse to work on your machine, you should send a bug report to me. The
+ best for this is to follow the instructions on the WWW-page for this
+ driver. Fill out the bug-report form, placed on the WWW-page and ship it,
+ so the bugs can be taken into account with maximum efforts. But, please
+ do not send bug reports about this driver to Linus Torvalds or Leonard
+ Zubkoff, as Linus is burried in E-Mail and Leonard is supervising all
+ SCSI-drivers and won't have the time left to look inside every single
+ driver to fix a bug and especially DO NOT send modified code to Linus
+ Torvalds, which has not been checked here!!! Recently, I got a lot of
+ bugreports for errors in the ibmmca.c code, which I could not imagine, but
+ a look inside some Linux-distribution showed me quite often some modified
+ code, which did no longer work on most other machines than the one of the
+ modifier. Ok, so now that there is maintenance service available for this
+ driver, please use this address first in order to keep the level of
+ confusion low. Thank you!
+
+ When you get a SCSI-error message that panics your system, a list of
+ register-entries of the SCSI-subsystem is shown (from Version 3.1d). With
+ this list, it is very easy for the maintainer to localize the problem in
+ the driver or in the configuration of the user. Please write down all the
+ values from this report and send them to the maintainer. This would really
+ help a lot and makes life easier concerning misunderstandings.
+
+ Use the bug-report form (see 5.4 for its address) to send all the bug-
+ stuff to the maintainer or write e-mail with the values from the table.
+
+ 5.4 Support WWW-page
+ --------------------
+ The address of the IBM SCSI-subsystem supporting WWW-page is:
+
+ http://www.uni-mainz.de/~langm000/linux.html
+
+ Here you can find info about the background of this driver, patches,
+ news and a bugreport form.
+
+ 6 References
+ ------------
+ 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. E.g. in Germany, "Hallo IBM" works really great.
+ 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).
+
+ 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
+
+ Helmut Rompel, "IBM Computerwelt GUIDE", What is what bei IBM., Systeme *
+ Programme * Begriffe, IWT-Verlag GmbH - Muenchen, 1988
+
+ 7 Trademarks
+ ------------
+ IBM, PS/2, OS/2, Microchannel are registered trademarks of International
+ Business Machines Corp.
+
+ MS-DOS is a registered trademark of Microsoft Corporation
+
+ OS-9 is a registered trademark of Microware Systems
+
+------
+Michael Lang
+(langa2@kph.uni-mainz.de)
*
* 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>
#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"
#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: */
#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
/* 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); \
}
#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); \
}
/* 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
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
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 */
/* 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. */
#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
/*-----------------------------------------------------------------------*/
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;
-
- /* 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");
- }
+ 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;
+
+ 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);
+ 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 ();
+ }
+ }
- /*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);
- }
-
- /*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);
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)
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("-");
}
/* 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];
}
/*
- 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 */
- }
+ 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[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++;
- }
+ 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. */
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_l(get_ldn[id][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(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));
-
- return;
+ printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
+
+ /* 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));
+
+ return;
}
/*--------------------------------------------------------------------*/
-static int
-device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length,
- int *device_type)
+static int device_exists (int host_index, 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;
- }
-
- 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;
-}
-
-/*--------------------------------------------------------------------*/
-
-#ifdef CONFIG_SCSI_IBMMCA
+ 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));
-void
-ibmmca_scsi_setup (char *str, int *ints)
-{
- 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];
- }
- }
-}
+ /*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
+
+void ibmmca_scsi_setup (char *str, int *ints)
+{
+ 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;
+}
#endif
/*--------------------------------------------------------------------*/
-int
-ibmmca_detect (Scsi_Host_Template * template)
+static int ibmmca_getinfo (char *buf, int slot, void *dev)
{
- 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;
-
- /*
- * 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");
- }
-
- return found;
+ 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");
+
+#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;
-
- /* 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;
-
- /* an ibm mca subsystem has been detected */
- return shpnt;
+ 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);
+
+ 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 */
+
+ 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;
/*--------------------------------------------------------------------*/
-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))
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,
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;
- }
-
- /*issue scb command, and return */
- issue_cmd (shpnt, virt_to_bus(scb), IM_SCB | ldn);
- return 0;
+ 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;
+
+ 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 ;
+ /* 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;
-#if 0
- struct Scsi_host *shpnt = cmd->host;
- unsigned int ldn;
- void (*saved_done) (Scsi_Cmnd *);
+ /* return SCSI_ABORT_SNOOZE ; */
-#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
- int target = 6 - cmd->target;
+#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 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;
+ /*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;
+ }
+
+ /* 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;
-
- 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;
- }
-
- /* 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;
+ 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(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;
+ }
+
+ /* 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);
}
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
#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;
}
/*--------------------------------------------------------------------*/
-
-